Changes so that WAL and exclusive-locking mode work together.

FossilOrigin-Name: 71e7b1cf9f4cd02a2a9bc8a3e58acd7a7e3c7e60
This commit is contained in:
dan 2010-05-11 12:19:26 +00:00
parent a10069dd22
commit 5543759b1b
6 changed files with 321 additions and 35 deletions

View File

@ -1,5 +1,5 @@
C Updates\sfor\sto\sWAL\sTCL\stest\sscripts\sto\ssupport\srunning\son\sWindows.
D 2010-05-11T02:46:17
C Changes\sso\sthat\sWAL\sand\sexclusive-locking\smode\swork\stogether.
D 2010-05-11T12:19:27
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -154,7 +154,7 @@ F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
F src/os_unix.c 34fe71c67fce72360411d60fe069c7f0dc612dd0
F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1
F src/pager.c a47af9c2c9ca425bd68642d61764266331a3323f
F src/pager.c 871ccb53e901dabf92b9b2806f0fbe4a2c039d99
F src/pager.h 934b598583a9d936bb13c37d62a2fe68ac48781c
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
@ -224,8 +224,8 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
F src/wal.c 65d1376c8d5ce500ac1fd1bf49e2287ad04cf6c4
F src/wal.h b4c42014b5fa3b4e6244ac8c65de7ff67adeb27c
F src/wal.c 7042647fd4c89b789da6dc934550effdf573a290
F src/wal.h 32f36b2a827b78373658dac5521291485dfa52b6
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@ -762,7 +762,7 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test 7a100918c45872fa19cfb4413299b9afb08727b6
F test/wal2.test 0f53c711d6530d3c7aba46752aef9fd44b708c6c
F test/wal2.test 913fc65e533593e3b5dfb193340ac32368da1914
F test/walbak.test a0e45187c7d8928df035dfea29b99b016b21ca3c
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
F test/walfault.test 98df47444944a6db2161eed5cef71d6c00bcb8c3
@ -813,7 +813,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 6e3735f72cb7d2f4d16c8f9bc59ff159c75243e5
R 6271f8fbb605ce59c9bcaa6c5c92af66
U shaneh
Z 6c6a591f5b1ea69fe4a6d39da0e8aca9
P 6a5630806c87b0f4e5632c37c357f98effd9608a
R ed8f197401fc52de24ef292a838d5248
U dan
Z ca9adf09cbf258f90f9e808c81428995

View File

@ -1 +1 @@
6a5630806c87b0f4e5632c37c357f98effd9608a
71e7b1cf9f4cd02a2a9bc8a3e58acd7a7e3c7e60

View File

@ -1404,8 +1404,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
}
pPager->journalOff = 0;
pPager->journalStarted = 0;
}else if( pPager->exclusiveMode
|| pPager->journalMode==PAGER_JOURNALMODE_PERSIST
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasMaster);
pager_error(pPager, rc);
@ -1439,6 +1439,17 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
if( pagerUseWal(pPager) ){
rc2 = sqlite3WalWriteLock(pPager->pWal, 0);
pPager->state = PAGER_SHARED;
/* If the connection was in locking_mode=exclusive mode but is no longer,
** drop the EXCLUSIVE lock held on the database file.
*/
if( rc2==SQLITE_OK
&& !pPager->exclusiveMode
&& sqlite3WalExclusiveMode(pPager->pWal, -1)
){
sqlite3WalExclusiveMode(pPager->pWal, 0);
rc2 = osUnlock(pPager->fd, SHARED_LOCK);
}
}else if( !pPager->exclusiveMode ){
rc2 = osUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
@ -4509,15 +4520,34 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
int rc = SQLITE_OK;
assert( pPager->state!=PAGER_UNLOCK );
pPager->subjInMemory = (u8)subjInMemory;
if( pPager->state==PAGER_SHARED ){
assert( pPager->pInJournal==0 );
assert( !MEMDB && !pPager->tempFile );
if( pagerUseWal(pPager) ){
/* If the pager is configured to use locking_mode=exclusive, and an
** exclusive lock on the database is not already held, obtain it now.
*/
if( pPager->exclusiveMode && !sqlite3WalExclusiveMode(pPager->pWal, -1) ){
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
pPager->state = PAGER_SHARED;
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3WalExclusiveMode(pPager->pWal, 1);
}
/* Grab the write lock on the log file. If successful, upgrade to
** PAGER_EXCLUSIVE state. Otherwise, return an error code to the caller.
** PAGER_RESERVED state. Otherwise, return an error code to the caller.
** The busy-handler is not invoked if another connection already
** holds the write-lock. If possible, the upper layer will call it.
**
** WAL mode sets Pager.state to PAGER_RESERVED when it has an open
** transaction, but never to PAGER_EXCLUSIVE. This is because in
** PAGER_EXCLUSIVE state the code to roll back savepoint transactions
** may copy data from the sub-journal into the database file as well
** as into the page cache. Which would be incorrect in WAL mode.
*/
rc = sqlite3WalWriteLock(pPager->pWal, 1);
if( rc==SQLITE_OK ){
@ -4525,6 +4555,9 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
pPager->state = PAGER_RESERVED;
pPager->journalOff = 0;
}
assert( rc!=SQLITE_OK || pPager->state==PAGER_RESERVED );
assert( rc==SQLITE_OK || pPager->state==PAGER_SHARED );
}else{
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
** is true, then immediately upgrade this to an EXCLUSIVE lock. The

View File

@ -132,6 +132,7 @@ struct Wal {
u32 *pWiData; /* Pointer to wal-index content in memory */
u8 lockState; /* SQLITE_SHM_xxxx constant showing lock state */
u8 readerType; /* SQLITE_SHM_READ or SQLITE_SHM_READ_FULL */
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
WalIndexHdr hdr; /* Wal-index for current snapshot */
char *zName; /* Name of underlying storage */
};
@ -217,14 +218,17 @@ static void walChecksumBytes(u8 *aByte, int nByte, u32 *aCksum){
** in pWal->readerType.
*/
static int walSetLock(Wal *pWal, int desiredStatus){
int rc, got;
if( pWal->lockState==desiredStatus ) return SQLITE_OK;
got = pWal->lockState;
rc = pWal->pVfs->xShmLock(pWal->pVfs, pWal->pWIndex, desiredStatus, &got);
pWal->lockState = got;
if( got==SQLITE_SHM_READ_FULL || got==SQLITE_SHM_READ ){
pWal->readerType = got;
pWal->lockState = SQLITE_SHM_READ;
int rc = SQLITE_OK; /* Return code */
if( pWal->exclusiveMode || pWal->lockState==desiredStatus ){
pWal->lockState = desiredStatus;
}else{
int got = pWal->lockState;
rc = pWal->pVfs->xShmLock(pWal->pVfs, pWal->pWIndex, desiredStatus, &got);
pWal->lockState = got;
if( got==SQLITE_SHM_READ_FULL || got==SQLITE_SHM_READ ){
pWal->readerType = got;
pWal->lockState = SQLITE_SHM_READ;
}
}
return rc;
}
@ -1231,7 +1235,7 @@ int sqlite3WalWriteLock(Wal *pWal, int op){
walSetLock(pWal, SQLITE_SHM_READ);
}
}
}else if( ALWAYS( pWal->lockState==SQLITE_SHM_WRITE ) ){
}else if( pWal->lockState==SQLITE_SHM_WRITE ){
rc = walSetLock(pWal, SQLITE_SHM_READ);
}
return rc;
@ -1250,18 +1254,20 @@ int sqlite3WalWriteLock(Wal *pWal, int op){
** function returns SQLITE_OK.
*/
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
int unused;
int rc;
Pgno iMax = pWal->hdr.iLastPg;
Pgno iFrame;
assert( pWal->pWiData==0 );
rc = walIndexReadHdr(pWal, &unused);
for(iFrame=pWal->hdr.iLastPg+1; rc==SQLITE_OK && iFrame<=iMax; iFrame++){
assert( pWal->lockState==SQLITE_SHM_WRITE );
rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
int rc = SQLITE_OK;
if( pWal->lockState==SQLITE_SHM_WRITE ){
int unused;
Pgno iMax = pWal->hdr.iLastPg;
Pgno iFrame;
assert( pWal->pWiData==0 );
rc = walIndexReadHdr(pWal, &unused);
for(iFrame=pWal->hdr.iLastPg+1; rc==SQLITE_OK && iFrame<=iMax; iFrame++){
assert( pWal->lockState==SQLITE_SHM_WRITE );
rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
}
walIndexUnmap(pWal);
}
walIndexUnmap(pWal);
return rc;
}
@ -1500,4 +1506,35 @@ int sqlite3WalCallback(Wal *pWal){
}
return (int)ret;
}
/*
** This function is called to set or query the exclusive-mode flag
** associated with the WAL connection passed as the first argument. The
** exclusive-mode flag should be set to indicate that the caller is
** holding an EXCLUSIVE lock on the database file (it does this in
** locking_mode=exclusive mode). If the EXCLUSIVE lock is to be dropped,
** the flag set by this function should be cleared before doing so.
**
** The value of the exclusive-mode flag may only be modified when
** the WAL connection is in READ state.
**
** When the flag is set, this module does not call the VFS xShmLock()
** method to obtain any locks on the wal-index (as it assumes it
** has exclusive access to the wal and wal-index files anyhow). It
** continues to hold (and does not drop) the existing READ lock on
** the wal-index.
**
** To set or clear the flag, the "op" parameter is passed 1 or 0,
** respectively. To query the flag, pass -1. In all cases, the value
** returned is the value of the exclusive-mode flag (after its value
** has been modified, if applicable).
*/
int sqlite3WalExclusiveMode(Wal *pWal, int op){
if( op>=0 ){
assert( pWal->lockState==SQLITE_SHM_READ );
pWal->exclusiveMode = (u8)op;
}
return pWal->exclusiveMode;
}
#endif /* #ifndef SQLITE_OMIT_WAL */

View File

@ -96,5 +96,10 @@ int sqlite3WalCheckpoint(
*/
int sqlite3WalCallback(Wal *pWal);
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
** by the pager layer on the database file.
*/
int sqlite3WalExclusiveMode(Wal *pWal, int op);
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */

View File

@ -362,8 +362,219 @@ do_test wal2-5.1 {
execsql { PRAGMA wal_checkpoint }
set ::locks
} {CHECKPOINT UNLOCK}
db close
tvfs delete
#-------------------------------------------------------------------------
# This block, test cases wal2-6.*, tests the operation of WAL with
# "PRAGMA locking_mode=EXCLUSIVE" set.
#
# wal2-6.1.*: Changing to WAL mode before setting locking_mode=exclusive.
#
# wal2-6.2.*: Changing to WAL mode after setting locking_mode=exclusive.
#
# wal2-6.3.*: Changing back to rollback mode from WAL mode after setting
# locking_mode=exclusive.
#
# wal2-6.4.*: Check that xShmLock calls are omitted in exclusive locking
# mode.
#
do_test wal2-6.1.1 {
file delete -force test.db test.db-wal test.db-journal
sqlite3 db test.db
execsql {
Pragma Journal_Mode = Wal;
Pragma Locking_Mode = Exclusive;
}
} {wal exclusive}
do_test wal2-6.1.2 {
execsql { PRAGMA lock_status }
} {main unlocked temp closed}
do_test wal2-6.1.3 {
execsql {
BEGIN;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
COMMIT;
PRAGMA lock_status;
}
} {main exclusive temp closed}
do_test wal2-6.1.4 {
execsql {
PRAGMA locking_mode = normal;
PRAGMA lock_status;
}
} {normal main exclusive temp closed}
do_test wal2-6.1.5 {
execsql {
SELECT * FROM t1;
PRAGMA lock_status;
}
} {1 2 main exclusive temp closed}
do_test wal2-6.1.6 {
execsql {
INSERT INTO t1 VALUES(3, 4);
PRAGMA lock_status;
}
} {main shared temp closed}
db close
do_test wal2-6.2.1 {
file delete -force test.db test.db-wal test.db-journal
sqlite3 db test.db
execsql {
Pragma Locking_Mode = Exclusive;
Pragma Journal_Mode = Wal;
Pragma Lock_Status;
}
} {exclusive wal main exclusive temp closed}
do_test wal2-6.2.2 {
execsql {
BEGIN;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
COMMIT;
Pragma loCK_STATus;
}
} {main exclusive temp closed}
do_test wal2-6.2.3 {
db close
sqlite3 db test.db
execsql { PRAGMA LOCKING_MODE = EXCLUSIVE }
} {exclusive}
do_test wal2-6.2.4 {
execsql {
SELECT * FROM t1;
pragma lock_status;
}
} {1 2 main shared temp closed}
do_test wal2-6.2.5 {
execsql {
INSERT INTO t1 VALUES(3, 4);
pragma lock_status;
}
} {main exclusive temp closed}
do_test wal2-6.2.6 {
execsql {
PRAGMA locking_mode = NORMAL;
pragma lock_status;
}
} {normal main exclusive temp closed}
do_test wal2-6.2.7 {
execsql {
BEGIN IMMEDIATE; COMMIT;
pragma lock_status;
}
} {main shared temp closed}
do_test wal2-6.2.8 {
execsql {
PRAGMA locking_mode = EXCLUSIVE;
BEGIN IMMEDIATE; COMMIT;
PRAGMA locking_mode = NORMAL;
}
execsql {
SELECT * FROM t1;
pragma lock_status;
}
} {1 2 3 4 main exclusive temp closed}
do_test wal2-6.2.9 {
execsql {
INSERT INTO t1 VALUES(5, 6);
SELECT * FROM t1;
pragma lock_status;
}
} {1 2 3 4 5 6 main shared temp closed}
db close
do_test wal2-6.3.1 {
file delete -force test.db test.db-wal test.db-journal
sqlite3 db test.db
execsql {
PRAGMA journal_mode = WAL;
PRAGMA locking_mode = exclusive;
BEGIN;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('Chico');
INSERT INTO t1 VALUES('Harpo');
COMMIT;
}
list [file exists test.db-wal] [file exists test.db-journal]
} {1 0}
do_test wal2-6.3.2 {
execsql { PRAGMA journal_mode = DELETE }
file exists test.db-wal
} {0}
do_test wal2-6.3.3 {
execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
execsql {
BEGIN;
INSERT INTO t1 VALUES('Groucho');
}
list [file exists test.db-wal] [file exists test.db-journal]
} {0 1}
do_test wal2-6.3.5 {
execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.6 {
execsql { COMMIT }
list [file exists test.db-wal] [file exists test.db-journal]
} {0 1}
do_test wal2-6.3.7 {
execsql { PRAGMA lock_status }
} {main exclusive temp closed}
db close
do_test wal2-6.4.1 {
file delete -force test.db test.db-wal test.db-journal
proc tvfs_cb {method args} {
set ::shm_file [lindex $args 0]
if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
return "SQLITE_OK"
}
testvfs tvfs tvfs_cb
sqlite3 db test.db -vfs tvfs
execsql {
PRAGMA journal_mode = WAL;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('Leonard');
INSERT INTO t1 VALUES('Arthur');
}
set ::locks [list]
execsql { PRAGMA locking_mode = exclusive }
set ::locks
} {}
do_test wal2-6.4.2 {
execsql { SELECT * FROM t1 }
} {Leonard Arthur}
do_test wal2-6.4.3 {
set ::locks
} {READ}
do_test wal2-6.4.4 {
execsql {
INSERT INTO t1 VALUES('Julius Henry');
SELECT * FROM t1;
}
} {Leonard Arthur {Julius Henry}}
do_test wal2-6.4.5 {
set ::locks
} {READ}
do_test wal2-6.4.6 {
execsql {
PRAGMA locking_mode = NORMAL;
DELETE FROM t1;
}
set ::locks
} {READ UNLOCK}
do_test wal2-6.4.7 {
set ::locks [list]
execsql { INSERT INTO t1 VALUES('Karl') }
set ::locks
} {READ WRITE READ UNLOCK}
db close
finish_test