| 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 |