Согласно справочной странице mmap():
КАРТА_ЧАСТНАЯ
Создайте частное сопоставление копирования при записи. Обновления сопоставления невидимы для других процессов, отображающих тот же файл, и не переносятся в базовый файл. Не указано, видны ли изменения, сделанные в файле после вызова mmap(), в отображаемой области.
Вопрос: как сделать, чтобы изменения в базовом файле после mmap() не были видны моей программе?
Предыстория. Я разрабатываю структуру данных для текстового редактора, позволяющего эффективно редактировать огромные текстовые файлы. Структура данных похожа на веревку на диске, но фактические строки указатель на mmap()-ed находится в диапазоне от исходного файла.
Поскольку файл может быть очень большим, есть несколько ограничений по дизайну:
Не следует загружать весь файл в ОЗУ, так как файл может быть больше, чем доступная физическая ОЗУ.
Не следует копировать файлы при открытии, так как это сделает открытие новых файлов очень медленным
Должен работать с файловыми системами, такими как ext4, которые не поддерживают копирование при записи (
cp --reflink
/ioctl_ficlone
)Не следует полагаться на обязательную блокировку файлов, поскольку она устарела и требует специальной опции монтирования
-o mand
в файловой системе.Пока изменения не видны в моем mmap(), базовый файл может измениться в файловой системе.
Нужно только поддерживать последнюю версию Linux, и использование системных API для Linux допустимо.
Структура данных, которую я разрабатываю, будет отслеживать список неотредактированных и отредактированных диапазонов в файле, сохраняя начальный и конечный индексы диапазонов в буфере mmap(). Пока пользователь просматривает файл, диапазоны текста, которые никогда не изменялись пользователем, будут считываться непосредственно из mmap()
исходного файла, в то время как в файле подкачки будут храниться диапазоны текстов, которые были отредактированы пользователем, но не был спасен.
Когда пользователь сохраняет файл, структура данных будет использовать copy_file_range соединить файл подкачки и исходный файл, чтобы собрать новый файл. Чтобы это соединение работало, исходный файл, видимый моей программе, должен оставаться неизменным на протяжении всего сеанса редактирования.
Проблема: пользователь может одновременно иметь другие программы, изменяющие тот же файл, возможно, другие текстовые редакторы или некоторые другие программы, которые изменяли текстовый файл на месте после внесения несохраненных изменений в моем текстовом редакторе.
В такой ситуации редактор может обнаружить такое внешнее изменение с помощью inotify, а затем я хочу дать пользователю два варианта, как продолжить:
отменить все несохраненные изменения и перечитать файл с диска, реализация этой опции довольно проста
позволить пользователю продолжить редактирование файла, а позже пользователь сможет сохранить несохраненные изменения в новом месте или перезаписать изменения, внесенные другой программой, но реализация этого кажется сложной
Поскольку мой редактор не сделал копию файла при открытии файла, когда другая программа перезаписывает файл, диапазоны текста, которые отслеживает моя структура данных, могут стать недействительными, поскольку данные на диске изменились, и эти изменения теперь виден через мой mmap()
. Это означает, что если мой редактор попытается записать несохраненные изменения после того, как файл был изменен другим процессом, он может объединять текстовые диапазоны в старом файле, используя данные из данных из нового файла, что может означать, что мой редактор может создавать поврежденный файл при сохранении несохраненных изменений.
Я не думаю, что рекомендательные блокировки спасут ситуацию во всех случаях, так как другие программы могут не соблюдать рекомендательные блокировки.
Моим идеальным решением было бы сделать так, чтобы, когда другие программы перезаписывают файл, система должна была прозрачно копировать файл, чтобы позволить моей программе продолжать видеть старую версию, в то время как другая программа заканчивает запись на диск и делает свою версию видимой в файловая система. Я думаю, что ioctl_ficlone мог бы сделать это возможным, но, насколько я понимаю, это работает только с файловой системой копирования при записи, такой как btrfs.
Возможно ли такое?
Любые другие предложения по решению этой проблемы также будут приветствоваться.
mmap()
сделать это, я не думаю, что есть хорошее решение. - person Barmar   schedule 07.06.2019