btmutex.c.svn-base
上传用户:sunhongbo
上传日期:2022-01-25
资源大小:3010k
文件大小:9k
源码类别:

数据库系统

开发平台:

C/C++

  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.9 2008/01/23 12:52:41 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. #if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
  22. /*
  23. ** Enter a mutex on the given BTree object.
  24. **
  25. ** If the object is not sharable, then no mutex is ever required
  26. ** and this routine is a no-op.  The underlying mutex is non-recursive.
  27. ** But we keep a reference count in Btree.wantToLock so the behavior
  28. ** of this interface is recursive.
  29. **
  30. ** To avoid deadlocks, multiple Btrees are locked in the same order
  31. ** by all database connections.  The p->pNext is a list of other
  32. ** Btrees belonging to the same database connection as the p Btree
  33. ** which need to be locked after p.  If we cannot get a lock on
  34. ** p, then first unlock all of the others on p->pNext, then wait
  35. ** for the lock to become available on p, then relock all of the
  36. ** subsequent Btrees that desire a lock.
  37. */
  38. void sqlite3BtreeEnter(Btree *p){
  39.   Btree *pLater;
  40.   /* Some basic sanity checking on the Btree.  The list of Btrees
  41.   ** connected by pNext and pPrev should be in sorted order by
  42.   ** Btree.pBt value. All elements of the list should belong to
  43.   ** the same connection. Only shared Btrees are on the list. */
  44.   assert( p->pNext==0 || p->pNext->pBt>p->pBt );
  45.   assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
  46.   assert( p->pNext==0 || p->pNext->db==p->db );
  47.   assert( p->pPrev==0 || p->pPrev->db==p->db );
  48.   assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
  49.   /* Check for locking consistency */
  50.   assert( !p->locked || p->wantToLock>0 );
  51.   assert( p->sharable || p->wantToLock==0 );
  52.   /* We should already hold a lock on the database connection */
  53.   assert( sqlite3_mutex_held(p->db->mutex) );
  54.   if( !p->sharable ) return;
  55.   p->wantToLock++;
  56.   if( p->locked ) return;
  57. #ifndef SQLITE_MUTEX_NOOP
  58.   /* In most cases, we should be able to acquire the lock we
  59.   ** want without having to go throught the ascending lock
  60.   ** procedure that follows.  Just be sure not to block.
  61.   */
  62.   if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
  63.     p->locked = 1;
  64.     return;
  65.   }
  66.   /* To avoid deadlock, first release all locks with a larger
  67.   ** BtShared address.  Then acquire our lock.  Then reacquire
  68.   ** the other BtShared locks that we used to hold in ascending
  69.   ** order.
  70.   */
  71.   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
  72.     assert( pLater->sharable );
  73.     assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
  74.     assert( !pLater->locked || pLater->wantToLock>0 );
  75.     if( pLater->locked ){
  76.       sqlite3_mutex_leave(pLater->pBt->mutex);
  77.       pLater->locked = 0;
  78.     }
  79.   }
  80.   sqlite3_mutex_enter(p->pBt->mutex);
  81.   p->locked = 1;
  82.   for(pLater=p->pNext; pLater; pLater=pLater->pNext){
  83.     if( pLater->wantToLock ){
  84.       sqlite3_mutex_enter(pLater->pBt->mutex);
  85.       pLater->locked = 1;
  86.     }
  87.   }
  88. #endif /* SQLITE_MUTEX_NOOP */
  89. }
  90. /*
  91. ** Exit the recursive mutex on a Btree.
  92. */
  93. void sqlite3BtreeLeave(Btree *p){
  94.   if( p->sharable ){
  95.     assert( p->wantToLock>0 );
  96.     p->wantToLock--;
  97.     if( p->wantToLock==0 ){
  98.       assert( p->locked );
  99.       sqlite3_mutex_leave(p->pBt->mutex);
  100.       p->locked = 0;
  101.     }
  102.   }
  103. }
  104. #ifndef NDEBUG
  105. /*
  106. ** Return true if the BtShared mutex is held on the btree.  
  107. **
  108. ** This routine makes no determination one why or another if the
  109. ** database connection mutex is held.
  110. **
  111. ** This routine is used only from within assert() statements.
  112. */
  113. int sqlite3BtreeHoldsMutex(Btree *p){
  114.   return (p->sharable==0 ||
  115.              (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
  116. }
  117. #endif
  118. #ifndef SQLITE_OMIT_INCRBLOB
  119. /*
  120. ** Enter and leave a mutex on a Btree given a cursor owned by that
  121. ** Btree.  These entry points are used by incremental I/O and can be
  122. ** omitted if that module is not used.
  123. */
  124. void sqlite3BtreeEnterCursor(BtCursor *pCur){
  125.   sqlite3BtreeEnter(pCur->pBtree);
  126. }
  127. void sqlite3BtreeLeaveCursor(BtCursor *pCur){
  128.   sqlite3BtreeLeave(pCur->pBtree);
  129. }
  130. #endif /* SQLITE_OMIT_INCRBLOB */
  131. /*
  132. ** Enter the mutex on every Btree associated with a database
  133. ** connection.  This is needed (for example) prior to parsing
  134. ** a statement since we will be comparing table and column names
  135. ** against all schemas and we do not want those schemas being
  136. ** reset out from under us.
  137. **
  138. ** There is a corresponding leave-all procedures.
  139. **
  140. ** Enter the mutexes in accending order by BtShared pointer address
  141. ** to avoid the possibility of deadlock when two threads with
  142. ** two or more btrees in common both try to lock all their btrees
  143. ** at the same instant.
  144. */
  145. void sqlite3BtreeEnterAll(sqlite3 *db){
  146.   int i;
  147.   Btree *p, *pLater;
  148.   assert( sqlite3_mutex_held(db->mutex) );
  149.   for(i=0; i<db->nDb; i++){
  150.     p = db->aDb[i].pBt;
  151.     if( p && p->sharable ){
  152.       p->wantToLock++;
  153.       if( !p->locked ){
  154.         assert( p->wantToLock==1 );
  155.         while( p->pPrev ) p = p->pPrev;
  156.         while( p->locked && p->pNext ) p = p->pNext;
  157.         for(pLater = p->pNext; pLater; pLater=pLater->pNext){
  158.           if( pLater->locked ){
  159.             sqlite3_mutex_leave(pLater->pBt->mutex);
  160.             pLater->locked = 0;
  161.           }
  162.         }
  163.         while( p ){
  164.           sqlite3_mutex_enter(p->pBt->mutex);
  165.           p->locked++;
  166.           p = p->pNext;
  167.         }
  168.       }
  169.     }
  170.   }
  171. }
  172. void sqlite3BtreeLeaveAll(sqlite3 *db){
  173.   int i;
  174.   Btree *p;
  175.   assert( sqlite3_mutex_held(db->mutex) );
  176.   for(i=0; i<db->nDb; i++){
  177.     p = db->aDb[i].pBt;
  178.     if( p && p->sharable ){
  179.       assert( p->wantToLock>0 );
  180.       p->wantToLock--;
  181.       if( p->wantToLock==0 ){
  182.         assert( p->locked );
  183.         sqlite3_mutex_leave(p->pBt->mutex);
  184.         p->locked = 0;
  185.       }
  186.     }
  187.   }
  188. }
  189. #ifndef NDEBUG
  190. /*
  191. ** Return true if the current thread holds the database connection
  192. ** mutex and all required BtShared mutexes.
  193. **
  194. ** This routine is used inside assert() statements only.
  195. */
  196. int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
  197.   int i;
  198.   if( !sqlite3_mutex_held(db->mutex) ){
  199.     return 0;
  200.   }
  201.   for(i=0; i<db->nDb; i++){
  202.     Btree *p;
  203.     p = db->aDb[i].pBt;
  204.     if( p && p->sharable &&
  205.          (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
  206.       return 0;
  207.     }
  208.   }
  209.   return 1;
  210. }
  211. #endif /* NDEBUG */
  212. /*
  213. ** Potentially dd a new Btree pointer to a BtreeMutexArray.
  214. ** Really only add the Btree if it can possibly be shared with
  215. ** another database connection.
  216. **
  217. ** The Btrees are kept in sorted order by pBtree->pBt.  That
  218. ** way when we go to enter all the mutexes, we can enter them
  219. ** in order without every having to backup and retry and without
  220. ** worrying about deadlock.
  221. **
  222. ** The number of shared btrees will always be small (usually 0 or 1)
  223. ** so an insertion sort is an adequate algorithm here.
  224. */
  225. void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
  226.   int i, j;
  227.   BtShared *pBt;
  228.   if( pBtree==0 || pBtree->sharable==0 ) return;
  229. #ifndef NDEBUG
  230.   {
  231.     for(i=0; i<pArray->nMutex; i++){
  232.       assert( pArray->aBtree[i]!=pBtree );
  233.     }
  234.   }
  235. #endif
  236.   assert( pArray->nMutex>=0 );
  237.   assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 );
  238.   pBt = pBtree->pBt;
  239.   for(i=0; i<pArray->nMutex; i++){
  240.     assert( pArray->aBtree[i]!=pBtree );
  241.     if( pArray->aBtree[i]->pBt>pBt ){
  242.       for(j=pArray->nMutex; j>i; j--){
  243.         pArray->aBtree[j] = pArray->aBtree[j-1];
  244.       }
  245.       pArray->aBtree[i] = pBtree;
  246.       pArray->nMutex++;
  247.       return;
  248.     }
  249.   }
  250.   pArray->aBtree[pArray->nMutex++] = pBtree;
  251. }
  252. /*
  253. ** Enter the mutex of every btree in the array.  This routine is
  254. ** called at the beginning of sqlite3VdbeExec().  The mutexes are
  255. ** exited at the end of the same function.
  256. */
  257. void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
  258.   int i;
  259.   for(i=0; i<pArray->nMutex; i++){
  260.     Btree *p = pArray->aBtree[i];
  261.     /* Some basic sanity checking */
  262.     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
  263.     assert( !p->locked || p->wantToLock>0 );
  264.     /* We should already hold a lock on the database connection */
  265.     assert( sqlite3_mutex_held(p->db->mutex) );
  266.     p->wantToLock++;
  267.     if( !p->locked && p->sharable ){
  268.       sqlite3_mutex_enter(p->pBt->mutex);
  269.       p->locked = 1;
  270.     }
  271.   }
  272. }
  273. /*
  274. ** Leave the mutex of every btree in the group.
  275. */
  276. void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
  277.   int i;
  278.   for(i=0; i<pArray->nMutex; i++){
  279.     Btree *p = pArray->aBtree[i];
  280.     /* Some basic sanity checking */
  281.     assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
  282.     assert( p->locked || !p->sharable );
  283.     assert( p->wantToLock>0 );
  284.     /* We should already hold a lock on the database connection */
  285.     assert( sqlite3_mutex_held(p->db->mutex) );
  286.     p->wantToLock--;
  287.     if( p->wantToLock==0 && p->locked ){
  288.       sqlite3_mutex_leave(p->pBt->mutex);
  289.       p->locked = 0;
  290.     }
  291.   }
  292. }
  293. #endif  /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */