btmutex.c

Go to the documentation of this file.
00001 /*
00002 ** 2007 August 27
00003 **
00004 ** The author disclaims copyright to this source code.  In place of
00005 ** a legal notice, here is a blessing:
00006 **
00007 **    May you do good and not evil.
00008 **    May you find forgiveness for yourself and forgive others.
00009 **    May you share freely, never taking more than you give.
00010 **
00011 *************************************************************************
00012 **
00013 ** $Id: btmutex.c,v 1.11 2008/10/07 15:25:48 drh Exp $
00014 **
00015 ** This file contains code used to implement mutexes on Btree objects.
00016 ** This code really belongs in btree.c.  But btree.c is getting too
00017 ** big and we want to break it down some.  This packaged seemed like
00018 ** a good breakout.
00019 */
00020 #include "btreeInt.h"
00021 #if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
00022 
00023 
00024 /*
00025 ** Enter a mutex on the given BTree object.
00026 **
00027 ** If the object is not sharable, then no mutex is ever required
00028 ** and this routine is a no-op.  The underlying mutex is non-recursive.
00029 ** But we keep a reference count in Btree.wantToLock so the behavior
00030 ** of this interface is recursive.
00031 **
00032 ** To avoid deadlocks, multiple Btrees are locked in the same order
00033 ** by all database connections.  The p->pNext is a list of other
00034 ** Btrees belonging to the same database connection as the p Btree
00035 ** which need to be locked after p.  If we cannot get a lock on
00036 ** p, then first unlock all of the others on p->pNext, then wait
00037 ** for the lock to become available on p, then relock all of the
00038 ** subsequent Btrees that desire a lock.
00039 */
00040 void sqlite3BtreeEnter(Btree *p){
00041   Btree *pLater;
00042 
00043   /* Some basic sanity checking on the Btree.  The list of Btrees
00044   ** connected by pNext and pPrev should be in sorted order by
00045   ** Btree.pBt value. All elements of the list should belong to
00046   ** the same connection. Only shared Btrees are on the list. */
00047   assert( p->pNext==0 || p->pNext->pBt>p->pBt );
00048   assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
00049   assert( p->pNext==0 || p->pNext->db==p->db );
00050   assert( p->pPrev==0 || p->pPrev->db==p->db );
00051   assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
00052 
00053   /* Check for locking consistency */
00054   assert( !p->locked || p->wantToLock>0 );
00055   assert( p->sharable || p->wantToLock==0 );
00056 
00057   /* We should already hold a lock on the database connection */
00058   assert( sqlite3_mutex_held(p->db->mutex) );
00059 
00060   if( !p->sharable ) return;
00061   p->wantToLock++;
00062   if( p->locked ) return;
00063 
00064   /* In most cases, we should be able to acquire the lock we
00065   ** want without having to go throught the ascending lock
00066   ** procedure that follows.  Just be sure not to block.
00067   */
00068   if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
00069     p->locked = 1;
00070     return;
00071   }
00072 
00073   /* To avoid deadlock, first release all locks with a larger
00074   ** BtShared address.  Then acquire our lock.  Then reacquire
00075   ** the other BtShared locks that we used to hold in ascending
00076   ** order.
00077   */
00078   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
00079     assert( pLater->sharable );
00080     assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
00081     assert( !pLater->locked || pLater->wantToLock>0 );
00082     if( pLater->locked ){
00083       sqlite3_mutex_leave(pLater->pBt->mutex);
00084       pLater->locked = 0;
00085     }
00086   }
00087   sqlite3_mutex_enter(p->pBt->mutex);
00088   p->locked = 1;
00089   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
00090     if( pLater->wantToLock ){
00091       sqlite3_mutex_enter(pLater->pBt->mutex);
00092       pLater->locked = 1;
00093     }
00094   }
00095 }
00096 
00097 /*
00098 ** Exit the recursive mutex on a Btree.
00099 */
00100 void sqlite3BtreeLeave(Btree *p){
00101   if( p->sharable ){
00102     assert( p->wantToLock>0 );
00103     p->wantToLock--;
00104     if( p->wantToLock==0 ){
00105       assert( p->locked );
00106       sqlite3_mutex_leave(p->pBt->mutex);
00107       p->locked = 0;
00108     }
00109   }
00110 }
00111 
00112 #ifndef NDEBUG
00113 /*
00114 ** Return true if the BtShared mutex is held on the btree.  
00115 **
00116 ** This routine makes no determination one why or another if the
00117 ** database connection mutex is held.
00118 **
00119 ** This routine is used only from within assert() statements.
00120 */
00121 int sqlite3BtreeHoldsMutex(Btree *p){
00122   return (p->sharable==0 ||
00123              (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
00124 }
00125 #endif
00126 
00127 
00128 #ifndef SQLITE_OMIT_INCRBLOB
00129 /*
00130 ** Enter and leave a mutex on a Btree given a cursor owned by that
00131 ** Btree.  These entry points are used by incremental I/O and can be
00132 ** omitted if that module is not used.
00133 */
00134 void sqlite3BtreeEnterCursor(BtCursor *pCur){
00135   sqlite3BtreeEnter(pCur->pBtree);
00136 }
00137 void sqlite3BtreeLeaveCursor(BtCursor *pCur){
00138   sqlite3BtreeLeave(pCur->pBtree);
00139 }
00140 #endif /* SQLITE_OMIT_INCRBLOB */
00141 
00142 
00143 /*
00144 ** Enter the mutex on every Btree associated with a database
00145 ** connection.  This is needed (for example) prior to parsing
00146 ** a statement since we will be comparing table and column names
00147 ** against all schemas and we do not want those schemas being
00148 ** reset out from under us.
00149 **
00150 ** There is a corresponding leave-all procedures.
00151 **
00152 ** Enter the mutexes in accending order by BtShared pointer address
00153 ** to avoid the possibility of deadlock when two threads with
00154 ** two or more btrees in common both try to lock all their btrees
00155 ** at the same instant.
00156 */
00157 void sqlite3BtreeEnterAll(sqlite3 *db){
00158   int i;
00159   Btree *p, *pLater;
00160   assert( sqlite3_mutex_held(db->mutex) );
00161   for(i=0; i<db->nDb; i++){
00162     p = db->aDb[i].pBt;
00163     if( p && p->sharable ){
00164       p->wantToLock++;
00165       if( !p->locked ){
00166         assert( p->wantToLock==1 );
00167         while( p->pPrev ) p = p->pPrev;
00168         while( p->locked && p->pNext ) p = p->pNext;
00169         for(pLater = p->pNext; pLater; pLater=pLater->pNext){
00170           if( pLater->locked ){
00171             sqlite3_mutex_leave(pLater->pBt->mutex);
00172             pLater->locked = 0;
00173           }
00174         }
00175         while( p ){
00176           sqlite3_mutex_enter(p->pBt->mutex);
00177           p->locked++;
00178           p = p->pNext;
00179         }
00180       }
00181     }
00182   }
00183 }
00184 void sqlite3BtreeLeaveAll(sqlite3 *db){
00185   int i;
00186   Btree *p;
00187   assert( sqlite3_mutex_held(db->mutex) );
00188   for(i=0; i<db->nDb; i++){
00189     p = db->aDb[i].pBt;
00190     if( p && p->sharable ){
00191       assert( p->wantToLock>0 );
00192       p->wantToLock--;
00193       if( p->wantToLock==0 ){
00194         assert( p->locked );
00195         sqlite3_mutex_leave(p->pBt->mutex);
00196         p->locked = 0;
00197       }
00198     }
00199   }
00200 }
00201 
00202 #ifndef NDEBUG
00203 /*
00204 ** Return true if the current thread holds the database connection
00205 ** mutex and all required BtShared mutexes.
00206 **
00207 ** This routine is used inside assert() statements only.
00208 */
00209 int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
00210   int i;
00211   if( !sqlite3_mutex_held(db->mutex) ){
00212     return 0;
00213   }
00214   for(i=0; i<db->nDb; i++){
00215     Btree *p;
00216     p = db->aDb[i].pBt;
00217     if( p && p->sharable &&
00218          (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
00219       return 0;
00220     }
00221   }
00222   return 1;
00223 }
00224 #endif /* NDEBUG */
00225 
00226 /*
00227 ** Add a new Btree pointer to a BtreeMutexArray. 
00228 ** if the pointer can possibly be shared with
00229 ** another database connection.
00230 **
00231 ** The pointers are kept in sorted order by pBtree->pBt.  That
00232 ** way when we go to enter all the mutexes, we can enter them
00233 ** in order without every having to backup and retry and without
00234 ** worrying about deadlock.
00235 **
00236 ** The number of shared btrees will always be small (usually 0 or 1)
00237 ** so an insertion sort is an adequate algorithm here.
00238 */
00239 void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
00240   int i, j;
00241   BtShared *pBt;
00242   if( pBtree==0 || pBtree->sharable==0 ) return;
00243 #ifndef NDEBUG
00244   {
00245     for(i=0; i<pArray->nMutex; i++){
00246       assert( pArray->aBtree[i]!=pBtree );
00247     }
00248   }
00249 #endif
00250   assert( pArray->nMutex>=0 );
00251   assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 );
00252   pBt = pBtree->pBt;
00253   for(i=0; i<pArray->nMutex; i++){
00254     assert( pArray->aBtree[i]!=pBtree );
00255     if( pArray->aBtree[i]->pBt>pBt ){
00256       for(j=pArray->nMutex; j>i; j--){
00257         pArray->aBtree[j] = pArray->aBtree[j-1];
00258       }
00259       pArray->aBtree[i] = pBtree;
00260       pArray->nMutex++;
00261       return;
00262     }
00263   }
00264   pArray->aBtree[pArray->nMutex++] = pBtree;
00265 }
00266 
00267 /*
00268 ** Enter the mutex of every btree in the array.  This routine is
00269 ** called at the beginning of sqlite3VdbeExec().  The mutexes are
00270 ** exited at the end of the same function.
00271 */
00272 void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
00273   int i;
00274   for(i=0; i<pArray->nMutex; i++){
00275     Btree *p = pArray->aBtree[i];
00276     /* Some basic sanity checking */
00277     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
00278     assert( !p->locked || p->wantToLock>0 );
00279 
00280     /* We should already hold a lock on the database connection */
00281     assert( sqlite3_mutex_held(p->db->mutex) );
00282 
00283     p->wantToLock++;
00284     if( !p->locked && p->sharable ){
00285       sqlite3_mutex_enter(p->pBt->mutex);
00286       p->locked = 1;
00287     }
00288   }
00289 }
00290 
00291 /*
00292 ** Leave the mutex of every btree in the group.
00293 */
00294 void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
00295   int i;
00296   for(i=0; i<pArray->nMutex; i++){
00297     Btree *p = pArray->aBtree[i];
00298     /* Some basic sanity checking */
00299     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
00300     assert( p->locked || !p->sharable );
00301     assert( p->wantToLock>0 );
00302 
00303     /* We should already hold a lock on the database connection */
00304     assert( sqlite3_mutex_held(p->db->mutex) );
00305 
00306     p->wantToLock--;
00307     if( p->wantToLock==0 && p->locked ){
00308       sqlite3_mutex_leave(p->pBt->mutex);
00309       p->locked = 0;
00310     }
00311   }
00312 }
00313 
00314 
00315 #endif  /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */

ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:51 2011 by Doxygen 1.6.1