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

Small. Fast. Reliable.
Choose any three.

1. Общий режим кэширования SQLite

Начиная с version 3.3.0 (2006-01-11), SQLite включает специальный режим "shared-cache" (отключенный по умолчанию) предназначенный для использования во встроенных серверах. Если общий режим кэширования позволен, и поток устанавливает многократные связи с той же самой базой данных, связи разделяют единственные данные и кэш схемы. Это может значительно уменьшить количество памяти и IO, требуемого системой.

В version 3.5.0 (2007-09-04) был изменен общий режим кэширования так, чтобы тот же самый кэш мог быть разделен на весь процесс, а не только в единственном потоке. До этого изменения были ограничения на соединения с базой данных между потоками. Те ограничения были сняты в 3.5.0. Этот документ описывает общий режим кэширования с версии 3.5.0.

Общий режим кэширования изменяет семантику модели блокировки в некоторых случаях. Детали описаны этим документом. Принято основное понимание нормальной логики блокировки SQLite (см. здесь).

1.1. Использование общего кэша

Общий режим кэширования это устаревшая особенность. Использованию общего режима кэширования препятствуют. Большинство вариантов использования для общего кэша лучше реализуется режимом WAL.

Общий режим кэширования был изобретен в 2006 по требованию разработчиков Symbian. Их проблема состояла в том что, если бы база данных контактов по телефону синхронизировалась, это блокировало бы файл базы данных. Тогда, если бы было входящее обращение, блокировка базы данных препятствовала бы тому, чтобы запросить базу данных контактов, чтобы найти соответствующую музыку для мобильного телефона для входящего вызова или фотографию, которую показывать на экране и т. д. Режим WAL (приблизительно 2010) является лучшим решением этой проблемы, поскольку это разрешает одновременный доступ, не ломая изоляцию транзакции.

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

Интерфейсы общего кэша, описанные здесь, продолжат поддерживаться в SQLite. Однако, использованию общего кэша препятствуют.

2. Модель блокировки общего кэша

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

Рис. 1

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

Есть три уровня модели блокировки общего кэша: блокировка уровня транзакций, блокировка уровня таблицы и блокировка уровня схемы. Они описаны в следующих трех подразделах.

2.1. Блокировка уровня транзакций

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

Самое большее одна связь с единственным общим кэшом может открыть транзакцию записи в любой момент. Это может сосуществовать с любым количеством транзакций чтения.

2.2. Блокировка уровня таблицы

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

В любой момент у единственной таблицы может быть любое количество активных блокировок чтения или единственная активная блокировка записи. Чтобы прочитать данные из таблицы, связь должна сначала получить блокировку чтения. Чтобы написать таблицу, связь должна сначала получить блокировку записи на той таблице. Если необходимая блокировка таблицы не может быть получена, запрос терпит неудачу, и SQLITE_LOCKED возвращена вызвавшему.

Как только связь получает блокировку таблицы, она не выпущена, пока текущая транзакция не завершена.

2.2.1. Читаемо-нейтральный способ изоляции

Поведение, описанное выше, может быть изменено немного при помощи read_uncommitted pragma, чтобы изменить уровень изоляции от преобразованного в последовательную форму (умолчание) на read-uncommitted.

Соединение с базой данных в режиме read-uncommitted не пытается получить блокировки чтения прежде, чем читать от таблиц базы данных, как описано выше. Это может привести к непоследовательным результатам запроса, если другое соединение с базой данных изменяет таблицу в то время, как она читается, но это также означает, что транзакция чтения, открытая связью в режиме read-uncommitted, не может ни заблокировать, ни быть заблокирована любой другой связью.

Режим Read-uncommitted не имеет никакого эффекта на блокировки, требуемые, чтобы написать таблицы базы данных (то есть, связи read-uncommitted должны все еще получить блокировки записи и следовательно запись в базу данных может все еще заблокировать или быть заблокирована). Кроме того, режим read-uncommitted не имеет никакого эффекта на блокировки 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(), чтобы создать его. Связь могла разделить кэш только с другой связью в том же самом потоке. Эти ограничения были сняты в version 3.5.0 (2007-09-04).

4. Общий кэш и виртуальные таблицы

В более старых версиях SQLite разделенный режим кэширования не мог использоваться вместе с виртуальными таблицами. Это ограничение было удалено в SQLite version 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 filenames параметр запроса "cache" может использоваться, чтобы определить, будет ли база данных использовать разделенный кэш. Используйте "cache=shared", чтобы позволить разделенный кэш и "cache=private", чтобы разрушить разделенный кэш. Способность использовать параметры запроса URI, чтобы определить поведение разделения кэша соединения с базой данных позволяет разделению кэша управляться в запросах ATTACH:

ATTACH 'file:aux.db?cache=shared' AS aux;

6. Общий кэш и базы данных в памяти

Начиная с SQLite version 3.7.13 (2012-06-11), разделенный кэш может использоваться на базах данных в памяти при условии, что база данных создается, используя URI filename. Для совместимости разделенный кэш всегда разрушается для баз данных в памяти, если имя ":memory:" используется, чтобы открыть базу данных. До версии 3.7.13 разделенный кэш всегда запрещен для баз данных в памяти независимо от используемого имени базы данных, существующих настроек системы общего кэша, параметров запроса или флагов.

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