xref: /sqlite-3.40.0/src/btmutex.c (revision f2fcd075)
1 /*
2 ** 2007 August 27
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 code used to implement mutexes on Btree objects.
14 ** This code really belongs in btree.c.  But btree.c is getting too
15 ** big and we want to break it down some.  This packaged seemed like
16 ** a good breakout.
17 */
18 #include "btreeInt.h"
19 #ifndef SQLITE_OMIT_SHARED_CACHE
20 #if SQLITE_THREADSAFE
21 
22 /*
23 ** Obtain the BtShared mutex associated with B-Tree handle p. Also,
24 ** set BtShared.db to the database handle associated with p and the
25 ** p->locked boolean to true.
26 */
27 static void lockBtreeMutex(Btree *p){
28   assert( p->locked==0 );
29   assert( sqlite3_mutex_notheld(p->pBt->mutex) );
30   assert( sqlite3_mutex_held(p->db->mutex) );
31 
32   sqlite3_mutex_enter(p->pBt->mutex);
33   p->pBt->db = p->db;
34   p->locked = 1;
35 }
36 
37 /*
38 ** Release the BtShared mutex associated with B-Tree handle p and
39 ** clear the p->locked boolean.
40 */
41 static void unlockBtreeMutex(Btree *p){
42   assert( p->locked==1 );
43   assert( sqlite3_mutex_held(p->pBt->mutex) );
44   assert( sqlite3_mutex_held(p->db->mutex) );
45   assert( p->db==p->pBt->db );
46 
47   sqlite3_mutex_leave(p->pBt->mutex);
48   p->locked = 0;
49 }
50 
51 /*
52 ** Enter a mutex on the given BTree object.
53 **
54 ** If the object is not sharable, then no mutex is ever required
55 ** and this routine is a no-op.  The underlying mutex is non-recursive.
56 ** But we keep a reference count in Btree.wantToLock so the behavior
57 ** of this interface is recursive.
58 **
59 ** To avoid deadlocks, multiple Btrees are locked in the same order
60 ** by all database connections.  The p->pNext is a list of other
61 ** Btrees belonging to the same database connection as the p Btree
62 ** which need to be locked after p.  If we cannot get a lock on
63 ** p, then first unlock all of the others on p->pNext, then wait
64 ** for the lock to become available on p, then relock all of the
65 ** subsequent Btrees that desire a lock.
66 */
67 void sqlite3BtreeEnter(Btree *p){
68   Btree *pLater;
69 
70   /* Some basic sanity checking on the Btree.  The list of Btrees
71   ** connected by pNext and pPrev should be in sorted order by
72   ** Btree.pBt value. All elements of the list should belong to
73   ** the same connection. Only shared Btrees are on the list. */
74   assert( p->pNext==0 || p->pNext->pBt>p->pBt );
75   assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
76   assert( p->pNext==0 || p->pNext->db==p->db );
77   assert( p->pPrev==0 || p->pPrev->db==p->db );
78   assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
79 
80   /* Check for locking consistency */
81   assert( !p->locked || p->wantToLock>0 );
82   assert( p->sharable || p->wantToLock==0 );
83 
84   /* We should already hold a lock on the database connection */
85   assert( sqlite3_mutex_held(p->db->mutex) );
86 
87   /* Unless the database is sharable and unlocked, then BtShared.db
88   ** should already be set correctly. */
89   assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
90 
91   if( !p->sharable ) return;
92   p->wantToLock++;
93   if( p->locked ) return;
94 
95   /* In most cases, we should be able to acquire the lock we
96   ** want without having to go throught the ascending lock
97   ** procedure that follows.  Just be sure not to block.
98   */
99   if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
100     p->pBt->db = p->db;
101     p->locked = 1;
102     return;
103   }
104 
105   /* To avoid deadlock, first release all locks with a larger
106   ** BtShared address.  Then acquire our lock.  Then reacquire
107   ** the other BtShared locks that we used to hold in ascending
108   ** order.
109   */
110   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
111     assert( pLater->sharable );
112     assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
113     assert( !pLater->locked || pLater->wantToLock>0 );
114     if( pLater->locked ){
115       unlockBtreeMutex(pLater);
116     }
117   }
118   lockBtreeMutex(p);
119   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
120     if( pLater->wantToLock ){
121       lockBtreeMutex(pLater);
122     }
123   }
124 }
125 
126 /*
127 ** Exit the recursive mutex on a Btree.
128 */
129 void sqlite3BtreeLeave(Btree *p){
130   if( p->sharable ){
131     assert( p->wantToLock>0 );
132     p->wantToLock--;
133     if( p->wantToLock==0 ){
134       unlockBtreeMutex(p);
135     }
136   }
137 }
138 
139 #ifndef NDEBUG
140 /*
141 ** Return true if the BtShared mutex is held on the btree, or if the
142 ** B-Tree is not marked as sharable.
143 **
144 ** This routine is used only from within assert() statements.
145 */
146 int sqlite3BtreeHoldsMutex(Btree *p){
147   assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
148   assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
149   assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
150   assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
151 
152   return (p->sharable==0 || p->locked);
153 }
154 #endif
155 
156 
157 #ifndef SQLITE_OMIT_INCRBLOB
158 /*
159 ** Enter and leave a mutex on a Btree given a cursor owned by that
160 ** Btree.  These entry points are used by incremental I/O and can be
161 ** omitted if that module is not used.
162 */
163 void sqlite3BtreeEnterCursor(BtCursor *pCur){
164   sqlite3BtreeEnter(pCur->pBtree);
165 }
166 void sqlite3BtreeLeaveCursor(BtCursor *pCur){
167   sqlite3BtreeLeave(pCur->pBtree);
168 }
169 #endif /* SQLITE_OMIT_INCRBLOB */
170 
171 
172 /*
173 ** Enter the mutex on every Btree associated with a database
174 ** connection.  This is needed (for example) prior to parsing
175 ** a statement since we will be comparing table and column names
176 ** against all schemas and we do not want those schemas being
177 ** reset out from under us.
178 **
179 ** There is a corresponding leave-all procedures.
180 **
181 ** Enter the mutexes in accending order by BtShared pointer address
182 ** to avoid the possibility of deadlock when two threads with
183 ** two or more btrees in common both try to lock all their btrees
184 ** at the same instant.
185 */
186 void sqlite3BtreeEnterAll(sqlite3 *db){
187   int i;
188   Btree *p, *pLater;
189   assert( sqlite3_mutex_held(db->mutex) );
190   for(i=0; i<db->nDb; i++){
191     p = db->aDb[i].pBt;
192     assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
193     if( p && p->sharable ){
194       p->wantToLock++;
195       if( !p->locked ){
196         assert( p->wantToLock==1 );
197         while( p->pPrev ) p = p->pPrev;
198         /* Reason for ALWAYS:  There must be at least on unlocked Btree in
199         ** the chain.  Otherwise the !p->locked test above would have failed */
200         while( p->locked && ALWAYS(p->pNext) ) p = p->pNext;
201         for(pLater = p->pNext; pLater; pLater=pLater->pNext){
202           if( pLater->locked ){
203             unlockBtreeMutex(pLater);
204           }
205         }
206         while( p ){
207           lockBtreeMutex(p);
208           p = p->pNext;
209         }
210       }
211     }
212   }
213 }
214 void sqlite3BtreeLeaveAll(sqlite3 *db){
215   int i;
216   Btree *p;
217   assert( sqlite3_mutex_held(db->mutex) );
218   for(i=0; i<db->nDb; i++){
219     p = db->aDb[i].pBt;
220     if( p && p->sharable ){
221       assert( p->wantToLock>0 );
222       p->wantToLock--;
223       if( p->wantToLock==0 ){
224         unlockBtreeMutex(p);
225       }
226     }
227   }
228 }
229 
230 #ifndef NDEBUG
231 /*
232 ** Return true if the current thread holds the database connection
233 ** mutex and all required BtShared mutexes.
234 **
235 ** This routine is used inside assert() statements only.
236 */
237 int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
238   int i;
239   if( !sqlite3_mutex_held(db->mutex) ){
240     return 0;
241   }
242   for(i=0; i<db->nDb; i++){
243     Btree *p;
244     p = db->aDb[i].pBt;
245     if( p && p->sharable &&
246          (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
247       return 0;
248     }
249   }
250   return 1;
251 }
252 #endif /* NDEBUG */
253 
254 /*
255 ** Add a new Btree pointer to a BtreeMutexArray.
256 ** if the pointer can possibly be shared with
257 ** another database connection.
258 **
259 ** The pointers are kept in sorted order by pBtree->pBt.  That
260 ** way when we go to enter all the mutexes, we can enter them
261 ** in order without every having to backup and retry and without
262 ** worrying about deadlock.
263 **
264 ** The number of shared btrees will always be small (usually 0 or 1)
265 ** so an insertion sort is an adequate algorithm here.
266 */
267 void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
268   int i, j;
269   BtShared *pBt;
270   if( pBtree==0 || pBtree->sharable==0 ) return;
271 #ifndef NDEBUG
272   {
273     for(i=0; i<pArray->nMutex; i++){
274       assert( pArray->aBtree[i]!=pBtree );
275     }
276   }
277 #endif
278   assert( pArray->nMutex>=0 );
279   assert( pArray->nMutex<ArraySize(pArray->aBtree)-1 );
280   pBt = pBtree->pBt;
281   for(i=0; i<pArray->nMutex; i++){
282     assert( pArray->aBtree[i]!=pBtree );
283     if( pArray->aBtree[i]->pBt>pBt ){
284       for(j=pArray->nMutex; j>i; j--){
285         pArray->aBtree[j] = pArray->aBtree[j-1];
286       }
287       pArray->aBtree[i] = pBtree;
288       pArray->nMutex++;
289       return;
290     }
291   }
292   pArray->aBtree[pArray->nMutex++] = pBtree;
293 }
294 
295 /*
296 ** Enter the mutex of every btree in the array.  This routine is
297 ** called at the beginning of sqlite3VdbeExec().  The mutexes are
298 ** exited at the end of the same function.
299 */
300 void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
301   int i;
302   for(i=0; i<pArray->nMutex; i++){
303     Btree *p = pArray->aBtree[i];
304     /* Some basic sanity checking */
305     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
306     assert( !p->locked || p->wantToLock>0 );
307 
308     /* We should already hold a lock on the database connection */
309     assert( sqlite3_mutex_held(p->db->mutex) );
310 
311     /* The Btree is sharable because only sharable Btrees are entered
312     ** into the array in the first place. */
313     assert( p->sharable );
314 
315     p->wantToLock++;
316     if( !p->locked ){
317       lockBtreeMutex(p);
318     }
319   }
320 }
321 
322 /*
323 ** Leave the mutex of every btree in the group.
324 */
325 void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
326   int i;
327   for(i=0; i<pArray->nMutex; i++){
328     Btree *p = pArray->aBtree[i];
329     /* Some basic sanity checking */
330     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
331     assert( p->locked );
332     assert( p->wantToLock>0 );
333 
334     /* We should already hold a lock on the database connection */
335     assert( sqlite3_mutex_held(p->db->mutex) );
336 
337     p->wantToLock--;
338     if( p->wantToLock==0 ){
339       unlockBtreeMutex(p);
340     }
341   }
342 }
343 
344 #else
345 void sqlite3BtreeEnter(Btree *p){
346   p->pBt->db = p->db;
347 }
348 void sqlite3BtreeEnterAll(sqlite3 *db){
349   int i;
350   for(i=0; i<db->nDb; i++){
351     Btree *p = db->aDb[i].pBt;
352     if( p ){
353       p->pBt->db = p->db;
354     }
355   }
356 }
357 #endif /* if SQLITE_THREADSAFE */
358 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
359