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