# 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 \
$(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 \
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
# 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 \
$(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 \
# 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 \
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
-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
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
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
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
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
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
-741d6fb096dcb232871d3a8468c386022afcf554
\ No newline at end of file
+b8cc493b47e618648f645ab73eb0253739e03fcd
\ No newline at end of file
--- /dev/null
+/*
+** 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 */
** 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.
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.
*/
const char *sqlite3BtreeGetFilename(Btree *p){
assert( p->pBt->pPager!=0 );
- assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerFilename(p->pBt->pPager);
}
*/
const char *sqlite3BtreeGetDirname(Btree *p){
assert( p->pBt->pPager!=0 );
- assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerDirname(p->pBt->pPager);
}
*/
const char *sqlite3BtreeGetJournalname(Btree *p){
assert( p->pBt->pPager!=0 );
- assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return sqlite3PagerJournalname(p->pBt->pPager);
}
** 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));
}
** 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));
}
** 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_
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(
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_ */
** 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>
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]);
}
*************************************************************************
** 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_
** 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"
** 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>
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. */
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 * *
p->popStack = pOp->p1;
p->pc = pc + 1;
p->pTos = pTos;
- return SQLITE_ROW;
+ rc = SQLITE_ROW;
+ goto vdbe_return;
}
/* Opcode: Concat P1 P2 *
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":(
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;
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);
}
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
** 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_
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*);
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 */
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
}
#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)
/*