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:
@@ -120,7 +120,7 @@ TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1
|
|||||||
|
|
||||||
# Object files for the SQLite library.
|
# 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 \
|
callback.lo complete.lo date.lo \
|
||||||
delete.lo expr.lo func.lo hash.lo journal.lo insert.lo loadext.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 \
|
main.lo malloc.lo mem1.lo mem2.lo mutex.lo \
|
||||||
@@ -138,6 +138,7 @@ SRC = \
|
|||||||
$(TOP)/src/analyze.c \
|
$(TOP)/src/analyze.c \
|
||||||
$(TOP)/src/attach.c \
|
$(TOP)/src/attach.c \
|
||||||
$(TOP)/src/auth.c \
|
$(TOP)/src/auth.c \
|
||||||
|
$(TOP)/src/btmutex.c \
|
||||||
$(TOP)/src/btree.c \
|
$(TOP)/src/btree.c \
|
||||||
$(TOP)/src/btree.h \
|
$(TOP)/src/btree.h \
|
||||||
$(TOP)/src/build.c \
|
$(TOP)/src/build.c \
|
||||||
@@ -340,6 +341,9 @@ attach.lo: $(TOP)/src/attach.c $(HDR)
|
|||||||
auth.lo: $(TOP)/src/auth.c $(HDR)
|
auth.lo: $(TOP)/src/auth.c $(HDR)
|
||||||
$(LTCOMPILE) -c $(TOP)/src/auth.c
|
$(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
|
btree.lo: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
|
||||||
$(LTCOMPILE) -c $(TOP)/src/btree.c
|
$(LTCOMPILE) -c $(TOP)/src/btree.c
|
||||||
|
|
||||||
|
10
main.mk
10
main.mk
@@ -55,7 +55,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
|
|||||||
|
|
||||||
# Object files for the SQLite library.
|
# 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 \
|
callback.o complete.o date.o delete.o \
|
||||||
expr.o func.o hash.o insert.o journal.o loadext.o \
|
expr.o func.o hash.o insert.o journal.o loadext.o \
|
||||||
main.o malloc.o mem1.o mem2.o mutex.o \
|
main.o malloc.o mem1.o mem2.o mutex.o \
|
||||||
@@ -91,6 +91,7 @@ SRC = \
|
|||||||
$(TOP)/src/analyze.c \
|
$(TOP)/src/analyze.c \
|
||||||
$(TOP)/src/attach.c \
|
$(TOP)/src/attach.c \
|
||||||
$(TOP)/src/auth.c \
|
$(TOP)/src/auth.c \
|
||||||
|
$(TOP)/src/btmutex.c \
|
||||||
$(TOP)/src/btree.c \
|
$(TOP)/src/btree.c \
|
||||||
$(TOP)/src/btree.h \
|
$(TOP)/src/btree.h \
|
||||||
$(TOP)/src/build.c \
|
$(TOP)/src/build.c \
|
||||||
@@ -194,11 +195,15 @@ SRC += \
|
|||||||
# Source code to the test files.
|
# Source code to the test files.
|
||||||
#
|
#
|
||||||
TESTSRC = \
|
TESTSRC = \
|
||||||
|
$(TOP)/src/btmutex.c \
|
||||||
$(TOP)/src/btree.c \
|
$(TOP)/src/btree.c \
|
||||||
$(TOP)/src/date.c \
|
$(TOP)/src/date.c \
|
||||||
$(TOP)/src/func.c \
|
$(TOP)/src/func.c \
|
||||||
$(TOP)/src/insert.c \
|
$(TOP)/src/insert.c \
|
||||||
$(TOP)/src/malloc.c \
|
$(TOP)/src/malloc.c \
|
||||||
|
$(TOP)/src/mem1.c \
|
||||||
|
$(TOP)/src/mem2.c \
|
||||||
|
$(TOP)/src/mutex.c \
|
||||||
$(TOP)/src/os.c \
|
$(TOP)/src/os.c \
|
||||||
$(TOP)/src/os_os2.c \
|
$(TOP)/src/os_os2.c \
|
||||||
$(TOP)/src/os_unix.c \
|
$(TOP)/src/os_unix.c \
|
||||||
@@ -337,6 +342,9 @@ attach.o: $(TOP)/src/attach.c $(HDR)
|
|||||||
auth.o: $(TOP)/src/auth.c $(HDR)
|
auth.o: $(TOP)/src/auth.c $(HDR)
|
||||||
$(TCCX) -c $(TOP)/src/auth.c
|
$(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
|
btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
|
||||||
$(TCCX) -c $(TOP)/src/btree.c
|
$(TCCX) -c $(TOP)/src/btree.c
|
||||||
|
|
||||||
|
31
manifest
31
manifest
@@ -1,6 +1,6 @@
|
|||||||
C Disable\stests\sthat\sdebug\son\sSQLITE_MEMDEBUG\swhen\sthat\smacro\sis\snot\sdefined.\s(CVS\s4306)
|
C Work\stoward\scorrect\sbtree\slocking\sin\sa\smultithreaded\senvironment.\s(CVS\s4307)
|
||||||
D 2007-08-27T23:48:24
|
D 2007-08-28T02:27:52
|
||||||
F Makefile.in 51bdcd1708f0971bc6b5d8eb47f00d127a899345
|
F Makefile.in e8296e112b8942a96c0ed504398bd0d43e3c67ce
|
||||||
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
|
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
F VERSION 6200589421a0dfe968cd39c431fc62277b963540
|
F VERSION 6200589421a0dfe968cd39c431fc62277b963540
|
||||||
@@ -63,7 +63,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
|||||||
F ext/icu/icu.c 61a345d8126686aa3487aa8d2d0f68abd655f7a4
|
F ext/icu/icu.c 61a345d8126686aa3487aa8d2d0f68abd655f7a4
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||||
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
|
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
|
||||||
F main.mk 238b00009433760c469ceb94f37f49e76dceae45
|
F main.mk 6b817f36cdfe3c1846cf6bac96afe8f73add5fe5
|
||||||
F mkdll.sh 37fa8a7412e51b5ab2bc6d4276135f022a0feffb
|
F mkdll.sh 37fa8a7412e51b5ab2bc6d4276135f022a0feffb
|
||||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||||
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
|
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
|
||||||
@@ -80,10 +80,11 @@ F src/alter.c fd78c6005456c727a6cb7c01c5266f2aacf6d401
|
|||||||
F src/analyze.c a14237d869c6bea0846493b59317e4097e81a0b6
|
F src/analyze.c a14237d869c6bea0846493b59317e4097e81a0b6
|
||||||
F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
|
F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
|
||||||
F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3
|
F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3
|
||||||
F src/btree.c dbb8ec48e619fc4900f42cafffc7de90b4b21250
|
F src/btmutex.c e11c59a7a68d9f295a1abfb753ffa4755b5037b1
|
||||||
F src/btree.h 76c89673981cb77575300c0b78a76eaa00a28743
|
F src/btree.c 850cd5de860e01233153ade9b24ffc775a794e8e
|
||||||
|
F src/btree.h a8fb26c56b745b57446c2bf29133619261313051
|
||||||
F src/btreeInt.h c1ba892252bc4dd76ad66da056536c64b23456e3
|
F src/btreeInt.h c1ba892252bc4dd76ad66da056536c64b23456e3
|
||||||
F src/build.c bc7406e2ea5bfa8276ee1abeae1db27a98fd0b33
|
F src/build.c 08001e8a12b06178193dc4a8f24610f58de80dae
|
||||||
F src/callback.c a542236a68060caad378efa30006ca46cf77b1b2
|
F src/callback.c a542236a68060caad378efa30006ca46cf77b1b2
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e
|
F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e
|
||||||
@@ -127,7 +128,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
|||||||
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
|
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
|
||||||
F src/sqlite.h.in 4cf42ce749e4bdf13b9bb4959e91439c3ce8a054
|
F src/sqlite.h.in 4cf42ce749e4bdf13b9bb4959e91439c3ce8a054
|
||||||
F src/sqlite3ext.h 9a26028378c288af500d8b94ed079666fed5806b
|
F src/sqlite3ext.h 9a26028378c288af500d8b94ed079666fed5806b
|
||||||
F src/sqliteInt.h ec674206f8a6a475ac58552c40e77d88d66862a2
|
F src/sqliteInt.h e681df44a19ffb6750d129802f124132ae240c83
|
||||||
F src/sqliteLimit.h 1bcbbdfa856f8b71b561abb31edb864b0eca1d12
|
F src/sqliteLimit.h 1bcbbdfa856f8b71b561abb31edb864b0eca1d12
|
||||||
F src/table.c c725e47f6f3092b9a7b569fc58e408e2173ee008
|
F src/table.c c725e47f6f3092b9a7b569fc58e408e2173ee008
|
||||||
F src/tclsqlite.c d76af53f45c9e9f7f7d39531fa4c7bee7d0adad6
|
F src/tclsqlite.c d76af53f45c9e9f7f7d39531fa4c7bee7d0adad6
|
||||||
@@ -157,11 +158,11 @@ F src/update.c e89b980b443d44b68bfc0b1746cdb6308e049ac9
|
|||||||
F src/utf.c 4af6259d5906b5a1bf3035cc387c4d7907bdd56e
|
F src/utf.c 4af6259d5906b5a1bf3035cc387c4d7907bdd56e
|
||||||
F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367
|
F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367
|
||||||
F src/vacuum.c 5ec133b69edf581a232af7e2b01f45c9f2b8be32
|
F src/vacuum.c 5ec133b69edf581a232af7e2b01f45c9f2b8be32
|
||||||
F src/vdbe.c 9d4d00589c174aad9a616f1615464ddddebba0ec
|
F src/vdbe.c 62d210babaac906a5847d7bd4c71e7b114595e85
|
||||||
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
|
F src/vdbe.h 5b3ee0fd91a08579f514713038fa7dbef9edf407
|
||||||
F src/vdbeInt.h 2bb602c9cb19191d574517bdec0f6c0b600bd3da
|
F src/vdbeInt.h 0681e0b74a43d3adfec65780d73b2db8f826c7c9
|
||||||
F src/vdbeapi.c bdd0aea216744482dd1b7fab56de18ba5b6fbdf4
|
F src/vdbeapi.c bdd0aea216744482dd1b7fab56de18ba5b6fbdf4
|
||||||
F src/vdbeaux.c 2889abf9a6fe954de158bea07652d46101577d08
|
F src/vdbeaux.c bffdf7b69de21a70520260d359e19df64f31aea4
|
||||||
F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7
|
F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7
|
||||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||||
F src/vdbemem.c 896fa3f8df9d2661eb15c7ce361857741b447268
|
F src/vdbemem.c 896fa3f8df9d2661eb15c7ce361857741b447268
|
||||||
@@ -562,7 +563,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P bc6d73d015327a9cf6b687aaf4b3f0d07e0fd484
|
P 741d6fb096dcb232871d3a8468c386022afcf554
|
||||||
R 2349531d73bc37131a9a7284d5308814
|
R ff3e167d1bd072e0909067b1f2888076
|
||||||
U drh
|
U drh
|
||||||
Z 56024ff7bdc953200a8a79d2b652027f
|
Z 6d8ca04435be2f950a1ddef0045b914b
|
||||||
|
@@ -1 +1 @@
|
|||||||
741d6fb096dcb232871d3a8468c386022afcf554
|
b8cc493b47e618648f645ab73eb0253739e03fcd
|
199
src/btmutex.c
Normal file
199
src/btmutex.c
Normal 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 */
|
99
src/btree.c
99
src/btree.c
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** 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.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** See the header comment on "btreeInt.h" for additional information.
|
** See the header comment on "btreeInt.h" for additional information.
|
||||||
@@ -1386,98 +1386,6 @@ int sqlite3BtreeClose(Btree *p){
|
|||||||
return SQLITE_OK;
|
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)
|
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
|
||||||
/*
|
/*
|
||||||
** Short-cuts for entering and leaving mutexes on a cursor.
|
** Short-cuts for entering and leaving mutexes on a cursor.
|
||||||
@@ -6680,7 +6588,6 @@ char *sqlite3BtreeIntegrityCheck(
|
|||||||
*/
|
*/
|
||||||
const char *sqlite3BtreeGetFilename(Btree *p){
|
const char *sqlite3BtreeGetFilename(Btree *p){
|
||||||
assert( p->pBt->pPager!=0 );
|
assert( p->pBt->pPager!=0 );
|
||||||
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
|
|
||||||
return sqlite3PagerFilename(p->pBt->pPager);
|
return sqlite3PagerFilename(p->pBt->pPager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6689,7 +6596,6 @@ const char *sqlite3BtreeGetFilename(Btree *p){
|
|||||||
*/
|
*/
|
||||||
const char *sqlite3BtreeGetDirname(Btree *p){
|
const char *sqlite3BtreeGetDirname(Btree *p){
|
||||||
assert( p->pBt->pPager!=0 );
|
assert( p->pBt->pPager!=0 );
|
||||||
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
|
|
||||||
return sqlite3PagerDirname(p->pBt->pPager);
|
return sqlite3PagerDirname(p->pBt->pPager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6700,7 +6606,6 @@ const char *sqlite3BtreeGetDirname(Btree *p){
|
|||||||
*/
|
*/
|
||||||
const char *sqlite3BtreeGetJournalname(Btree *p){
|
const char *sqlite3BtreeGetJournalname(Btree *p){
|
||||||
assert( p->pBt->pPager!=0 );
|
assert( p->pBt->pPager!=0 );
|
||||||
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
|
|
||||||
return sqlite3PagerJournalname(p->pBt->pPager);
|
return sqlite3PagerJournalname(p->pBt->pPager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6780,7 +6685,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|||||||
** Return non-zero if a transaction is active.
|
** Return non-zero if a transaction is active.
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeIsInTrans(Btree *p){
|
int sqlite3BtreeIsInTrans(Btree *p){
|
||||||
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
|
|
||||||
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
|
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
|
||||||
return (p && (p->inTrans==TRANS_WRITE));
|
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.
|
** Return non-zero if a read (or write) transaction is active.
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeIsInReadTrans(Btree *p){
|
int sqlite3BtreeIsInReadTrans(Btree *p){
|
||||||
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
|
|
||||||
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
|
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
|
||||||
return (p && (p->inTrans!=TRANS_NONE));
|
return (p && (p->inTrans!=TRANS_NONE));
|
||||||
}
|
}
|
||||||
|
26
src/btree.h
26
src/btree.h
@@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** 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_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@@ -41,6 +41,18 @@
|
|||||||
typedef struct Btree Btree;
|
typedef struct Btree Btree;
|
||||||
typedef struct BtCursor BtCursor;
|
typedef struct BtCursor BtCursor;
|
||||||
typedef struct BtShared BtShared;
|
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 sqlite3BtreeOpen(
|
||||||
@@ -170,4 +182,16 @@ void sqlite3BtreeCursorList(Btree*);
|
|||||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||||
#endif
|
#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_ */
|
#endif /* _BTREE_H_ */
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -164,6 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||||||
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
||||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||||
|
sqlite3VdbeAddMutexBtree(v, db->aDb[iDb].pBt);
|
||||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||||
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
|
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** 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_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -233,8 +233,8 @@ struct BusyHandler {
|
|||||||
** Defer sourcing vdbe.h and btree.h until after the "u8" and
|
** Defer sourcing vdbe.h and btree.h until after the "u8" and
|
||||||
** "BusyHandler typedefs.
|
** "BusyHandler typedefs.
|
||||||
*/
|
*/
|
||||||
#include "vdbe.h"
|
|
||||||
#include "btree.h"
|
#include "btree.h"
|
||||||
|
#include "vdbe.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
|
|
||||||
|
|
||||||
|
36
src/vdbe.c
36
src/vdbe.c
@@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -465,6 +465,7 @@ int sqlite3VdbeExec(
|
|||||||
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
|
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
|
||||||
assert( db->magic==SQLITE_MAGIC_BUSY );
|
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||||
pTos = p->pTos;
|
pTos = p->pTos;
|
||||||
|
sqlite3BtreeMutexSetEnter(&p->mtxSet);
|
||||||
if( p->rc==SQLITE_NOMEM ){
|
if( p->rc==SQLITE_NOMEM ){
|
||||||
/* This happens if a malloc() inside a call to sqlite3_column_text() or
|
/* This happens if a malloc() inside a call to sqlite3_column_text() or
|
||||||
** sqlite3_column_text16() failed. */
|
** sqlite3_column_text16() failed. */
|
||||||
@@ -685,10 +686,11 @@ case OP_Halt: { /* no-push */
|
|||||||
rc = sqlite3VdbeHalt(p);
|
rc = sqlite3VdbeHalt(p);
|
||||||
assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
|
assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
|
||||||
if( rc==SQLITE_BUSY ){
|
if( rc==SQLITE_BUSY ){
|
||||||
p->rc = SQLITE_BUSY;
|
p->rc = rc = SQLITE_BUSY;
|
||||||
return SQLITE_BUSY;
|
}else{
|
||||||
|
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
||||||
}
|
}
|
||||||
return p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
goto vdbe_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Integer P1 * *
|
/* Opcode: Integer P1 * *
|
||||||
@@ -1003,7 +1005,8 @@ case OP_Callback: { /* no-push */
|
|||||||
p->popStack = pOp->p1;
|
p->popStack = pOp->p1;
|
||||||
p->pc = pc + 1;
|
p->pc = pc + 1;
|
||||||
p->pTos = pTos;
|
p->pTos = pTos;
|
||||||
return SQLITE_ROW;
|
rc = SQLITE_ROW;
|
||||||
|
goto vdbe_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: Concat P1 P2 *
|
/* Opcode: Concat P1 P2 *
|
||||||
@@ -2462,15 +2465,16 @@ case OP_AutoCommit: { /* no-push */
|
|||||||
p->pTos = pTos;
|
p->pTos = pTos;
|
||||||
p->pc = pc;
|
p->pc = pc;
|
||||||
db->autoCommit = 1-i;
|
db->autoCommit = 1-i;
|
||||||
p->rc = SQLITE_BUSY;
|
p->rc = rc = SQLITE_BUSY;
|
||||||
return SQLITE_BUSY;
|
goto vdbe_return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( p->rc==SQLITE_OK ){
|
if( p->rc==SQLITE_OK ){
|
||||||
return SQLITE_DONE;
|
rc = SQLITE_DONE;
|
||||||
}else{
|
}else{
|
||||||
return SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
goto vdbe_return;
|
||||||
}else{
|
}else{
|
||||||
sqlite3SetString(&p->zErrMsg,
|
sqlite3SetString(&p->zErrMsg,
|
||||||
(!i)?"cannot start a transaction within a transaction":(
|
(!i)?"cannot start a transaction within a transaction":(
|
||||||
@@ -2513,9 +2517,9 @@ case OP_Transaction: { /* no-push */
|
|||||||
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
|
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
|
||||||
if( rc==SQLITE_BUSY ){
|
if( rc==SQLITE_BUSY ){
|
||||||
p->pc = pc;
|
p->pc = pc;
|
||||||
p->rc = SQLITE_BUSY;
|
p->rc = rc = SQLITE_BUSY;
|
||||||
p->pTos = pTos;
|
p->pTos = pTos;
|
||||||
return SQLITE_BUSY;
|
goto vdbe_return;
|
||||||
}
|
}
|
||||||
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
|
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
@@ -2755,9 +2759,9 @@ case OP_OpenWrite: { /* no-push */
|
|||||||
switch( rc ){
|
switch( rc ){
|
||||||
case SQLITE_BUSY: {
|
case SQLITE_BUSY: {
|
||||||
p->pc = pc;
|
p->pc = pc;
|
||||||
p->rc = SQLITE_BUSY;
|
p->rc = rc = SQLITE_BUSY;
|
||||||
p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
|
p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
|
||||||
return SQLITE_BUSY;
|
goto vdbe_return;
|
||||||
}
|
}
|
||||||
case SQLITE_OK: {
|
case SQLITE_OK: {
|
||||||
int flags = sqlite3BtreeFlags(pCur->pCursor);
|
int flags = sqlite3BtreeFlags(pCur->pCursor);
|
||||||
@@ -5193,6 +5197,12 @@ vdbe_halt:
|
|||||||
}
|
}
|
||||||
sqlite3VdbeHalt(p);
|
sqlite3VdbeHalt(p);
|
||||||
p->pTos = pTos;
|
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;
|
return rc;
|
||||||
|
|
||||||
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
|
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** 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_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -120,6 +120,7 @@ void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
|||||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||||
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
|
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
|
||||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||||
|
void sqlite3VdbeAddMutexBtree(Vdbe*, Btree*);
|
||||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||||
void sqlite3VdbeDelete(Vdbe*);
|
void sqlite3VdbeDelete(Vdbe*);
|
||||||
|
@@ -317,7 +317,7 @@ struct Vdbe {
|
|||||||
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
||||||
int errorAction; /* Recovery action to do in case of an error */
|
int errorAction; /* Recovery action to do in case of an error */
|
||||||
int inTempTrans; /* True if temp database is transactioned */
|
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 returnDepth; /* Next unused element in returnStack[] */
|
||||||
int nResColumn; /* Number of columns in one row of the result set */
|
int nResColumn; /* Number of columns in one row of the result set */
|
||||||
char **azResColumn; /* Values for one row of result */
|
char **azResColumn; /* Values for one row of result */
|
||||||
@@ -332,6 +332,7 @@ struct Vdbe {
|
|||||||
u8 inVtabMethod; /* See comments above */
|
u8 inVtabMethod; /* See comments above */
|
||||||
int nChange; /* Number of db changes made since last reset */
|
int nChange; /* Number of db changes made since last reset */
|
||||||
i64 startTime; /* Time when query started - used for profiling */
|
i64 startTime; /* Time when query started - used for profiling */
|
||||||
|
BtreeMutexSet mtxSet; /* Set of Btree mutexes */
|
||||||
int nSql; /* Number of bytes in zSql */
|
int nSql; /* Number of bytes in zSql */
|
||||||
char *zSql; /* Text of the SQL statement that generated this */
|
char *zSql; /* Text of the SQL statement that generated this */
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
|
@@ -658,6 +658,13 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user