![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
Работая в общем режиме кэширования, операция по базе данных может
потерпеть неудачу с ошибкой SQLITE_LOCKED,
если необходимые блокировки в общем кэше или отдельных таблицах в общем кэше
не могут быть получены. См.
описание захвата общего кэша.
API может использоваться, чтобы зарегистрировать отзыв, который вызовет
SQLite, когда связь, в настоящее время держащая необходимую блокировку, ее
оставит. Этот API доступен только если библиотека была собрана с определенным
символом C-препроцессора
SQLITE_ENABLE_UNLOCK_NOTIFY. Блокировки общего кэша выпущены, когда соединение с базой данных завершает
свою текущую транзакцию. Когда связь (известная как заблокированная связь) не может получить
блокировка общего кэша, и SQLITE_LOCKED возвращается, идентичность соединения
с базой данных (связь блокирования), которая захватила необходимый ресурс,
сохранена внутренне. После того, как приложение получает ошибку
SQLITE_LOCKED, оно может вызвать метод sqlite3_unlock_notify()
с заблокированным обработчиком связи как первый аргумент, чтобы
зарегистрироваться для отзыва, который будет вызван, когда текущая транзакция
связей блокирования будет завершена. Отзыв вызван из
sqlite3_step или
sqlite3_close, что завершает
транзакцию связи блокирования. Если sqlite3_unlock_notify() вызывают в многопоточном приложении, есть
шанс, что связь блокирования уже завершит свою транзакцию к тому времени,
когда вызвали sqlite3_unlock_notify().
Если это происходит, то указанный отзыв немедленно вызван из
sqlite3_unlock_notify(). Если заблокированная связь пытается получить блокировку записи на
таблице в общем кэше и больше, чем еще одна связь в настоящее время держит
блокировку чтения на той же самой таблице, то SQLite произвольно выбирает
одну из других связей, чтобы использовать в качестве связи блокирования. Может быть самое большее один отзыв, зарегистрированный заблокированной
связью. Если sqlite3_unlock_notify() вызывают, когда у заблокированной связи
уже есть зарегистрированный отзыв, то новый отзыв заменяет старый. Если
sqlite3_unlock_notify() вызывают с NULL как его второй аргумент, то любой
существующий отзыв уведомления отменяется. Отзыв может также быть отменен,
закрыв заблокированную связь, используя
sqlite3_close(). Если приложение вызывает какие-либо функции API sqlite3_xxx,
из отзыва уведомления, катастрофа или мертвая блокировка
могут быть результатом. Если мертвая блокировка не обнаружена (см. ниже),
sqlite3_unlock_notify() всегда вернет SQLITE_OK. Детали вызова отзыва Когда отзыв зарегистрирован, применение обеспечивает единственный
указатель void*, который передается к отзыву, когда это вызвано. Однако,
сигнатура функции обратного вызова позволяет SQLite передавать ему множество
указателей контекста void*. Первый аргумент, переданный
отзыву это указатель на множество указателей void*,
вторым является количество записей во множестве. Когда транзакция связи блокирования завершена, может быть больше, чем одна
заблокированная связь, которая зарегистрировалась для отзыва уведомления.
Если две или больше таких заблокированных связи определили ту же самую
функцию обратного вызова, то вместо того, чтобы вызвать функцию обратного
вызова многократно, она вызвана однажды с набором указателей контекста,
определенных заблокированными связями, связанными вместе во множество.
Это дает применению возможность расположить по приоритетам любые действия,
связанные с набором открытых соединений с базой данных. Обнаружение мертвой блокировки Предположим, что после регистрации отзыва база данных ждет отзыва, который
будет выпущен прежде, чем принять дальнейшие меры (разумное предположение),
затем используя этот API, может зайти в тупик. Например, если связь X будет
ждать завершения соединения транзакции Y, а связь Y ждет транзакцию X, то
никакая связь не продолжится, и система может остаться заведенной
в тупик неопределенно долго. Чтобы избежать этого сценария, sqlite3_unlock_notify()
выполняет обнаружение мертвой блокировки. Если бы данный запрос к
sqlite3_unlock_notify() поместил бы систему в заведенное в тупик состояние,
то SQLITE_LOCKED возвращен, и отзыв не регистрируют.
Система, как говорят, находится в заведенном в тупик состоянии,
если связь A зарегистрировала отзыв
относительно заключения транзакции Б связи, и связь B самостоятельно
зарегистрировала отзыв, когда транзакция А связи завершена.
Косвенная мертвая блокировка также обнаружена, таким образом, система также
считается заведенной в тупик, если связь B зарегистрировала отзыв
уведомления относительно заключения транзакции C,
где связь C ждет связь A. Любое количество уровней абстракции позволено. Исключение "DROP TABLE" Когда sqlite3_step() вовзращает SQLITE_LOCKED,
почти всегда уместно вызвать sqlite3_unlock_notify().
Есть, однако, одно исключение. Выполняя запрос "DROP TABLE" или "DROP INDEX",
SQLite проверяет, есть ли какие-либо в настоящее время выполняющиеся
операторы SELECT, которые принадлежат той же самой связи.
Если есть, SQLITE_LOCKED возвращен. В этом случае нет никакой
"связи блокирования", таким образом, результаты вызова
sqlite3_unlock_notify() поступают немедленно. Если приложение повторно
делает попытку запроса "DROP TABLE" или "DROP INDEX",
бесконечный цикл мог бы быть результатом. Один обход этой проблемы состоит в том, чтобы проверить расширенный код
ошибки, возвращенный sqlite3_step().
Если есть связь блокирования, то расширенный код ошибки установлен в
SQLITE_LOCKED_SHAREDCACHE. Иначе, в специальном случае
"DROP TABLE/INDEX" расширенный код ошибки это просто SQLITE_LOCKED.
Choose any three.
SQLite C Interface
Разблокировать уведомление
int sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
);