-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
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
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
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
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
-6a5630806c87b0f4e5632c37c357f98effd9608a
\ No newline at end of file
+71e7b1cf9f4cd02a2a9bc8a3e58acd7a7e3c7e60
\ No newline at end of file
}
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);
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;
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 ){
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
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 */
};
** 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;
}
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;
** 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;
}
}
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 */
*/
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_ */
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
+