Unlock Notification
Unlock Notification
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 */
在共享高速缓存模式下运行时,如果无法获取共享高速缓存或共享高速缓存内的单个表上所需的锁,则数据库操作可能会失败,并显示SQLITE_LOCKED错误。有关共享缓存锁定的说明,请参阅SQLite共享缓存模式。这个API可以用于注册一个回调,SQLite将在当前持有所需锁的连接放弃它时调用该回调。只有在定义了SQLITE_ENABLE_UNLOCK_NOTIFY C预处理程序符号的情况下才编译该库,该API才可用。
Callback Invocation Details
当注册一个unlock-notify回调函数时,应用程序提供一个void *指针,该指针在被调用时传递给回调函数。但是,回调函数的签名允许SQLite将它传递给一个void *上下文指针数组。传递给unlock-notify回调的第一个参数是指向void *指针数组的指针,第二个参数是数组中的条目数。
当阻塞连接事务结束时,可能有多个已注册解锁通知回调的阻塞连接。如果两个或多个这样的阻塞连接指定了相同的回调函数,则不是多次调用回调函数,而是使用捆绑在一起的阻塞连接指定的void *上下文指针集合调用一次数组。这为应用程序提供了一个机会,可以确定与未阻止的数据库连接集相关的任何操作的优先级。
Deadlock Detection
假设注册一个unlock-notify回调后,数据库在采取任何进一步行动(一个合理的假设)之前等待回调被发出,那么使用这个API可能会导致应用程序死锁。例如,如果连接X正在等待连接Y的事务结束,并且类似地连接Y正在等待连接X的事务,则两个连接都不会继续,系统可能无限期地保持死锁。
为了避免这种情况,sqlite3_unlock_notify()执行死锁检测。如果对sqlite3_unlock_notify()的给定调用会使系统处于死锁状态,则返回SQLITE_LOCKED,并且不会注册unlock-notify回调。如果在连接B的事务结束时连接A已经注册了解锁通知回调,并且当连接A的事务结束时连接B本身已经注册了解锁通知回调,则称该系统处于死锁状态。间接死锁也被检测到,所以如果连接B已经在连接C的事务结束时注册了解锁通知回调,那么系统也被认为是死锁的,其中连接C正在连接A上等待。任何数量的间接级别是允许。
The "DROP TABLE" Exception
当对sqlite3_step()的调用返回SQLITE_LOCKED时,调用sqlite3_unlock_notify()几乎总是合适的。然而,有一个例外。当执行“DROP TABLE”或“DROP INDEX”语句时,SQLite将检查是否有任何当前正在执行的SELECT语句属于同一个连接。如果有,则返回SQLITE_LOCKED。在这种情况下,没有“阻塞连接”,因此调用sqlite3_unlock_notify()会立即调用unlock-notify回调。如果应用程序然后重新尝试“DROP TABLE”或“DROP INDEX”查询,则可能导致无限循环。
解决此问题的一种方法是检查由sqlite3_step()调用返回的扩展错误代码。如果存在阻塞连接,则扩展错误代码将设置为SQLITE_LOCKED_SHAREDCACHE。否则,在特殊的“DROP TABLE / INDEX”情况下,扩展错误代码只是SQLITE_LOCKED。
SQLite is in the Public Domain.