Режим совместного кэша SQLite
Содержание
1. Режим совместного кэша SQLite
В версии 3.5.0 (2007-09-04), режим совместного кэша был изменён таким образом, что кэш может быть общим для всего процесса, а не только для одного потока. До этого изменения были ограничения на передачу подключений к базе данных между потоками. Эти ограничения были сняты в обновлении 3.5.0. В данном документе описывается режим совместного кэша, начиная с версии 3.5.0.
Режим совместного кэша изменяет семантику модели блокировки в некоторых случаях. Подробности описаны в данном документе. Предполагается базовое понимание обычной модели блокировки SQLite (см. Файловые блокировки и одновременность в SQLite версии 3 для получения подробностей).
1.1. Использование совместного кэша не рекомендуется
Режим совместного кэша — устаревшая функция. Использование режима совместного кэша не рекомендуется. Большинство случаев использования совместного кэша лучше обслуживаются режимом WAL.
Режим совместного кэша был разработан в 2006 году по запросу разработчиков Symbian. Их проблема заключалась в том, что если база данных контактов на телефоне синхронизировалась, это блокировало базу данных. Затем, если поступал звонок, блокировка базы данных препятствовала запросу к базе данных контактов для поиска соответствующего мелодии звонка, фотографии звонящего и т.д. Режим WAL (примерно 2010 год) является лучшим решением этой проблемы, так как он допускает одновременный доступ без нарушения изоляции транзакций.
Приложениям, которые создают свою копию SQLite из исходного кода, рекомендуется использовать опцию компиляции -DSQLITE_OMIT_SHARED_CACHE, так как полученный двоичный файл будет как меньше, так и быстрее.
Интерфейсы совместного кэша, описанные здесь, будут продолжать поддерживаться в SQLite, чтобы гарантировать полную обратную совместимость. Однако использование совместного кэша не рекомендуется.
2. Модель блокировки совместного кэша
Внешне, с точки зрения другого процесса или потока, два или более подключений к базе данных, использующих общий кэш, выглядят как одно подключение. Протокол блокировки, используемый для арбитража между несколькими общими кэшами или обычными пользователями базы данных, описан в другом месте.
| |
Рисунок 1
Рисунок 1 показывает пример конфигурации выполнения, где установлено три подключения к базе данных. Подключение 1 — обычное подключение к базе данных SQLite. Подключения 2 и 3 используют общий кэш. Обычный протокол блокировки используется для сериализации доступа к базе данных между подключением 1 и общим кэшем. Внутренний протокол, используемый для сериализации (или нет, см. "Режим изоляции Read-Uncommitted" ниже) доступа к общему кэшу подключениями 2 и 3, описан в остальной части этого раздела.
Модель блокировки совместного кэша имеет три уровня: блокировка на уровне транзакции, блокировка на уровне таблицы и блокировка на уровне схемы. Они описаны в следующих трёх подразделах.
2.1. Блокировка на уровне транзакции
Подключения к SQLite могут открывать два вида транзакций: чтение и запись. Это не делается явно, транзакция неявно является транзакцией чтения до первого записи в таблицу базы данных, после чего она становится транзакцией записи.
Максимум одно подключение к одному общему кэшу может открыть транзакцию записи в любой момент времени. Это может сосуществовать с любым количеством транзакций чтения.
2.2. Блокировка на уровне таблицы
Когда два или более подключения используют общий кэш, блокировки используются для сериализации попыток одновременного доступа к каждой таблице. Таблицы поддерживают два типа блокировок: "чтение" и "запись". Блокировки предоставляются подключениям — в любой момент времени каждое подключение к базе данных имеет либо блокировку чтения, блокировку записи, или без блокировки каждой таблицы базы данных.
В любой момент времени одна таблица может иметь любое количество активных блокировок чтения или одну активную блокировку записи. Для чтения данных из таблицы подключение должно сначала получить блокировку чтения. Для записи в таблицу подключение должно получить блокировку записи по этой таблице. Если необходимая блокировка таблицы не может быть получена, запрос терпит неудачу, и вызывающему методу возвращается SQLITE_LOCKED.
После получения блокировки таблицы подключение не высвобождает её до завершения текущей транзакции (чтение или запись).
2.2.1. Режим изоляции Read-Uncommitted
Указанное выше поведение может быть незначительно изменено с помощью предика read_uncommitted для изменения уровня изоляции с сериализованного (по умолчанию) на read-uncommitted.
Подключение к базе данных в режиме read-uncommitted не пытается получить блокировки чтения перед чтением из таблиц базы данных, как описано выше. Это может привести к несогласованным результатам запроса, если другое подключение к базе данных изменяет таблицу во время чтения, но также означает, что транзакция чтения, открытая подключением в режиме read-uncommitted, не может заблокировать и не может быть заблокирована никаким другим подключением.
Режим read-uncommitted не влияет на блокировки, необходимые для записи в таблицы базы данных (т.е. подключения в режиме read-uncommitted всё ещё должны получать блокировки записи, и, следовательно, запись в базу данных всё ещё может блокировать или быть заблокирована). Кроме того, режим read-uncommitted не влияет на блокировки sqlite_schema, требуемые правилами, перечисленными ниже (см. раздел "Блокировка на уровне схемы (sqlite_schema)").
/* Set the value of the read-uncommitted flag: ** ** True -> Set the connection to read-uncommitted mode. ** False -> Set the connection to serialized (the default) mode. */ PRAGMA read_uncommitted = <boolean>; /* Retrieve the current value of the read-uncommitted flag */ PRAGMA read_uncommitted;
2.3. Блокировка на уровне схемы (sqlite_schema)
Таблица sqlite_schema поддерживает блокировки чтения и записи в режиме совместного кэша так же, как и все другие таблицы базы данных (см. описание выше). Также применяются следующие специальные правила:
- Подключение должно получить блокировку чтения на sqlite_schema перед доступом к любым таблицам базы данных или получением любых других блокировок чтения или записи.
- Перед выполнением оператора, изменяющего структуру базы данных (т.е. оператора CREATE или DROP TABLE), подключение должно получить блокировку записи на sqlite_schema.
- Подключение не может скомпилировать оператор SQL, если какое-либо другое подключение держит блокировку записи в таблице sqlite_schema любой присоединённой базы данных (включая базу данных по умолчанию, "main").
3. Проблемы, связанные с потоками
В версиях SQLite с 3.3.0 до 3.4.2 при включённом режиме совместного кэша подключение к базе данных может использоваться только потоком, который вызвал sqlite3_open() для его создания. И подключение могло использовать общий кэш только с другим подключением в том же потоке. Эти ограничения были сняты, начиная с SQLite версии 3.5.0 (2007-09-04).
4. Совместный кэш и виртуальные таблицы
В более старых версиях SQLite режим совместного кэша не мог использоваться вместе с виртуальными таблицами. Это ограничение было удалено в SQLite версии 3.6.17 (2009-08-10).
5. Включение режима совместного кэша
Режим совместного кэша включается на основе всего процесса. Используя интерфейс C, можно использовать следующий API для глобального включения или выключения режима совместного кэша:
int sqlite3_enable_shared_cache(int);
Каждый вызов sqlite3_enable_shared_cache() влияет на последующие подключения к базе данных, созданные с помощью sqlite3_open(), sqlite3_open16() или sqlite3_open_v2(). Существующие подключения не затрагиваются. Каждый вызов sqlite3_enable_shared_cache() переопределяет все предыдущие вызовы в рамках того же процесса.
Индивидуальные подключения к базе данных, созданные с помощью sqlite3_open_v2(), могут выбрать участие или нет в режиме совместного кэша, используя флаги SQLITE_OPEN_SHAREDCACHE или SQLITE_OPEN_PRIVATECACHE в третьем параметре. Использование любого из этих флагов переопределяет глобальную настройку режима совместного кэша, установленную с помощью sqlite3_enable_shared_cache(). Не должно использоваться более одного флага; если оба флага SQLITE_OPEN_SHAREDCACHE и SQLITE_OPEN_PRIVATECACHE используются в третьем аргументе sqlite3_open_v2(), то поведение неопределено.
При использовании URI имён файлов параметр запроса "cache" можно использовать для указания того, будет ли база данных использовать общий кэш. Используйте "cache=shared", чтобы включить общий кэш, и "cache=private", чтобы отключить общий кэш. Возможность использования параметров запроса URI для указания поведения совместного использования кэша подключения к базе данных позволяет управлять совместным использованием кэша в операторах ATTACH. Например:
ATTACH 'file:aux.db?cache=shared' AS aux;
6. Совместный кэш и базы данных в памяти
Включение общего кэша для базы данных в оперативной памяти позволяет двум или более подключениям к базе данных в одном процессе получить доступ к одной и той же базе данных в оперативной памяти. База данных в оперативной памяти с общим кэшем автоматически удаляется и освобождает память, когда закрывается последнее подключение к этой базе данных.
Эта страница была изменена в последний раз 02.01.2023 14:22:42 UTC
SQLite is in the Public Domain.
https://sqlite.org/sharedcache.html