1/*
2** 2009 March 3
3**
4** The author disclaims copyright to this source code.  In place of
5** a legal notice, here is a blessing:
6**
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.
10**
11*************************************************************************
12**
13** This file contains the implementation of the sqlite3_unlock_notify()
14** API method and its associated functionality.
15*/
16#include "sqliteInt.h"
17#include "btreeInt.h"
18
19/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
20#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
21
22/*
23** Public interfaces:
24**
25**   sqlite3ConnectionBlocked()
26**   sqlite3ConnectionUnlocked()
27**   sqlite3ConnectionClosed()
28**   sqlite3_unlock_notify()
29*/
30
31#define assertMutexHeld() \
32  assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
33
34/*
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_MASTER
38** mutex is held.
39*/
40static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
41
42#ifndef NDEBUG
43/*
44** This function is a complex assert() that verifies the following
45** properties of the blocked connections list:
46**
47**   1) Each entry in the list has a non-NULL value for either
48**      pUnlockConnection or pBlockingConnection, or both.
49**
50**   2) All entries in the list that share a common value for
51**      xUnlockNotify are grouped together.
52**
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.
56*/
57static void checkListProperties(sqlite3 *db){
58  sqlite3 *p;
59  for(p=sqlite3BlockedList; p; p=p->pNextBlocked){
60    int seen = 0;
61    sqlite3 *p2;
62
63    /* Verify property (1) */
64    assert( p->pUnlockConnection || p->pBlockingConnection );
65
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 );
72    }
73  }
74}
75#else
76# define checkListProperties(x)
77#endif
78
79/*
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.
82*/
83static void removeFromBlockedList(sqlite3 *db){
84  sqlite3 **pp;
85  assertMutexHeld();
86  for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
87    if( *pp==db ){
88      *pp = (*pp)->pNextBlocked;
89      break;
90    }
91  }
92}
93
94/*
95** Add connection db to the blocked connections list. It is assumed
96** that it is not already a part of the list.
97*/
98static void addToBlockedList(sqlite3 *db){
99  sqlite3 **pp;
100  assertMutexHeld();
101  for(
102    pp=&sqlite3BlockedList;
103    *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
104    pp=&(*pp)->pNextBlocked
105  );
106  db->pNextBlocked = *pp;
107  *pp = db;
108}
109
110/*
111** Obtain the STATIC_MASTER mutex.
112*/
113static void enterMutex(void){
114  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
115  checkListProperties(0);
116}
117
118/*
119** Release the STATIC_MASTER mutex.
120*/
121static void leaveMutex(void){
122  assertMutexHeld();
123  checkListProperties(0);
124  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
125}
126
127/*
128** Register an unlock-notify callback.
129**
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.
134**
135** If there is no blocking connection, the callback is invoked immediately,
136** before this routine returns.
137**
138** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate
139** a deadlock.
140**
141** Otherwise, make arrangements to invoke xNotify when pOther drops
142** its locks.
143**
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
146** cancelled.
147*/
148int sqlite3_unlock_notify(
149  sqlite3 *db,
150  void (*xNotify)(void **, int),
151  void *pArg
152){
153  int rc = SQLITE_OK;
154
155  sqlite3_mutex_enter(db->mutex);
156  enterMutex();
157
158  if( xNotify==0 ){
159    removeFromBlockedList(db);
160    db->pBlockingConnection = 0;
161    db->pUnlockConnection = 0;
162    db->xUnlockNotify = 0;
163    db->pUnlockArg = 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
167    ** immediately.
168    */
169    xNotify(&pArg, 1);
170  }else{
171    sqlite3 *p;
172
173    for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){}
174    if( p ){
175      rc = SQLITE_LOCKED;              /* Deadlock detected. */
176    }else{
177      db->pUnlockConnection = db->pBlockingConnection;
178      db->xUnlockNotify = xNotify;
179      db->pUnlockArg = pArg;
180      removeFromBlockedList(db);
181      addToBlockedList(db);
182    }
183  }
184
185  leaveMutex();
186  assert( !db->mallocFailed );
187  sqlite3Error(db, rc, (rc?"database is deadlocked":0));
188  sqlite3_mutex_leave(db->mutex);
189  return rc;
190}
191
192/*
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.
197*/
198void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
199  enterMutex();
200  if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){
201    addToBlockedList(db);
202  }
203  db->pBlockingConnection = pBlocker;
204  leaveMutex();
205}
206
207/*
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.
211**
212** This function loops through each entry in the blocked connections
213** list and does the following:
214**
215**   1) If the sqlite3.pBlockingConnection member of a list entry is
216**      set to db, then set pBlockingConnection=0.
217**
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.
221**
222**   3) If the two steps above mean that pBlockingConnection==0 and
223**      pUnlockConnection==0, remove the entry from the blocked connections
224**      list.
225*/
226void 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 */
233
234  aArg = aStatic;
235  enterMutex();         /* Enter STATIC_MASTER mutex */
236
237  /* This loop runs once for each entry in the blocked-connections list. */
238  for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
239    sqlite3 *p = *pp;
240
241    /* Step 1. */
242    if( p->pBlockingConnection==db ){
243      p->pBlockingConnection = 0;
244    }
245
246    /* Step 2. */
247    if( p->pUnlockConnection==db ){
248      assert( p->xUnlockNotify );
249      if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){
250        xUnlockNotify(aArg, nArg);
251        nArg = 0;
252      }
253
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*)))
259      ){
260        /* The aArg[] array needs to grow. */
261        void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
262        if( pNew ){
263          memcpy(pNew, aArg, nArg*sizeof(void *));
264          sqlite3_free(aDyn);
265          aDyn = aArg = pNew;
266        }else{
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.
271          **
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
278          ** arrive.
279          **
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
289          ** circumstances.
290          */
291          xUnlockNotify(aArg, nArg);
292          nArg = 0;
293        }
294      }
295      sqlite3EndBenignMalloc();
296
297      aArg[nArg++] = p->pUnlockArg;
298      xUnlockNotify = p->xUnlockNotify;
299      p->pUnlockConnection = 0;
300      p->xUnlockNotify = 0;
301      p->pUnlockArg = 0;
302    }
303
304    /* Step 3. */
305    if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){
306      /* Remove connection p from the blocked connections list. */
307      *pp = p->pNextBlocked;
308      p->pNextBlocked = 0;
309    }else{
310      pp = &p->pNextBlocked;
311    }
312  }
313
314  if( nArg!=0 ){
315    xUnlockNotify(aArg, nArg);
316  }
317  sqlite3_free(aDyn);
318  leaveMutex();         /* Leave STATIC_MASTER mutex */
319}
320
321/*
322** This is called when the database connection passed as an argument is
323** being closed. The connection is removed from the blocked list.
324*/
325void sqlite3ConnectionClosed(sqlite3 *db){
326  sqlite3ConnectionUnlocked(db);
327  enterMutex();
328  removeFromBlockedList(db);
329  checkListProperties(db);
330  leaveMutex();
331}
332#endif
333