Annotation of embedaddon/sqlite3/src/btmutex.c, revision 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>