Сопоставление файлов кажется естественным выбором. Однако это вызывает вопросы относительно целостности данных. Изменения, внесенные в страницы памяти, асинхронно отражаются в базовом файле. А в случае аварийного завершения (сбой процесса сервера или отключение питания) данные, скорее всего, окажутся в несогласованном состоянии.
Я хотел бы решить эту проблему, используя транзакционный подход. техника. То есть все изменения, внесенные в сопоставление файлов, должны рассматриваться как «временные», и в случае аварийного завершения должна быть возможность их откатить. В какой-то момент изменения должны быть «зафиксированы», это должна быть атомарная операция, после которой изменения считаются постоянными.
На данный момент я придумал следующие стратегии проектирования и буду будем рады услышать больше идей и предложений.
- Файл журнала WAL с явным запросом доступа для записи.
Затем, чтобы зафиксировать изменения, будет выполнено следующее:
- Очистить файл журнала (в Windows, fsync в Linux).
Код: Выделить всё
FlushFileBuffers - Сбросить сопоставление файлов (в Windows, msync в Linux).
Код: Выделить всё
FlushViewOfFile - Очистить базовый файл сопоставления.
- Измените размер файла журнала на 0. .
- Очистить файл журнала. И, при необходимости, удалите его.
Примечание: приведенное выше гарантирует согласованность в случае, если мы предполагаем, что этот файловый ввод-вывод, хотя и асинхронный, выполняется по порядку. Это означает, что если мы скопируем содержимое страницы в файл журнала, а затем изменим доступную память, которая, в свою очередь, будет генерировать ввод-вывод в файл данных, эти два асинхронных ввода-вывода выполняются по порядку, т.е. файл журнала. обновляется раньше файла данных.
- Неявный доступ на запись, инициируемый нарушением прав доступа.
Код: Выделить всё
PAGE_READONLY). Всякий раз, когда приложение пытается выполнить запись в это место, возникает исключение. В Windows это можно обрабатывать через SEH, в Linux должна быть возможность обрабатывать обработчик сигнала SIGSEGVВо время обработки содержимое страницы сохраняется в файл журнала. , и его защита изменяется на PAGE_READWRITE.
Затем во время фиксации восстанавливается защита страницы только для чтения.
Я уже реализовал это на Windows, кажется, работает правильно, и я считаю, что то же самое можно сделать и в Linux.
- Использовать защиту памяти от копирования при записи.
Это грубая идея, я пока не разбираюсь во всех деталях, но теоретически можно использовать защиту памяти PAGE_WRITECOPY (не конечно, если подобная защита существует в Linux).
При этом все грязные страницы будут выделены ОС автоматически, заполнение данными останется прежним. Затем, на этапе фиксации, эти страницы должны быть идентифицированы и скопированы в базовый файл данных (с защитой WAL), а затем защита состояния страниц должна быть восстановлена. - Файл с поддержкой журнала.
Теоретически должен быть способ справиться с этим на уровне файловой системы. То есть отображение памяти должно поддерживаться файлом, поддерживающим режим транзакций. Все изменения в файле следует рассматривать как временные до тех пор, пока файл не будет «зафиксирован», и выполнять откат, если файл закрыт без такой фиксации.
< /ol>
Итак, вот какие идеи мне пришли в голову.
Вариант (1) кажется самым «безопасным» вариант, не мешает ли он таким вещам, как обработка исключений/сигналов. При первом написании страницы производительность также снижается меньше (известно, что обработка исключений требует больших усилий).
Однако у нее есть следующие недостатки: - Необходимо вызывать явную функцию каждый раз, когда мы должны изменить данные. Необходимо обновить весь код, который должен работать с этими данными, что, конечно, очень неудобно.
- Каждый раз проверять, не загрязнена ли страница, может быть затратно. Необходимо иметь соответствующую структуру данных (битовую маску, карту или их комбинацию). В случае, когда на одной странице происходит множество изменений (что вполне вероятно), это может быть более эффективным, чем обработка исключения/сигнала ОС только один раз.
Вариант (3) – я не знаю, возможно ли это вообще, т. е. есть ли обычный API для этого. Но теоретически это может быть полезно, поскольку копирование при записи полностью выполняется в режиме ядра, и нет необходимости обрабатывать эти вещи явно.
И, наконец, вариант (4). На самом деле это должно быть лучше во всех смыслах, поскольку поведение, подобное транзакциям, происходит именно там, где и должно быть - на уровне файла, когда изменения сопоставления файлов окончательно сбрасываются. Также самый быстрый и простой в отношении. кодирование.
Единственный вопрос: возможно ли это вообще? Существует ли файловая система, поддерживающая это?
Это мои идеи на данный момент. Буду рад услышать больше.
Заранее спасибо.
Подробнее здесь: https://stackoverflow.com/questions/790 ... -integrity
Мобильная версия