Annotation of embedaddon/sqlite3/src/btmutex.c, revision 1.1.1.1

1.1       misho       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:   BtShared *pBt = p->pBt;
                     43:   assert( p->locked==1 );
                     44:   assert( sqlite3_mutex_held(pBt->mutex) );
                     45:   assert( sqlite3_mutex_held(p->db->mutex) );
                     46:   assert( p->db==pBt->db );
                     47: 
                     48:   sqlite3_mutex_leave(pBt->mutex);
                     49:   p->locked = 0;
                     50: }
                     51: 
                     52: /*
                     53: ** Enter a mutex on the given BTree object.
                     54: **
                     55: ** If the object is not sharable, then no mutex is ever required
                     56: ** and this routine is a no-op.  The underlying mutex is non-recursive.
                     57: ** But we keep a reference count in Btree.wantToLock so the behavior
                     58: ** of this interface is recursive.
                     59: **
                     60: ** To avoid deadlocks, multiple Btrees are locked in the same order
                     61: ** by all database connections.  The p->pNext is a list of other
                     62: ** Btrees belonging to the same database connection as the p Btree
                     63: ** which need to be locked after p.  If we cannot get a lock on
                     64: ** p, then first unlock all of the others on p->pNext, then wait
                     65: ** for the lock to become available on p, then relock all of the
                     66: ** subsequent Btrees that desire a lock.
                     67: */
                     68: void sqlite3BtreeEnter(Btree *p){
                     69:   Btree *pLater;
                     70: 
                     71:   /* Some basic sanity checking on the Btree.  The list of Btrees
                     72:   ** connected by pNext and pPrev should be in sorted order by
                     73:   ** Btree.pBt value. All elements of the list should belong to
                     74:   ** the same connection. Only shared Btrees are on the list. */
                     75:   assert( p->pNext==0 || p->pNext->pBt>p->pBt );
                     76:   assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
                     77:   assert( p->pNext==0 || p->pNext->db==p->db );
                     78:   assert( p->pPrev==0 || p->pPrev->db==p->db );
                     79:   assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
                     80: 
                     81:   /* Check for locking consistency */
                     82:   assert( !p->locked || p->wantToLock>0 );
                     83:   assert( p->sharable || p->wantToLock==0 );
                     84: 
                     85:   /* We should already hold a lock on the database connection */
                     86:   assert( sqlite3_mutex_held(p->db->mutex) );
                     87: 
                     88:   /* Unless the database is sharable and unlocked, then BtShared.db
                     89:   ** should already be set correctly. */
                     90:   assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
                     91: 
                     92:   if( !p->sharable ) return;
                     93:   p->wantToLock++;
                     94:   if( p->locked ) return;
                     95: 
                     96:   /* In most cases, we should be able to acquire the lock we
                     97:   ** want without having to go throught the ascending lock
                     98:   ** procedure that follows.  Just be sure not to block.
                     99:   */
                    100:   if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
                    101:     p->pBt->db = p->db;
                    102:     p->locked = 1;
                    103:     return;
                    104:   }
                    105: 
                    106:   /* To avoid deadlock, first release all locks with a larger
                    107:   ** BtShared address.  Then acquire our lock.  Then reacquire
                    108:   ** the other BtShared locks that we used to hold in ascending
                    109:   ** order.
                    110:   */
                    111:   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
                    112:     assert( pLater->sharable );
                    113:     assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
                    114:     assert( !pLater->locked || pLater->wantToLock>0 );
                    115:     if( pLater->locked ){
                    116:       unlockBtreeMutex(pLater);
                    117:     }
                    118:   }
                    119:   lockBtreeMutex(p);
                    120:   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
                    121:     if( pLater->wantToLock ){
                    122:       lockBtreeMutex(pLater);
                    123:     }
                    124:   }
                    125: }
                    126: 
                    127: /*
                    128: ** Exit the recursive mutex on a Btree.
                    129: */
                    130: void sqlite3BtreeLeave(Btree *p){
                    131:   if( p->sharable ){
                    132:     assert( p->wantToLock>0 );
                    133:     p->wantToLock--;
                    134:     if( p->wantToLock==0 ){
                    135:       unlockBtreeMutex(p);
                    136:     }
                    137:   }
                    138: }
                    139: 
                    140: #ifndef NDEBUG
                    141: /*
                    142: ** Return true if the BtShared mutex is held on the btree, or if the
                    143: ** B-Tree is not marked as sharable.
                    144: **
                    145: ** This routine is used only from within assert() statements.
                    146: */
                    147: int sqlite3BtreeHoldsMutex(Btree *p){
                    148:   assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
                    149:   assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
                    150:   assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
                    151:   assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
                    152: 
                    153:   return (p->sharable==0 || p->locked);
                    154: }
                    155: #endif
                    156: 
                    157: 
                    158: #ifndef SQLITE_OMIT_INCRBLOB
                    159: /*
                    160: ** Enter and leave a mutex on a Btree given a cursor owned by that
                    161: ** Btree.  These entry points are used by incremental I/O and can be
                    162: ** omitted if that module is not used.
                    163: */
                    164: void sqlite3BtreeEnterCursor(BtCursor *pCur){
                    165:   sqlite3BtreeEnter(pCur->pBtree);
                    166: }
                    167: void sqlite3BtreeLeaveCursor(BtCursor *pCur){
                    168:   sqlite3BtreeLeave(pCur->pBtree);
                    169: }
                    170: #endif /* SQLITE_OMIT_INCRBLOB */
                    171: 
                    172: 
                    173: /*
                    174: ** Enter the mutex on every Btree associated with a database
                    175: ** connection.  This is needed (for example) prior to parsing
                    176: ** a statement since we will be comparing table and column names
                    177: ** against all schemas and we do not want those schemas being
                    178: ** reset out from under us.
                    179: **
                    180: ** There is a corresponding leave-all procedures.
                    181: **
                    182: ** Enter the mutexes in accending order by BtShared pointer address
                    183: ** to avoid the possibility of deadlock when two threads with
                    184: ** two or more btrees in common both try to lock all their btrees
                    185: ** at the same instant.
                    186: */
                    187: void sqlite3BtreeEnterAll(sqlite3 *db){
                    188:   int i;
                    189:   Btree *p;
                    190:   assert( sqlite3_mutex_held(db->mutex) );
                    191:   for(i=0; i<db->nDb; i++){
                    192:     p = db->aDb[i].pBt;
                    193:     if( p ) sqlite3BtreeEnter(p);
                    194:   }
                    195: }
                    196: void sqlite3BtreeLeaveAll(sqlite3 *db){
                    197:   int i;
                    198:   Btree *p;
                    199:   assert( sqlite3_mutex_held(db->mutex) );
                    200:   for(i=0; i<db->nDb; i++){
                    201:     p = db->aDb[i].pBt;
                    202:     if( p ) sqlite3BtreeLeave(p);
                    203:   }
                    204: }
                    205: 
                    206: /*
                    207: ** Return true if a particular Btree requires a lock.  Return FALSE if
                    208: ** no lock is ever required since it is not sharable.
                    209: */
                    210: int sqlite3BtreeSharable(Btree *p){
                    211:   return p->sharable;
                    212: }
                    213: 
                    214: #ifndef NDEBUG
                    215: /*
                    216: ** Return true if the current thread holds the database connection
                    217: ** mutex and all required BtShared mutexes.
                    218: **
                    219: ** This routine is used inside assert() statements only.
                    220: */
                    221: int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
                    222:   int i;
                    223:   if( !sqlite3_mutex_held(db->mutex) ){
                    224:     return 0;
                    225:   }
                    226:   for(i=0; i<db->nDb; i++){
                    227:     Btree *p;
                    228:     p = db->aDb[i].pBt;
                    229:     if( p && p->sharable &&
                    230:          (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
                    231:       return 0;
                    232:     }
                    233:   }
                    234:   return 1;
                    235: }
                    236: #endif /* NDEBUG */
                    237: 
                    238: #ifndef NDEBUG
                    239: /*
                    240: ** Return true if the correct mutexes are held for accessing the
                    241: ** db->aDb[iDb].pSchema structure.  The mutexes required for schema
                    242: ** access are:
                    243: **
                    244: **   (1) The mutex on db
                    245: **   (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt.
                    246: **
                    247: ** If pSchema is not NULL, then iDb is computed from pSchema and
                    248: ** db using sqlite3SchemaToIndex().
                    249: */
                    250: int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
                    251:   Btree *p;
                    252:   assert( db!=0 );
                    253:   if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
                    254:   assert( iDb>=0 && iDb<db->nDb );
                    255:   if( !sqlite3_mutex_held(db->mutex) ) return 0;
                    256:   if( iDb==1 ) return 1;
                    257:   p = db->aDb[iDb].pBt;
                    258:   assert( p!=0 );
                    259:   return p->sharable==0 || p->locked==1;
                    260: }
                    261: #endif /* NDEBUG */
                    262: 
                    263: #else /* SQLITE_THREADSAFE>0 above.  SQLITE_THREADSAFE==0 below */
                    264: /*
                    265: ** The following are special cases for mutex enter routines for use
                    266: ** in single threaded applications that use shared cache.  Except for
                    267: ** these two routines, all mutex operations are no-ops in that case and
                    268: ** are null #defines in btree.h.
                    269: **
                    270: ** If shared cache is disabled, then all btree mutex routines, including
                    271: ** the ones below, are no-ops and are null #defines in btree.h.
                    272: */
                    273: 
                    274: void sqlite3BtreeEnter(Btree *p){
                    275:   p->pBt->db = p->db;
                    276: }
                    277: void sqlite3BtreeEnterAll(sqlite3 *db){
                    278:   int i;
                    279:   for(i=0; i<db->nDb; i++){
                    280:     Btree *p = db->aDb[i].pBt;
                    281:     if( p ){
                    282:       p->pBt->db = p->db;
                    283:     }
                    284:   }
                    285: }
                    286: #endif /* if SQLITE_THREADSAFE */
                    287: #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>