LINUX.ORG.RU

C++: атомарно добавить в файл 128MB данных.

 ,


0

2

Предложите алгоритм.

Хочется добавить в файл 128MB данных, чтобы это переживало отрубание питалова в любой момент с такими последствиями: либо я вижу консистентные 128MB добавленных данных, либо я вижу некий кусок мусора с консистентным заголовком, из которого ясно какого точно размера мусор.

«добавить в файл» не означает строго то, что файл надо открыть в режиме O_APPEND и буквально добавить. Файл на пару гигов можно выделить заранее и манипулировать какими-то страницами в нём.

Т.е. хочется чего-то типа double-buffer, когда сначала куча страниц пишется в специальную временную область файла, потом вызывается fsync(), а потом они пишутся в нормальное место. Если в процессе записи в нормальное место рубанут питалово, то процесс находит во временном буфере то, что недописалось в «нормальное место» и пишет это туда. Ну в общем, интересуют всякие такие истории, не буквально этот подход.

Вся эта тема предполагает некоторые атомарные операции с файлом (сектор HDD, меньше которого нельзя записать; или даже несколько дорог в черепичной записи, меньше которых черепичный HDD не умеет записывать). Скажем, если размер атомарной записи = 512 байт, то нужно ещё и выравнивать - нельзя с позиции 12 записать 512 байт, ведь такая запист будет физически из 2 кусков - 512 + 512 — первый для 500, второй для 12.

Короче, куда копать?

скопировать файл, добавить в него, затем mv поверх старого,

но если у тебя файл большой, или добавлять часто то есесно это не выход

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

Следи за хешем файла (или его частей), как вариант.

peregrine ★★★★★
()

Возможно, стоит посмотреть в сторону конфига размеров страницы и когерентности mmap (не уверен что оно так умеет).

Если контролируешь формат файла - проще и надёжнее писать блоками с контрольными суммами.

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

Ну и кстати. Причём тут c++?

Для привлечения внимания пытливых умов, хипстеры-то на вопрос не ответят.

hlamotron
() автор топика
Ответ на: комментарий от pon4ik

Если контролируешь формат файла - проще и надёжнее писать блоками с контрольными суммами.

А как писать блоками? Как определить размер блока, который запишется атомарно? И писать видимо обязательно с позиций кратных размеру блока?

hlamotron
() автор топика
Ответ на: комментарий от tailgunner

В конец данных добавляешь SHA1.

Начал писать 128MB (вызвал write(fd, buff, 128MB)), наполовине питалово сдохло, HDD успел дописать какой-то сектор и помер.

Потом начинаю читать файл - а там в конце какая-то херь и SHA1 нету. Как определить, что это херь?

hlamotron
() автор топика

Кури технику записи wal в субд.

TOXA ★★
()

Делай сначала append, потом fsync. Если все прошло удачно, в заголовке обнови указатель на новые данные

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

потом fsync

потом fdatasync(3), а потом ещё хорошенько помолиться :)

Если нужно совсем надёжно, то новый файл + rename(3).

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

Именно поэтому ты решил поставить хипстерский тег?

anonymous
()
Ответ на: комментарий от hlamotron

Для винчестера атомарный блок это сектор 512 байт. Для флешнакопителей без понятия, может кто просветит?

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

потом fdatasync(3), а потом ещё хорошенько помолиться :)

Нафиг fdatasync? fsync возвращается после физической записи буфера для данного дескриптора на диск. Что ещё нужно сверх того? А молиться почему?

hlamotron
() автор топика
Ответ на: комментарий от tailgunner

Используй SHA1.

У тебя sha1 в конце, он не дописался. У тебя в конце непонятный кусок мусора с неизвестным размером и без sha1 - его даже перешагнуть невозможно, весь файл считай кончился.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Не, писать блоками кратными степени двойки желательно но необязательно. Пишешь примерно так: в основной, а лучше в индексный файл - номер блока и контрольная сумма.

Размер блока видимо размер страницы mmap.

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

Не, писать блоками кратными степени двойки желательно но необязательно

Что даст именно степень двойки? Любая запись больше 1 сектора уже опасна, поэтому писать надо имено сектор по-моему.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Из этого ты можешь сделать вывод, что файл не дописался, и поступать как сам сочтешь нужным - игнорировать мусор, открывать WAL, писать письма пользователю или что-то еще.

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

Это если ты хочешь всё руками реализовать а не на откуп ОС отдать. А руками тебе дисковые кэши скорее всего всё равно не дадут, если ты не из ядра писать будешь.

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

Размер блока ФС, блока устройства, и размер страницы в общем случае не связаны (окей, блок ФС _обычно_ равен странице, но не всегда).

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

Просто сброс страницы вроде как атомарный в mmap, но я могу путать с виндой. Т.е. понятно что сама по себе операция неатомарна, но записанное будет считаться мусором на диске а не частью файла в случае отсутсвия финализации?

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

Просто сброс страницы вроде как атомарный в mmap

Ничего не знаю об атомарности mmap.

но записанное будет считаться мусором на диске а не частью файла в случае отсутсвия финализации?

Считаться кем? ФС всё равно.

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

Потому что журналируемые файловые системы гарантируют целостность файловой системы, а не твоих данных. Что произойдёт с открытыми на запись файлами при выключении питания - никто не знает.

Журнал для данных есть в ext3/4, но рукожопые китайцы умеют делать винты, которые рапортуют ОК, когда данные попали в кеш винта, а не на диск.

Так что только усердными молитвами мы сможем сохранить наши данные :)

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

Из этого ты можешь сделать вывод, что файл не дописался, и поступать как сам сочтешь нужным - игнорировать мусор, открывать WAL, писать письма пользователю или что-то еще.

Из чего «этого»? Я незнаю, дописался он или нет. Вначале блока у тебя нет размера этого блока...

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

fsync возвращается после физической записи буфера для данного дескриптора на диск

Ха-ха-ха! Нет.

https://lwn.net/Articles/457667/

Алсо тебе никто не гарантирует, что данные не осядут в кэше диска.

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

Кеш диска гарантированно дописывается при подрыве питания. Вроде. И неясно как тебе поможет fdatasync(), если fsync() не помогает. fdatasync() есть просто урезанная версия fsync(), которая типа дату модификации файла не пишет. Но fsync() уж точно делает всё, что делает fdatasync(). При том, где-то я читал, что современный линукс эти 2 функции одинаково выполняет абсолютно, т.е. fdatasync() апдейтит время модификации файла, насрав на спеку.

Короче, не убедил )

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Из чего «этого»?

Из несовпадения SHA1 с содержимым.

Я незнаю, дописался он или нет. Вначале блока у тебя нет размера этого блока...

Ты вроде спрашивал, как записать 128М, а сейчас не знаешь размер блока?

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

Кеш диска гарантированно дописывается при подрыве питания. Вроде.

Гарантированно и вроде в одном предложении - это прекрасно.

И неясно как тебе поможет fdatasync(), если fsync() не помогает.

Никак не поможет. Я лишь указал на то, что fsync() скорее всего не будет достаточно.

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

Ты вроде спрашивал, как записать 128М, а сейчас не знаешь размер блока?

Да, блок произвольного размера :)

hlamotron
() автор топика
Ответ на: комментарий от hateyoufeel

Никак не поможет. Я лишь указал на то, что fsync() скорее всего не будет достаточно.

Не, я не спорю. Просто хочу конструктива. Какие есть ещё варианты? По-поему картинка выглядит так: fsync() кладёт данные максимально хардварно, и да это может означать кеш диска. Но дисковый аппаратный кеш на запись может быть, исходя из здравого смысла, ограничен способностью диска при обрыве питания дописать это всё на винт. Иначе получится ситуация, когда при работающем оборудовании никто ничего не гарантирует, а это уже лютый бред. Поэтому у меня вот такая картинка, в котором fsync() оказывается железно достаточно, если диск не рехнулся.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

вообще ИБП спасает.... тем более если промышленное применение твоей системы. А так - могу посоветовать только смотреть в сторону контроллера с flash-backend buffer, который при пропадании питания сбросит кеш записи на флеш и только потом отключится. Причем контроллер(ы) желательно выделить отдельно под задачу, если уж данные такие важные.

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

Иначе получится ситуация, когда при работающем оборудовании никто ничего не гарантирует, а это уже лютый бред.

Это суровая реальность.

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

Некоторые ФС не следят за целостностью данных. При неудачном стечении обстоятельств часть данных на диске может получиться записаной с ошибками. Если хочется понадежнее, можно положить рядом с блоком хэш (как уже несколько раз посоветовали)

Deleted
()
Ответ на: комментарий от hateyoufeel

Это суровая реальность.

Твоя реальность как-то с реальной реальносью расходится, ведь даже обычные СУБД данных вообще не теряют при любом расколбасе питания, пока диск физически нормален.

hlamotron
() автор топика

Если рубанут питалово — то записанные данные гарантированно окажутся в конце (так как речь про добавление в конец). А значит, что если ты вначале запишешь, сколько их должно быть, а потом объём данных не сойдётся — удаляешь всё от размера до конца файла. Ну или я не понял, в чём сложность

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

Если рубанут питалово — то записанные данные гарантированно окажутся в конце (так как речь про добавление в конец). А значит, что если ты вначале запишешь, сколько их должно быть, а потом объём данных не сойдётся — удаляешь всё от размера до конца файла. Ну или я не понял, в чём сложность

Да, отлично, всё так.

hlamotron
() автор топика

чтобы это переживало отрубание питалова в любой момент

глюпий, может и пожар должно пережить? а ваще, кури транзацкии.

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

глюпий, может и пожар должно пережить? а ваще, кури транзацкии.

Инна, изабелла.

hlamotron
() автор топика
Ответ на: комментарий от tailgunner

Там описаны сбои дисков, а не СУБД.

Да, и? Это что-то меняет? Чувак утверждает, что СУБД магическим образом пишут на диск так что данные не теряются.

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

Да, и? Это что-то меняет? Чувак утверждает, что СУБД магическим образом пишут на диск так что данные не теряются.

Чувак этого не утверждал. Магии не существует. Чувак утверждал, что на исправном оборудовании есть способы гарантированно не просрать данные. Мы не рассматриваем случаи неисправного оборудования.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Мы не рассматриваем случаи неисправного оборудования.

Ты по ссылкам вообще ходишь? Там чуваки тестировали новые SSD.

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

Скажем, если размер атомарной записи = 512 байт

Для очень старых дисков нужен алгоритм? Уже давненько физический минимум 4096 байт. А 512 байт - это только для совместимости.

fsync() кладёт данные максимально хардварно, и да это может означать кеш диска.

А может означать пустышку. В зависимости от того, как настроена конкретная система (см. ссылку на lwn выше). Т.е. твоя прога обязана предупредить пользователя (а он, в свою очередь, администратора), чтобы он принял все от него зависящие меры.

Но дисковый аппаратный кеш на запись может быть, исходя из здравого смысла, ограничен способностью диска при обрыве питания дописать это всё на винт. Иначе получится ситуация, когда при работающем оборудовании никто ничего не гарантирует, а это уже лютый бред.

Возьмём диск с кешем 128 МБ. Представим, что записывать надо в конец, где скорость уже около 60-70 МБ/с. Отрубаем питание - и? Он явно не продолжает работать в течение почти 2 секунд, а мгновенно паркует головки. Или кому-то встречался диск с буфером в виде суперконденсатора или чего-то подобного?

Кстати, даже гарантии записи и чтения данных постоянно имеют вероятностный характер: любой бит в любой момент времени может оказаться с потолка. Пусть это и должно происходить сравнительно редко.

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