示例#1
0
/* This is a helper function for sqlite3BtreeLock(). By moving
** complex, but seldom used logic, out of sqlite3BtreeLock() and
** into this routine, we avoid unnecessary stack pointer changes
** and thus help the sqlite3BtreeLock() routine to run much faster
** in the common case.
*/
static void SQLITE_NOINLINE btreeLockCarefully(Btree *p) {
    Btree *pLater;

    /* In most cases, we should be able to acquire the lock we
    ** want without having to go through the ascending lock
    ** procedure that follows.  Just be sure not to block.
    */
    if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ) {
        p->pBt->db = p->db;
        p->locked = 1;
        return;
    }

    /* To avoid deadlock, first release all locks with a larger
    ** BtShared address.  Then acquire our lock.  Then reacquire
    ** the other BtShared locks that we used to hold in ascending
    ** order.
    */
    for(pLater=p->pNext; pLater; pLater=pLater->pNext) {
        assert( pLater->sharable );
        assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
        assert( !pLater->locked || pLater->wantToLock>0 );
        if( pLater->locked ) {
            unlockBtreeMutex(pLater);
        }
    }
    lockBtreeMutex(p);
    for(pLater=p->pNext; pLater; pLater=pLater->pNext) {
        if( pLater->wantToLock ) {
            lockBtreeMutex(pLater);
        }
    }
}
/*
** Enter a mutex on the given BTree object.
**
** If the object is not sharable, then no mutex is ever required
** and this routine is a no-op.  The underlying mutex is non-recursive.
** But we keep a reference count in Btree.wantToLock so the behavior
** of this interface is recursive.
**
** To avoid deadlocks, multiple Btrees are locked in the same order
** by all database connections.  The p->pNext is a list of other
** Btrees belonging to the same database connection as the p Btree
** which need to be locked after p.  If we cannot get a lock on
** p, then first unlock all of the others on p->pNext, then wait
** for the lock to become available on p, then relock all of the
** subsequent Btrees that desire a lock.
*/
void sqlite3BtreeEnter(Btree *p){
  Btree *pLater;

  /* Some basic sanity checking on the Btree.  The list of Btrees
  ** connected by pNext and pPrev should be in sorted order by
  ** Btree.pBt value. All elements of the list should belong to
  ** the same connection. Only shared Btrees are on the list. */
  assert( p->pNext==0 || p->pNext->pBt>p->pBt );
  assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
  assert( p->pNext==0 || p->pNext->db==p->db );
  assert( p->pPrev==0 || p->pPrev->db==p->db );
  assert( p->sharable || (p->pNext==0 && p->pPrev==0) );

  /* Check for locking consistency */
  assert( !p->locked || p->wantToLock>0 );
  assert( p->sharable || p->wantToLock==0 );

  /* We should already hold a lock on the database connection */
  assert( sqlite3_mutex_held(p->db->mutex) );

  /* Unless the database is sharable and unlocked, then BtShared.db
  ** should already be set correctly. */
  assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );

  if( !p->sharable ) return;
  p->wantToLock++;
  if( p->locked ) return;

  /* In most cases, we should be able to acquire the lock we
  ** want without having to go throught the ascending lock
  ** procedure that follows.  Just be sure not to block.
  */
  if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
    p->pBt->db = p->db;
    p->locked = 1;
    return;
  }

  /* To avoid deadlock, first release all locks with a larger
  ** BtShared address.  Then acquire our lock.  Then reacquire
  ** the other BtShared locks that we used to hold in ascending
  ** order.
  */
  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    assert( pLater->sharable );
    assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
    assert( !pLater->locked || pLater->wantToLock>0 );
    if( pLater->locked ){
      unlockBtreeMutex(pLater);
    }
  }
  lockBtreeMutex(p);
  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    if( pLater->wantToLock ){
      lockBtreeMutex(pLater);
    }
  }
}
/*
** Exit the recursive mutex on a Btree.
*/
void sqlite3BtreeLeave(Btree *p){
  if( p->sharable ){
    assert( p->wantToLock>0 );
    p->wantToLock--;
    if( p->wantToLock==0 ){
      unlockBtreeMutex(p);
    }
  }
}
示例#4
0
/*
** Exit the recursive mutex on a Btree.
*/
void sqlite3BtreeLeave(Btree *p) {
    assert( sqlite3_mutex_held(p->db->mutex) );
    if( p->sharable ) {
        assert( p->wantToLock>0 );
        p->wantToLock--;
        if( p->wantToLock==0 ) {
            unlockBtreeMutex(p);
        }
    }
}
示例#5
0
/*
** Enter a mutex on the given BTree object.
** 在给定的B树对象上输入一个互斥锁。
** If the object is not sharable, then no mutex is ever required
** and this routine is a no-op.  The underlying mutex is non-recursive.
** But we keep a reference count in Btree.wantToLock so the behavior
** of this interface is recursive.
**
** To avoid deadlocks, multiple Btrees are locked in the same order
** by all database connections.  The p->pNext is a list of other
** Btrees belonging to the same database connection as the p Btree
** which need to be locked after p.  If we cannot get a lock on
** p, then first unlock all of the others on p->pNext, then wait
** for the lock to become available on p, then relock all of the
** subsequent Btrees that desire a lock.
** 如果对象不可共享,那么不需要互斥锁并且这个程序是无操作的。这个潜在的互斥锁是非递归的。
** 但是在Btree.wantToLock中保持对参数的计数,因此这歌接口的操作是递归的。
** 
** 为了避免死锁,多个btree以相同的顺序被所有数据库连接锁定。p->pNext是其他属于相同数据库连接的B树列表
** 作为B树p,p->pNext需要在p后被锁。如果在p上不能的锁,那么首先在p->pNext上解除其他所有锁,然后等待
** 直到在p上的锁可用,接着对需要加锁的所有后续B树重新加锁。
*/
void sqlite3BtreeEnter(Btree *p){
  Btree *pLater;

  /* Some basic sanity checking on the Btree.  The list of Btrees
  ** connected by pNext and pPrev should be in sorted order by
  ** Btree.pBt value. All elements of the list should belong to
  ** the same connection. Only shared Btrees are on the list. 
  ** 在B树上进行基本的完整性检查。通过pNext和pPrev连接的B树列表应该
  ** 按Btree.pBt的值进行排序。列表的所有元素都应属于相同的连接。只有共享的B树在列表中。
  */
  assert( p->pNext==0 || p->pNext->pBt>p->pBt );
  assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
  assert( p->pNext==0 || p->pNext->db==p->db );
  assert( p->pPrev==0 || p->pPrev->db==p->db );
  assert( p->sharable || (p->pNext==0 && p->pPrev==0) );

  /* Check for locking consistency 检查锁的一致性*/
  assert( !p->locked || p->wantToLock>0 );
  assert( p->sharable || p->wantToLock==0 );

  /* We should already hold a lock on the database connection 在数据库连接上应该已经持有一个锁*/
  assert( sqlite3_mutex_held(p->db->mutex) );

  /* Unless the database is sharable and unlocked, then BtShared.db
  ** should already be set correctly. 
  ** 如果数据库是可共享的并且没有被锁,那么BtShared.db应该已经被正确设置。
  */
  assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );

  if( !p->sharable ) return;
  p->wantToLock++;
  if( p->locked ) return;

  /* In most cases, we should be able to acquire the lock we
  ** want without having to go throught the ascending lock
  ** procedure that follows.  Just be sure not to block.
  ** 在大多数情况下,我们应该能得到锁,我们想要的这个锁不必通过追溯在其后的锁进程。只是对块不确定。
  */
  if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
    p->pBt->db = p->db;
    p->locked = 1;
    return;
  }

  /* To avoid deadlock, first release all locks with a larger
  ** BtShared address.  Then acquire our lock.  Then reacquire
  ** the other BtShared locks that we used to hold in ascending
  ** order.
  ** 为了避免死锁,首先释放所有更大BtShared地址的锁。然后获得我们的锁。
  ** 接着再次获取我们曾在提升顺序中持有的其他锁。
  */
  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    assert( pLater->sharable );
    assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
    assert( !pLater->locked || pLater->wantToLock>0 );
    if( pLater->locked ){
      unlockBtreeMutex(pLater);
    }
  }
  lockBtreeMutex(p);
  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    if( pLater->wantToLock ){
      lockBtreeMutex(pLater);
    }
  }
}