
# Атомарність і відновлення

`AtomicFilesystem::write_atomic()` записує дані в тимчасовий файл, виконує flush і fsync для дескриптора цього файлу, перейменовує його на цільовий шлях і намагається виконати fsync батьківського каталогу. Якщо запис не вдається, тимчасовий файл видаляється.

Екземпляри сховища з можливістю запису реєструють маркер для кожного процесу в `.storh/writers/` і видаляють його під час коректного завершення роботи. Під час відкриття сховища перевіряються ці маркери: якщо власники всіх маркерів активні (або маркерів немає), відкриття займає сталий час; якщо процес-власник маркера завершився, це означає аварійне завершення запису, тож під час відкриття перевіряється колекція, видаляються осиротілі тимчасові файли та застарілий маркер. `repair()` завжди виконує таку перевірку.

Під час відновлення DocStore поміщає пошкоджені або обрізані файли записів у карантин `.storh/corrupt/` і перебудовує вторинні індекси за рештою коректних записів. Перевірка DocStore також зіставляє файли індексів із повним скануванням записів, щоб виявити відсутні чи застарілі записи індексу, перш ніж вважати їх коректними.

Рушії з журналом лише для додавання виконують flush і fsync для дескрипторів файлів журналу, перш ніж вважати події зафіксованими в пам'яті. Надійність збереження під час втрати живлення все одно залежить від того, чи файлова система й параметри монтування коректно виконують синхронізацію файлів і каталогів.

Сегментований журнал записує кожен рядок у такому форматі:

```text
<byte-length>\t<xxh32>\t<json>\n
```

Під час читання перевіряються довжина в байтах і контрольна сума. Відновлення сканує кожен сегмент і обрізає файл до останнього повного коректного рядка, видаляючи неповні записи в кінці. Під час перевірки активний похідний індекс стану зіставляється з незалежним відтворенням сегментів, щоб виявити зовнішні зміни або застарілий стан до його відновлення.

Під час перевірки черги декодується кожна довговічна подія, а поточний стан очікуваних завдань, завдань в обробці й виконаних завдань, даних і порядку отримання зіставляється з незалежним відтворенням журналу. Відновлення перебудовує цей стан із `queue.log` і обрізає неповні події в кінці. Під час отримання завдань і завершення їх обробки утримується блокування черги, доки дані не синхронізуються з довговічним журналом, тож кілька робочих процесів не отримають одне й те саме очікуване завдання.

Під час ущільнення записуються нові файли сегментів `compact-*`, а потім оновлюється маніфест. Якщо процес завершується до заміни маніфесту, під час повторного відкриття видаляються непов'язані результати ущільнення, а робота триває зі старим маніфестом. Після завершення ущільнення старі закриті сегменти навмисно залишаються, щоб читачі, які вже читають їх потоково, могли продовжити роботу.
