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

Work toward correct btree locking in a multithreaded environment. (CVS 4307)

FossilOrigin-Name: b8cc493b47e618648f645ab73eb0253739e03fcd
This commit is contained in:
drh
2007-08-28 02:27:51 +00:00
parent da57895fec
commit 900b31ef49
13 changed files with 294 additions and 135 deletions

View File

@@ -120,7 +120,7 @@ TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1
# Object files for the SQLite library.
#
LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btmutex.lo btree.lo build.lo \
callback.lo complete.lo date.lo \
delete.lo expr.lo func.lo hash.lo journal.lo insert.lo loadext.lo \
main.lo malloc.lo mem1.lo mem2.lo mutex.lo \
@@ -138,6 +138,7 @@ SRC = \
$(TOP)/src/analyze.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
@@ -340,6 +341,9 @@ attach.lo: $(TOP)/src/attach.c $(HDR)
auth.lo: $(TOP)/src/auth.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/auth.c
btmutex.lo: $(TOP)/src/btmutex.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/btmutex.c
btree.lo: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/btree.c

10
main.mk
View File

@@ -55,7 +55,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
# Object files for the SQLite library.
#
LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
LIBOBJ+= alter.o analyze.o attach.o auth.o btmutex.o btree.o build.o \
callback.o complete.o date.o delete.o \
expr.o func.o hash.o insert.o journal.o loadext.o \
main.o malloc.o mem1.o mem2.o mutex.o \
@@ -91,6 +91,7 @@ SRC = \
$(TOP)/src/analyze.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
@@ -194,11 +195,15 @@ SRC += \
# Source code to the test files.
#
TESTSRC = \
$(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
$(TOP)/src/date.c \
$(TOP)/src/func.c \
$(TOP)/src/insert.c \
$(TOP)/src/malloc.c \
$(TOP)/src/mem1.c \
$(TOP)/src/mem2.c \
$(TOP)/src/mutex.c \
$(TOP)/src/os.c \
$(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \
@@ -337,6 +342,9 @@ attach.o: $(TOP)/src/attach.c $(HDR)
auth.o: $(TOP)/src/auth.c $(HDR)
$(TCCX) -c $(TOP)/src/auth.c
btmutex.o: $(TOP)/src/btmutex.c $(HDR) $(TOP)/src/btreeInt.h
$(TCCX) -c $(TOP)/src/btmutex.c
btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
$(TCCX) -c $(TOP)/src/btree.c

View File

@@ -1,6 +1,6 @@
C Disable\stests\sthat\sdebug\son\sSQLITE_MEMDEBUG\swhen\sthat\smacro\sis\snot\sdefined.\s(CVS\s4306)
D 2007-08-27T23:48:24
F Makefile.in 51bdcd1708f0971bc6b5d8eb47f00d127a899345
C Work\stoward\scorrect\sbtree\slocking\sin\sa\smultithreaded\senvironment.\s(CVS\s4307)
D 2007-08-28T02:27:52
F Makefile.in e8296e112b8942a96c0ed504398bd0d43e3c67ce
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F VERSION 6200589421a0dfe968cd39c431fc62277b963540
@@ -63,7 +63,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
F ext/icu/icu.c 61a345d8126686aa3487aa8d2d0f68abd655f7a4
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
F main.mk 238b00009433760c469ceb94f37f49e76dceae45
F main.mk 6b817f36cdfe3c1846cf6bac96afe8f73add5fe5
F mkdll.sh 37fa8a7412e51b5ab2bc6d4276135f022a0feffb
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
@@ -80,10 +80,11 @@ F src/alter.c fd78c6005456c727a6cb7c01c5266f2aacf6d401
F src/analyze.c a14237d869c6bea0846493b59317e4097e81a0b6
F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3
F src/btree.c dbb8ec48e619fc4900f42cafffc7de90b4b21250
F src/btree.h 76c89673981cb77575300c0b78a76eaa00a28743
F src/btmutex.c e11c59a7a68d9f295a1abfb753ffa4755b5037b1
F src/btree.c 850cd5de860e01233153ade9b24ffc775a794e8e
F src/btree.h a8fb26c56b745b57446c2bf29133619261313051
F src/btreeInt.h c1ba892252bc4dd76ad66da056536c64b23456e3
F src/build.c bc7406e2ea5bfa8276ee1abeae1db27a98fd0b33
F src/build.c 08001e8a12b06178193dc4a8f24610f58de80dae
F src/callback.c a542236a68060caad378efa30006ca46cf77b1b2
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e
@@ -127,7 +128,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
F src/sqlite.h.in 4cf42ce749e4bdf13b9bb4959e91439c3ce8a054
F src/sqlite3ext.h 9a26028378c288af500d8b94ed079666fed5806b
F src/sqliteInt.h ec674206f8a6a475ac58552c40e77d88d66862a2
F src/sqliteInt.h e681df44a19ffb6750d129802f124132ae240c83
F src/sqliteLimit.h 1bcbbdfa856f8b71b561abb31edb864b0eca1d12
F src/table.c c725e47f6f3092b9a7b569fc58e408e2173ee008
F src/tclsqlite.c d76af53f45c9e9f7f7d39531fa4c7bee7d0adad6
@@ -157,11 +158,11 @@ F src/update.c e89b980b443d44b68bfc0b1746cdb6308e049ac9
F src/utf.c 4af6259d5906b5a1bf3035cc387c4d7907bdd56e
F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367
F src/vacuum.c 5ec133b69edf581a232af7e2b01f45c9f2b8be32
F src/vdbe.c 9d4d00589c174aad9a616f1615464ddddebba0ec
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
F src/vdbeInt.h 2bb602c9cb19191d574517bdec0f6c0b600bd3da
F src/vdbe.c 62d210babaac906a5847d7bd4c71e7b114595e85
F src/vdbe.h 5b3ee0fd91a08579f514713038fa7dbef9edf407
F src/vdbeInt.h 0681e0b74a43d3adfec65780d73b2db8f826c7c9
F src/vdbeapi.c bdd0aea216744482dd1b7fab56de18ba5b6fbdf4
F src/vdbeaux.c 2889abf9a6fe954de158bea07652d46101577d08
F src/vdbeaux.c bffdf7b69de21a70520260d359e19df64f31aea4
F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 896fa3f8df9d2661eb15c7ce361857741b447268
@@ -562,7 +563,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P bc6d73d015327a9cf6b687aaf4b3f0d07e0fd484
R 2349531d73bc37131a9a7284d5308814
P 741d6fb096dcb232871d3a8468c386022afcf554
R ff3e167d1bd072e0909067b1f2888076
U drh
Z 56024ff7bdc953200a8a79d2b652027f
Z 6d8ca04435be2f950a1ddef0045b914b

View File

@@ -1 +1 @@
741d6fb096dcb232871d3a8468c386022afcf554
b8cc493b47e618648f645ab73eb0253739e03fcd

199
src/btmutex.c Normal file
View File

@@ -0,0 +1,199 @@
/*
** 2007 August 27
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** $Id: btmutex.c,v 1.1 2007/08/28 02:27:52 drh Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
** big and we want to break it down some. This packaged seemed like
** a good breakout.
*/
#include "btreeInt.h"
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** 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->pSqlite==p->pSqlite );
assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite );
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( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
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->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);
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
if( pLater->wantToLock ){
sqlite3_mutex_enter(pLater->pBt->mutex);
pLater->locked = 1;
}
}
}
/*
** Exit the recursive mutex on a Btree.
*/
void sqlite3BtreeLeave(Btree *p){
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
}
}
/*
** Potentially dd a new Btree pointer to a BtreeMutexSet.
** Really only add the Btree if it can possibly be shared with
** another database connection.
**
** The Btrees are kept in sorted order by pBtree->pBt. That
** way when we go to enter all the mutexes, we can enter them
** in order without every having to backup and retry and without
** worrying about deadlock.
**
** The number of shared btrees will always be small (usually 0 or 1)
** so an insertion sort is an adequate algorithm here.
*/
void sqlite3BtreeMutexSetInsert(BtreeMutexSet *pSet, Btree *pBtree){
int i, j;
BtShared *pBt;
if( !pBtree->sharable ) return;
#ifndef NDEBUG
{
for(i=0; i<pSet->nMutex; i++){
assert( pSet->aBtree[i]!=pBtree );
}
}
#endif
assert( pSet->nMutex>=0 );
assert( pSet->nMutex<sizeof(pSet->aBtree)/sizeof(pSet->aBtree[0])-1 );
pBt = pBtree->pBt;
for(i=0; i<pSet->nMutex; i++){
assert( pSet->aBtree[i]!=pBtree );
if( pSet->aBtree[i]->pBt>pBt ){
for(j=pSet->nMutex; j>i; j--){
pSet->aBtree[j] = pSet->aBtree[j-1];
}
pSet->aBtree[i] = pBtree;
return;
}
}
pSet->aBtree[pSet->nMutex++] = pBtree;
}
/*
** Enter the mutex of every btree in the set. This routine is
** called at the beginning of sqlite3VdbeExec(). The mutexes are
** exited at the end of the same function.
*/
void sqlite3BtreeMutexSetEnter(BtreeMutexSet *pSet){
int i;
for(i=0; i<pSet->nMutex; i++){
Btree *p = pSet->aBtree[i];
/* Some basic sanity checking */
assert( i==0 || pSet->aBtree[i-1]->pBt<p->pBt );
assert( !p->locked || p->wantToLock>0 );
assert( p->sharable );
/* We should already hold a lock on the database connection */
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
p->wantToLock++;
if( !p->locked ){
sqlite3_mutex_enter(p->pBt->mutex);
}
}
}
/*
** Leave the mutex of every btree in the set.
*/
void sqlite3BtreeMutexSetLeave(BtreeMutexSet *pSet){
int i;
for(i=0; i<pSet->nMutex; i++){
Btree *p = pSet->aBtree[i];
/* Some basic sanity checking */
assert( i==0 || pSet->aBtree[i-1]->pBt<p->pBt );
assert( p->locked );
assert( p->sharable );
assert( p->wantToLock>0 );
/* We should already hold a lock on the database connection */
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
p->wantToLock--;
if( p->wantToLock==0 ){
sqlite3_mutex_leave(p->pBt->mutex);
}
}
}
#endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.412 2007/08/24 11:52:29 danielk1977 Exp $
** $Id: btree.c,v 1.413 2007/08/28 02:27:52 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@@ -1386,98 +1386,6 @@ int sqlite3BtreeClose(Btree *p){
return SQLITE_OK;
}
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** 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->pSqlite==p->pSqlite );
assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite );
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( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
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->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);
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
if( pLater->wantToLock ){
sqlite3_mutex_enter(pLater->pBt->mutex);
pLater->locked = 1;
}
}
}
#endif /* !SQLITE_OMIT_SHARED_CACHE */
/*
** Exit the recursive mutex on a Btree.
*/
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
void sqlite3BtreeLeave(Btree *p){
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
}
}
#endif
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Short-cuts for entering and leaving mutexes on a cursor.
@@ -6680,7 +6588,6 @@ char *sqlite3BtreeIntegrityCheck(
*/
const char *sqlite3BtreeGetFilename(Btree *p){
assert( p->pBt->pPager!=0 );
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerFilename(p->pBt->pPager);
}
@@ -6689,7 +6596,6 @@ const char *sqlite3BtreeGetFilename(Btree *p){
*/
const char *sqlite3BtreeGetDirname(Btree *p){
assert( p->pBt->pPager!=0 );
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerDirname(p->pBt->pPager);
}
@@ -6700,7 +6606,6 @@ const char *sqlite3BtreeGetDirname(Btree *p){
*/
const char *sqlite3BtreeGetJournalname(Btree *p){
assert( p->pBt->pPager!=0 );
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerJournalname(p->pBt->pPager);
}
@@ -6780,7 +6685,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
** Return non-zero if a transaction is active.
*/
int sqlite3BtreeIsInTrans(Btree *p){
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
return (p && (p->inTrans==TRANS_WRITE));
}
@@ -6798,7 +6702,6 @@ int sqlite3BtreeIsInStmt(Btree *p){
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
return (p && (p->inTrans!=TRANS_NONE));
}

View File

@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.86 2007/08/22 02:56:43 drh Exp $
** @(#) $Id: btree.h,v 1.87 2007/08/28 02:27:52 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -41,6 +41,18 @@
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
typedef struct BtreeMutexSet BtreeMutexSet;
/*
** This structure records all of the Btrees that need to hold
** a mutex before we enter sqlite3VdbeExec(). The Btrees are
** are placed in aBtree[] in order of aBtree[]->pBt. That way,
** we can always lock and unlock them all quickly.
*/
struct BtreeMutexSet {
int nMutex;
Btree *aBtree[SQLITE_MAX_ATTACHED+1];
};
int sqlite3BtreeOpen(
@@ -170,4 +182,16 @@ void sqlite3BtreeCursorList(Btree*);
int sqlite3BtreePageDump(Btree*, int, int recursive);
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
void sqlite3BtreeMutexSetEnter(BtreeMutexSet*);
void sqlite3BtreeMutexSetLeave(BtreeMutexSet*);
void sqlite3BtreeMutexSetInsert(BtreeMutexSet*, Btree*);
#else
# define sqlite3BtreeMutexSetEnter(X)
# define sqlite3BtreeMutexSetLeave(X)
# define sqlite3BtreeMutexSetInsert(X,Y)
#endif
#endif /* _BTREE_H_ */

View File

@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.438 2007/08/22 20:18:22 drh Exp $
** $Id: build.c,v 1.439 2007/08/28 02:27:52 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -164,6 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue;
sqlite3VdbeAddMutexBtree(v, db->aDb[iDb].pBt);
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}

View File

@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.602 2007/08/27 23:26:59 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.603 2007/08/28 02:27:52 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -233,8 +233,8 @@ struct BusyHandler {
** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler typedefs.
*/
#include "vdbe.h"
#include "btree.h"
#include "vdbe.h"
#include "pager.h"

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.644 2007/08/21 19:33:57 drh Exp $
** $Id: vdbe.c,v 1.645 2007/08/28 02:27:52 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -465,6 +465,7 @@ int sqlite3VdbeExec(
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY );
pTos = p->pTos;
sqlite3BtreeMutexSetEnter(&p->mtxSet);
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
@@ -685,10 +686,11 @@ case OP_Halt: { /* no-push */
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
if( rc==SQLITE_BUSY ){
p->rc = SQLITE_BUSY;
return SQLITE_BUSY;
p->rc = rc = SQLITE_BUSY;
}else{
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
}
return p->rc ? SQLITE_ERROR : SQLITE_DONE;
goto vdbe_return;
}
/* Opcode: Integer P1 * *
@@ -1003,7 +1005,8 @@ case OP_Callback: { /* no-push */
p->popStack = pOp->p1;
p->pc = pc + 1;
p->pTos = pTos;
return SQLITE_ROW;
rc = SQLITE_ROW;
goto vdbe_return;
}
/* Opcode: Concat P1 P2 *
@@ -2462,15 +2465,16 @@ case OP_AutoCommit: { /* no-push */
p->pTos = pTos;
p->pc = pc;
db->autoCommit = 1-i;
p->rc = SQLITE_BUSY;
return SQLITE_BUSY;
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
}
if( p->rc==SQLITE_OK ){
return SQLITE_DONE;
rc = SQLITE_DONE;
}else{
return SQLITE_ERROR;
rc = SQLITE_ERROR;
}
goto vdbe_return;
}else{
sqlite3SetString(&p->zErrMsg,
(!i)?"cannot start a transaction within a transaction":(
@@ -2513,9 +2517,9 @@ case OP_Transaction: { /* no-push */
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
if( rc==SQLITE_BUSY ){
p->pc = pc;
p->rc = SQLITE_BUSY;
p->rc = rc = SQLITE_BUSY;
p->pTos = pTos;
return SQLITE_BUSY;
goto vdbe_return;
}
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
goto abort_due_to_error;
@@ -2755,9 +2759,9 @@ case OP_OpenWrite: { /* no-push */
switch( rc ){
case SQLITE_BUSY: {
p->pc = pc;
p->rc = SQLITE_BUSY;
p->rc = rc = SQLITE_BUSY;
p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
return SQLITE_BUSY;
goto vdbe_return;
}
case SQLITE_OK: {
int flags = sqlite3BtreeFlags(pCur->pCursor);
@@ -5193,6 +5197,12 @@ vdbe_halt:
}
sqlite3VdbeHalt(p);
p->pTos = pTos;
/* This is the only way out of this procedure. We have to
** release the mutexes on btrees that were acquired at the
** top. */
vdbe_return:
sqlite3BtreeMutexSetLeave(&p->mtxSet);
return rc;
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH

View File

@@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.110 2007/05/08 21:45:28 drh Exp $
** $Id: vdbe.h,v 1.111 2007/08/28 02:27:52 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -120,6 +120,7 @@ void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqlite3VdbeAddMutexBtree(Vdbe*, Btree*);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);

View File

@@ -317,7 +317,7 @@ struct Vdbe {
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
int returnStack[25]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
@@ -332,6 +332,7 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
BtreeMutexSet mtxSet; /* Set of Btree mutexes */
int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_DEBUG

View File

@@ -658,6 +658,13 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
}
#endif
/*
** Add a btree to the set of btrees that might need a mutex.
*/
void sqlite3VdbeAddMutexBtree(Vdbe *p, Btree *pBtree){
sqlite3BtreeMutexSetInsert(&p->mtxSet, pBtree);
}
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*