1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

When a b-tree transaction is committed when there are open cursors, downgrade shared-cache write-locks to read-locks instead of relinquishing all locks. Fix for #3942. (CVS 6837)

FossilOrigin-Name: 611e704fdf90a3d3932ca1cbab4be7e282bf1ddf
This commit is contained in:
danielk1977
2009-07-02 17:21:57 +00:00
parent 602b466e99
commit 94b30733f7
5 changed files with 127 additions and 48 deletions

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.648 2009/07/02 07:47:33 danielk1977 Exp $
** $Id: btree.c,v 1.649 2009/07/02 17:21:58 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@@ -81,6 +81,7 @@ int sqlite3_enable_shared_cache(int enable){
#define querySharedCacheTableLock(a,b,c) SQLITE_OK
#define setSharedCacheTableLock(a,b,c) SQLITE_OK
#define clearAllSharedCacheTableLocks(a)
#define downgradeAllSharedCacheTableLocks(a)
#define hasSharedCacheTableLock(a,b,c,d) 1
#define hasReadConflicts(a, b) 0
#endif
@@ -393,6 +394,21 @@ static void clearAllSharedCacheTableLocks(Btree *p){
pBt->isPending = 0;
}
}
static void downgradeAllSharedCacheTableLocks(Btree *p){
BtShared *pBt = p->pBt;
if( pBt->pWriter==p ){
BtLock *pLock;
pBt->pWriter = 0;
pBt->isExclusive = 0;
pBt->isPending = 0;
for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
assert( pLock->eLock==READ_LOCK || pLock->pBtree==p );
pLock->eLock = READ_LOCK;
}
}
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
static void releasePage(MemPage *pPage); /* Forward reference */
@@ -2901,6 +2917,48 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
return rc;
}
/*
** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback()
** at the conclusion of a transaction.
*/
static void btreeEndTransaction(Btree *p){
BtShared *pBt = p->pBt;
BtCursor *pCsr;
assert( sqlite3BtreeHoldsMutex(p) );
/* Search for a cursor held open by this b-tree connection. If one exists,
** then the transaction will be downgraded to a read-only transaction
** instead of actually concluded. A subsequent call to CommitPhaseTwo()
** or Rollback() will finish the transaction and unlock the database. */
for(pCsr=pBt->pCursor; pCsr && pCsr->pBtree!=p; pCsr=pCsr->pNext);
assert( pCsr==0 || p->inTrans>TRANS_NONE );
btreeClearHasContent(pBt);
if( pCsr ){
downgradeAllSharedCacheTableLocks(p);
p->inTrans = TRANS_READ;
}else{
/* If the handle had any kind of transaction open, decrement the
** transaction count of the shared btree. If the transaction count
** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused()
** call below will unlock the pager. */
if( p->inTrans!=TRANS_NONE ){
clearAllSharedCacheTableLocks(p);
pBt->nTransaction--;
if( 0==pBt->nTransaction ){
pBt->inTransaction = TRANS_NONE;
}
}
/* Set the current transaction state to TRANS_NONE and unlock the
** pager if this call closed the only read or write transaction. */
p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
}
btreeIntegrity(p);
}
/*
** Commit the transaction currently in progress.
**
@@ -2937,27 +2995,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
pBt->inTransaction = TRANS_READ;
}
/* If the handle has any kind of transaction open, decrement the transaction
** count of the shared btree. If the transaction count reaches 0, set
** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below
** will unlock the pager.
*/
if( p->inTrans!=TRANS_NONE ){
clearAllSharedCacheTableLocks(p);
pBt->nTransaction--;
if( 0==pBt->nTransaction ){
pBt->inTransaction = TRANS_NONE;
}
}
/* Set the current transaction state to TRANS_NONE and unlock
** the pager if this call closed the only read or write transaction.
*/
btreeClearHasContent(pBt);
p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
btreeIntegrity(p);
btreeEndTransaction(p);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
@@ -3079,20 +3117,7 @@ int sqlite3BtreeRollback(Btree *p){
pBt->inTransaction = TRANS_READ;
}
if( p->inTrans!=TRANS_NONE ){
clearAllSharedCacheTableLocks(p);
assert( pBt->nTransaction>0 );
pBt->nTransaction--;
if( 0==pBt->nTransaction ){
pBt->inTransaction = TRANS_NONE;
}
}
btreeClearHasContent(pBt);
p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
btreeIntegrity(p);
btreeEndTransaction(p);
sqlite3BtreeLeave(p);
return rc;
}