RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Small. Fast. Reliable.
Choose any three.

I/O с отображенной памятью

Механизм по умолчанию, которым SQLite работает с дисковыми файлами базы данных, это методы xRead() и xWrite() объекта VFS sqlite3_io_methods. Эти методы, как правило, осуществляются, как системные вызовы "read()" и "write()", которые заставляют операционную систему копировать дисковое содержание между ядерным кэш-буфером и пространством пользователя.

Начиная с version 3.7.17 (2013-05-20), SQLite имеет выбор доступа к дисковому содержанию, непосредственно используя I/O с отображенной памятью и новые методы xFetch() и xUnfetch() в sqlite3_io_methods.

Есть преимущества и недостатки использования I/O с отображенной памятью. Преимущества включают:

  1. Много операций, особенно интенсивно использующие средства ввода-вывода, могут быть быстрее, так как содержание не должно быть скопировано между ядерным пространством и пространством пользователя.

  2. Библиотеке SQLite, возможно, понадобится меньше RAM, так как это поделится страницами с кэшем страницы операционной системы и не всегда нуждается в собственной копии рабочих страниц.

Но есть также недостатки:

  1. Ошибка I/O на файле с отображенной памятью не может быть зафиксирована и имеет дело с SQLite. Вместо этого ошибка I/O вызывает сигнал, который, если не пойман приложением, приводит к катастрофе программы.

  2. У операционной системы должен быть объединенный кэш-буфер для расширения I/O с отображенной памятью, чтобы работать правильно, особенно в ситуациях, где два процесса получают доступ к тому же самому файлу базы данных, и один процесс использует I/O с отображенной памятью, в то время как другой нет. Не у всех операционных систем есть объединенный кэш-буфер. В некоторых операционных системах, которые утверждают, что имеют объединенный кэш-буфер, внедрение глючное и может испортить базы данных.

  3. Производительность не всегда увеличивается с I/O с отображенной памятью. На самом деле возможно построить тестовые сценарии, где она уменьшается при помощи I/O с отображенной памятью.

  4. Windows неспособен усечь файл с отображенной памятью. Следовательно, на Windows, если операция, такая как VACUUM или auto_vacuum, пытается уменьшить размер файла базы данных с отображенной памятью, попытка сокращения размера тихо потерпит неудачу, оставляя неиспользуемое место в конце файла базы данных. Никакие данные не потеряны из-за этой проблемы, и неиспользуемое место будет снова использовано снова в следующий раз, когда база данных растет. Однако, если версия SQLite до 3.7.0 выполняет PRAGMA integrity_check на такой базе данных, это (неправильно) сообщит о повреждении базы данных из-за неиспользуемого места в конце. Или если версия SQLite до 3.7.0 пишет базе данных, в то время как у нее все еще есть неиспользуемое место в конце, это может сделать то неиспользуемое место недоступным повторному использованию до окончания следующего VACUUM.

Из-за потенциальных недостатков I/O с отображенной памятью отключен по умолчанию. Чтобы активировать I/O с отображенной памятью, используйте mmap_size pragma и установите mmap_size в некоторое большое количество, обычно 256 МБ или больше, в зависимости от того, сколько адресного пространства ваше приложение может сэкономить. Остальное автоматически. PRAGMA mmap_size будет тихо ничего не делать на системах, которые не поддерживают I/O с отображенной памятью.

Как I/O с отображенной памятью работает

Чтобы прочитать страницу содержания базы данных с использованием метода xRead(), SQLite сначала ассигнует кусок размера страницы памяти кучи, затем вызывает xRead(), который заставляет содержание страницы базы данных быть скопированным в недавно ассигнованную память кучи. Это включает (как минимум) копию всей страницы.

Но если SQLite хочет получить доступ к странице файла базы данных, а I/O с отображенной памятью позволен, это сначала вызывает метод xFetch(). Он просит, чтобы операционная система возвратила указатель на требуемую страницу, если это возможно. Если требуемая страница была или может быть отображена в прикладное адресное пространство, то xFetch возвращает указатель на ту страницу для SQLite, чтобы использовать, не имея необходимость копировать что-либо. Пропуск шага копии это то, что делает I/O с отображенной памятью быстрее.

SQLite не предполагает, что xFetch() будет работать. Если вызов xFetch() вернет NULL (указание, что требуемая страница в настоящее время не отображается в прикладное адресное пространство), тогда SQLite тихо отступает к использованию xRead(). Об ошибке сообщают только, если xRead() также терпит неудачу.

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

После того, как все необходимые изменения закончены, применяется xWrite(), чтобы положить обратно содержание в файл базы данных. Следовательно, использование I/O с отображенной памятью не изменяет значительно исполнение изменений базы данных. I/O с отображенной памятью главным образом выгодно для запросов.

Формирование I/O с отображенной памятью

"mmap_size" это максимальное количество байтов файла базы данных, которое SQLite попытается отобразить в адресное пространство процесса когда-то. mmap_size применяется отдельно к каждому файлу базы данных, таким образом, общая сумма адресного пространства процесса, которое могло потенциально использоваться, является mmap_size умножить на количество открытых файлов базы данных.

Чтобы активировать I/O с отображенной памятью, приложение может установить mmap_size в некоторое большое значение. Например:

PRAGMA mmap_size=268435456;

Чтобы отключить I/O с отображенной памятью, просто установите mmap_size в ноль:

PRAGMA mmap_size=0;

Если mmap_size = N, все текущие внедрения отображают первые N байт файла базы данных и используют xRead() к любому содержанию вне N байт. Если файл базы данных меньше, чем N байт, то весь файл отображен. В будущих, новых интерфейсах OS, в теории, можно отобразить области файла кроме первых N байт, но никакое такое внедрение в настоящее время не существует.

mmap_size установлен отдельно для каждого файла базы данных, используя "PRAGMA mmap_size". Обычно умолчание mmap_size является нолем, означая, что I/O с отображенной памятью отключен по умолчанию. Однако, умолчание mmap_size может быть увеличено во время компиляции с использованием макроса SQLITE_DEFAULT_MMAP_SIZE или во время запуска, используя sqlite3_config( SQLITE_CONFIG_MMAP_SIZE,...).

SQLite также поддерживает твердую верхнюю границу на mmap_size. Попытки увеличить mmap_size выше этой твердой верхней границы (используя PRAGMA mmap_size) автоматически установят mmap_size к твердой верхней границе. Если твердая верхняя граница ноль, то I/O с отображенной памятью невозможен. Твердая верхняя граница может быть установлена во время компиляции, используя макрос SQLITE_MAX_MMAP_SIZE . Если SQLITE_MAX_MMAP_SIZE = 0, то код, используемый, чтобы осуществить I/O с отображенной памятью, пропущен. Твердая верхняя граница автоматически установлена в ноль на определенных платформах (например, OpenBSD), где I/O с отображенной памятью не работает из-за отсутствия объединенного кэш-буфера.

Если твердая верхняя граница на mmap_size отлична от нуля во время компиляции, это может все еще быть уменьшено или обнулено во время запуска, используя sqlite3_config( SQLITE_CONFIG_MMAP_SIZE,X,Y). Параметры X и Y это 64-bit signed integer. X задает mmap_size процесса, Y это новая твердая верхняя граница. Твердая верхняя граница не может быть увеличена выше ее урегулирования времени компиляции, используя SQLITE_CONFIG_MMAP_SIZE, но может быть уменьшена или обнулена.