1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Use the read and write version fields of the database header to mark a database as operating in wal-mode.

FossilOrigin-Name: 96bef18c1411c3e0348295886f105e1646c46320
This commit is contained in:
dan
2010-04-20 18:53:15 +00:00
parent 8d22a17411
commit e04dc88be5
10 changed files with 327 additions and 128 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\ssqlite3_log_hook()\sinterface\sfor\sscheduling\scheckpoints. C Use\sthe\sread\sand\swrite\sversion\sfields\sof\sthe\sdatabase\sheader\sto\smark\sa\sdatabase\sas\soperating\sin\swal-mode.
D 2010-04-19T18:03:52 D 2010-04-20T18:53:15
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -109,8 +109,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c e86634da8c48357a759694c9c7c471125cd8d5a8 F src/backup.c e86634da8c48357a759694c9c7c471125cd8d5a8
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0 F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c 01559397cbd4a5aa62a822e8ca9ac94b6db14743 F src/btree.c 013cf019484e309e909a667654612b38a02dc2b6
F src/btree.h ad6cff92286f9b02ec32f0b97136e9a544249f37 F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
F src/btreeInt.h 22447d259639271774a931cbf66aa55112846681 F src/btreeInt.h 22447d259639271774a931cbf66aa55112846681
F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7 F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
@ -154,13 +154,13 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1 F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053 F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
F src/pager.c f9ad51dfa617131240ae77545c0083118324fc81 F src/pager.c 1dcf76bead8f1b51809bd8189ef9b02f2c94dc7f
F src/pager.h aeaee9ceb4a4a6d15c2163ef4e11a7590fd54b59 F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76 F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
F src/pragma.c f12cb58a8aa0d80cfed282ef87a285ed71beb793 F src/pragma.c bae3ce82ca6d0ac5d3ca3e46b286856d1f0ddd70
F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7 F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@ -214,7 +214,7 @@ F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
F src/vdbe.c 2e2aaa765de667dd15e0462cf853efd1b2f97998 F src/vdbe.c 304851b32c5f918a7ce92e4e9f94fbde0b604b21
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3 F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
F src/vdbeapi.c 466044df5bc916f778833e927165fd02cdef6086 F src/vdbeapi.c 466044df5bc916f778833e927165fd02cdef6086
@ -758,9 +758,10 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test a56ff378f58b145fd3bf38c277fbfe792cd47bdd F test/wal.test 273c0006e75c99cb34d0659851e7103fd4748c20
F test/walcrash.test 45cfbab30bb7cbe0b2e9d5cabe90dbcad10cb89b F test/walcrash.test 45cfbab30bb7cbe0b2e9d5cabe90dbcad10cb89b
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47 F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
F test/walmode.test cd6ee20f08af2d81fddc049f8d7e387a807f067e
F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2 F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2
F test/walthread.test 27e44ee6fd02f1f494a24f999c97086af3ab739d F test/walthread.test 27e44ee6fd02f1f494a24f999c97086af3ab739d
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
@ -806,7 +807,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 9d51c3b754f0b94fea5ef3d669ad583b93b2b024 P 9bda601455705475075e33bfa85687bce34b15ff
R 8eb45c9f56fe0d743248bffdfb606bc1 R b30f3db6dd942a33d471d74ec2e33c70
U dan U dan
Z e82f118f370901abf724c6ac84b89351 Z d82da3172ce11d2f9fc95cc996cdb180

View File

@ -1 +1 @@
9bda601455705475075e33bfa85687bce34b15ff 96bef18c1411c3e0348295886f105e1646c46320

View File

@ -2261,13 +2261,25 @@ static int lockBtree(BtShared *pBt){
if( memcmp(page1, zMagicHeader, 16)!=0 ){ if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed; goto page1_init_failed;
} }
if( page1[18]>1 ){ if( page1[18]>2 ){
pBt->readOnly = 1; pBt->readOnly = 1;
} }
if( page1[19]>1 ){ if( page1[19]>2 ){
goto page1_init_failed; goto page1_init_failed;
} }
/* If the write version is set to 2, turn on write-ahead logging mode. */
if( page1[19]==2 ){
int isOpen = 0;
rc = sqlite3PagerOpenLog(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
}
/* The maximum embedded fraction must be exactly 25%. And the minimum /* The maximum embedded fraction must be exactly 25%. And the minimum
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data. ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
** The original design allowed these amounts to vary, but as of ** The original design allowed these amounts to vary, but as of
@ -7963,3 +7975,26 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
pCur->isIncrblobHandle = 1; pCur->isIncrblobHandle = 1;
} }
#endif #endif
/*
** Set both the "read version" (single byte at byte offset 18) and
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
*/
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
BtShared *pBt = pBtree->pBt;
int rc; /* Return code */
assert( pBtree->inTrans==TRANS_WRITE );
assert( pBt->pPage1 );
assert( iVersion==1 || iVersion==2 );
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc==SQLITE_OK ){
u8 *aData = pBt->pPage1->aData;
aData[18] = (u8)iVersion;
aData[19] = (u8)iVersion;
}
return rc;
}

View File

@ -186,6 +186,8 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *); void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *);
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
#ifndef NDEBUG #ifndef NDEBUG
int sqlite3BtreeCursorIsValid(BtCursor*); int sqlite3BtreeCursorIsValid(BtCursor*);
#endif #endif

View File

@ -1405,9 +1405,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
/* This branch may be executed with Pager.journalMode==MEMORY if /* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal ** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to ** file should be closed and deleted. If this connection writes to
** the database file, it will do so using an in-memory journal. */ ** the database file, it will do so using an in-memory journal.
*/
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
); );
sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->jfd);
if( !pPager->tempFile ){ if( !pPager->tempFile ){
@ -3724,54 +3726,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
return rc; return rc;
} }
/*
** Open a connection to the write-ahead log file for pager pPager. If
** the log connection is already open, this function is a no-op.
*/
static int pagerOpenLog(Pager *pPager){
if( !pPager->pLog ){
int rc; /* Return code */
/* Before opening the log file, obtain a SHARED lock on the database
** file. This lock will not be released until after the log file
** connection has been closed. The purpose of this lock is to stop
** any other process from unlinking the log or log-summary files while
** this connection still has them open. An EXCLUSIVE lock on the
** database file is required to unlink either of those two files.
*/
assert( pPager->state==PAGER_UNLOCK );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
assert( pPager->state==PAGER_UNLOCK );
return pager_error(pPager, rc);
}
assert( pPager->state>=SHARED_LOCK );
/* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), unlock the database file and
** return an error code.
*/
rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
if( rc!=SQLITE_OK ){
osUnlock(pPager->fd, SQLITE_LOCK_NONE);
pPager->state = PAGER_UNLOCK;
return rc;
}
}else{
/* If the log file was already open, check that the pager is still holding
** the required SHARED lock on the database file.
*/
#ifdef SQLITE_DEBUG
int locktype;
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
assert( locktype==SQLITE_LOCK_SHARED );
#endif
pPager->state = PAGER_SHARED;
}
return SQLITE_OK;
}
/* /*
** This function is called to obtain a shared lock on the database file. ** This function is called to obtain a shared lock on the database file.
@ -3826,16 +3780,9 @@ int sqlite3PagerSharedLock(Pager *pPager){
pager_reset(pPager); pager_reset(pPager);
} }
if( pagerUseLog(pPager) ){
if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
int changed = 0; /* True if the cache must be flushed */ int changed = 0; /* True if the cache must be flushed */
/* Open the log file, if it is not already open. */
rc = pagerOpenLog(pPager);
if( rc!=SQLITE_OK ){
return rc;
}
/* Open a log snapshot to read from. */ /* Open a log snapshot to read from. */
rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed); rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -3846,6 +3793,8 @@ int sqlite3PagerSharedLock(Pager *pPager){
} }
rc = sqlite3PagerPagecount(pPager, &dummy); rc = sqlite3PagerPagecount(pPager, &dummy);
} }
pPager->state = PAGER_SHARED;
}else if( pPager->state==PAGER_UNLOCK || isErrorReset ){ }else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs * const pVfs = pPager->pVfs; sqlite3_vfs * const pVfs = pPager->pVfs;
int isHotJournal = 0; int isHotJournal = 0;
@ -4002,6 +3951,10 @@ int sqlite3PagerSharedLock(Pager *pPager){
} }
} }
assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED ); assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
pPager->journalMode = PAGER_JOURNALMODE_DELETE;
}
} }
failed: failed:
@ -4384,6 +4337,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pPager->dbOrigSize = pPager->dbSize; pPager->dbOrigSize = pPager->dbSize;
pPager->state = PAGER_RESERVED; pPager->state = PAGER_RESERVED;
pPager->journalOff = 0;
} }
}else{ }else{
/* Obtain a RESERVED lock on the database file. If the exFlag parameter /* Obtain a RESERVED lock on the database file. If the exFlag parameter
@ -4485,7 +4439,7 @@ static int pager_write(PgHdr *pPg){
} }
if( !isOpen(pPager->jfd) if( !isOpen(pPager->jfd)
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF && pPager->journalMode!=PAGER_JOURNALMODE_OFF
&& pPager->journalMode!=PAGER_JOURNALMODE_WAL && !pagerUseLog(pPager)
){ ){
assert( pPager->useJournal ); assert( pPager->useJournal );
rc = pager_open_journal(pPager); rc = pager_open_journal(pPager);
@ -5621,7 +5575,7 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
** PAGER_JOURNALMODE_WAL ** PAGER_JOURNALMODE_WAL
** **
** If the parameter is not _QUERY, then the journal_mode is set to the ** If the parameter is not _QUERY, then the journal_mode is set to the
** value specified if the change is allowed. The change is disallowed ** value specified if the change is allowed. The change may be disallowed
** for the following reasons: ** for the following reasons:
** **
** * An in-memory database can only have its journal_mode set to _OFF ** * An in-memory database can only have its journal_mode set to _OFF
@ -5640,7 +5594,12 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
|| eMode==PAGER_JOURNALMODE_WAL || eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY ); || eMode==PAGER_JOURNALMODE_MEMORY );
assert( PAGER_JOURNALMODE_QUERY<0 ); assert( PAGER_JOURNALMODE_QUERY<0 );
if( eMode>=0
if( eMode==PAGER_JOURNALMODE_WAL
&& pPager->journalMode==PAGER_JOURNALMODE_DELETE
){
pPager->journalMode = PAGER_JOURNALMODE_WAL;
}else if( eMode>=0
&& (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL) && (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL)
&& (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF) && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF)
&& !pPager->dbModified && !pPager->dbModified
@ -5659,13 +5618,6 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
} }
/* Switching into WAL mode can only take place when no
** locks are held on the database file.
*/
if( eMode==PAGER_JOURNALMODE_WAL && pPager->state!=PAGER_UNLOCK ){
return (int)pPager->journalMode;
}
pPager->journalMode = (u8)eMode; pPager->journalMode = (u8)eMode;
} }
return (int)pPager->journalMode; return (int)pPager->journalMode;
@ -5713,4 +5665,77 @@ int sqlite3PagerLogCallback(Pager *pPager){
return sqlite3LogCallback(pPager->pLog); return sqlite3LogCallback(pPager->pLog);
} }
/*
** Open a connection to the write-ahead log file for pager pPager. If
** the log connection is already open, this function is a no-op.
**
** The caller must be holding a SHARED lock on the database file to call
** this function.
*/
int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen){
int rc = SQLITE_OK; /* Return code */
#ifdef SQLITE_DEBUG
int locktype;
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
assert( locktype==SQLITE_LOCK_SHARED );
assert( pPager->state>=PAGER_SHARED );
#endif
if( !pPager->pLog ){
/* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), unlock the database file and
** return an error code.
*/
rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
if( rc==SQLITE_OK ){
pPager->journalMode = PAGER_JOURNALMODE_WAL;
}
}else{
*pisOpen = 1;
}
return rc;
}
/*
** This function is called to close the connection to the log file prior
** to switching from WAL to rollback mode.
**
** Before closing the log file, this function attempts to take an
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
int sqlite3PagerCloseLog(Pager *pPager){
int rc = SQLITE_OK;
if( pPager->pLog ){
/* Try to obtain an EXCLUSIVE lock on the database file. */
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
/* If the EXCLUSIVE lock was obtained, checkpoint and close the log. */
if( rc==SQLITE_OK ){
rc = sqlite3LogClose(pPager->pLog, pPager->fd,
(pPager->noSync ? 0 : pPager->sync_flags),
(u8*)pPager->pTmpSpace
);
pPager->pLog = 0;
}
/* Make sure the EXCLUSIVE lock has not been lost somehow */
#ifdef SQLITE_DEBUG
{
int locktype;
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype);
assert( locktype==SQLITE_LOCK_EXCLUSIVE );
}
#endif
}
return rc;
}
#endif /* SQLITE_OMIT_DISKIO */ #endif /* SQLITE_OMIT_DISKIO */

View File

@ -136,6 +136,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerCheckpoint(Pager *pPager); int sqlite3PagerCheckpoint(Pager *pPager);
int sqlite3PagerLogCallback(Pager *pPager); int sqlite3PagerLogCallback(Pager *pPager);
int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen);
int sqlite3PagerCloseLog(Pager *pPager);
/* Functions used to query pager state and configuration. */ /* Functions used to query pager state and configuration. */
u8 sqlite3PagerIsreadonly(Pager*); u8 sqlite3PagerIsreadonly(Pager*);

View File

@ -257,6 +257,28 @@ static const char *actionName(u8 action){
} }
#endif #endif
/*
** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
** defined in pager.h. This function returns the associated lowercase
** journal-mode name.
*/
const char *sqlite3JournalModename(int eMode){
static char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory", "wal"
};
assert( PAGER_JOURNALMODE_DELETE==0 );
assert( PAGER_JOURNALMODE_PERSIST==1 );
assert( PAGER_JOURNALMODE_OFF==2 );
assert( PAGER_JOURNALMODE_TRUNCATE==3 );
assert( PAGER_JOURNALMODE_MEMORY==4 );
assert( PAGER_JOURNALMODE_WAL==5 );
assert( eMode>=0 && eMode<=ArraySize(azModeName) );
if( eMode==ArraySize(azModeName) ) return 0;
return azModeName[eMode];
}
/* /*
** Process a pragma statement. ** Process a pragma statement.
** **
@ -513,18 +535,21 @@ void sqlite3Pragma(
** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory) ** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
*/ */
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){ if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
int eMode; int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
static char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory", "wal" sqlite3VdbeSetNumCols(v, 1);
}; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
if( zRight==0 ){ if( zRight==0 ){
eMode = PAGER_JOURNALMODE_QUERY; eMode = PAGER_JOURNALMODE_QUERY;
}else{ }else{
const char *zMode;
int n = sqlite3Strlen30(zRight); int n = sqlite3Strlen30(zRight);
eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1; for(eMode=0; (zMode = sqlite3JournalModename(eMode)); eMode++){
while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
eMode--; }
if( !zMode ){
eMode = PAGER_JOURNALMODE_QUERY;
} }
} }
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){ if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
@ -533,40 +558,32 @@ void sqlite3Pragma(
** the journal-mode of the main database). ** the journal-mode of the main database).
*/ */
eMode = db->dfltJournalMode; eMode = db->dfltJournalMode;
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
}else{ }else{
Pager *pPager; int ii;
if( pId2->n==0 ){
if( pId2->n==0 && eMode!=PAGER_JOURNALMODE_WAL ){
/* This indicates that no database name was specified as part /* This indicates that no database name was specified as part
** of the PRAGMA command. In this case the journal-mode must be ** of the PRAGMA command. In this case the journal-mode must be
** set on all attached databases, as well as the main db file. ** set on all attached databases, as well as the main db file.
** **
** Also, the sqlite3.dfltJournalMode variable is set so that ** Also, the sqlite3.dfltJournalMode variable is set so that
** any subsequently attached databases also use the specified ** any subsequently attached databases also use the specified
** journal mode. ** journal mode. Except, the default journal mode is never set
** to WAL.
*/ */
int ii;
assert(pDb==&db->aDb[0]);
for(ii=1; ii<db->nDb; ii++){
if( db->aDb[ii].pBt ){
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
sqlite3PagerJournalMode(pPager, eMode);
}
}
db->dfltJournalMode = (u8)eMode; db->dfltJournalMode = (u8)eMode;
} }
pPager = sqlite3BtreePager(pDb->pBt);
eMode = sqlite3PagerJournalMode(pPager, eMode); for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3VdbeUsesBtree(v, ii);
sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
}
}
} }
assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
azModeName[eMode], P4_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else }else

View File

@ -5187,6 +5187,9 @@ case OP_AggFinal: {
} }
/* Opcode: Checkpoint P1 * * * * /* Opcode: Checkpoint P1 * * * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
** WAL mode.
*/ */
case OP_Checkpoint: { case OP_Checkpoint: {
Btree *pBt; /* Btree to checkpoint */ Btree *pBt; /* Btree to checkpoint */
@ -5198,6 +5201,84 @@ case OP_Checkpoint: {
break; break;
}; };
/* Opcode: JournalMode P1 P2 P3 * *
**
** Change the journal mode of database P1 to P3. P3 must be one of the
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
** modes (delete, truncate, persist, off and memory), this is a simple
** operation. No IO is required.
**
** If changing into or out of WAL mode the procedure is more complicated.
**
** Write a string containing the final journal-mode to register P2.
*/
case OP_JournalMode: {
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew = pOp->p3; /* New journal mode */
assert( eNew==PAGER_JOURNALMODE_DELETE
|| eNew==PAGER_JOURNALMODE_TRUNCATE
|| eNew==PAGER_JOURNALMODE_PERSIST
|| eNew==PAGER_JOURNALMODE_OFF
|| eNew==PAGER_JOURNALMODE_MEMORY
|| eNew==PAGER_JOURNALMODE_WAL
|| eNew==PAGER_JOURNALMODE_QUERY
);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pBt = db->aDb[pOp->p1].pBt;
pPager = sqlite3BtreePager(pBt);
if( eNew!=PAGER_JOURNALMODE_QUERY ){
int eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY);
if( (eNew!=eOld)
&& (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
){
if( !db->autoCommit || db->activeVdbeCnt>1 ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
(eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
}else{
/* If leaving WAL mode, close the log file. If successful, the call to
** PagerCloseLog() checkpoints and deletes the write-ahead-log file.
** An EXCLUSIVE lock is still held on the database file after returning.
*/
if( eOld==PAGER_JOURNALMODE_WAL ){
rc = sqlite3PagerCloseLog(pPager);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
sqlite3PagerJournalMode(pPager, eNew);
}else{
sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
}
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
assert( sqlite3BtreeIsInTrans(pBt)==0 );
rc = sqlite3BtreeBeginTrans(pBt, 2);
assert( rc==SQLITE_OK || eOld!=PAGER_JOURNALMODE_WAL );
if( rc!=SQLITE_OK ) goto abort_due_to_error;
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
}
eNew = sqlite3PagerJournalMode(pPager, eNew);
pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
pOut->z = sqlite3JournalModename(eNew);
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
break;
};
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* Opcode: Vacuum * * * * * /* Opcode: Vacuum * * * * *
** **

View File

@ -31,6 +31,7 @@ proc blob {nByte} {
proc sqlite3_wal {args} { proc sqlite3_wal {args} {
eval sqlite3 $args eval sqlite3 $args
[lindex $args 0] eval { PRAGMA page_size = 1024 }
[lindex $args 0] eval { PRAGMA journal_mode = wal } [lindex $args 0] eval { PRAGMA journal_mode = wal }
[lindex $args 0] eval { PRAGMA synchronous = normal } [lindex $args 0] eval { PRAGMA synchronous = normal }
[lindex $args 0] function blob blob [lindex $args 0] function blob blob
@ -60,14 +61,19 @@ do_test wal-0.1 {
execsql { PRAGMA synchronous = normal } execsql { PRAGMA synchronous = normal }
execsql { PRAGMA journal_mode = wal } execsql { PRAGMA journal_mode = wal }
} {wal} } {wal}
do_test wal-0.2 {
file size test.db
} {1024}
do_test wal-1.0 { do_test wal-1.0 {
execsql { execsql {
BEGIN; BEGIN;
CREATE TABLE t1(a, b); CREATE TABLE t1(a, b);
} }
list [file exists test.db-journal] [file exists test.db-wal] list [file exists test.db-journal] \
} {0 1} [file exists test.db-wal] \
[file size test.db]
} {0 1 1024}
do_test wal-1.1 { do_test wal-1.1 {
execsql COMMIT execsql COMMIT
list [file exists test.db-journal] [file exists test.db-wal] list [file exists test.db-journal] [file exists test.db-wal]
@ -197,9 +203,10 @@ foreach sector {512 4096} {
foreach pgsz {512 1024 2048 4096} { foreach pgsz {512 1024 2048 4096} {
file delete -force test.db test.db-wal file delete -force test.db test.db-wal
do_test wal-6.$sector.$pgsz.1 { do_test wal-6.$sector.$pgsz.1 {
sqlite3_wal db test.db -vfs devsym sqlite3 db test.db -vfs devsym
execsql " execsql "
PRAGMA page_size = $pgsz ; PRAGMA page_size = $pgsz;
PRAGMA journal_mode = wal;
" "
execsql " execsql "
CREATE TABLE t1(a, b); CREATE TABLE t1(a, b);
@ -224,7 +231,7 @@ do_test wal-7.1 {
INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(1, 2);
} }
list [file size test.db] [file size test.db-wal] list [file size test.db] [file size test.db-wal]
} [list 0 [log_file_size 3 1024]] } [list 1024 [log_file_size 3 1024]]
do_test wal-7.2 { do_test wal-7.2 {
execsql { PRAGMA checkpoint } execsql { PRAGMA checkpoint }
list [file size test.db] [file size test.db-wal] list [file size test.db] [file size test.db-wal]
@ -235,11 +242,17 @@ do_test wal-7.2 {
# #
do_test wal-8.1 { do_test wal-8.1 {
reopen_db reopen_db
catch { db close }
file delete -force test.db test.db-wal
sqlite3 db test.db
db function blob blob
execsql { execsql {
PRAGMA auto_vacuum = 1; PRAGMA auto_vacuum = 1;
PRAGMA journal_mode = wal;
PRAGMA auto_vacuum; PRAGMA auto_vacuum;
} }
} {1} } {wal 1}
do_test wal-8.2 { do_test wal-8.2 {
execsql { execsql {
PRAGMA page_size = 1024; PRAGMA page_size = 1024;
@ -269,7 +282,6 @@ do_test wal-8.3 {
do_test wal-9.1 { do_test wal-9.1 {
reopen_db reopen_db
execsql { execsql {
PRAGMA page_size = 1024;
CREATE TABLE t1(x PRIMARY KEY); CREATE TABLE t1(x PRIMARY KEY);
INSERT INTO t1 VALUES(blob(900)); INSERT INTO t1 VALUES(blob(900));
INSERT INTO t1 VALUES(blob(900)); INSERT INTO t1 VALUES(blob(900));
@ -282,7 +294,7 @@ do_test wal-9.1 {
INSERT INTO t1 SELECT blob(900) FROM t1; /* 256 */ INSERT INTO t1 SELECT blob(900) FROM t1; /* 256 */
} }
file size test.db file size test.db
} 0 } 1024
do_test wal-9.2 { do_test wal-9.2 {
sqlite3_wal db2 test.db sqlite3_wal db2 test.db
execsql {PRAGMA integrity_check } db2 execsql {PRAGMA integrity_check } db2
@ -560,7 +572,7 @@ do_test wal-11.1 {
CREATE TABLE t1(x PRIMARY KEY); CREATE TABLE t1(x PRIMARY KEY);
} }
list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
} {0 3} } {1 3}
do_test wal-11.2 { do_test wal-11.2 {
execsql { PRAGMA checkpoint } execsql { PRAGMA checkpoint }
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
@ -613,7 +625,7 @@ do_test wal-11.10 {
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
} }
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]] } [list 37 [log_file_size 37 1024]]
do_test wal-11.11 { do_test wal-11.11 {
execsql { execsql {
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
@ -623,7 +635,7 @@ do_test wal-11.11 {
} {32 16} } {32 16}
do_test wal-11.12 { do_test wal-11.12 {
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]] } [list 37 [log_file_size 37 1024]]
do_test wal-11.13 { do_test wal-11.13 {
execsql { execsql {
INSERT INTO t1 VALUES( blob(900) ); INSERT INTO t1 VALUES( blob(900) );
@ -633,7 +645,7 @@ do_test wal-11.13 {
} {17 ok} } {17 ok}
do_test wal-11.14 { do_test wal-11.14 {
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]] } [list 37 [log_file_size 37 1024]]
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -650,11 +662,12 @@ do_test wal-12.1 {
INSERT INTO t1 VALUES('A', 1); INSERT INTO t1 VALUES('A', 1);
} }
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 0 [log_file_size 5 1024]] } [list 1 [log_file_size 5 1024]]
do_test wal-12.2 { do_test wal-12.2 {
db close db close
sqlite3_wal db test.db sqlite3 db test.db
execsql { execsql {
PRAGMA synchronous = normal;
UPDATE t1 SET y = 0 WHERE x = 'A'; UPDATE t1 SET y = 0 WHERE x = 'A';
} }
list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044] list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
@ -668,7 +681,6 @@ do_test wal-12.4 {
file copy -force test.db test2.db file copy -force test.db test2.db
file copy -force test.db-wal test2.db-wal file copy -force test.db-wal test2.db-wal
sqlite3_wal db2 test2.db sqlite3_wal db2 test2.db
breakpoint
execsql { SELECT * FROM t2 } db2 execsql { SELECT * FROM t2 } db2
} {B 1} } {B 1}
db2 close db2 close
@ -695,6 +707,5 @@ do_test wal-12.4 {
} {B 2} } {B 2}
db2 close db2 close
finish_test finish_test

25
test/walmode.test Normal file
View File

@ -0,0 +1,25 @@
# 2010 April 19
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the operation of the library in
# "PRAGMA journal_mode=WAL" mode.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test walmode-1.1 {
execsql {
PRAGMA journal_mode = wal;
}
} {wal}
finish_test