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