Beispiel #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);
        }
    }
}
Beispiel #2
0
/**
@SYMTestCaseID			PDS-SQLITE3-UT-4040
@SYMTestCaseDesc		SQLITE3 - mutex API tests.
						List of called SQLITE3 functions:
						 - sqlite3_mutex_alloc;
						 - sqlite3_mutex_enter;
						 - sqlite3_mutex_free;
						 - sqlite3_mutex_held;
						 - sqlite3_mutex_leave;
						 - sqlite3_mutex_notheld;
						 - sqlite3_mutex_try;
@SYMTestPriority		High
@SYMTestActions			SQLITE3 - mutex API tests.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ10424
*/
static void TestSqliteMutexApi()
	{
	sqlite3_mutex* mtx = 0;
	int err;
	int type;
	
	TEST(TheDb != 0);
		
	for(type=SQLITE_MUTEX_FAST;type<=SQLITE_MUTEX_STATIC_LRU2;++type)
		{
		mtx = sqlite3_mutex_alloc(type);
		TEST(mtx != NULL);

		err = sqlite3_mutex_try(mtx);
		TEST(err == SQLITE_BUSY || err == SQLITE_OK);

		sqlite3_mutex_enter(mtx);

		sqlite3_mutex_leave(mtx);
		
		if(type <= SQLITE_MUTEX_RECURSIVE)
			{
			sqlite3_mutex_free(mtx);
			}
		mtx = 0;
		}
	}
Beispiel #3
0
/*
** 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) );

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

#ifndef SQLITE_MUTEX_NOOP
  /* 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->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 ){
      sqlite3_mutex_leave(pLater->pBt->mutex);
      pLater->locked = 0;
    }
  }
  sqlite3_mutex_enter(p->pBt->mutex);
  p->locked = 1;
  for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    if( pLater->wantToLock ){
      sqlite3_mutex_enter(pLater->pBt->mutex);
      pLater->locked = 1;
    }
  }
#endif /* SQLITE_MUTEX_NOOP */
}
Beispiel #4
0
/*
** Try to release n bytes of memory by freeing buffers associated 
** with the memory registers of currently unused vdbes.
*/
int sqlite3VdbeReleaseMemory(int n){
  Vdbe *p;
  Vdbe *pNext;
  int nFree = 0;

  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
  for(p=sqlite3LruStatements.pFirst; p && nFree<n; p=pNext){
    pNext = p->pLruNext;

    /* For each statement handle in the lru list, attempt to obtain the
    ** associated database mutex. If it cannot be obtained, continue
    ** to the next statement handle. It is not possible to block on
    ** the database mutex - that could cause deadlock.
    */
    if( SQLITE_OK==sqlite3_mutex_try(p->db->mutex) ){
      nFree += sqlite3VdbeReleaseBuffers(p);
      stmtLruRemoveNomutex(p);
      sqlite3_mutex_leave(p->db->mutex);
    }
  }
  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));

  return nFree;
}
Beispiel #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);
    }
  }
}