Как обновить два файла одновременно, чтобы гарантировать их атомарность?

Как можно сделать атомарное обновление двух файлов (снапшота и лога) для обеспечения отката к корректному состоянию в случае сбоя, не записывая полное состояние файлов в UNDO лог из-за их потенциально большого размера?
  • 26 января 2024 г. 13:49
Ответы на вопрос 2
Атомарное обновление двух файлов может быть сложным, особенно если учитывать возможность сбоев в самый неподходящий момент. Рассмотрим несколько стратегий, которые позволят достичь желаемой атомарности без необходимости записи полного состояния в UNDO лог.

1. **Файловая система с поддержкой атомарных транзакций:** Некоторые файловые системы, такие как ZFS или Btrfs, предлагают механизмы транзакций, которые могут обеспечить атомарное изменение нескольких файлов. Используя такие файловые системы, можно обновлять файлы в рамках одной транзакции.

2. **Теневое копирование:** Создайте теневые копии обоих файлов перед их обновлением. После успешного обновления замените оригиналы этими копиями. Это можно сделать, например, с помощью атомарной операции переименования в большинстве операционных систем.

   - Создать временные теневые копии `snapshot.temp` и `log.temp`.
   - Перезаписать эти копии новыми данными.
   - Если обе перезаписи успешны, атомарно переименовать `snapshot.temp` в `snapshot` и `log.temp` в `log`.

3. **Write-ahead logging (WAL):** Этот подход используется в системах баз данных для обеспечения атомарности и долговременной сохранности. Перед изменением основных файлов, сначала записывается журнал предполагаемых изменений. В случае сбоя, система сможет восстановить состояние на момент последней консистентной точки, используя данные из этого журнала.

4. **Использование метаданных и ссылок в файловой системе:** Можно управлять версиями файлов с помощью метаданных, указывающих на текущие версии файлов. Метаданные обновляются атомарно (например, с помощью атомарного обновления символической ссылки), чтобы переключаться между разными версиями файлов:
   
   - Создать копии файлов со снапшотом и логом.
   - Обновить копии.
   - Поменять метаданные (например, обновить символические ссылки), указывающие на актуальную версию файлов.

5. **Техника “Double write” или “Dual phase commit”:** В этом методе используются две фазы для записи файлов. Первая фаза записывает обновления во временные файлы и, если они завершаются успешно, вторая фаза подтверждает изменения путем переименования временных файлов в основные.

Эти стратегии помогут обеспечить атомарность обновления двух файлов, сохраняя при этом возможность отката, минимизируя использование UNDO лога. Выбор определенной стратегии будет зависеть от контекста использования, ограничений и требуемых гарантий отказоустойчивости.
Движок ESE от Microsoft (его используют системные БД MS Windows и MS Exchange) на для уменьшения объема просматриваемого журнала транзакций ("лога", он там хранится не в одном большом файле а в куче мелких) при рестарте создает и обновляет отдельный файл контрольной точки, в котором сохраняется ссылка на транзакцию, до которой все точно зафиксировано. А при рестарте - запускает применение журнала транзакций с контрольной точки. 
Попробуйте подумать в эту сторону - может, подойдет.
PS А еще в Windows, в файловой системе NTFS есть встроенная поддержка транзакционного обновления. Но, во-первых - это только в Windows, а во-вторых, я не помню, чтобы в .NET была библиотека для использования этой возможности, так что, не исключено, что доступаться до нее придется через P/Invoke
Похожие вопросы