4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This file contains the implementation of the sqlite3_unlock_notify()
14 ** API method and its associated functionality.
16 #include "sqliteInt.h"
19 /* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
20 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
25 ** sqlite3ConnectionBlocked()
26 ** sqlite3ConnectionUnlocked()
27 ** sqlite3ConnectionClosed()
28 ** sqlite3_unlock_notify()
31 #define assertMutexHeld() \
32 assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) )
35 ** Head of a linked list of all sqlite3 objects created by this process
36 ** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
37 ** is not NULL. This variable may only accessed while the STATIC_MAIN
40 static sqlite3
*SQLITE_WSD sqlite3BlockedList
= 0;
44 ** This function is a complex assert() that verifies the following
45 ** properties of the blocked connections list:
47 ** 1) Each entry in the list has a non-NULL value for either
48 ** pUnlockConnection or pBlockingConnection, or both.
50 ** 2) All entries in the list that share a common value for
51 ** xUnlockNotify are grouped together.
53 ** 3) If the argument db is not NULL, then none of the entries in the
54 ** blocked connections list have pUnlockConnection or pBlockingConnection
55 ** set to db. This is used when closing connection db.
57 static void checkListProperties(sqlite3
*db
){
59 for(p
=sqlite3BlockedList
; p
; p
=p
->pNextBlocked
){
63 /* Verify property (1) */
64 assert( p
->pUnlockConnection
|| p
->pBlockingConnection
);
66 /* Verify property (2) */
67 for(p2
=sqlite3BlockedList
; p2
!=p
; p2
=p2
->pNextBlocked
){
68 if( p2
->xUnlockNotify
==p
->xUnlockNotify
) seen
= 1;
69 assert( p2
->xUnlockNotify
==p
->xUnlockNotify
|| !seen
);
70 assert( db
==0 || p
->pUnlockConnection
!=db
);
71 assert( db
==0 || p
->pBlockingConnection
!=db
);
76 # define checkListProperties(x)
80 ** Remove connection db from the blocked connections list. If connection
81 ** db is not currently a part of the list, this function is a no-op.
83 static void removeFromBlockedList(sqlite3
*db
){
86 for(pp
=&sqlite3BlockedList
; *pp
; pp
= &(*pp
)->pNextBlocked
){
88 *pp
= (*pp
)->pNextBlocked
;
95 ** Add connection db to the blocked connections list. It is assumed
96 ** that it is not already a part of the list.
98 static void addToBlockedList(sqlite3
*db
){
102 pp
=&sqlite3BlockedList
;
103 *pp
&& (*pp
)->xUnlockNotify
!=db
->xUnlockNotify
;
104 pp
=&(*pp
)->pNextBlocked
106 db
->pNextBlocked
= *pp
;
111 ** Obtain the STATIC_MAIN mutex.
113 static void enterMutex(void){
114 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN
));
115 checkListProperties(0);
119 ** Release the STATIC_MAIN mutex.
121 static void leaveMutex(void){
123 checkListProperties(0);
124 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN
));
128 ** Register an unlock-notify callback.
130 ** This is called after connection "db" has attempted some operation
131 ** but has received an SQLITE_LOCKED error because another connection
132 ** (call it pOther) in the same process was busy using the same shared
133 ** cache. pOther is found by looking at db->pBlockingConnection.
135 ** If there is no blocking connection, the callback is invoked immediately,
136 ** before this routine returns.
138 ** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate
141 ** Otherwise, make arrangements to invoke xNotify when pOther drops
144 ** Each call to this routine overrides any prior callbacks registered
145 ** on the same "db". If xNotify==0 then any prior callbacks are immediately
148 int sqlite3_unlock_notify(
150 void (*xNotify
)(void **, int),
155 sqlite3_mutex_enter(db
->mutex
);
159 removeFromBlockedList(db
);
160 db
->pBlockingConnection
= 0;
161 db
->pUnlockConnection
= 0;
162 db
->xUnlockNotify
= 0;
164 }else if( 0==db
->pBlockingConnection
){
165 /* The blocking transaction has been concluded. Or there never was a
166 ** blocking transaction. In either case, invoke the notify callback
173 for(p
=db
->pBlockingConnection
; p
&& p
!=db
; p
=p
->pUnlockConnection
){}
175 rc
= SQLITE_LOCKED
; /* Deadlock detected. */
177 db
->pUnlockConnection
= db
->pBlockingConnection
;
178 db
->xUnlockNotify
= xNotify
;
179 db
->pUnlockArg
= pArg
;
180 removeFromBlockedList(db
);
181 addToBlockedList(db
);
186 assert( !db
->mallocFailed
);
187 sqlite3ErrorWithMsg(db
, rc
, (rc
?"database is deadlocked":0));
188 sqlite3_mutex_leave(db
->mutex
);
193 ** This function is called while stepping or preparing a statement
194 ** associated with connection db. The operation will return SQLITE_LOCKED
195 ** to the user because it requires a lock that will not be available
196 ** until connection pBlocker concludes its current transaction.
198 void sqlite3ConnectionBlocked(sqlite3
*db
, sqlite3
*pBlocker
){
200 if( db
->pBlockingConnection
==0 && db
->pUnlockConnection
==0 ){
201 addToBlockedList(db
);
203 db
->pBlockingConnection
= pBlocker
;
208 ** This function is called when
209 ** the transaction opened by database db has just finished. Locks held
210 ** by database connection db have been released.
212 ** This function loops through each entry in the blocked connections
213 ** list and does the following:
215 ** 1) If the sqlite3.pBlockingConnection member of a list entry is
216 ** set to db, then set pBlockingConnection=0.
218 ** 2) If the sqlite3.pUnlockConnection member of a list entry is
219 ** set to db, then invoke the configured unlock-notify callback and
220 ** set pUnlockConnection=0.
222 ** 3) If the two steps above mean that pBlockingConnection==0 and
223 ** pUnlockConnection==0, remove the entry from the blocked connections
226 void sqlite3ConnectionUnlocked(sqlite3
*db
){
227 void (*xUnlockNotify
)(void **, int) = 0; /* Unlock-notify cb to invoke */
228 int nArg
= 0; /* Number of entries in aArg[] */
229 sqlite3
**pp
; /* Iterator variable */
230 void **aArg
; /* Arguments to the unlock callback */
231 void **aDyn
= 0; /* Dynamically allocated space for aArg[] */
232 void *aStatic
[16]; /* Starter space for aArg[]. No malloc required */
235 enterMutex(); /* Enter STATIC_MAIN mutex */
237 /* This loop runs once for each entry in the blocked-connections list. */
238 for(pp
=&sqlite3BlockedList
; *pp
; /* no-op */ ){
242 if( p
->pBlockingConnection
==db
){
243 p
->pBlockingConnection
= 0;
247 if( p
->pUnlockConnection
==db
){
248 assert( p
->xUnlockNotify
);
249 if( p
->xUnlockNotify
!=xUnlockNotify
&& nArg
!=0 ){
250 xUnlockNotify(aArg
, nArg
);
254 sqlite3BeginBenignMalloc();
255 assert( aArg
==aDyn
|| (aDyn
==0 && aArg
==aStatic
) );
256 assert( nArg
<=(int)ArraySize(aStatic
) || aArg
==aDyn
);
257 if( (!aDyn
&& nArg
==(int)ArraySize(aStatic
))
258 || (aDyn
&& nArg
==(int)(sqlite3MallocSize(aDyn
)/sizeof(void*)))
260 /* The aArg[] array needs to grow. */
261 void **pNew
= (void **)sqlite3Malloc(nArg
*sizeof(void *)*2);
263 memcpy(pNew
, aArg
, nArg
*sizeof(void *));
267 /* This occurs when the array of context pointers that need to
268 ** be passed to the unlock-notify callback is larger than the
269 ** aStatic[] array allocated on the stack and the attempt to
270 ** allocate a larger array from the heap has failed.
272 ** This is a difficult situation to handle. Returning an error
273 ** code to the caller is insufficient, as even if an error code
274 ** is returned the transaction on connection db will still be
275 ** closed and the unlock-notify callbacks on blocked connections
276 ** will go unissued. This might cause the application to wait
277 ** indefinitely for an unlock-notify callback that will never
280 ** Instead, invoke the unlock-notify callback with the context
281 ** array already accumulated. We can then clear the array and
282 ** begin accumulating any further context pointers without
283 ** requiring any dynamic allocation. This is sub-optimal because
284 ** it means that instead of one callback with a large array of
285 ** context pointers the application will receive two or more
286 ** callbacks with smaller arrays of context pointers, which will
287 ** reduce the applications ability to prioritize multiple
288 ** connections. But it is the best that can be done under the
291 xUnlockNotify(aArg
, nArg
);
295 sqlite3EndBenignMalloc();
297 aArg
[nArg
++] = p
->pUnlockArg
;
298 xUnlockNotify
= p
->xUnlockNotify
;
299 p
->pUnlockConnection
= 0;
300 p
->xUnlockNotify
= 0;
305 if( p
->pBlockingConnection
==0 && p
->pUnlockConnection
==0 ){
306 /* Remove connection p from the blocked connections list. */
307 *pp
= p
->pNextBlocked
;
310 pp
= &p
->pNextBlocked
;
315 xUnlockNotify(aArg
, nArg
);
318 leaveMutex(); /* Leave STATIC_MAIN mutex */
322 ** This is called when the database connection passed as an argument is
323 ** being closed. The connection is removed from the blocked list.
325 void sqlite3ConnectionClosed(sqlite3
*db
){
326 sqlite3ConnectionUnlocked(db
);
328 removeFromBlockedList(db
);
329 checkListProperties(db
);