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