Как иметь файл контрольной точки с помощью mmap, который только синхронизируется к диску вручную

Мне нужен самый быстрый способ периодически синхронизировать файл с памятью.

То, что я думаю, что хотел бы, должно иметь mmap'd файл, который является только sync'd к диску вручную. Я не уверен, как предотвратить любую автоматическую синхронизацию.

Файл не может быть изменен кроме во времена, которые я вручную указываю. Точка должна иметь файл контрольной точки, который сохраняет снимок состояния в памяти. Я хотел бы постараться не копировать как можно больше, так как это будет потребностью к названному справедливо часто, и скорость важна.

6
задан arsenm 30 June 2010 в 04:34
поделиться

4 ответа

mmap не может быть использован для этой цели. Нет способа предотвратить запись данных на диск. На практике использование mlock() для того, чтобы сделать память незаменяемой может иметь побочный эффект предотвращения записи данных на диск, кроме тех случаев, когда вы просите записать их, но гарантии нет. Конечно, если другой процесс откроет файл, он увидит копию, кэшированную в памяти (с вашими последними изменениями), а не копию на физическом диске. Во многом то, что вам следует делать, зависит от того, пытаетесь ли вы выполнить синхронизацию с другими процессами или просто для безопасности на случай сбоя или отключения питания.

Если размер ваших данных невелик, вы можете попробовать несколько других методов атомарной синхронизации на диск. Один из способов - хранить весь набор данных в имени файла и создать пустой файл с таким именем, а затем удалить старый файл. Если при запуске существует 2 файла (из-за крайне маловероятного времени сбоя), удалите более старый и возобновите работу с более нового. write() может также быть атомарным, если размер ваших данных меньше блока файловой системы, размера страницы или блока диска, но я не знаю никаких гарантий на этот счет. Вам придется провести некоторые исследования.

Другой очень стандартный подход, который работает, пока ваши данные не настолько велики, что две копии не помещаются на диск: просто создайте вторую копию с временным именем, затем rename() ее поверх старой. rename() всегда атомарна. Вероятно, это лучший подход, если у вас нет причин не делать это таким образом.

2
ответ дан 10 December 2019 в 00:32
поделиться

Все, что вы записываете в память в рамках сопоставления MAP_SHARED файла, считается записанным в файл в то время, как если бы вы использовали ] write () . msync () в этом смысле полностью аналогичен fsync () - он просто гарантирует, что изменения, которые вы уже внесли в файл, будут фактически перенесены на постоянное место. место хранения. Вы не можете это изменить - так определяется работа mmap () .

В общем, безопасный способ сделать это - записать полную непротиворечивую копию данных во временный файл, синхронизировать временный файл, а затем атомарно переименовать его по сравнению с предыдущим файлом контрольной точки.Это единственный способ гарантировать, что сбой между контрольными точками не приведет к возникновению несогласованного файла. Любое решение, которое делает меньше копирования, потребует как более сложного формата файла в стиле журнала транзакций, так и будет более навязчивым для остальной части вашего приложения (требуя, чтобы определенные хуки вызывались в каждом месте, где изменяется состояние в памяти) .

4
ответ дан 10 December 2019 в 00:32
поделиться

Как уже говорили другие респонденты, я не думаю, что существует переносимый способ сделать то, что вы хотите, без копирования. Если вы хотите сделать это в специализированной среде, где вы можете контролировать ОС и т.д., вы можете сделать это в Linux с файловой системой btrfs.

btrfs поддерживает новую операцию reflink(), которая, по сути, является копированием файловой системы по записи. Вы можете reflink() ваш файл во временный при запуске, mmap() временный, затем msync() и reflink() временный обратно в исходный для контрольной точки.

2
ответ дан 10 December 2019 в 00:32
поделиться

Я сильно подозреваю, что это не может быть использовано какой-либо ОС, но было бы возможно для ОС заметить оптимизацию для:

int fd = open("file", O_RDWR | O_SYNC | O_DIRECT);

size_t length = get_lenght(fd);

uint8_t * map_addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);

...

// This represents all of the changes that could possibly happen before you
// want to update the on disk file.
change_various_data(map_addr);

if (is_time_to_update()) {
   write(fd, map_addr, length);
   lseek(fd, 0, SEEK_SET);
   // you could have just used pwrite here and not seeked
}

Причины, по которым ОС может, возможно, использовать это в том, что пока вы не записываете на определенную страницу (и никто другой тоже не записывает), ОС, вероятно, просто использует фактическую страницу файла в этом месте как своп для этой страницы.

Затем, когда вы записывали на некоторый набор этих страниц, ОС копировала на записывала эти страницы для вашего процесса, но при этом сохраняла незаписанные страницы в резервной копии исходного файла.

Затем, при вызове write ОС могла заметить, что запись была выровнена по блокам как в памяти, так и на диске, а затем она могла заметить, что некоторые страницы исходной памяти уже синхронизированы с теми страницами файловой системы, на которые они записывались, и записать только те страницы, которые изменились.

Учитывая все вышесказанное, я не удивлюсь, если эта оптимизация не выполняется ни в одной ОС, и такой код в итоге получается очень медленным и вызывает много записей на диск при вызове 'write'. Было бы здорово, если бы этим воспользовались.

0
ответ дан 10 December 2019 в 00:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: