![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
SQLite version 3.5.0 (2007-09-04) вводит новый слой интерфейса OS, который
несовместим со всеми предыдущими версиями SQLite. Кроме того, несколько
существующих интерфейсов были обобщены, чтобы работать через все соединения с
базой данных в рамках процесса, а не просто все связи в потоке.
Цель этой статьи состоит в том, чтобы описать изменения 3.5.0 подробно так,
чтобы пользователи предыдущих версий SQLite могли
модернизировать до более новых версий. Быстрое перечисление изменений в версии 3.5.0 SQLite обеспечивается здесь.
Последующие секции опишут эти изменения более подробно. Из этих изменений, только 1a и с 2a по 2c
имеют несовместимости в любом формальном смысле. Но пользователи, которые
ранее сделали модификации исходного текста SQLite (например, чтобы добавить
свой слой OS для встроенных аппаратных средств) могли бы найти, что эти
изменения оказывают большее влияние. С другой стороны, важная цель этих
изменений состоит в том, чтобы сделать намного легче настройку SQLite для
использования на различных операционных системах. Если ваша система определит свой
интерфейс OS для SQLite или если вы использовали недокументированный
sqlite3_os_switch(), то необходимо будет сделать модификации, чтобы
модернизировать до версии 3.5.0 SQLite. Это может казаться болезненным на
первый взгляд. Но вы, вероятно, обнаружите, что ваши изменения делаются
меньше, их легче понять и справиться с новым интерфейсом SQLite.
Вероятно, что ваши изменения будут теперь также работать беспрепятственно с
объединением SQLite. Вы больше не должны будете делать изменения в коде
SQLite. Все ваши изменения могут быть вызваны кодом приложения, их
можно скомпоновать со стандартной, неизмененной, версией SQLite.
Кроме того, слой интерфейса OS, который был раньше не документирован, теперь
официально интерфейс поддержки для SQLite.
Таким образом, у вас есть некоторая гарантия, что это будет одноразовым
изменением и что ваш новый бэкенд продолжит работать в
будущих версиях SQLite. Новый интерфейс OS для SQLite строится вокруг объекта, названного
sqlite3_vfs. "vfs" это "Virtual File System".
Объект sqlite3_vfs в основном структура, содержащая указатели на функции,
которые осуществляют примитивный дисковый I/O, который должен выполнить
SQLite, чтобы прочитать и написать базы данных. В этой статье мы будем часто
именовать объекты sqlite3_vfs как "VFS". SQLite в состоянии использовать много VFS в то же время.
Каждое отдельное соединение с базой данных связано со всего одним VFS.
Но если у вас есть многократные соединения с базой данных, каждая связь может
быть связана с различным VFS. Всегда есть VFS по умолчанию. Старые интерфейсы
sqlite3_open() и
sqlite3_open16() всегда его используют.
Новый интерфейс для создания соединений с базой данных,
sqlite3_open_v2(),
позволяет вам определять, какой VFS вы хотите использовать по имени. Обычные сборки SQLite для Unix или Windows поставляются с единственным
VFS, названным "unix" или "win32", соответственно.
Этот VFS также используется по умолчанию.
Таким образом, если вы будете использовать старые функции, все продолжит
работать, как прежде. Изменение в том, что у применения теперь есть гибкость
добавления новых модулей VFS, чтобы осуществить настроенный слой OS.
sqlite3_vfs_register() API
может использоваться, чтобы сказать SQLite об одном или нескольких
определенных применением модулях VFS: Приложения могут вызвать sqlite3_vfs_register()
в любое время, хотя, конечно, VFS должен быть зарегистрирован, прежде чем
сможет использоваться. Первый аргумент это указатель на настроенный объект
VFS, который подготовило применение. Второй аргумент true,
чтобы сделать новый VFS по умолчанию, чтобы это использовалось старыми
sqlite3_open() и
sqlite3_open16() API. Если новый VFS не по
умолчанию, то необходимо будет, вероятно, использовать новый
sqlite3_open_v2() API.
Отметьте, однако, что, если новый VFS это единственный VFS, известный SQLite
(если SQLite был собран без его обычного VFS по умолчанию
или если предварительно собранный VFS по умолчанию удален через
sqlite3_vfs_unregister()),
новый VFS автоматически становится VFS по умолчанию независимо от параметра
makeDflt в sqlite3_vfs_register(). Стандартные сборки включают VFS по умолчанию "unix" или "win32".
Но если вы используете выбор времени компиляции -DOS_OTHER=1,
тогда SQLite собирается без VFS по умолчанию. В этом случае приложение должно
зарегистрировать по крайней мере один VFS до запроса
sqlite3_open().
Это подход, который должны использовать встраиваемые приложения.
Вместо того, чтобы изменять SQLite, чтобы вставить альтернативный слой OS,
как было сделано в предшествующих выпусках SQLite, соберите неизмененный
исходный файл SQLite с опцией -DOS_OTHER=1, потом вызовите
sqlite3_vfs_register(),
чтобы определить интерфейс к основной файловой системе до создания любых
соединений с базой данных. sqlite3_vfs_unregister() API
используется, чтобы удалить существующий VFS из системы. sqlite3_vfs_find() API
используется, чтобы определить местонахождение конкретного
VFS по имени. Его прототип такой: Аргумент это символьное имя для желаемого VFS. Если аргумент NULL,
возвращен VFS по умолчанию. Функция возвращает указатель на объект
sqlite3_vfs, который осуществляет VFS.
Или это возвращает NULL, если никакой объект не мог бы быть найден,
который соответствовал критериям поиска. Как только VFS был зарегистрирован, он никогда не должен изменяться.
Если изменение в поведении требуется, новый VFS должен быть зарегистрирован.
Применение могло, возможно, использовать
sqlite3_vfs_find(),
чтобы определить местонахождение старого VFS, превратить копию старого
VFS в новый объект sqlite3_vfs,
сделать желаемые модификации к новому VFS, разрегистрировать старый VFS,
затем зарегистрировать новый VFS на его месте. Существующие соединения с
базой данных продолжили бы использовать старый VFS даже после того, как это
разрегистрировано, но новые соединения с базой данных использовали
бы новый VFS. Объект VFS это экземпляр следующей структуры: Чтобы создать новый VFS, приложение заполняет экземпляр
этой структуры с соответствующими значениями и затем вызывает
sqlite3_vfs_register(). Поле iVersion в sqlite3_vfs должно быть
1 для SQLite version 3.5.0. Это число может увеличиться в будущих версиях
SQLite, если мы должны изменить объект VFS в некотором роде. Мы надеемся, что
этого никогда не будет, но на всякий случай предусмотрели. Поле szOsFile это размер в байтах структуры, которая определяет открытый
файл: объект sqlite3_file.
Этот объект будет описан более полно ниже. Каждое внедрение VFS может
определить свой собственный объект sqlite3_file,
содержащий любую информацию, которую внедрение VFS должно хранить об открытом
файле. SQLite должен знать, насколько большой этот объект, чтобы
предварительно ассигновать достаточно места. Поле mxPathname это максимальная длина пути файла, который может
использовать этот VFS. SQLite иногда должен предварительно ассигновать буфера
этого размера, таким образом, это должно быть максимально маленьким.
Некоторые файловые системы разрешают огромные пути, но на практике пути редко
были больше 100 байтов или около этого.
Вы не должны помещать самый большой путь, с которым основная файловая система
может обращаться, здесь. Необходимо поместить самый большой путь, с которым
вы хотите, чтобы SQLite был в состоянии обращаться.
Несколько сотен это хорошее значение в большинстве случаев. Поле pNext используется внутренне SQLite. Определенно, SQLite использует
это поле, чтобы сформировать связанный список зарегистрированных VFS. Поле zName это символьное имя VFS. Это имя, по которому
sqlite3_vfs_find() ищет VFS. pAppData не использован ядром SQLite. Указатель доступен, чтобы хранить
вспомогательную информацию, которую информация VFS могла бы хотеть. Остающиеся области объекта sqlite3_vfs
хранят указатели на функции, которые осуществляют примитивные операции.
Мы называем эти "методы". Первый метод, xOpen, используется, чтобы
открыть файлы на носителе. Результат: объект
sqlite3_file.
Есть дополнительные методы, определенные самим объектом
sqlite3_file, которые используются, чтобы
прочитать, написать и закрыть файл. Дополнительные методы детализированы
ниже. Имя файла находится в UTF-8. SQLite гарантирует, что последовательность
zFilename, переданная xOpen(), является полным путем, как произведено
xFullPathname() и что последовательность будет действительна и неизменна,
пока не будет вызван xClose(). Таким образом,
sqlite3_file
может сохранить указатель на имя файла, если это должно помнить имя
файла по некоторым причинам. Аргументом flags для xOpen()
является копия аргумента флагов sqlite3_open_v2(). Если sqlite3_open() или
sqlite3_open16() используется, то флаги
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE.
Если xOpen() открывает файл только для чтения, он устанавливает
*pOutFlags, чтобы включить
SQLITE_OPEN_READONLY. Другие биты в *pOutFlags
могут быть установлены. SQLite также добавит один из следующих флагов к
xOpen(), в зависимости от открываемого объекта:
Различия между базой данных
SQLITE_OPEN_TEMP_DB и
SQLITE_OPEN_TRANSIENT_DB:
SQLITE_OPEN_TEMP_DB используется для явно заявленных и названных таблиц
TEMP (используя CREATE TEMP TABLE) или для названных таблиц
во временной базе данных, которая создается, открывая базу данных с именем
файла, которое является пустой строкой.
SQLITE_OPEN_TRANSIENT_DB хранит
таблицу базы данных, которую SQLite создает автоматически, чтобы оценить
подвопрос или пункт GROUP BY или ORDER BY. Базы данных TEMP_DB и TRANSIENT_DB
частные и удалены автоматически. Базы данных TEMP_DB существует в период
соединения с базой данных. Базы данных TRANSIENT_DB существуют только
при работе единственного SQL-оператора. Метод xDelete используется, чтобы удалить файл. Название файла дано во
втором параметре. Имя файла будет в UTF-8. VFS должен преобразовать имя файла
в любое символьное представление, которое ожидает основная операционная
система. Если syncDir = true, xDelete
не должен возвращаться до изменения директивного содержания для каталога,
содержащего удаленный файл, чтобы гарантировать, что файл не "вновь
появляется", если перебой в питании происходит вскоре после действия. Метод xAccess используется, чтобы проверить права доступа на файле.
Имя файла будет закодировано в UTF-8. Аргументом flags будет
SQLITE_ACCESS_EXISTS,
чтобы проверить на существование файла,
SQLITE_ACCESS_READWRITE,
чтобы проверить, чтобы видеть, читаемый и перезаписываемый файл или нет,
или SQLITE_ACCESS_READ,
чтобы проверить, читаемый ли файл по крайней мере.
"file", названный вторым параметром, мог бы быть именем каталога. Метод xGetTempName вычисляет название временного файла, который может
использовать SQLite. Имя должно быть написано в буфер, данный вторым
параметром. SQLite измерит тот буфер, чтобы хранить
по крайней мере, mxPathname байт.
Произведенное имя файла должно быть в UTF-8. Чтобы избежать проблем
безопасности, произведенное временное имя файла должно содержать достаточно
хаотичности, чтобы препятствовать тому, чтобы нападавший предположил
временное имя файла заранее. Метод xFullPathname используется, чтобы преобразовать относительный путь
в полный. Получающийся полный путь написан в буфер, обеспеченный третьим
параметром. SQLite измерит буфер вывода к по крайней мере mxPathname байт.
Оба имени ввода и вывода должны быть в UTF-8. Методы xDlOpen, xDlError, xDlSym и xDlClose
используются для доступа к общим библиотекам во время выполнения.
Эти методы могут быть опущены (и их указатели установлены к нолю), если
библиотека собрана с
SQLITE_OMIT_LOAD_EXTENSION или если
sqlite3_enable_load_extension() никогда не используется,
чтобы позволить динамическую дополнительную нагрузку. Метод xDlOpen открывает
общую библиотеку или DLL и возвращает указатель на обработчик.
Если не открылась, вернет NULL. Если открытие терпит неудачу, метод xDlError
может использоваться, чтобы получить текстовое сообщение об ошибке.
Сообщение написано в буфер zErrMsg третьего параметра, который является по
крайней мере nByte байт в длину. xDlSym возвращает указатель на символ в
общей библиотеке. Название символа дано вторым параметром.
Кодирование UTF-8 принято. Если символ не найден, вернется NULL.
xDlClose закрывает общую библиотеку. Метод xRandomness используется точно однажды, чтобы инициализировать
генератор псевдослучайного числа (PRNG) в SQLite. Только xRandomness метод
применяется на VFS по умолчанию. К методам xRandomness на другом VFS никогда
не получает доступ SQLite. xRandomness просит, чтобы nByte байт хаотичности
были написаны в zOut. Возвращает фактическое число байтов полученной
хаотичности. Качество хаотичности, так полученной, определит качество
хаотичности, произведенной встроенными функциями SQLite вроде random() и
randomblob(). SQLite также использует свой PRNG, чтобы произвести временные
имена файлов. На некоторых платформах (исключая: Windows) SQLite
предполагает, что временные имена файлов уникальны, на самом деле не проверяя
на столкновения, таким образом, важно иметь хаотичность хорошего качества,
даже если random() и randomblob() никогда не используются. Метод xSleep используется, чтобы приостановить вызывающий поток на хотя бы
заданное число микросекунд. Этот метод используется, чтобы осуществить
sqlite3_sleep() и
sqlite3_busy_timeout() API.
В случае sqlite3_sleep() всегда используется
метод xSleep VFS по умолчанию. Если у основной системы нет способности сна
с точностью до микросекунд, то время сна должно быть округлено, xSleep
возвращает это округленное значение. Метод xCurrentTime находит текущее время и дату и пишет результат как
значение с плавающей точкой двойной точности в указатель, обеспеченный вторым
параметром. Время и дата даны в coordinated universal time (UTC)
является номером дня по Юлианскому календарю. Результатом открытия файла является экземпляр объекта
sqlite3_file.
Объект sqlite3_file это
абстрактный базовый класс, определенный следующим образом: Каждое внедрение VFS подклассифицирует
sqlite3_file, добавляя дополнительные области в конце, чтобы содержать
информацию, которую VFS должен знать об открытом файле. Не имеет значения,
какая информация хранится, пока полный размер структуры не превышает
szOsFile в объекте sqlite3_vfs. Объект sqlite3_io_methods
это структура, которая содержит указатели на методы для чтения, записи
и другого контакта с файлами. Этот объект определяется следующим образом: Поле iVersion sqlite3_io_methods
обеспечивается как страховка от будущих изменений. iVersion должно всегда
быть 1 для версии SQLite version 3.5. Метод xClose закрывает файл. Место для структуры
sqlite3_file освобождено вызывающим. Но если
sqlite3_file содержит указатели на другую
ассигнованную память или ресурсы, те должны быть
освобождены методом xClose. Метод xRead читает iAmt байт из файла, начиная с байтового смещения iOfst.
Прочитанные данные хранятся в указателе второго параметра. xRead возвращает
SQLITE_OK при успехе,
SQLITE_IOERR_SHORT_READ,
если это не смогло прочитать полное число байтов, потому что это достигло
конца файла или SQLITE_IOERR_READ
для любой другой ошибки. Метод xWrite пишет iAmt байт данных из второго параметра в файл, начиная
со смещения iOfst. Если размер файла меньше, чем iOfst байт до записи, xWrite
должен гарантировать, что файл расширен нолями до хотя бы iAmt+iOfst байт
до начала записи. xWrite расширяет файл по мере необходимости так, чтобы
размер файла был, по крайней мере, iAmt+iOfst байтами в конце xWrite.
xWrite возвращает SQLITE_OK при успехе,
Если запись не может закончиться, потому что среда базовой системы хранения
полна, то вернется SQLITE_FULL.
SQLITE_IOERR_WRITE
должен быть возвращен для любой другой ошибки. Метод xTruncate усекает файл до nByte байт в длину.
Если файл уже nByte байт или меньше, тогда этот метод ничего не делает.
Метод xTruncate вернет SQLITE_OK при успехе и
SQLITE_IOERR_TRUNCATE,
если что-нибудь идет не так, как надо. Метод xSync используется, чтобы вынудить ранее записанные
данные покинуть кэш операционной системы. Второй параметр обычно
SQLITE_SYNC_NORMAL.
Если второй параметр
SQLITE_SYNC_FULL, xSync
должен удостовериться, что данные также сброшены из кэша контроллера диска.
SQLITE_SYNC_FULL
аналог F_FULLSYNC ioctl() в Mac OS X. xSync возвращает
SQLITE_OK при успехе и
SQLITE_IOERR_FSYNC иначе. Метод xFileSize() определяет текущий размер файла в байтах и вписывает в
*pSize. Это возвращает SQLITE_OK
при успехе и SQLITE_IOERR_FSTAT,
если что-то идет не так, как надо. Методы xLock и xUnlock используются, чтобы установить и очистить
блокировки файла. SQLite поддерживает пять уровней блокировки файла в:
Метод xCheckReservedLock() проверяет,
держит ли другая связь или другой процесс в настоящее время блокировку
reserved, pending или exclusive на файле. Возвращает true или false. xFileControl() это универсальный интерфейс, который позволяет
внедрениям VFS непосредственно управлять открытым файлом, используя
(новый и экспериментальный)
sqlite3_file_control(). Второй аргумент "op" задает код
операции в виде целого числа. Третий аргумент это универсальный указатель,
который предназначается, чтобы быть указателем на структуру, которая может
содержать аргументы или место, в которое можно написать возвращаемые
значения. Потенциальное использование для xFileControl()
могло бы быть функциями, чтобы позволить блокировки с тайм-аутами, изменить
стратегию захвата (например, чтобы использовать точечные блокировки файла),
справиться о статусе блокировки или снять старые. Ядро SQLite резервирует
коды операции меньше 100 для его собственного использования.
Список кодов операции меньше 100 доступен. Запросы, которые определяют
свой метод xFileControl, должны использовать коды операции больше 100,
чтобы избежать конфликтов. xSectorSize возвращает "размер сектора" основных
энергонезависимых носителей. "Сектор" определяется как самая
маленькая единица хранения, которая может быть написана, не нарушая смежное
хранение. На дисководе "размер сектора" до недавнего времени
составлял 512 байт, хотя есть усилия увеличить это значение до 4KiB.
SQLite должен знать размер сектора так, чтобы это могло написать полный
сектор за один раз, и таким образом не портить смежное пространство
памяти, если потери питания происходят посреди записи. xDeviceCharacteristics возвращает битовый вектор целого числа, который
определяет любые специальные свойства, которые SQLite может использовать,
чтобы увеличить производительность. Позволенное возвращение это
OR следующих значений:
Предыдущие абзацы содержат большую информацию. Чтобы упростить создание
новой VFS для SQLite, мы предлагаем следующий
контрольный список внедрения: В рамках вашего приложения вызовите процедуру, осуществленную в последнем
шаге выше, как часть вашего процесса инициализации, прежде чем любые
соединения с базой данных будут открыты. С версии 3.5 SQLite получает всю память кучи с использованием
sqlite3_malloc(),
sqlite3_free() и
sqlite3_realloc().
Это существовало в предыдущих версиях SQLite, но SQLite ранее обошел этот
установленный порядок и использовал его собственного распределителя памяти.
Это изменено в версии 3.5.0. Исходное дерево SQLite на самом деле содержит много
версий распределителя памяти. Наиболее быстродействующая версия, найденная в
"mem1.c", используется для большинства сборок.
Но если флаг SQLITE_MEMDEBUG позволен, отдельный распределитель памяти
"mem2.c" используется вместо этого. Распределитель mem2.c осуществляет много
перехватов, чтобы сделать проверку на ошибки и моделировать сбои выделения
памяти для целей тестирования. Оба распределителя используют malloc()/free()
в стандартной библиотеке для C. Настройки не требуются, чтобы использовать любого из этих стандартных
распределителей памяти. Если SQLite собран с
SQLITE_OMIT_MEMORY_ALLOCATION,
тогда никакое внедрение для sqlite3_malloc(),
sqlite3_realloc() и
sqlite3_free() не обеспечиваются.
Вместо этого применение, которое связывается с SQLite,
должно обеспечить свое собственное внедрение этих функций.
Применение не обязано использовать malloc()/free()
в стандартной библиотеке для C. Встраиваемое приложение могло бы предоставить
альтернативный распределитель памяти, который использует память для пула
постоянной памяти, отложенного для исключительного
использования SQLite, например. Приложения, которые осуществляют их собственный распределитель памяти,
должны обеспечить внедрение для обычных трех функций распределения
sqlite3_malloc(),
sqlite3_realloc() и
sqlite3_free(). Они должны также
осуществить четвертую функцию: sqlite3_memory_alarm
используется, чтобы зарегистрировать отзыв на события выделения памяти.
Этот установленный порядок регистрирует или очищает отзыв, который
срабатывает, когда ассигнованный объем памяти превышает iThreshold.
Только единственный отзыв может быть зарегистрирован за один раз.
Каждый вызов sqlite3_memory_alarm()
переписывает предыдущий отзыв. Отзыв отключен, установив xCallback = NULL. Параметры отзыва это значение pArg, объем памяти, использующийся в
настоящее время, и размер распределения, которое вызвало отзыв.
Отзыв по-видимому вызовет sqlite3_free(),
чтобы освободить память. Отзыв может вызвать
sqlite3_malloc() или
sqlite3_realloc(),
но если это сделает, никакие дополнительные отзывы не будут
вызваны рекурсивными вызовами. sqlite3_soft_heap_limit()
работает, регистрируя сигнал памяти в мягком пределе кучи и вызывая
sqlite3_release_memory()
в сигнальном отзыве. Прикладные программы не должны пытаться использовать
sqlite3_memory_alarm(), потому что
выполнение этого вмешается в модуль
sqlite3_soft_heap_limit().
Этот интерфейс выставляется только, чтобы приложения могли обеспечить свое
собственное альтернативное внедрение, когда ядро SQLite собрано с
SQLITE_OMIT_MEMORY_ALLOCATION. Встроенные распределители памяти в SQLite также обеспечивают
следующие дополнительные интерфейсы: Эти интерфейсы могут использоваться приложением, чтобы
контролировать, сколько памяти SQLite использует.
sqlite3_memory_used()
возвращает число байтов использующейся в настоящее время памяти, а
sqlite3_memory_highwater()
возвращает максимальное мгновенное использование памяти.
Никакой установленный порядок не включает издержки, связанные с
распределителем памяти. Этот установленный порядок обеспечивается для
использования применением. SQLite никогда не призывает их сам. Таким образом,
если применение обеспечивает свою собственную подсистему выделения памяти,
оно может опустить эти интерфейсы при желании. SQLite всегда был ориентирован на многопотоковое исполнение в том смысле,
что безопасно использовать различные соединения с базой данных SQLite в
различных потоках в то же время. Ограничение состояло в том, что то же самое
соединение с базой данных не могло использоваться в двух отдельных потоках
сразу. Версия 3.5.0 SQLite ослабляет это ограничение. Чтобы позволить многократным потокам
использовать то же самое соединение с базой данных в то же время, SQLite
должен сделать широкое применение mutexes.
И поэтому новая mutex подсистема добавлена: Хотя этот установленный порядок существует для использования ядром
SQLite, код приложения может его использовать
также при желании. mutex это объект
sqlite3_mutex. sqlite3_mutex_alloc()
ассигнует новый объект mutex и возвращает указатель на него. Аргументом
sqlite3_mutex_alloc() должен быть
SQLITE_MUTEX_FAST или
SQLITE_MUTEX_RECURSIVE
для нерекурсивного и рекурсивного mutexes, соответственно.
Если основная система не обеспечивает нерекурсивный mutexes, то рекурсивным
mutex можно заменить в этом случае. Аргумент
sqlite3_mutex_alloc()
может также быть постоянным обозначением одного из
нескольких статических mutexes:
sqlite3_mutex_free()
должен использоваться, чтобы освободить нестатический mutex.
Если статический mutex передается этой функции, поведение не определено. sqlite3_mutex_enter()
пытается войти в mutex и блокирует, если другой поток уже занял.
sqlite3_mutex_try()
пытается войти и возвращает SQLITE_OK
при успехе или SQLITE_BUSY иначе.
sqlite3_mutex_leave()
выходит из mutex. mutex проводится, пока количество выходов не соответствует
количеству входов. Если
sqlite3_mutex_leave() вызывают на mutex, который в настоящее время не
держит поток, то поведение не определено. Если функцию вызывают для
освобожденного mutex, то поведение не определено. Исходный код SQLite обеспечивает многократные внедрения API,
подходящие для переменной окружающей среды. Если SQLite собран с флагом
SQLITE_THREADSAFE=0, тогда обеспечивается внедрение mutex, которое быстро, но
не делает никакого реального взаимного исключения.
То внедрение подходит для использования в однопоточных системах.
Другие реальные внедрения mutex обеспечиваются на основе
основной операционной системы. Встраиваемые приложения могут хотеть обеспечить свое собственное
mutex-внедрение. Если SQLite собран с флагом времени компиляции
-DSQLITE_MUTEX_APPDEF=1, ядро SQLite не обеспечивает mutex-подсистемы, и
mutex-подсистема, которая соответствует интерфейсу, описанному выше, должна
быть обеспечена приложением, которое связывается с SQLite. Version 3.5.0 SQLite изменяет поведение некоторых API способами, которые
технически несовместимы. Однако они, API редко используется и даже когда они
используются, трудно вообразить сценарий, где изменение могло бы сломать
что-то. Изменения на самом деле заставляют их
взаимодействовать намного лучше. До версии 3.5.0
sqlite3_enable_shared_cache() API
включал и отключал общий кэш для всех связей в единственном потоке, из
которого вызвали sqlite3_enable_shared_cache().
Соединения с базой данных, которые использовали общий кэш,
были ограничены управлением в том же самом потоке, в котором
они были открыты. Начиная с версии 3.5.0, sqlite3_enable_shared_cache()
относится ко всем соединениям с базой данных во всех потоках
в рамках процесса. Теперь соединения с базой данных в отдельных потоках
могут разделить кэш. Соединения с базой данных, которые используют общий
кэш, могут мигрировать от одного потока в другой. До версии 3.5.0
sqlite3_soft_heap_limit() устанавливал верхнюю границу использования
памяти кучи для всех соединений с базой данных в единственном потоке.
У каждого потока мог быть свой собственный предел кучи.
Начиная с версии 3.5.0, есть единственный предел кучи для всего процесса.
Это кажется более строгим (один предел в противоположность многим), но на
практике это то, что хочет большинство пользователей. До версии 3.5.0
sqlite3_release_memory() попыталась бы освободить
память от всех соединений с базой данных в том же самом потоке, где вызвана
sqlite3_release_memory(). Начиная с версии 3.5.0, sqlite3_release_memory()
попытается восстановить память от всех соединений с базой данных
во всех потоках. Переход от версии 3.4.2 SQLite до 3.5.0 является существенным изменением.
Каждый файл исходного кода в ядре SQLite должен был быть изменен, некоторые
значительно. Изменение ввело некоторые незначительные несовместимости в
интерфейсе C. Но мы чувствуем, что выгода перехода от 3.4.2 до 3.5.0 далеко
перевешивает проблемы переноса. Новый слой VFS теперь четко определен и
стабилен и должен упростить будущие настройки. Слой VFS, отдельный
распределитель памяти и mutex подсистемы позволяют стандартному объединению
исходного кода SQLite использоваться во вложенном проекте без изменения,
значительно упрощая управление конфигурацией. И получающаяся система намного
более терпима к очень сложным проектам.
Choose any three.
Изменения SQLite от версии 3.4.2 до 3.5.0
1.0. Обзор изменений
2.0. Слой интерфейса OS
2.1. Объект виртуальной файловой системы
2.1.1. Регистрация новых объектов VFS
int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
2.1.2. Дополнительный контроль над объектами VFS
int sqlite3_vfs_unregister(sqlite3_vfs*);
sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
2.1.3. Модификации существующего VFS
2.1.4. Объект VFS
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
int iVersion; /* Structure version number */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags);
int (*xGetTempName)(sqlite3_vfs*, char *zOut);
int (*xFullPathname)(sqlite3_vfs*, const char *zName, char *zOut);
void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol);
void (*xDlClose)(sqlite3_vfs*, void*);
int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
/* New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens. */
};
Внедрение файлового ввода-вывода может использовать флаги типа объекта для
изменения того, как оно имеет дело с файлами. Например, применение, которое
не заботится о восстановлении катастрофы или обратной перемотке, могло бы
заставить открытый журнал ничего не делать. Записи в него также могут не
работать. Любая попытка прочитать журнал возвращает
SQLITE_IOERR.
Или внедрение могло бы использовать файл базы данных, выровненный
со страницей на сектор для чтения и записи в произвольном порядке и настроил
свою подсистему I/O соответственно. SQLite мог бы также добавить один из
следующих флагов к методу xOpen:
SQLITE_OPEN_DELETEONCLOSE
означает, что файл должен быть удален, когда закрывается. Это будет всегда
устанавливаться для баз данных TEMP, журналов и для поджурналов.
SQLITE_OPEN_EXCLUSIVE
означает, что файл должен быть открыт для эксклюзивного доступа.
Этот флаг установлен для всех файлов за исключением главного файла базы
данных. Структура sqlite3_file, переданная как
третий аргумент xOpen, ассигнуется вызывающим.
xOpen просто заполняет ее. Вызывающий ассигнует минимум szOsFile байтов для
структуры sqlite3_file.
2.1.5. Открытый объект файла
typedef struct sqlite3_file sqlite3_file;
struct sqlite3_file {const struct sqlite3_io_methods *pMethods;};
typedef struct sqlite3_io_methods sqlite3_io_methods;
struct sqlite3_io_methods {
int iVersion;
int (*xClose)(sqlite3_file*);
int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
int (*xSync)(sqlite3_file*, int flags);
int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
int (*xLock)(sqlite3_file*, int);
int (*xUnlock)(sqlite3_file*, int);
int (*xCheckReservedLock)(sqlite3_file*);
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
/* Additional methods may be added in future releases */
};
SQLITE_IOCAP_ATOMIC
значит, что все записи атомные в том смысле, что или вся запись происходит,
или не происходит вообще. Другие значения
SQLITE_IOCAP_ATOMICnnn
указывают, что записи в выровненных блоках обозначенного размера атомные.
SQLITE_IOCAP_SAFE_APPEND
означает, что, расширяя файл с новыми данными, сначала новые данные
написаны, и затем размер файла обновляется. Таким образом, если перебой в
питании происходит, нет никакого шанса, что файл, возможно, был расширен с
хаотичностью. SQLITE_IOCAP_SEQUENTIAL
значит, что все записи происходят в порядке, в котором
они выпущены и не переупорядочены основной файловой системой.
2.1.6. Контрольный список для создания новой VFS
3.0. Подсистема выделения памяти
int sqlite3_memory_alarm(void(*xCallback)(void *pArg, sqlite3_int64 used,
int N), void *pArg, sqlite3_int64 iThreshold);
sqlite3_int64 sqlite3_memory_used(void);
sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
4.0. Подсистема Mutex
sqlite3_mutex *sqlite3_mutex_alloc(int);
void sqlite3_mutex_free(sqlite3_mutex*);
void sqlite3_mutex_enter(sqlite3_mutex*);
int sqlite3_mutex_try(sqlite3_mutex*);
void sqlite3_mutex_leave(sqlite3_mutex*);
Эти статические mutexes резервируются для использования внутренне SQLite и не
должны использоваться приложением. Статические mutexes все нерекурсивные.
5.0. Другие интерфейсные изменения
6.0. Резюме