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