LINUX.ORG.RU

Стратегии атомарной записи в файлы.


0

2

1) ext3fs, NTFS, др. распространённые системы гарантируют последовательность записи? Если я сказал записать 4096 байт в конец файла, потом передвинул на начало 3-гигового файла и записал в начало 512 байт, то может оказаться так, что 512 байт в начале окажутся записанными, а 4096 в конце диск/система хитро запланируют записать потом? Я хочу выделить 3 гигабайта места, начать туда записывать, а подтверждение готовности всей бодяги выразить в наличии в начале файла 512 специальных байтов. Если при открытии такого файла в начале есть кодовые 512 байт, значит всё что было нужно записать в остальной части файла — уже записалось. Я понимаю, что в реальности тяжёлая радиация попортит сектора в любой момент и не спасут никакие флаги и заголовки, надо контрольную сумму всего барахла считать, но куле, это Васе понятно. Вопрос про здоровый диск, но с выдёргиванием шнура питания.

2) Допустим я открою один файл, долго буду его записывать 3 гига данных, потом создам рядом файл «ready» нулевой длины как атомарный способ обозначения факта готовности снепшота. При этом я не вызываю fsync() всяких, а просто соблюдаю последовательность. Всё идёт через буферы ФС с отложенной записью. Дёргаю шнур питалова в неопределённый момент. Потом я открываю каталог и смотрю — если лежит «ready» нулевой длины, значит 3-гиговый файл точно дописалсо, иначе бекап считается просранным. Может ли так оказаться, что ФС сработает так, что «ready» будет лежать, а хвост 3-гигового файла ФС ещё только собиралась дописывать? Я куею.

1) Этот кейс с 512 байтами должен гарантированно работать, если драйвер ФС posix-совместимый. Читаем документацию по write() из POSIX:

Writes can be serialized with respect to other reads and writes. If a read() of file data can be proven (by any means) to occur after a write() of the data, it must reflect that write(), even if the calls are made by different processes. A similar requirement applies to multiple write operations to the same file position. This is needed to guarantee the propagation of data from write() calls to subsequent read() calls. This requirement is particularly significant for networked file systems, where some caching schemes violate these semantics.

Note that this is specified in terms of read() and write(). The XSI extensions readv() and writev() also obey these semantics. A new «high-performance» write analog that did not follow these serialization requirements would also be permitted by this wording. This volume of POSIX.1-2008 is also silent about any effects of application-level caching (such as that done by stdio).

2) Вряд ли тут есть какие-либо гарантии

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

If a read() of file data can be proven (by any means) to occur after a write() of the data, it must reflect that write(), even if the calls are made by different processes.

Если умножить это на выдергивание шнура питания, то получаем что каждый write(), прежде чем вернуть управление, обязан сперва дождаться, что данные легли на пластины НЖМД.

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 2)

Я куею.

Да, я тоже. Очень жаль, что fsync-и есть, а вот аналогичных barrier-ов не предусмотрено.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

Да, гарантированная последовательность записи при выдергиваниях шнуров питания не гарантируется, пожалуй. :) Речь только о когерентности read() / write(), но не более.

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

То есть, если когерентность read() / write() есть, то на деле может оказаться, что выполненная запись в начало файла после записи в конец файла может реально записаться первой, а конец остаться недописанным?

kiverattes ★☆
() автор топика

Просто делай fsync в нужных точках, тебе что тяжело? Просто пока что выглядит как «Я разогнался и с размаху головой об стену как бабахну. Теперь голова болит. Я куею»

vertexua ★★★★★
()

Насколько мне известно, в обоих случаях фейл, т. е. никаких гарантий. Потому что writeback.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от Manhunt

Если нечасто, только в контрольных точках - то норм. Обычно можно ухитриться чтобы делать такие вещи раз в минуту например

vertexua ★★★★★
()
Ответ на: комментарий от kiverattes

Нет, потому что read() вправе прочитать из буфера в памяти.

Сценарий следующий:
1. Жду возврата write();
2. Жму на резет;
3. Делаю read().

Из какого буфера read теперь должен прочитать, чтобы гарантированно увидеть мой (кагбе завершившийся!!!!) write?

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

Если умножить это на выдергивание шнура питания, то получаем что каждый write(), прежде чем вернуть управление, обязан сперва дождаться, что данные легли на пластины НЖМД.

При синхронной записи так и происходит. Другое дело, что ФС любят монтировать с опциями, разрешающими асинхронную запись(тот же barrier на ext4, async/sync на NFS). Но обычно дефолтный вариант(sync в NFS, barrier=1 в ext4) - более безопасный, но менее производительный

Pinkbyte ★★★★★
()
Ответ на: комментарий от Manhunt

Это здорово ударяет по производительности.

А тут нужно решать, что важнее - шашечки(скорость работы) или ехать(сохранность данных). Потому что одновременно не потеряв ни в чём получить это не удастся. Чем-то придется пожертвовать.

Pinkbyte ★★★★★
()
Ответ на: комментарий от Pinkbyte

Но обычно дефолтный вариант(sync в NFS, barrier=1 в ext4) - более безопасный, но менее производительный

Мы говорим сейчас о гарантиях, а не о «более-менее». Так вот в ext4 по умолчанию активирован delayed allocation (https://www.kernel.org/doc/Documentation/filesystems/ext4.txt) , поэтому никаких гарантий что твой write будет виден после резета у тебя нет.

PS Я проверял экспериментально, на самом деле даже цепочка open+write+close+rename на ext4 запросто даёт переименованные файлы нулевого размера. По-крайней мере, при условии, что rename не перезатирает какой-то из существующих файлов.

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

А тут нужно решать, что важнее - шашечки(скорость работы) или ехать(сохранность данных). Потому что одновременно не потеряв ни в чём получить это не удастся. Чем-то придется пожертвовать.

Ты ОП читал вообще? Нужна не сохранность данных как таковая, а способ узнать на этапе рекавери, что определенная порция данных самом деле записались полностью. Это абсолютно разные вещи. Потери производительности были бы на много порядков меньше, если программа могла вместо sync-ов заказывать barrier-ы.

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 1)
Ответ на: комментарий от Manhunt

Вопрос не в сохранности данных после резета, а в сохранности последовательности после резета. То есть, чтобы то, что было сделано после чего-то не было после резета видно, как будто сделано ДО этого чего-то.

kiverattes ★☆
() автор топика
Ответ на: комментарий от Manhunt

Ну не в этом был вопрос. Что всё с диском не синхронизировано всем и так понятно. Вопрос был про последовательности.

kiverattes ★☆
() автор топика

привет мриадус
давно не виделись. Работу-то нашел?

Progressive
()
Ответ на: комментарий от Manhunt

способ узнать на этапе рекавери, что определенная порция данных самом деле записались полностью

Синхронная запись, отсутствие всяких отложенных аллокаций, кешей на запись(привет ZFS) и прочего, не?

Pinkbyte ★★★★★
()
Ответ на: комментарий от Pinkbyte

кешей на запись(привет ZFS)

А кто мешает использовать синхронную запись zfs? ZIL на зеркало из ssd/flash и никаких проблем.

EvgGad_303 ★★★★★
()
Ответ на: комментарий от EvgGad_303

Я не говорил что это невозможно, я лишь указал на дефолт. Почти все ФС нынче дают более-менее усредненные дефолтные настройки сохранность данных/скорость. Кто-то больше, кто-то меньше. Всё можно настроить, ZFS не исключение, даже более - с ZIL можно веселые вещи творить :-)

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)

Если обстрагироватся от конкретной ФС с конкретными настройками и предположить что задача запускается хз на какой системе с ХЗ какой ФС то ни в первом ни во втором случае гарантий нету. Нужны гарантии - делай sync (только в первом случае тебе достаточно засинхронизировать файл, во втором нужно синхронизировать всю ФС).

Теперь вода: Проблема в том что работа с диском на уровне ядря идет грубо говоря 2х уровняя. Уровень 1 - ФС который обробытывает всякие опен/read/write и тд. и передает это все на уровень 2 - подсистему блочного ввода/вывода (BIO) в виде запроса прочитать блок #x записать блок #y в какой последовательности эти запросы будут обробатыватся на уровне BIO ФС не занет и в принципе знать ей и не нужно. Задача же BIO заключается в том чтоб максимально эффэктивно использовать железо (как правило HDD) и соотвецтвенно запросы могут выполнятся в порядке отличном от того в котором они поступали. Если задача решается под себя то можно настройками ядра (выбор политики BIO + ФС) добится справедливости пункта №1 но второй выглядет совсем печально для меня.

zaz ★★★★
()
Ответ на: комментарий от Manhunt

А если в конце каждой порции писать ее номер и контрольную сумму? При чтении пока все совпадает - живем.

AIv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.