File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / btmutex.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>