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.7.0 (2010-07-21), новый выбор "журнал с упреждающей записью" (в дальнейшем именуемый "WAL") доступен.

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

  1. WAL значительно быстрее в большинстве сценариев.
  2. WAL обеспечивает больше параллелизма, поскольку читатели не блокируют писателей, и писатель не блокирует читателей. Чтение и запись могут продолжиться одновременно.
  3. Дисковый I/O имеет тенденцию быть более последовательным с использованием WAL.
  4. WAL использует много меньше fsync() и таким образом менее уязвим для проблем на системах, где системный вызов fsync() неправильный.

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

  1. WAL обычно требует, чтобы VFS поддерживала примитивы общей памяти. Исключение: WAL без общей памяти. Встроенный Unix и windows VFS поддерживают это, но сторонний дополнительный VFS для других операционных систем может и нет.
  2. Все процессы, использующие базу данных должны быть на том же самом компьютере: WAL не работает по сетевой файловой системе.
  3. Транзакции, которые включают изменения многих баз данных ATTACHed, атомные для каждой отдельной базы данных, но не атомные через все базы данных как набор.
  4. Невозможно изменить page_size после входа в режим WAL на пустой базе данных, при помощи VACUUM или восстанавливая из резервной копии, используя backup API. Необходимо быть в режиме журнала обратной перемотки, чтобы изменить размер страницы.
  5. Невозможно открыть read-only WAL БД. Процесс открытия должен иметь привилегии записи для файла общей памяти "-shm" wal-index, связанного с базой данных, если тот файл существует, иначе доступ для записи в каталог, содержащей файл базы данных, если файл "-shm" отсутствует. С version 3.22.0 (2018-01-22) файл базы данных WAL только для чтения может быть открыт, если файлы -shm и -wal уже существуют, те файлы могут быть созданы или база данных неизменна.
  6. WAL мог бы быть очень немного медленнее (возможно, на 1% или 2%), чем традиционный подход журнала обратной перемотки в запросах, которые делают главным образом чтение и редко пишут.
  7. Есть дополнительный квазипостоянный файл "-wal" и файл общей памяти "-shm", связанный с каждой базой данных.
  8. Есть дополнительная операция checkpointing, которая, хотя автоматическая по умолчанию, является все еще чем-то, что разработчики приложений должны помнить.
  9. WAL работает лучше всего с меньшими транзакциями. WAL не работает хорошо на очень больших транзакциях. Для транзакций больше приблизительно 100 мегабайт традиционный режим журнала обратной перемотки, вероятно, будет быстрее. Для транзакций больше гигабайта режим WAL может потерпеть неудачу с дисковой ошибкой. Рекомендуется, чтобы один из режимов журнала обратной перемотки использовался для транзакций больше, чем несколько дюжин мегабайт. Начиная с version 3.11.0 (2016-02-15), режим WAL работает так эффективно с большими транзакциями, как режим обратной перемотки.

2. Как работает WAL

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

Подход WAL инвертирует это. Оригинальное содержание сохранено в файле базы данных, и изменения приложены в отдельный файл WAL. COMMIT происходит, когда специальный отчет, указывающий на передачу, добавлен к WAL. Таким образом COMMIT может произойти, без обращения к оригинальной базе данных, что позволяет читателям продолжать работать с оригинальной неизменной базой данных в то время, как изменения одновременно передаются в WAL. Многократные транзакции могут быть приложены до конца единственного файла WAL.

2.1. Checkpointing

Конечно, каждый хочет в конечном счете передать все транзакции, которые приложены в файле WAL, назад в оригинальную базу данных. Перемещение обратно транзакций по файлу WAL в базу данных называют "контрольной точкой".

Другой способ думать о различии между обратной перемоткой и журналом с упреждающей записью состоит в том, что в подходе журнала обратной перемотки, есть две примитивных операции, чтение и запись, тогда как с журналом с упреждающей записью есть теперь три примитивных операции: чтение, запись и checkpointing.

По умолчанию SQLite делает контрольную точку автоматически, когда файл WAL достигает порогового размера 1000 страниц. Выбор времени компиляции SQLITE_DEFAULT_WAL_AUTOCHECKPOINT может использоваться, чтобы определить различное умолчание. Запросы, используя WAL, ничего не должны делать для этих контрольных точек. Но если они хотят, запросы могут приспособить автоматический порог контрольной точки. Или они могут выключить автоматические контрольные точки и управлять контрольными точками в течение моментов без работы, в отдельном потоке или процессе.

2.2. Параллелизм

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

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

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

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

Таким образом продолжительная транзакция чтения может препятствовать тому, чтобы checkpointer работал. Но по-видимому каждая транзакция чтения в конечном счете закончится, и checkpointer будет в состоянии продолжить.

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

2.3. Исполнительные соображения

Транзакции записи очень быстры, так как они включают только написание содержания однажды (против дважды для журнала обратной перемотки) и потому что все записи последовательны. Далее синхронизация содержания с диском не требуется, пока применение готово пожертвовать длительностью после потерь мощности или "жесткой" перезагрузки. Синхронизация писателей, которую передают WAL на каждой транзакции сделана, если PRAGMA synchronous = FULL, но эта синхронизация опущена, если PRAGMA synchronous = NORMAL.

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

Checkpointing действительно требует синхронизирующих операций, чтобы избежать возможности повреждения базы данных после потерь мощности или "жесткой" перезагрузки. WAL должен синхронизироваться к постоянному хранению до перемещения содержания от WAL в базу данных, и файл базы данных должен синхронизирован до сброса WAL. Контрольная точка также требует большего количества поиска. checkpointer прилагает усилие, чтобы сделать передачу страниц базе данных при записи максимально последовательной (страницы, которые будут передаваться от WAL до базы данных в порядке возрастания), но даже тогда, как правило, будет, много операций поиска среди записи страниц. Эти факторы объединяются и делают контрольные точки медленнее, чем транзакции записи.

Стратегия по умолчанию состоит в том, чтобы позволить последовательным транзакциям записи выращивать WAL, пока WAL не становится приблизительно 1000 страниц в размере, затем управлять операцией по контрольной точке для каждого последующего COMMIT, пока WAL не перезагружается, чтобы быть меньше 1000 страниц. По умолчанию контрольной точкой будет управлять автоматически тот же самый поток, который делает COMMIT, который выдвигает WAL по его пределу размера. Это имеет эффект того, чтобы заставлять большинство операций COMMIT быть очень быстрыми, но случайный COMMIT (который вызывает контрольную точку) быть намного медленнее. Если этот эффект нежелательный, то применение может отключить автоматический checkpointing и управлять периодическими контрольными точками в отдельном потоке или процессе. Связи с командами и интерфейсами, чтобы достигнуть этого показаны здесь.

Обратите внимание на то, что с PRAGMA synchronous = NORMAL, контрольная точка это единственная операция, чтобы снять барьер I/O или выполнить синхронизирующую операцию (fsync() в unix или FlushFileBuffers() в windows). Если применение поэтому управляет контрольной точкой в отдельном потоке или процессе, главный поток, который делает запросы и обновления базы данных, никогда не будут блокировать на синхронизирующей операции. Это помогает предотвратить "замок" в запросах на занятом дисководе. Оборотная сторона этой конфигурации в том, что транзакции больше не длительны, и возможна обратная перемотка после перебоя в питании или жесткой перезагрузки.

Заметьте также, что есть компромисс между средней производительностью чтения и средней производительностью записи. Чтобы максимизировать производительность чтения, каждый хочет держать WAL как можно меньше и следовательно управлять контрольными точками часто, возможно так же часто как каждый COMMIT. Чтобы максимизировать производительность записи, каждый хочет амортизировать стоимость каждой контрольной точки по как можно большему числу записей, подразумевая, что каждый хочет управлять контрольными точками редко и позволить WAL вырасти как можно больше перед каждой контрольной точкой. Решение о том, как часто управлять контрольными точками, может поэтому измениться от одного применения до другого в зависимости от требования производительности чтения и записи применения. Стратегия по умолчанию состоит в том, чтобы управлять контрольной точкой, как только WAL достигает 1000 страниц, и эта стратегия, кажется, работает хорошо в тестовых приложениях на рабочих станциях, но другие стратегии могли бы работать лучше с различными платформами или для различной рабочей нагрузки.

3. Активация и формирование режима WAL

Соединение с базой данных SQLite по умолчанию в journal_mode=DELETE. Чтобы преобразовать в режим WAL, используйте следующий pragma:

PRAGMA journal_mode=WAL;

journal_mode pragma возвращает последовательность, которая является новым режимом журнала. На успехе pragma возвратит последовательность "wal". Если преобразование в WAL не могло бы быть закончено (например, если VFS не поддержит необходимые примитивы общей памяти), тогда режим будет неизменен, и последовательность, возвращенная из примитива, будет предшествующим режимом журналирования (например, "delete").

3.1. Автоматическая контрольная точка

По умолчанию SQLite будет автоматически выполнять контрольную точку каждый раз, когда происходит COMMIT, который заставляет файл WAL составлять 1000 страниц или больше в размере или когда последнее соединение с базой данных на файле базы данных закрывается. Конфигурация по умолчанию предназначается, чтобы работать хорошо в большинстве ситуаций. Но программы, которые хотят больше контроля, могут вызвать контрольную точку явно, используя wal_checkpoint pragma или sqlite3_wal_checkpoint(). Автоматический порог контрольной точки может быть изменен или автоматический checkpointing может быть полностью отключен, используя wal_autocheckpoint pragma или sqlite3_wal_autocheckpoint(). Программа может также использовать sqlite3_wal_hook(), чтобы зарегистрировать отзыв, который будет вызван каждый раз, когда любая транзакция коммитит WAL. Этот отзыв может тогда вызвать sqlite3_wal_checkpoint() или sqlite3_wal_checkpoint_v2() на основе любых критериев, которые считает подходящими. Автоматический механизм контрольной точки осуществляется как простая обертка вокруг sqlite3_wal_hook().

3.2. Начатые применением контрольные точки

Применение может начать контрольную точку, используя любое перезаписываемое соединение с базой данных на базе данных просто вызывая sqlite3_wal_checkpoint() или sqlite3_wal_checkpoint_v2(). Есть три подтипа контрольных точек, которые варьируются по их агрессивности: PASSIVE, FULL и RESTART. Стиль контрольной точки по умолчанию PASSIVE, который действительно работает, не вмешиваясь в другие соединения с базой данных и не может завершиться, если есть параллельные читатели или писатели. Всеми контрольными точками, начатыми sqlite3_wal_checkpoint() и автоматическим механизмом контрольной точки, является PASSIVE. Контрольные точки FULL и RESTART пытаются тяжелее управлять контрольной точкой к завершению и могут быть начаты только обращением к sqlite3_wal_checkpoint_v2(). См. описание sqlite3_wal_checkpoint_v2() для получения дополнительной информации о контрольных точках RESET и FULL.

3.3. Постоянство режима WAL

В отличие от других режимов журналирования, PRAGMA journal_mode=WAL постоянный. Если процесс устанавливает режим WAL, то при закрытии и повторном открытии БД она останется в режиме WAL. Напротив, если процесс установит (например), PRAGMA journal_mode=TRUNCATE, а затем переоткроет БД, то база данных возвратится в режим обратной перемотки по умолчанию DELETE, а не предыдущего урегулирования TRUNCATE.

Постоянство WAL означает, что запросы могут быть преобразованы в использование SQLite в режиме WAL, не внося изменений в само приложение. Нужно просто управлять "PRAGMA journal_mode=WAL;" на файле (файлах) базы данных, используя оболочку командной строки или другую утилиту, затем перезапустить приложение.

Режим WAL будет установлен на всех связях с тем же самым файлом базы данных, если это будет установлено на какой-либо связи.

4. Файл WAL

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

Файл WAL существует, пока у любого соединения с базой данных есть открытая база данных. Обычно файл WAL удален автоматически, когда последняя связь с базой данных закрывается. Однако, если последний процесс, который открыл базу данных, завершился не закрывая соединение с базой данных, или если использован SQLITE_FCNTL_PERSIST_WAL file control, файл WAL мог бы быть сохранен на диске после того, как все связи с базой данных были закрыты. Файл WAL это часть постоянного состояния базы данных и должен быть сохранен с базой данных, если база данных скопирована или перемещена. Если файл базы данных отделен от его файла WAL, то транзакции, которые ранее коммитились в базу данных, могли бы быть потеряны, или файл базы данных мог бы стать испорченным. Единственный безопасный способ удалить файл WAL состоит в том, чтобы открыть файл базы данных, используя один из sqlite3_open(), затем немедленно закрыть базу данных, используя sqlite3_close().

Формат файла WAL точно определяется и кросс-платформенный.

5. Read-Only БД

Более старые версии SQLite не могли прочитать базу данных WAL-режима, которая была только для чтения. Другими словами, доступ для записи требовался, чтобы прочитать базу данных WAL-режима. Это ограничение было смягчено с SQLite version 3.22.0 (2018-01-22).

На более новых версиях SQLite база данных WAL-режима на носителе read-only или база данных WAL-режима, у которой нет права записи, может все еще быть прочитана, если одно или больше следующих условий выполнены:

  1. Файлы -shm и -wal уже есть и удобочитаемы.
  2. Есть право записи в каталоге, содержащем базу данных так, чтобы можно было создать файлы -shm и -wal.
  3. Соединение с базой данных открыто, используя неизменный параметр запроса.

Даже при том, что возможно открыть базу данных WAL-режима только для чтения, хорошая практика перейти на PRAGMA journal_mode=DELETE до записи базы данных SQLite на носитель только для чтения.

6. Предотвращение чрезмерно больших файлов WAL

В нормальных случаях новое содержание приложено к файлу WAL, пока файл WAL не накапливает приблизительно 1000 страниц (и таким образом приблизительно 4 МБ в размере), в этом пункте автоматически управляют контрольной точкой, и файл WAL переработан. Контрольная точка обычно не усекает файл WAL (если не задан journal_size_limit pragma). Вместо этого это просто заставляет SQLite начинать переписывать файл WAL с начала. Это сделано, потому что обычно быстрее переписать существующий файл, чем добавить. Когда последняя связь с базой данных закрывается, та связь делает одну последнюю контрольную точку и затем удаляет WAL и его связанный файл общей памяти, чтобы очистить диск.

Таким образом в подавляющем большинстве случаев, запросы не должны волноваться о файле WAL вообще. SQLite будет автоматически заботиться о нем. Но возможно получить SQLite в состоянии, где файл WAL вырастет без ограничения, вызывающего избыточное использование дискового пространства и замедлит скорость запросов. Следующие пункты перечисляют некоторые способы, которыми это может произойти и как этого избежать.

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

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

    Однако, если у базы данных будут многие параллельные перекрывающиеся читатели и всегда есть по крайней мере один активный читатель, то никакие контрольные точки не будут в состоянии закончить, и следовательно файл WAL вырастет без ограничений.

    Этого сценария можно избежать, гарантировав, что есть "промежутки читателя": времена, когда никакие процессы не читают от базы данных и что контрольные точки предприняты в течение тех времен. В приложениях со многими параллельными читателями можно было бы также рассмотреть ручные контрольные точки с SQLITE_CHECKPOINT_RESTART или SQLITE_CHECKPOINT_TRUNCATE, который гарантирует, что контрольная точка доходит до конца перед возвращением. Недостаток использования SQLITE_CHECKPOINT_RESTART и SQLITE_CHECKPOINT_TRUNCATE в том, что читатели могли быть заблокированы в то время, как работает контрольная точка.

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

    С SQLite version 3.11.0 (2016-02-15) файл WAL для единственной транзакции должен быть пропорционален в размере самой транзакции. Страницы, которые изменяются транзакцией, должны быть написаны в файл WAL только однажды. Однако, с более старыми версиями SQLite, та же самая страница могла бы быть написана в файл WAL многократно, если транзакция растет больше кэша.

7. Внедрение общей памяти для WAL-индекса

wal-index осуществляется, используя обычный файл, который отображен для надежности. Ранний (предварительный показ) внедрения режима WAL сохранил wal-index в изменчивой общей памяти, такой как файлы, созданные в /dev/shm в Linux или в /tmp в других unix. Проблема с тем подходом состоит в том, что процессы с различным корневым каталогом (измененным через chroot) будут видеть различные файлы и следовательно использовать различные области общей памяти, приводя к повреждению базы данных. Другие методы для создания неназванных блоков общей памяти не портативны через различные unix. И мы не могли найти какой-то метод создать неназванные блоки общей памяти в windows. Единственным путем, который мы нашли, чтобы гарантировать, что все процессы, получающие доступ к тому же самому файлу базы данных, используют ту же самую общую память, является создание общей памяти, отобразив файл в том же самом каталоге, как сама база данных.

Использование обычного дискового файла, чтобы обеспечить общую память, имеет тот недостаток, что это могло бы на самом деле сделать ненужный дисковый I/O при записи в общую память. Однако, разработчики не думают, что это главное беспокойство, так как wal-индекс редко превышает 32KB в размере и никогда не синхронизируется. Кроме того, файл поддержки wal-индекса удален, когда последнее соединение с базой данных разъединяется, это часто предотвращает любой реальный дисковый I/O.

Специализированные приложения, для которых реализация по умолчанию общей памяти недопустима, могут создать альтернативные методы через свою VFS. Например, если известно, что к конкретной базе данных получат доступ только потоки в рамках единственного процесса, wal-индекс может быть осуществлен, используя память кучи вместо истинной общей памяти.

8. Использование WAL без общей памяти

С SQLite version 3.7.4 (2010-12-07) WAL-БД могут быть созданы, прочитаны и записаны даже если общая память недоступна, пока locking_mode = EXCLUSIVE перед первым предпринятым доступом. Другими словами, процесс может взаимодействовать с базой данных WAL, не используя общую память, если тот процесс, как гарантируют, будет единственным процессом, получающим доступ к базе данных. Эта особенность позволяет базам данных WAL быть созданными, читаемыми и написанными старыми VFS, у которых нет "version 2" разделяемой памяти в виде методов xShmMap, xShmLock, xShmBarrier и xShmUnmap объекта sqlite3_io_methods.

Если режим блокировки EXCLUSIVE установлен до первого доступа к базе данных WAL, то SQLite никогда не пытается вызвать любой из методов общей памяти, следовательно никакой wal-индекс общей памяти никогда не создается. В этом случае соединение с базой данных остается в режиме EXCLUSIVE пока режим журнала WAL, попытки изменить режим блокировки, используя "PRAGMA locking_mode=NORMAL;" ничего не делают. Единственный способ изменить режим блокировки EXCLUSIVE состоит в том, чтобы сначала выйти из режима WAL.

Если режим блокировки NORMAL в действительности для первого доступа к базе данных WAL, то wal-индекс общей памяти создается. Это означает, что основной VFS должен поддерживать общую память "version 2". Если VFS не поддерживает методы общей памяти, то попытка открыть базу данных, которая уже находится в режиме WAL, или попытка преобразовать базу данных в WAL потерпит неудачу. Пока точно одна связь использует wal-индекс общей памяти, режим блокировки может быть изменен свободно между NORMAL и EXCLUSIVE. Это только когда wal-индекс общей памяти опущен, когда режим блокировки EXCLUSIVE до первого доступа к базе данных WAL режим блокировки застревает в EXCLUSIVE.

9. Иногда запрос возвращает SQLITE_BUSY в режиме WAL

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

Случаи, когда запрос базы данных WAL может возвратить SQLITE_BUSY, включают следующее:

  • Если у другого соединения с базой данных будет база данных, открытая в режиме exclusive locking mode, то все запросы этой базы данных возвратят SQLITE_BUSY. Chrome и Firefox открывают их файлы базы данных в режиме блокировки exclusive, так что попытки прочитать базы данных Chrome или Firefox в то, время как приложения работают, столкнется с этой проблемой.

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

  • Если последняя связь с базой данных потерпела крах, то первая новая связь, которая откроет базу данных, начнет процесс восстановления. Монопольная блокировка проведена во время восстановления. Таким образом, если третье соединение с базой данных попытается что-то запросить в то время, как вторая связь управляет восстановлением, третья связь получит ошибку SQLITE_BUSY.

10. Совместимость

Формат файла базы данных неизменен для режима WAL. Однако, файл WAL и wal-index это новые понятия и таким образом, более старые версии SQLite не будут знать, как возвратить поврежденную базу данных SQLite, которая работала в режиме WAL, когда катастрофа произошла. Чтобы предотвратить более старые версии SQLite (до версии 3.7.0, 2010-07-22) от попытки починить базу данных WAL (и угрохать БД окончательно), номера версий формата файла базы данных (байты 18 и 19 в заголовке базы данных) увеличены от 1 до 2 в режиме WAL. Таким образом, если более старая версия SQLite попытается соединиться с базой данных SQLite, которая работает в режиме WAL, это сообщит, что есть ошибка вроде "file is encrypted or is not a database".

Можно явно выйти из режима WAL, используя pragma, такой как это:

PRAGMA journal_mode=DELETE;

Сознательный выход из режима WAL изменяет номера версий формата файла базы данных назад на 1 так, чтобы более старые версии SQLite могли получить доступ к файлу базы данных.