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.9 2008/01/23 12:52:41 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 #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 #ifndef SQLITE_MUTEX_NOOP 65 /* In most cases, we should be able to acquire the lock we 66 ** want without having to go throught the ascending lock 67 ** procedure that follows. Just be sure not to block. 68 */ 69 if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ 70 p->locked = 1; 71 return; 72 } 73 74 /* To avoid deadlock, first release all locks with a larger 75 ** BtShared address. Then acquire our lock. Then reacquire 76 ** the other BtShared locks that we used to hold in ascending 77 ** order. 78 */ 79 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ 80 assert( pLater->sharable ); 81 assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); 82 assert( !pLater->locked || pLater->wantToLock>0 ); 83 if( pLater->locked ){ 84 sqlite3_mutex_leave(pLater->pBt->mutex); 85 pLater->locked = 0; 86 } 87 } 88 sqlite3_mutex_enter(p->pBt->mutex); 89 p->locked = 1; 90 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ 91 if( pLater->wantToLock ){ 92 sqlite3_mutex_enter(pLater->pBt->mutex); 93 pLater->locked = 1; 94 } 95 } 96 #endif /* SQLITE_MUTEX_NOOP */ 97 } 98 99 /* 100 ** Exit the recursive mutex on a Btree. 101 */ 102 void sqlite3BtreeLeave(Btree *p){ 103 if( p->sharable ){ 104 assert( p->wantToLock>0 ); 105 p->wantToLock--; 106 if( p->wantToLock==0 ){ 107 assert( p->locked ); 108 sqlite3_mutex_leave(p->pBt->mutex); 109 p->locked = 0; 110 } 111 } 112 } 113 114 #ifndef NDEBUG 115 /* 116 ** Return true if the BtShared mutex is held on the btree. 117 ** 118 ** This routine makes no determination one why or another if the 119 ** database connection mutex is held. 120 ** 121 ** This routine is used only from within assert() statements. 122 */ 123 int sqlite3BtreeHoldsMutex(Btree *p){ 124 return (p->sharable==0 || 125 (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex))); 126 } 127 #endif 128 129 130 #ifndef SQLITE_OMIT_INCRBLOB 131 /* 132 ** Enter and leave a mutex on a Btree given a cursor owned by that 133 ** Btree. These entry points are used by incremental I/O and can be 134 ** omitted if that module is not used. 135 */ 136 void sqlite3BtreeEnterCursor(BtCursor *pCur){ 137 sqlite3BtreeEnter(pCur->pBtree); 138 } 139 void sqlite3BtreeLeaveCursor(BtCursor *pCur){ 140 sqlite3BtreeLeave(pCur->pBtree); 141 } 142 #endif /* SQLITE_OMIT_INCRBLOB */ 143 144 145 /* 146 ** Enter the mutex on every Btree associated with a database 147 ** connection. This is needed (for example) prior to parsing 148 ** a statement since we will be comparing table and column names 149 ** against all schemas and we do not want those schemas being 150 ** reset out from under us. 151 ** 152 ** There is a corresponding leave-all procedures. 153 ** 154 ** Enter the mutexes in accending order by BtShared pointer address 155 ** to avoid the possibility of deadlock when two threads with 156 ** two or more btrees in common both try to lock all their btrees 157 ** at the same instant. 158 */ 159 void sqlite3BtreeEnterAll(sqlite3 *db){ 160 int i; 161 Btree *p, *pLater; 162 assert( sqlite3_mutex_held(db->mutex) ); 163 for(i=0; i<db->nDb; i++){ 164 p = db->aDb[i].pBt; 165 if( p && p->sharable ){ 166 p->wantToLock++; 167 if( !p->locked ){ 168 assert( p->wantToLock==1 ); 169 while( p->pPrev ) p = p->pPrev; 170 while( p->locked && p->pNext ) p = p->pNext; 171 for(pLater = p->pNext; pLater; pLater=pLater->pNext){ 172 if( pLater->locked ){ 173 sqlite3_mutex_leave(pLater->pBt->mutex); 174 pLater->locked = 0; 175 } 176 } 177 while( p ){ 178 sqlite3_mutex_enter(p->pBt->mutex); 179 p->locked++; 180 p = p->pNext; 181 } 182 } 183 } 184 } 185 } 186 void sqlite3BtreeLeaveAll(sqlite3 *db){ 187 int i; 188 Btree *p; 189 assert( sqlite3_mutex_held(db->mutex) ); 190 for(i=0; i<db->nDb; i++){ 191 p = db->aDb[i].pBt; 192 if( p && p->sharable ){ 193 assert( p->wantToLock>0 ); 194 p->wantToLock--; 195 if( p->wantToLock==0 ){ 196 assert( p->locked ); 197 sqlite3_mutex_leave(p->pBt->mutex); 198 p->locked = 0; 199 } 200 } 201 } 202 } 203 204 #ifndef NDEBUG 205 /* 206 ** Return true if the current thread holds the database connection 207 ** mutex and all required BtShared mutexes. 208 ** 209 ** This routine is used inside assert() statements only. 210 */ 211 int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){ 212 int i; 213 if( !sqlite3_mutex_held(db->mutex) ){ 214 return 0; 215 } 216 for(i=0; i<db->nDb; i++){ 217 Btree *p; 218 p = db->aDb[i].pBt; 219 if( p && p->sharable && 220 (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){ 221 return 0; 222 } 223 } 224 return 1; 225 } 226 #endif /* NDEBUG */ 227 228 /* 229 ** Potentially dd a new Btree pointer to a BtreeMutexArray. 230 ** Really only add the Btree if it can possibly be shared with 231 ** another database connection. 232 ** 233 ** The Btrees are kept in sorted order by pBtree->pBt. That 234 ** way when we go to enter all the mutexes, we can enter them 235 ** in order without every having to backup and retry and without 236 ** worrying about deadlock. 237 ** 238 ** The number of shared btrees will always be small (usually 0 or 1) 239 ** so an insertion sort is an adequate algorithm here. 240 */ 241 void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){ 242 int i, j; 243 BtShared *pBt; 244 if( pBtree==0 || pBtree->sharable==0 ) return; 245 #ifndef NDEBUG 246 { 247 for(i=0; i<pArray->nMutex; i++){ 248 assert( pArray->aBtree[i]!=pBtree ); 249 } 250 } 251 #endif 252 assert( pArray->nMutex>=0 ); 253 assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 ); 254 pBt = pBtree->pBt; 255 for(i=0; i<pArray->nMutex; i++){ 256 assert( pArray->aBtree[i]!=pBtree ); 257 if( pArray->aBtree[i]->pBt>pBt ){ 258 for(j=pArray->nMutex; j>i; j--){ 259 pArray->aBtree[j] = pArray->aBtree[j-1]; 260 } 261 pArray->aBtree[i] = pBtree; 262 pArray->nMutex++; 263 return; 264 } 265 } 266 pArray->aBtree[pArray->nMutex++] = pBtree; 267 } 268 269 /* 270 ** Enter the mutex of every btree in the array. This routine is 271 ** called at the beginning of sqlite3VdbeExec(). The mutexes are 272 ** exited at the end of the same function. 273 */ 274 void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){ 275 int i; 276 for(i=0; i<pArray->nMutex; i++){ 277 Btree *p = pArray->aBtree[i]; 278 /* Some basic sanity checking */ 279 assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); 280 assert( !p->locked || p->wantToLock>0 ); 281 282 /* We should already hold a lock on the database connection */ 283 assert( sqlite3_mutex_held(p->db->mutex) ); 284 285 p->wantToLock++; 286 if( !p->locked && p->sharable ){ 287 sqlite3_mutex_enter(p->pBt->mutex); 288 p->locked = 1; 289 } 290 } 291 } 292 293 /* 294 ** Leave the mutex of every btree in the group. 295 */ 296 void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){ 297 int i; 298 for(i=0; i<pArray->nMutex; i++){ 299 Btree *p = pArray->aBtree[i]; 300 /* Some basic sanity checking */ 301 assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); 302 assert( p->locked || !p->sharable ); 303 assert( p->wantToLock>0 ); 304 305 /* We should already hold a lock on the database connection */ 306 assert( sqlite3_mutex_held(p->db->mutex) ); 307 308 p->wantToLock--; 309 if( p->wantToLock==0 && p->locked ){ 310 sqlite3_mutex_leave(p->pBt->mutex); 311 p->locked = 0; 312 } 313 } 314 } 315 316 317 #endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */ 318