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