Атомарность и восстановление
AtomicFilesystem::write_atomic() записывает данные во временный файл, сбрасывает его и
вызывает fsync для дескриптора файла, переименовывает его, заменяя целевой путь, а затем пытается вызвать fsync для родительского каталога. При неудачной записи временный файл удаляется.
Записывающие экземпляры хранилища создают маркер процесса в .storh/writers/ и удаляют его при штатном завершении. При открытии хранилища проверяются эти маркеры: если процессы-владельцы всех маркеров ещё работают (или маркеров нет), открытие занимает постоянное время; если процесс-владелец маркера завершился, значит, произошёл сбой записи, и при открытии выполняется поиск временных файлов-сирот в коллекции, а устаревший маркер удаляется. repair() всегда выполняет такой поиск.
При восстановлении DocStore помещает повреждённые или усечённые файлы записей в карантин в .storh/corrupt/ и заново строит вторичные индексы по оставшимся корректным записям. Проверка DocStore также сравнивает файлы индексов с полным сканированием записей, чтобы сообщить об отсутствующих или устаревших записях индекса до того, как они будут признаны корректными.
Движки с добавлением только в конец файла сбрасывают и синхронизируют файлы журналов через fsync, прежде чем считать события сохранёнными в памяти. Сохранность данных при отключении питания по-прежнему зависит от того, поддерживают ли файловая система и параметры монтирования синхронизацию файлов и каталогов.
Сегментированный журнал записывает каждую строку в таком формате:
<byte-length>\t<xxh32>\t<json>\n
При чтении проверяются длина в байтах и контрольная сумма. Восстановление сканирует каждый сегмент и усекает файл до последней полной корректной строки, удаляя незавершённые записи в конце. Проверка сравнивает активный индекс производного состояния с независимым воспроизведением сегментов, чтобы сообщить о внешних изменениях или устаревшем состоянии до его восстановления.
Проверка очереди декодирует каждое сохранённое событие и сравнивает текущее состояние ожидающих и обрабатываемых задач, завершённых задач, данных и порядка захвата с независимым воспроизведением журнала. Восстановление заново строит это состояние из queue.log и усекает незавершённые события в конце. При захвате и завершении задач блокировка очереди удерживается во время синхронизации с сохранённым журналом, поэтому несколько рабочих процессов не захватят одну и ту же ожидающую задачу.
При уплотнении создаются новые файлы сегментов compact-*, после чего обновляется манифест.
Если процесс завершится до замены манифеста, при повторном открытии удаляется неиспользуемый результат уплотнения, и работа продолжается по старому манифесту. После завершённого уплотнения старые запечатанные сегменты намеренно остаются на месте, чтобы читатели, уже считывающие их, могли продолжить работу.