1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Add "pragma journal_mode=memory". Change the way rollback works for in-memory databases so that it reuses the journal_mode=memory code. (CVS 5830)

FossilOrigin-Name: 39ebf01addf9d0867daafd06a38719e725128f9c
This commit is contained in:
danielk1977
2008-10-17 18:51:52 +00:00
parent 7b228b3e39
commit b3175389c7
15 changed files with 422 additions and 491 deletions

View File

@ -57,6 +57,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
func.o global.o hash.o \ func.o global.o hash.o \
icu.o insert.o journal.o legacy.o loadext.o \ icu.o insert.o journal.o legacy.o loadext.o \
main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o mem6.o \ main.o malloc.o mem1.o mem2.o mem3.o mem4.o mem5.o mem6.o \
memjournal.o \
mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
opcodes.o os.o os_os2.o os_unix.o os_win.o \ opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pcache.o pragma.o prepare.o printf.o \ pager.o parse.o pcache.o pragma.o prepare.o printf.o \
@ -104,6 +105,7 @@ SRC = \
$(TOP)/src/mem4.c \ $(TOP)/src/mem4.c \
$(TOP)/src/mem5.c \ $(TOP)/src/mem5.c \
$(TOP)/src/mem6.c \ $(TOP)/src/mem6.c \
$(TOP)/src/memjournal.c \
$(TOP)/src/mutex.c \ $(TOP)/src/mutex.c \
$(TOP)/src/mutex.h \ $(TOP)/src/mutex.h \
$(TOP)/src/mutex_noop.c \ $(TOP)/src/mutex_noop.c \

View File

@ -1,5 +1,5 @@
C Fix\sa\stypo\sin\sdocumentation.\s\sTicket\s#3447.\s(CVS\s5829) C Add\s"pragma\sjournal_mode=memory".\sChange\sthe\sway\srollback\sworks\sfor\sin-memory\sdatabases\sso\sthat\sit\sreuses\sthe\sjournal_mode=memory\scode.\s(CVS\s5830)
D 2008-10-17T15:10:37 D 2008-10-17T18:51:52
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 2014e5a4010ad5ebbcaedff98240b3d14ee83838 F Makefile.in 2014e5a4010ad5ebbcaedff98240b3d14ee83838
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -79,7 +79,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc
F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869 F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210 F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210
F main.mk 725b8b0ee2c1a7e53adb172984c43165eca61be1 F main.mk c0baa7e57584ce3666a854015ad8743c5fe38dec
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@ -138,12 +138,12 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
F src/os_os2.c 24221ff5ab20cf3472e3ec7eec595f759de55298 F src/os_os2.c 24221ff5ab20cf3472e3ec7eec595f759de55298
F src/os_unix.c 5e3b3c9a54546249c1317cff5343e965192f7f2b F src/os_unix.c 5e3b3c9a54546249c1317cff5343e965192f7f2b
F src/os_win.c 13bed718f62d64031b17bb3685adcf994dbf0232 F src/os_win.c 13bed718f62d64031b17bb3685adcf994dbf0232
F src/pager.c d98f56128e849083f2f612196efebd982c491fea F src/pager.c fd11076a5a2f46a831688f036f03c57bd730dff5
F src/pager.h 9c1917be28fff58118e1fe0ddbc7adfb8dd4f44d F src/pager.h 4a57b219c0765fe1870238064e3f46e4eb2cf5af
F src/parse.y f4620f42b5e0141e20243b5f963d0fc9c180ab9b F src/parse.y f4620f42b5e0141e20243b5f963d0fc9c180ab9b
F src/pcache.c f8d7beceba164a34441ac37e88abb3a404f968a7 F src/pcache.c 5b80676e664019c1ebc8356cc25332dd69da6269
F src/pcache.h 974d8ba609c7069af7c050cd3de698cadd090405 F src/pcache.h 2caf2deb6cbaa75c423b8b96fc1411069ee77c75
F src/pragma.c f0f48d0d50e9d8fa785178fc2410244c06f6a287 F src/pragma.c 10d61f211d819acd97174a41acc56394bd5bde7e
F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51 F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51
@ -152,7 +152,7 @@ F src/select.c d910d7350df0d918e22286c5bfd39d4ea68ec813
F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967
F src/sqlite.h.in ee95eeed2196e5fa98fdad007301b8d5d3733b6d F src/sqlite.h.in ee95eeed2196e5fa98fdad007301b8d5d3733b6d
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 69ad0023756cc738d2a5f9def8a0b21d90350667 F src/sqliteInt.h e5e3909f565fb020a820ccce11abca040902f075
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
@ -393,7 +393,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
F test/jrnlmode.test 54469696db41e185a37aed3b3848998cca4e0c37 F test/jrnlmode.test c2e8212a6f6d32f8fd8f869b93553154eaf2244c
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
F test/laststmtchanges.test 18ead86c8a87ade949a1d5658f6dc4bb111d1b02 F test/laststmtchanges.test 18ead86c8a87ade949a1d5658f6dc4bb111d1b02
F test/like.test fef924922828d5a2a5bff80b9bdd9ff57a1ca500 F test/like.test fef924922828d5a2a5bff80b9bdd9ff57a1ca500
@ -450,14 +450,14 @@ F test/nan.test c627d79b3d36ea892563fd67584b3e8a18f0618a
F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df
F test/pager.test 1e1832795e9e07a359c959ffdddcf7275a88f54c F test/pager.test fd3f5009985728ef7bf0dfe32a1bbc112e6895c5
F test/pager2.test 070983b89a308adaba525a2f9c1ba0592c72fa3d F test/pager2.test d84c59ae4a803e03d19d72cbb5b14c71850c6163
F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4
F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f
F test/pcache2.test e2260293e892190be65de89526dbc4f92c8b5a7c F test/pcache2.test e2260293e892190be65de89526dbc4f92c8b5a7c
F test/permutations.test a80a319ed2e825fa828af086d322b47fc9d9c664 F test/permutations.test 3f24cf55e9646b138a6980f78f18190f318af9a3
F test/pragma.test 583937903d01cad823ae195573d90c02ea945717 F test/pragma.test 583937903d01cad823ae195573d90c02ea945717
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef
@ -467,7 +467,7 @@ F test/quick.test 70695607082b3e1ca54023b2c856991604b07703
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47 F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/rollback.test d67022e8f99fdb1f115de7e8ea65139263b4bd40 F test/rollback.test 1f70ab4301d8d105d41438a436cad1fc8897f5e5
F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c
F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf
F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6 F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
@ -633,7 +633,7 @@ F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf
F tool/mkkeywordhash.c c219ee2b8b5b8e7011cccfa1caec62d9812e82e7 F tool/mkkeywordhash.c c219ee2b8b5b8e7011cccfa1caec62d9812e82e7
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c.tcl 8aff2d49beb7d94a63841e86f3ffd4770e5054aa F tool/mksqlite3c.tcl ab98a8321f292b4871e362bb4435be234993d46b
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87 F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
@ -648,7 +648,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff 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
P 8065a92f705dfa04863ba4a828f5bd2803901be8 P 5ce2ddffea807d45318619cc9e259a99dfa14346
R 4bd0b87e5fdde7ed86abc759091ffc21 R d3d208ea9f507cd99d0a55a9424ad33c
U drh U danielk1977
Z 9251407651b2b71ae84b77628eaaa866 Z e1e732a777069a84074d19c41d686a93

View File

@ -1 +1 @@
5ce2ddffea807d45318619cc9e259a99dfa14346 39ebf01addf9d0867daafd06a38719e725128f9c

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.497 2008/10/07 11:51:20 danielk1977 Exp $ ** @(#) $Id: pager.c,v 1.498 2008/10/17 18:51:52 danielk1977 Exp $
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h" #include "sqliteInt.h"
@ -309,11 +309,7 @@ static const unsigned char aJournalMagic[] = {
*/ */
static int pageInStatement(PgHdr *pPg){ static int pageInStatement(PgHdr *pPg){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
if( MEMDB ){ return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno);
return pPg->apSave[1]!=0;
}else{
return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno);
}
} }
/* /*
@ -470,7 +466,7 @@ static u32 pager_set_pagehash(PgHdr *pPage){
#define CHECK_PAGE(x) checkPage(x) #define CHECK_PAGE(x) checkPage(x)
static void checkPage(PgHdr *pPg){ static void checkPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
assert( !pPg->pageHash || pPager->errCode || MEMDB assert( !pPg->pageHash || pPager->errCode
|| (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); || (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) );
} }
@ -664,7 +660,7 @@ static int writeJournalHdr(Pager *pPager){
** that garbage data is never appended to the journal file. ** that garbage data is never appended to the journal file.
*/ */
assert(pPager->fd->pMethods||pPager->noSync); assert(pPager->fd->pMethods||pPager->noSync);
if( (pPager->noSync) if( (pPager->noSync) || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY)
|| (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
){ ){
put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
@ -796,7 +792,8 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
u32 cksum = 0; u32 cksum = 0;
char zBuf[sizeof(aJournalMagic)+2*4]; char zBuf[sizeof(aJournalMagic)+2*4];
if( !zMaster || pPager->setMaster) return SQLITE_OK; if( !zMaster || pPager->setMaster ) return SQLITE_OK;
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ) return SQLITE_OK;
pPager->setMaster = 1; pPager->setMaster = 1;
len = strlen(zMaster); len = strlen(zMaster);
@ -880,50 +877,46 @@ static void pager_reset(Pager *pPager){
*/ */
static void pager_unlock(Pager *pPager){ static void pager_unlock(Pager *pPager){
if( !pPager->exclusiveMode ){ if( !pPager->exclusiveMode ){
if( !MEMDB ){ int rc = osUnlock(pPager->fd, NO_LOCK);
int rc = osUnlock(pPager->fd, NO_LOCK); if( rc ) pPager->errCode = rc;
if( rc ) pPager->errCode = rc; pPager->dbSize = -1;
pPager->dbSize = -1; IOTRACE(("UNLOCK %p\n", pPager))
IOTRACE(("UNLOCK %p\n", pPager))
/* Always close the journal file when dropping the database lock. /* Always close the journal file when dropping the database lock.
** Otherwise, another connection with journal_mode=delete might ** Otherwise, another connection with journal_mode=delete might
** delete the file out from under us. ** delete the file out from under us.
*/ */
if( pPager->journalOpen ){ if( pPager->journalOpen ){
sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->jfd);
pPager->journalOpen = 0; pPager->journalOpen = 0;
sqlite3BitvecDestroy(pPager->pInJournal); sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0; pPager->pInJournal = 0;
sqlite3BitvecDestroy(pPager->pAlwaysRollback); sqlite3BitvecDestroy(pPager->pAlwaysRollback);
pPager->pAlwaysRollback = 0; pPager->pAlwaysRollback = 0;
}
/* If Pager.errCode is set, the contents of the pager cache cannot be
** trusted. Now that the pager file is unlocked, the contents of the
** cache can be discarded and the error code safely cleared.
*/
if( pPager->errCode ){
if( rc==SQLITE_OK ) pPager->errCode = SQLITE_OK;
pager_reset(pPager);
if( pPager->stmtOpen ){
sqlite3OsClose(pPager->stfd);
sqlite3BitvecDestroy(pPager->pInStmt);
pPager->pInStmt = 0;
}
pPager->stmtOpen = 0;
pPager->stmtInUse = 0;
pPager->journalOff = 0;
pPager->journalStarted = 0;
pPager->stmtAutoopen = 0;
pPager->origDbSize = 0;
}
} }
if( !MEMDB || pPager->errCode==SQLITE_OK ){ /* If Pager.errCode is set, the contents of the pager cache cannot be
pPager->state = PAGER_UNLOCK; ** trusted. Now that the pager file is unlocked, the contents of the
pPager->changeCountDone = 0; ** cache can be discarded and the error code safely cleared.
*/
if( pPager->errCode ){
if( rc==SQLITE_OK ) pPager->errCode = SQLITE_OK;
pager_reset(pPager);
if( pPager->stmtOpen ){
sqlite3OsClose(pPager->stfd);
sqlite3BitvecDestroy(pPager->pInStmt);
pPager->pInStmt = 0;
}
pPager->stmtOpen = 0;
pPager->stmtInUse = 0;
pPager->journalOff = 0;
pPager->journalStarted = 0;
pPager->stmtAutoopen = 0;
pPager->origDbSize = 0;
} }
pPager->state = PAGER_UNLOCK;
pPager->changeCountDone = 0;
} }
} }
@ -961,7 +954,6 @@ static void pagerUnlockAndRollback(Pager *p){
static int pager_end_transaction(Pager *pPager, int hasMaster){ static int pager_end_transaction(Pager *pPager, int hasMaster){
int rc = SQLITE_OK; int rc = SQLITE_OK;
int rc2 = SQLITE_OK; int rc2 = SQLITE_OK;
assert( !MEMDB );
if( pPager->state<PAGER_RESERVED ){ if( pPager->state<PAGER_RESERVED ){
return SQLITE_OK; return SQLITE_OK;
} }
@ -971,7 +963,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
pPager->stmtOpen = 0; pPager->stmtOpen = 0;
} }
if( pPager->journalOpen ){ if( pPager->journalOpen ){
if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
int isMemoryJournal = sqlite3IsMemJournal(pPager->jfd);
sqlite3OsClose(pPager->jfd);
pPager->journalOpen = 0;
if( !isMemoryJournal ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
}else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE
&& (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){ && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){
pPager->journalOff = 0; pPager->journalOff = 0;
pPager->journalStarted = 0; pPager->journalStarted = 0;
@ -1017,7 +1016,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
pPager->setMaster = 0; pPager->setMaster = 0;
pPager->needSync = 0; pPager->needSync = 0;
/* lruListSetFirstSynced(pPager); */ /* lruListSetFirstSynced(pPager); */
pPager->dbSize = -1; if( !MEMDB ){
pPager->dbSize = -1;
}
pPager->dbModified = 0; pPager->dbModified = 0;
return (rc==SQLITE_OK?rc2:rc); return (rc==SQLITE_OK?rc2:rc);
@ -1667,7 +1668,7 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
*/ */
#ifndef SQLITE_OMIT_PAGER_PRAGMAS #ifndef SQLITE_OMIT_PAGER_PRAGMAS
void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){ void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){
pPager->noSync = level==1 || pPager->tempFile || MEMDB; pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile; pPager->fullSync = level==3 && !pPager->tempFile;
pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL); pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
if( pPager->noSync ) pPager->needSync = 0; if( pPager->noSync ) pPager->needSync = 0;
@ -1741,12 +1742,18 @@ int sqlite3PagerOpen(
int readOnly = 0; int readOnly = 0;
int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0;
int noReadlock = (flags & PAGER_NO_READLOCK)!=0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0;
int journalFileSize = sqlite3JournalSize(pVfs); int journalFileSize;
int pcacheSize = sqlite3PcacheSize(); int pcacheSize = sqlite3PcacheSize();
int szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; int szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;
char *zPathname = 0; char *zPathname = 0;
int nPathname = 0; int nPathname = 0;
if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
journalFileSize = sqlite3JournalSize(pVfs);
}else{
journalFileSize = sqlite3MemJournalSize();
}
/* The default return is a NULL pointer */ /* The default return is a NULL pointer */
*ppPager = 0; *ppPager = 0;
@ -1764,7 +1771,6 @@ int sqlite3PagerOpen(
if( strcmp(zFilename,":memory:")==0 ){ if( strcmp(zFilename,":memory:")==0 ){
memDb = 1; memDb = 1;
zPathname[0] = 0; zPathname[0] = 0;
useJournal = 0;
}else }else
#endif #endif
{ {
@ -1782,7 +1788,8 @@ int sqlite3PagerOpen(
sizeof(*pPager) + /* Pager structure */ sizeof(*pPager) + /* Pager structure */
pcacheSize + /* PCache object */ pcacheSize + /* PCache object */
journalFileSize + /* The journal file structure */ journalFileSize + /* The journal file structure */
pVfs->szOsFile * 3 + /* The main db and two journal files */ pVfs->szOsFile + /* The main db file */
journalFileSize * 2 + /* The two journal files */
3*nPathname + 40 /* zFilename, zDirectory, zJournal */ 3*nPathname + 40 /* zFilename, zDirectory, zJournal */
); );
if( !pPager ){ if( !pPager ){
@ -1793,9 +1800,9 @@ int sqlite3PagerOpen(
pPtr = ((u8 *)&pPager[1]) + pcacheSize; pPtr = ((u8 *)&pPager[1]) + pcacheSize;
pPager->vfsFlags = vfsFlags; pPager->vfsFlags = vfsFlags;
pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0]; pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0];
pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1]; pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile];
pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*2]; pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile+journalFileSize];
pPager->zFilename = (char*)&pPtr[pVfs->szOsFile*2+journalFileSize]; pPager->zFilename = (char*)&pPtr[pVfs->szOsFile+2*journalFileSize];
pPager->zDirectory = &pPager->zFilename[nPathname+1]; pPager->zDirectory = &pPager->zFilename[nPathname+1];
pPager->zJournal = &pPager->zDirectory[nPathname+1]; pPager->zJournal = &pPager->zDirectory[nPathname+1];
pPager->pVfs = pVfs; pPager->pVfs = pVfs;
@ -1845,10 +1852,14 @@ int sqlite3PagerOpen(
} }
} }
} }
}else if( !memDb ){ }else{
/* If a temporary file is requested, it is not opened immediately. /* If a temporary file is requested, it is not opened immediately.
** In this case we accept the default page size and delay actually ** In this case we accept the default page size and delay actually
** opening the file until the first call to OsWrite(). ** opening the file until the first call to OsWrite().
**
** This branch is also run for an in-memory database. An in-memory
** database is the same as a temp-file that is never written out to
** disk and uses an in-memory rollback journal.
*/ */
tempFile = 1; tempFile = 1;
pPager->state = PAGER_EXCLUSIVE; pPager->state = PAGER_EXCLUSIVE;
@ -1920,9 +1931,10 @@ int sqlite3PagerOpen(
/* pPager->pLast = 0; */ /* pPager->pLast = 0; */
pPager->nExtra = nExtra; pPager->nExtra = nExtra;
pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT; pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
assert(pPager->fd->pMethods||memDb||tempFile); assert(pPager->fd->pMethods||tempFile);
if( !memDb ){ setSectorSize(pPager);
setSectorSize(pPager); if( memDb ){
pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
} }
/* pPager->pBusyHandler = 0; */ /* pPager->pBusyHandler = 0; */
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
@ -2043,7 +2055,7 @@ void enable_simulated_io_errors(void){
int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
int rc = SQLITE_OK; int rc = SQLITE_OK;
memset(pDest, 0, N); memset(pDest, 0, N);
assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); assert(pPager->fd->pMethods||pPager->tempFile);
if( pPager->fd->pMethods ){ if( pPager->fd->pMethods ){
IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
rc = sqlite3OsRead(pPager->fd, pDest, N, 0); rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
@ -2139,7 +2151,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
/* If the file is currently unlocked then the size must be unknown */ /* If the file is currently unlocked then the size must be unknown */
assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB ); assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 );
if( pPager->state>=locktype ){ if( pPager->state>=locktype ){
rc = SQLITE_OK; rc = SQLITE_OK;
@ -2161,25 +2173,19 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
*/ */
int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( pPager->state>=PAGER_SHARED || MEMDB ); assert( pPager->state>=PAGER_SHARED );
sqlite3PagerPagecount(pPager, 0); sqlite3PagerPagecount(pPager, 0);
if( pPager->errCode ){ if( pPager->errCode ){
rc = pPager->errCode; rc = pPager->errCode;
}else if( nPage<(unsigned)pPager->dbSize ){ }else if( nPage<(unsigned)pPager->dbSize ){
if( MEMDB ){ rc = syncJournal(pPager);
pPager->dbSize = nPage; if( rc==SQLITE_OK ){
pager_truncate_cache(pPager); /* Get an exclusive lock on the database before truncating. */
}else{ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
rc = syncJournal(pPager); }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
/* Get an exclusive lock on the database before truncating. */ rc = pager_truncate(pPager, nPage);
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
}
if( rc==SQLITE_OK ){
rc = pager_truncate(pPager, nPage);
}
} }
} }
@ -2207,7 +2213,9 @@ int sqlite3PagerClose(Pager *pPager){
pPager->errCode = 0; pPager->errCode = 0;
pPager->exclusiveMode = 0; pPager->exclusiveMode = 0;
pager_reset(pPager); pager_reset(pPager);
pagerUnlockAndRollback(pPager); if( !MEMDB ){
pagerUnlockAndRollback(pPager);
}
enable_simulated_io_errors(); enable_simulated_io_errors();
sqlite3EndBenignMalloc(); sqlite3EndBenignMalloc();
PAGERTRACE2("CLOSE %d\n", PAGERID(pPager)); PAGERTRACE2("CLOSE %d\n", PAGERID(pPager));
@ -2283,7 +2291,8 @@ static int syncJournal(Pager *pPager){
** (assuming there is a journal and it needs to be synced.) ** (assuming there is a journal and it needs to be synced.)
*/ */
if( pPager->needSync ){ if( pPager->needSync ){
if( !pPager->tempFile ){ assert( !pPager->tempFile );
if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
assert( pPager->journalOpen ); assert( pPager->journalOpen );
@ -2439,6 +2448,7 @@ static int pagerStress(void *p, PgHdr *pPg){
if( pPg->flags&PGHDR_NEED_SYNC ){ if( pPg->flags&PGHDR_NEED_SYNC ){
rc = syncJournal(pPager); rc = syncJournal(pPager);
if( rc==SQLITE_OK && pPager->fullSync && if( rc==SQLITE_OK && pPager->fullSync &&
!(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
!(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
){ ){
pPager->nRec = 0; pPager->nRec = 0;
@ -2572,140 +2582,139 @@ static int pagerSharedLock(Pager *pPager){
if( pPager->state==PAGER_UNLOCK || isErrorReset ){ if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs *pVfs = pPager->pVfs; sqlite3_vfs *pVfs = pPager->pVfs;
if( !MEMDB ){ assert( !MEMDB );
int isHotJournal; int isHotJournal;
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
if( !pPager->noReadlock ){ if( !pPager->noReadlock ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK); rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
assert( pPager->state==PAGER_UNLOCK ); assert( pPager->state==PAGER_UNLOCK );
return pager_error(pPager, rc); return pager_error(pPager, rc);
}
assert( pPager->state>=SHARED_LOCK );
} }
assert( pPager->state>=SHARED_LOCK );
/* If a journal file exists, and there is no RESERVED lock on the }
** database file, then it either needs to be played back or deleted.
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
if( !isErrorReset ){
rc = hasHotJournal(pPager, &isHotJournal);
if( rc!=SQLITE_OK ){
goto failed;
}
}
if( isErrorReset || isHotJournal ){
/* Get an EXCLUSIVE lock on the database file. At this point it is
** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the
** database file, detect the RESERVED lock, and conclude that the
** database is safe to read while this process is still rolling it
** back.
**
** Because the intermediate RESERVED lock is not requested, the
** second process will get to this point in the code and fail to
** obtain its own EXCLUSIVE lock on the database file.
*/ */
if( !isErrorReset ){ if( pPager->state<EXCLUSIVE_LOCK ){
rc = hasHotJournal(pPager, &isHotJournal); rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
goto failed;
}
}
if( isErrorReset || isHotJournal ){
/* Get an EXCLUSIVE lock on the database file. At this point it is
** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the
** database file, detect the RESERVED lock, and conclude that the
** database is safe to read while this process is still rolling it
** back.
**
** Because the intermediate RESERVED lock is not requested, the
** second process will get to this point in the code and fail to
** obtain its own EXCLUSIVE lock on the database file.
*/
if( pPager->state<EXCLUSIVE_LOCK ){
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc);
goto failed;
}
pPager->state = PAGER_EXCLUSIVE;
}
/* Open the journal for read/write access. This is because in
** exclusive-access mode the file descriptor will be kept open and
** possibly used for a transaction later on. On some systems, the
** OsTruncate() call used in exclusive-access mode also requires
** a read/write file handle.
*/
if( !isErrorReset && pPager->journalOpen==0 ){
int res;
rc = sqlite3OsAccess(pVfs,pPager->zJournal,SQLITE_ACCESS_EXISTS,&res);
if( rc==SQLITE_OK ){
if( res ){
int fout = 0;
int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
assert( !pPager->tempFile );
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
if( fout&SQLITE_OPEN_READONLY ){
rc = SQLITE_BUSY;
sqlite3OsClose(pPager->jfd);
}
}else{
/* If the journal does not exist, that means some other process
** has already rolled it back */
rc = SQLITE_BUSY;
}
}
}
if( rc!=SQLITE_OK ){
if( rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_UNLOCK
&& rc!=SQLITE_IOERR_NOMEM
){
rc = SQLITE_BUSY;
}
goto failed;
}
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
/* Playback and delete the journal. Drop the database write
** lock and reacquire the read lock.
*/
rc = pager_playback(pPager, 1);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc); rc = pager_error(pPager, rc);
goto failed; goto failed;
} }
assert(pPager->state==PAGER_SHARED || pPager->state = PAGER_EXCLUSIVE;
(pPager->exclusiveMode && pPager->state>PAGER_SHARED) }
);
/* Open the journal for read/write access. This is because in
** exclusive-access mode the file descriptor will be kept open and
** possibly used for a transaction later on. On some systems, the
** OsTruncate() call used in exclusive-access mode also requires
** a read/write file handle.
*/
if( !isErrorReset && pPager->journalOpen==0 ){
int res;
rc = sqlite3OsAccess(pVfs,pPager->zJournal,SQLITE_ACCESS_EXISTS,&res);
if( rc==SQLITE_OK ){
if( res ){
int fout = 0;
int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
assert( !pPager->tempFile );
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
if( fout&SQLITE_OPEN_READONLY ){
rc = SQLITE_BUSY;
sqlite3OsClose(pPager->jfd);
}
}else{
/* If the journal does not exist, that means some other process
** has already rolled it back */
rc = SQLITE_BUSY;
}
}
}
if( rc!=SQLITE_OK ){
if( rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_UNLOCK
&& rc!=SQLITE_IOERR_NOMEM
){
rc = SQLITE_BUSY;
}
goto failed;
}
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
/* Playback and delete the journal. Drop the database write
** lock and reacquire the read lock.
*/
rc = pager_playback(pPager, 1);
if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc);
goto failed;
}
assert(pPager->state==PAGER_SHARED ||
(pPager->exclusiveMode && pPager->state>PAGER_SHARED)
);
}
if( sqlite3PcachePagecount(pPager->pPCache)>0 ){
/* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous
** read or write transaction). Check to see if the database
** has been modified. If the database has changed, flush the
** cache.
**
** Database changes is detected by looking at 15 bytes beginning
** at offset 24 into the file. The first 4 of these 16 bytes are
** a 32-bit counter that is incremented with each change. The
** other bytes change randomly with each file change when
** a codec is in use.
**
** There is a vanishingly small chance that a change will not be
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
char dbFileVers[sizeof(pPager->dbFileVers)];
sqlite3PagerPagecount(pPager, 0);
if( pPager->errCode ){
rc = pPager->errCode;
goto failed;
} }
if( sqlite3PcachePagecount(pPager->pPCache)>0 ){ if( pPager->dbSize>0 ){
/* The shared-lock has just been acquired on the database file IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
** and there are already pages in the cache (from a previous rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
** read or write transaction). Check to see if the database if( rc!=SQLITE_OK ){
** has been modified. If the database has changed, flush the
** cache.
**
** Database changes is detected by looking at 15 bytes beginning
** at offset 24 into the file. The first 4 of these 16 bytes are
** a 32-bit counter that is incremented with each change. The
** other bytes change randomly with each file change when
** a codec is in use.
**
** There is a vanishingly small chance that a change will not be
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
char dbFileVers[sizeof(pPager->dbFileVers)];
sqlite3PagerPagecount(pPager, 0);
if( pPager->errCode ){
rc = pPager->errCode;
goto failed; goto failed;
} }
}else{
memset(dbFileVers, 0, sizeof(dbFileVers));
}
if( pPager->dbSize>0 ){ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); pager_reset(pPager);
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
goto failed;
}
}else{
memset(dbFileVers, 0, sizeof(dbFileVers));
}
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager);
}
} }
} }
assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED ); assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED );
@ -2808,7 +2817,7 @@ int sqlite3PagerAcquire(
assert( pPager->state==PAGER_UNLOCK assert( pPager->state==PAGER_UNLOCK
|| sqlite3PcacheRefCount(pPager->pPCache)>0 || sqlite3PcacheRefCount(pPager->pPCache)>0
|| pgno==1 || pgno==1
); );
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
@ -2845,7 +2854,6 @@ int sqlite3PagerAcquire(
PAGER_INCR(pPager->nMiss); PAGER_INCR(pPager->nMiss);
pPg->pPager = pPager; pPg->pPager = pPager;
if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){ if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
assert( !MEMDB );
pPg->flags |= PGHDR_IN_JOURNAL; pPg->flags |= PGHDR_IN_JOURNAL;
} }
memset(pPg->pExtra, 0, pPager->nExtra); memset(pPg->pExtra, 0, pPager->nExtra);
@ -2948,7 +2956,6 @@ static int pager_open_journal(Pager *pPager){
int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE); int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE);
int rc; int rc;
assert( !MEMDB );
assert( pPager->state>=PAGER_RESERVED ); assert( pPager->state>=PAGER_RESERVED );
assert( pPager->useJournal ); assert( pPager->useJournal );
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
@ -2965,13 +2972,18 @@ static int pager_open_journal(Pager *pPager){
}else{ }else{
flags |= (SQLITE_OPEN_MAIN_JOURNAL); flags |= (SQLITE_OPEN_MAIN_JOURNAL);
} }
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3MemJournalOpen(pPager->jfd);
rc = SQLITE_OK;
}else{
#ifdef SQLITE_ENABLE_ATOMIC_WRITE #ifdef SQLITE_ENABLE_ATOMIC_WRITE
rc = sqlite3JournalOpen( rc = sqlite3JournalOpen(
pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
); );
#else #else
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
#endif #endif
}
assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
pPager->journalOff = 0; pPager->journalOff = 0;
pPager->setMaster = 0; pPager->setMaster = 0;
@ -3046,28 +3058,24 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){
assert( pPager->state!=PAGER_UNLOCK ); assert( pPager->state!=PAGER_UNLOCK );
if( pPager->state==PAGER_SHARED ){ if( pPager->state==PAGER_SHARED ){
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
assert( !MEMDB );
sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL); sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
if( MEMDB ){ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
pPager->state = PAGER_EXCLUSIVE; if( rc==SQLITE_OK ){
pPager->origDbSize = pPager->dbSize; pPager->state = PAGER_RESERVED;
}else{ if( exFlag ){
rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
if( exFlag ){
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
}
}
if( rc!=SQLITE_OK ){
return rc;
}
pPager->dirtyCache = 0;
PAGERTRACE2("TRANSACTION %d\n", PAGERID(pPager));
if( pPager->useJournal && !pPager->tempFile
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
rc = pager_open_journal(pPager);
} }
} }
if( rc!=SQLITE_OK ){
return rc;
}
pPager->dirtyCache = 0;
PAGERTRACE2("TRANSACTION %d\n", PAGERID(pPager));
if( pPager->useJournal && !pPager->tempFile
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
rc = pager_open_journal(pPager);
}
}else if( pPager->journalOpen && pPager->journalOff==0 ){ }else if( pPager->journalOpen && pPager->journalOff==0 ){
/* This happens when the pager was in exclusive-access mode the last /* This happens when the pager was in exclusive-access mode the last
** time a (read or write) transaction was successfully concluded ** time a (read or write) transaction was successfully concluded
@ -3192,57 +3200,49 @@ static int pager_write(PgHdr *pPg){
** EXCLUSIVE lock on the main database file. Write the current page to ** EXCLUSIVE lock on the main database file. Write the current page to
** the transaction journal if it is not there already. ** the transaction journal if it is not there already.
*/ */
if( !(pPg->flags&PGHDR_IN_JOURNAL) && (pPager->journalOpen || MEMDB) ){ if( !(pPg->flags&PGHDR_IN_JOURNAL) && pPager->journalOpen ){
if( (int)pPg->pgno <= pPager->origDbSize ){ if( (int)pPg->pgno <= pPager->origDbSize ){
if( MEMDB ){ u32 cksum;
PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); char *pData2;
rc = sqlite3PcachePreserve(pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
}else{
u32 cksum;
char *pData2;
/* We should never write to the journal file the page that /* We should never write to the journal file the page that
** contains the database locks. The following assert verifies ** contains the database locks. The following assert verifies
** that we do not. */ ** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
pData2 = CODEC2(pPager, pData, pPg->pgno, 7); pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
cksum = pager_cksum(pPager, (u8*)pData2); cksum = pager_cksum(pPager, (u8*)pData2);
rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize,
pPager->journalOff + 4); pPager->journalOff + 4);
pPager->journalOff += pPager->pageSize+4; pPager->journalOff += pPager->pageSize+4;
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = write32bits(pPager->jfd, pPager->journalOff, cksum); rc = write32bits(pPager->jfd, pPager->journalOff, cksum);
pPager->journalOff += 4; pPager->journalOff += 4;
} }
IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
pPager->journalOff, pPager->pageSize)); pPager->journalOff, pPager->pageSize));
PAGER_INCR(sqlite3_pager_writej_count); PAGER_INCR(sqlite3_pager_writej_count);
PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n",
PAGERID(pPager), pPg->pgno, PAGERID(pPager), pPg->pgno,
((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)); ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg));
/* An error has occured writing to the journal file. The /* An error has occured writing to the journal file. The
** transaction will be rolled back by the layer above. ** transaction will be rolled back by the layer above.
*/ */
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
pPager->nRec++; pPager->nRec++;
assert( pPager->pInJournal!=0 ); assert( pPager->pInJournal!=0 );
sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
if( !pPager->noSync ){ if( !pPager->noSync ){
pPg->flags |= PGHDR_NEED_SYNC; pPg->flags |= PGHDR_NEED_SYNC;
} }
if( pPager->stmtInUse ){ if( pPager->stmtInUse ){
sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
}
} }
}else{ }else{
if( !pPager->journalStarted && !pPager->noSync ){ if( !pPager->journalStarted && !pPager->noSync ){
@ -3269,27 +3269,19 @@ static int pager_write(PgHdr *pPg){
){ ){
assert( (pPg->flags&PGHDR_IN_JOURNAL) assert( (pPg->flags&PGHDR_IN_JOURNAL)
|| (int)pPg->pgno>pPager->origDbSize ); || (int)pPg->pgno>pPager->origDbSize );
if( MEMDB ){ i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
rc = sqlite3PcachePreserve(pPg, 1); char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
if( rc!=SQLITE_OK ){ rc = write32bits(pPager->stfd, offset, pPg->pgno);
return rc; if( rc==SQLITE_OK ){
} rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
}else{
i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
rc = write32bits(pPager->stfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
}
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc!=SQLITE_OK ){
return rc;
}
pPager->stmtNRec++;
assert( pPager->pInStmt!=0 );
sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
} }
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc!=SQLITE_OK ){
return rc;
}
pPager->stmtNRec++;
assert( pPager->pInStmt!=0 );
sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
} }
} }
@ -3298,7 +3290,7 @@ static int pager_write(PgHdr *pPg){
assert( pPager->state>=PAGER_SHARED ); assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize<(int)pPg->pgno ){ if( pPager->dbSize<(int)pPg->pgno ){
pPager->dbSize = pPg->pgno; pPager->dbSize = pPg->pgno;
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ if( pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
pPager->dbSize++; pPager->dbSize++;
} }
} }
@ -3322,7 +3314,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
if( !MEMDB && nPagePerSector>1 ){ if( nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */ Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */ Pgno pg1; /* First page of the sector pPg is located on. */
int nPage; /* Number of pages starting at pg1 to journal */ int nPage; /* Number of pages starting at pg1 to journal */
@ -3332,6 +3324,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
/* Set the doNotSync flag to 1. This is because we cannot allow a journal /* Set the doNotSync flag to 1. This is because we cannot allow a journal
** header to be written between the pages journaled by this function. ** header to be written between the pages journaled by this function.
*/ */
assert( !MEMDB );
assert( pPager->doNotSync==0 ); assert( pPager->doNotSync==0 );
pPager->doNotSync = 1; pPager->doNotSync = 1;
@ -3439,7 +3432,7 @@ int sqlite3PagerDontWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
int rc; int rc;
if( MEMDB || pPg->pgno>pPager->origDbSize ){ if( pPg->pgno>pPager->origDbSize ){
return SQLITE_OK; return SQLITE_OK;
} }
if( pPager->pAlwaysRollback==0 ){ if( pPager->pAlwaysRollback==0 ){
@ -3500,7 +3493,6 @@ void sqlite3PagerDontRollback(DbPage *pPg){
){ ){
return; return;
} }
assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */
#ifdef SQLITE_SECURE_DELETE #ifdef SQLITE_SECURE_DELETE
if( (pPg->flags & PGHDR_IN_JOURNAL)!=0 || (int)pPg->pgno>pPager->origDbSize ){ if( (pPg->flags & PGHDR_IN_JOURNAL)!=0 || (int)pPg->pgno>pPager->origDbSize ){
@ -3792,16 +3784,9 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
return SQLITE_OK; return SQLITE_OK;
} }
PAGERTRACE2("COMMIT %d\n", PAGERID(pPager)); PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
if( MEMDB ){ assert( pPager->state==PAGER_SYNCED || MEMDB || !pPager->dirtyCache );
sqlite3PcacheCommit(pPager->pPCache, 0); rc = pager_end_transaction(pPager, pPager->setMaster);
sqlite3PcacheCleanAll(pPager->pPCache); rc = pager_error(pPager, rc);
sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
pPager->state = PAGER_SHARED;
}else{
assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
rc = pager_end_transaction(pPager, pPager->setMaster);
rc = pager_error(pPager, rc);
}
return rc; return rc;
} }
@ -3820,16 +3805,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
int sqlite3PagerRollback(Pager *pPager){ int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; int rc = SQLITE_OK;
PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){ if( !pPager->dirtyCache || !pPager->journalOpen ){
sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter);
sqlite3PcacheRollback(pPager->pPCache, 0, pPager->xReiniter);
sqlite3PcacheCleanAll(pPager->pPCache);
sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
pPager->dbSize = pPager->origDbSize;
pager_truncate_cache(pPager);
pPager->stmtInUse = 0;
pPager->state = PAGER_SHARED;
}else if( !pPager->dirtyCache || !pPager->journalOpen ){
rc = pager_end_transaction(pPager, pPager->setMaster); rc = pager_end_transaction(pPager, pPager->setMaster);
}else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){ if( pPager->state>=PAGER_EXCLUSIVE ){
@ -3848,7 +3824,9 @@ int sqlite3PagerRollback(Pager *pPager){
rc = pager_playback(pPager, 0); rc = pager_playback(pPager, 0);
} }
pPager->dbSize = -1; if( !MEMDB ){
pPager->dbSize = -1;
}
/* If an error occurs during a ROLLBACK, we can no longer trust the pager /* If an error occurs during a ROLLBACK, we can no longer trust the pager
** cache. So call pager_error() on the way out to make any error ** cache. So call pager_error() on the way out to make any error
@ -3918,11 +3896,6 @@ static int pagerStmtBegin(Pager *pPager){
assert( pPager->state>=PAGER_SHARED ); assert( pPager->state>=PAGER_SHARED );
assert( pPager->dbSize>=0 ); assert( pPager->dbSize>=0 );
PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager)); PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
if( MEMDB ){
pPager->stmtInUse = 1;
pPager->stmtSize = pPager->dbSize;
return SQLITE_OK;
}
if( !pPager->journalOpen ){ if( !pPager->journalOpen ){
pPager->stmtAutoopen = 1; pPager->stmtAutoopen = 1;
return SQLITE_OK; return SQLITE_OK;
@ -3939,9 +3912,13 @@ static int pagerStmtBegin(Pager *pPager){
pPager->stmtHdrOff = 0; pPager->stmtHdrOff = 0;
pPager->stmtCksum = pPager->cksumInit; pPager->stmtCksum = pPager->cksumInit;
if( !pPager->stmtOpen ){ if( !pPager->stmtOpen ){
rc = sqlite3PagerOpentemp(pPager, pPager->stfd, SQLITE_OPEN_SUBJOURNAL); if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
if( rc ){ sqlite3MemJournalOpen(pPager->stfd);
goto stmt_begin_failed; }else{
rc = sqlite3PagerOpentemp(pPager, pPager->stfd, SQLITE_OPEN_SUBJOURNAL);
if( rc ){
goto stmt_begin_failed;
}
} }
pPager->stmtOpen = 1; pPager->stmtOpen = 1;
pPager->stmtNRec = 0; pPager->stmtNRec = 0;
@ -3968,14 +3945,13 @@ int sqlite3PagerStmtBegin(Pager *pPager){
int sqlite3PagerStmtCommit(Pager *pPager){ int sqlite3PagerStmtCommit(Pager *pPager){
if( pPager->stmtInUse ){ if( pPager->stmtInUse ){
PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){ sqlite3BitvecDestroy(pPager->pInStmt);
sqlite3BitvecDestroy(pPager->pInStmt); pPager->pInStmt = 0;
pPager->pInStmt = 0;
}else{
sqlite3PcacheCommit(pPager->pPCache, 1);
}
pPager->stmtNRec = 0; pPager->stmtNRec = 0;
pPager->stmtInUse = 0; pPager->stmtInUse = 0;
if( sqlite3IsMemJournal(pPager->stfd) ){
sqlite3OsTruncate(pPager->stfd, 0);
}
} }
pPager->stmtAutoopen = 0; pPager->stmtAutoopen = 0;
return SQLITE_OK; return SQLITE_OK;
@ -3988,14 +3964,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){
int rc; int rc;
if( pPager->stmtInUse ){ if( pPager->stmtInUse ){
PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){ rc = pager_stmt_playback(pPager);
sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter);
pPager->dbSize = pPager->stmtSize;
pager_truncate_cache(pPager);
rc = SQLITE_OK;
}else{
rc = pager_stmt_playback(pPager);
}
sqlite3PagerStmtCommit(pPager); sqlite3PagerStmtCommit(pPager);
}else{ }else{
rc = SQLITE_OK; rc = SQLITE_OK;
@ -4124,7 +4093,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
} }
if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){ if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
assert( !MEMDB );
pPg->flags |= PGHDR_IN_JOURNAL; pPg->flags |= PGHDR_IN_JOURNAL;
} }
@ -4233,16 +4201,19 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
** journal-mode. ** journal-mode.
*/ */
int sqlite3PagerJournalMode(Pager *pPager, int eMode){ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
assert( eMode==PAGER_JOURNALMODE_QUERY if( !MEMDB ){
|| eMode==PAGER_JOURNALMODE_DELETE assert( eMode==PAGER_JOURNALMODE_QUERY
|| eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_OFF ); || eMode==PAGER_JOURNALMODE_PERSIST
assert( PAGER_JOURNALMODE_QUERY<0 ); || eMode==PAGER_JOURNALMODE_OFF
if( eMode>=0 ){ || eMode==PAGER_JOURNALMODE_MEMORY );
pPager->journalMode = eMode; assert( PAGER_JOURNALMODE_QUERY<0 );
}else{ if( eMode>=0 ){
assert( eMode==PAGER_JOURNALMODE_QUERY ); pPager->journalMode = eMode;
}else{
assert( eMode==PAGER_JOURNALMODE_QUERY );
}
} }
return (int)pPager->journalMode; return (int)pPager->journalMode;
} }

View File

@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** at a time and provides a journal for rollback.
** **
** @(#) $Id: pager.h,v 1.85 2008/09/29 11:49:48 danielk1977 Exp $ ** @(#) $Id: pager.h,v 1.86 2008/10/17 18:51:53 danielk1977 Exp $
*/ */
#ifndef _PAGER_H_ #ifndef _PAGER_H_
@ -66,6 +66,7 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
/* /*
** See source code comments for a detailed description of the following ** See source code comments for a detailed description of the following

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file implements that page cache. ** This file implements that page cache.
** **
** @(#) $Id: pcache.c,v 1.33 2008/09/29 11:49:48 danielk1977 Exp $ ** @(#) $Id: pcache.c,v 1.34 2008/10/17 18:51:53 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -491,8 +491,6 @@ static void pcachePageFree(PgHdr *p){
if( p->pCache->bPurgeable ){ if( p->pCache->bPurgeable ){
pcache_g.nCurrentPage--; pcache_g.nCurrentPage--;
} }
pcacheFree(p->apSave[0]);
pcacheFree(p->apSave[1]);
pcacheFree(p); pcacheFree(p);
} }
@ -813,7 +811,6 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
static void pcacheMakeClean(PgHdr *p){ static void pcacheMakeClean(PgHdr *p){
PCache *pCache = p->pCache; PCache *pCache = p->pCache;
assert( p->apSave[0]==0 && p->apSave[1]==0 );
assert( p->flags & PGHDR_DIRTY ); assert( p->flags & PGHDR_DIRTY );
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
pcacheAddToList(&pCache->pClean, p); pcacheAddToList(&pCache->pClean, p);
@ -844,7 +841,6 @@ void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p; PgHdr *p;
pcacheEnterMutex(); pcacheEnterMutex();
while( (p = pCache->pDirty)!=0 ){ while( (p = pCache->pDirty)!=0 ){
assert( p->apSave[0]==0 && p->apSave[1]==0 );
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
p->flags &= ~PGHDR_DIRTY; p->flags &= ~PGHDR_DIRTY;
pcacheAddToList(&pCache->pClean, p); pcacheAddToList(&pCache->pClean, p);
@ -869,10 +865,6 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
pcacheRemoveFromHash(p); pcacheRemoveFromHash(p);
p->pgno = newPgno; p->pgno = newPgno;
if( newPgno==0 ){ if( newPgno==0 ){
pcacheFree(p->apSave[0]);
pcacheFree(p->apSave[1]);
p->apSave[0] = 0;
p->apSave[1] = 0;
if( (p->flags & PGHDR_DIRTY) ){ if( (p->flags & PGHDR_DIRTY) ){
pcacheMakeClean(p); pcacheMakeClean(p);
} }
@ -970,72 +962,6 @@ void sqlite3PcacheClose(PCache *pCache){
pcacheExitMutex(); pcacheExitMutex();
} }
/*
** Preserve the content of the page. It is assumed that the content
** has not been preserved already.
**
** If idJournal==0 then this is for the overall transaction.
** If idJournal==1 then this is for the statement journal.
**
** This routine is used for in-memory databases only.
**
** Return SQLITE_OK or SQLITE_NOMEM if a memory allocation fails.
*/
int sqlite3PcachePreserve(PgHdr *p, int idJournal){
void *x;
int sz;
assert( p->pCache->bPurgeable==0 );
assert( p->apSave[idJournal]==0 );
sz = p->pCache->szPage;
p->apSave[idJournal] = x = sqlite3PageMalloc( sz );
if( x==0 ) return SQLITE_NOMEM;
memcpy(x, p->pData, sz);
return SQLITE_OK;
}
/*
** Commit a change previously preserved.
*/
void sqlite3PcacheCommit(PCache *pCache, int idJournal){
PgHdr *p;
int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff;
pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */
for(p=pCache->pDirty; p; p=p->pNext){
if( p->apSave[idJournal] ){
pcacheFree(p->apSave[idJournal]);
p->apSave[idJournal] = 0;
}
p->flags &= mask;
}
pcacheExitMutex();
}
/*
** Rollback a change previously preserved.
*/
void sqlite3PcacheRollback(
PCache *pCache, /* Pager cache */
int idJournal, /* Which copy to rollback to */
void (*xReiniter)(PgHdr*) /* Called on each rolled back page */
){
PgHdr *p;
int sz;
int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff;
pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */
sz = pCache->szPage;
for(p=pCache->pDirty; p; p=p->pNext){
if( p->apSave[idJournal] ){
memcpy(p->pData, p->apSave[idJournal], sz);
pcacheFree(p->apSave[idJournal]);
p->apSave[idJournal] = 0;
if( xReiniter ){
xReiniter(p);
}
}
p->flags &= mask;
}
pcacheExitMutex();
}
#ifndef NDEBUG #ifndef NDEBUG
/* /*

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite page cache ** This header file defines the interface that the sqlite page cache
** subsystem. ** subsystem.
** **
** @(#) $Id: pcache.h,v 1.13 2008/10/11 17:42:29 drh Exp $ ** @(#) $Id: pcache.h,v 1.14 2008/10/17 18:51:53 danielk1977 Exp $
*/ */
#ifndef _PCACHE_H_ #ifndef _PCACHE_H_
@ -40,7 +40,7 @@ struct PgHdr {
*/ */
i16 nRef; /* Number of users of this page */ i16 nRef; /* Number of users of this page */
PCache *pCache; /* Cache that owns this page */ PCache *pCache; /* Cache that owns this page */
void *apSave[2]; /* Journal entries for in-memory databases */
/********************************************************************** /**********************************************************************
** Elements above are accessible at any time by the owner of the cache ** Elements above are accessible at any time by the owner of the cache
** without the need for a mutex. The elements that follow can only be ** without the need for a mutex. The elements that follow can only be
@ -109,11 +109,6 @@ void sqlite3PcacheMove(PgHdr*, Pgno);
/* Remove all pages with pgno>x. Reset the cache if x==0 */ /* Remove all pages with pgno>x. Reset the cache if x==0 */
void sqlite3PcacheTruncate(PCache*, Pgno x); void sqlite3PcacheTruncate(PCache*, Pgno x);
/* Routines used to implement transactions on memory-only databases. */
int sqlite3PcachePreserve(PgHdr*, int); /* Preserve current page content */
void sqlite3PcacheCommit(PCache*, int); /* Drop preserved copy */
void sqlite3PcacheRollback(PCache*, int, void (*xReiniter)(PgHdr*));
/* Get a list of all dirty pages in the cache, sorted by page number */ /* Get a list of all dirty pages in the cache, sorted by page number */
PgHdr *sqlite3PcacheDirtyList(PCache*); PgHdr *sqlite3PcacheDirtyList(PCache*);

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the PRAGMA command. ** This file contains code used to implement the PRAGMA command.
** **
** $Id: pragma.c,v 1.189 2008/10/10 17:47:21 danielk1977 Exp $ ** $Id: pragma.c,v 1.190 2008/10/17 18:51:53 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -455,11 +455,13 @@ void sqlite3Pragma(
/* /*
** PRAGMA [database.]journal_mode ** PRAGMA [database.]journal_mode
** PRAGMA [database.]journal_mode = (delete|persist|off) ** PRAGMA [database.]journal_mode = (delete|persist|memory|off)
*/ */
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){ if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
int eMode; int eMode;
static char * const azModeName[] = {"delete", "persist", "off", "truncate"}; static char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory"
};
if( zRight==0 ){ if( zRight==0 ){
eMode = PAGER_JOURNALMODE_QUERY; eMode = PAGER_JOURNALMODE_QUERY;
@ -503,7 +505,8 @@ void sqlite3Pragma(
assert( eMode==PAGER_JOURNALMODE_DELETE assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF ); || eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_MEMORY );
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", P4_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", P4_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.784 2008/10/13 15:35:09 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.785 2008/10/17 18:51:53 danielk1977 Exp $
*/ */
#ifndef _SQLITEINT_H_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@ -2505,6 +2505,10 @@ int sqlite3FindInIndex(Parse *, Expr *, int*);
#define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
#endif #endif
void sqlite3MemJournalOpen(sqlite3_file *);
int sqlite3MemJournalSize();
int sqlite3IsMemJournal(sqlite3_file *);
#if SQLITE_MAX_EXPR_DEPTH>0 #if SQLITE_MAX_EXPR_DEPTH>0
void sqlite3ExprSetHeight(Parse *pParse, Expr *p); void sqlite3ExprSetHeight(Parse *pParse, Expr *p);
int sqlite3SelectExprHeight(Select *); int sqlite3SelectExprHeight(Select *);

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The focus # This file implements regression tests for SQLite library. The focus
# of these tests is the journal mode pragma. # of these tests is the journal mode pragma.
# #
# $Id: jrnlmode.test,v 1.6 2008/09/26 21:08:08 drh Exp $ # $Id: jrnlmode.test,v 1.7 2008/10/17 18:51:53 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -95,7 +95,7 @@ ifcapable attach {
PRAGMA main.journal_mode; PRAGMA main.journal_mode;
PRAGMA aux1.journal_mode; PRAGMA aux1.journal_mode;
} }
} {persist persist} } {persist memory}
do_test jrnlmode-1.10 { do_test jrnlmode-1.10 {
execsql { execsql {
PRAGMA main.journal_mode = OFF; PRAGMA main.journal_mode = OFF;
@ -105,7 +105,7 @@ ifcapable attach {
PRAGMA temp.journal_mode; PRAGMA temp.journal_mode;
PRAGMA aux1.journal_mode; PRAGMA aux1.journal_mode;
} }
} {off persist persist} } {off persist memory}
do_test jrnlmode-1.11 { do_test jrnlmode-1.11 {
execsql { execsql {
PRAGMA journal_mode; PRAGMA journal_mode;
@ -120,8 +120,9 @@ ifcapable attach {
PRAGMA aux1.journal_mode; PRAGMA aux1.journal_mode;
PRAGMA aux2.journal_mode; PRAGMA aux2.journal_mode;
} }
} {off persist persist} } {off memory memory}
do_test jrnlmode-1.11 { do_test jrnlmode-1.11 {
# The journal-mode used by in-memory databases cannot be changed.
execsql { execsql {
PRAGMA aux1.journal_mode = DELETE; PRAGMA aux1.journal_mode = DELETE;
} }
@ -130,7 +131,7 @@ ifcapable attach {
PRAGMA aux1.journal_mode; PRAGMA aux1.journal_mode;
PRAGMA aux2.journal_mode; PRAGMA aux2.journal_mode;
} }
} {off delete persist} } {off memory memory}
do_test jrnlmode-1.12 { do_test jrnlmode-1.12 {
execsql { execsql {
PRAGMA journal_mode = delete; PRAGMA journal_mode = delete;
@ -141,7 +142,7 @@ ifcapable attach {
PRAGMA aux1.journal_mode; PRAGMA aux1.journal_mode;
PRAGMA aux2.journal_mode; PRAGMA aux2.journal_mode;
} }
} {delete delete delete delete} } {delete delete memory memory}
do_test jrnlmode-1.13 { do_test jrnlmode-1.13 {
execsql { execsql {
ATTACH ':memory:' as aux3; ATTACH ':memory:' as aux3;
@ -153,7 +154,7 @@ ifcapable attach {
PRAGMA aux2.journal_mode; PRAGMA aux2.journal_mode;
PRAGMA aux3.journal_mode; PRAGMA aux3.journal_mode;
} }
} {delete delete delete delete delete} } {delete delete memory memory memory}
do_test jrnlmode-1.14 { do_test jrnlmode-1.14 {
execsql { execsql {
PRAGMA journal_mode = TRUNCATE; PRAGMA journal_mode = TRUNCATE;
@ -165,7 +166,7 @@ ifcapable attach {
PRAGMA aux2.journal_mode; PRAGMA aux2.journal_mode;
PRAGMA aux3.journal_mode; PRAGMA aux3.journal_mode;
} }
} {truncate truncate truncate truncate truncate} } {truncate truncate memory memory memory}
do_test jrnlmode-1.99 { do_test jrnlmode-1.99 {
execsql { execsql {

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is page cache subsystem. # focus of this script is page cache subsystem.
# #
# $Id: pager.test,v 1.31 2008/08/20 14:49:25 danielk1977 Exp $ # $Id: pager.test,v 1.32 2008/10/17 18:51:53 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -415,12 +415,14 @@ ifcapable memorydb {
pager_truncate $::p2 5 pager_truncate $::p2 5
} {} } {}
do_test pager-4.6.3 { do_test pager-4.6.3 {
set page1 [page_get $::p2 1]
for {set i 1} {$i<5} {incr i} { for {set i 1} {$i<5} {incr i} {
set p [page_get $::p2 $i] set p [page_get $::p2 $i]
page_write $p "Page $i" page_write $p "Page $i"
pager_commit $::p2 pager_commit $::p2
page_unref $p page_unref $p
} }
page_unref $page1
# pager_truncate $::p2 3 # pager_truncate $::p2 3
} {} } {}
do_test pager-4.6.4 { do_test pager-4.6.4 {

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is page cache subsystem. # focus of this script is page cache subsystem.
# #
# $Id: pager2.test,v 1.7 2008/08/20 14:49:25 danielk1977 Exp $ # $Id: pager2.test,v 1.8 2008/10/17 18:51:53 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -33,13 +33,13 @@ do_test pager2-1.0 {
} {0} } {0}
do_test pager2-1.1 { do_test pager2-1.1 {
pager_stats $::p1 pager_stats $::p1
} {ref 0 page 0 max 10 size 0 state 0 err 0 hit 0 miss 0 ovfl 0} } {ref 0 page 0 max 10 size 0 state 4 err 0 hit 0 miss 0 ovfl 0}
do_test pager2-1.2 { do_test pager2-1.2 {
pager_pagecount $::p1 pager_pagecount $::p1
} {0} } {0}
do_test pager2-1.3 { do_test pager2-1.3 {
pager_stats $::p1 pager_stats $::p1
} {ref 0 page 0 max 10 size 0 state 0 err 0 hit 0 miss 0 ovfl 0} } {ref 0 page 0 max 10 size 0 state 4 err 0 hit 0 miss 0 ovfl 0}
do_test pager2-1.4 { do_test pager2-1.4 {
pager_close $::p1 pager_close $::p1
} {} } {}
@ -62,7 +62,7 @@ do_test pager2-2.3.1 {
} {} } {}
do_test pager2-2.3.2 { do_test pager2-2.3.2 {
pager_stats $::p1 pager_stats $::p1
} {ref 0 page 0 max 10 size 0 state 0 err 0 hit 0 miss 0 ovfl 0} } {ref 0 page 0 max 10 size 0 state 4 err 0 hit 0 miss 0 ovfl 0}
do_test pager2-2.3.3 { do_test pager2-2.3.3 {
set v [catch { set v [catch {
set ::g1 [page_get $::p1 1] set ::g1 [page_get $::p1 1]
@ -72,7 +72,7 @@ do_test pager2-2.3.3 {
} {0} } {0}
do_test pager2-2.3.3 { do_test pager2-2.3.3 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.3.4 { do_test pager2-2.3.4 {
set ::gx [page_lookup $::p1 1] set ::gx [page_lookup $::p1 1]
page_unref $::gx page_unref $::gx
@ -80,22 +80,22 @@ do_test pager2-2.3.4 {
} {1} } {1}
do_test pager2-2.3.5 { do_test pager2-2.3.5 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.3.6 { do_test pager2-2.3.6 {
expr {$::g1==$::gx} expr {$::g1==$::gx}
} {1} } {1}
do_test pager2-2.3.7 { do_test pager2-2.3.7 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.4 { do_test pager2-2.4 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.5 { do_test pager2-2.5 {
pager_pagecount $::p1 pager_pagecount $::p1
} {0} } {0}
do_test pager2-2.6 { do_test pager2-2.6 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.7 { do_test pager2-2.7 {
page_number $::g1 page_number $::g1
} {1} } {1}
@ -107,7 +107,7 @@ do_test pager2-2.9 {
} {} } {}
do_test pager2-2.10 { do_test pager2-2.10 {
pager_stats $::p1 pager_stats $::p1
} {ref 0 page 1 max 10 size 0 state 0 err 0 hit 0 miss 1 ovfl 0} } {ref 0 page 1 max 10 size 0 state 4 err 0 hit 0 miss 1 ovfl 0}
do_test pager2-2.11 { do_test pager2-2.11 {
set ::g1 [page_get $::p1 1] set ::g1 [page_get $::p1 1]
expr {$::g1!=0} expr {$::g1!=0}
@ -117,7 +117,7 @@ do_test pager2-2.12 {
} {1} } {1}
do_test pager2-2.13 { do_test pager2-2.13 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 1 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 0 state 4 err 0 hit 1 miss 1 ovfl 0}
do_test pager2-2.14 { do_test pager2-2.14 {
set v [catch { set v [catch {
page_write $::g1 "Page-One" page_write $::g1 "Page-One"
@ -138,19 +138,19 @@ do_test pager2-2.17 {
} {0 {}} } {0 {}}
do_test pager2-2.20 { do_test pager2-2.20 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 1 state 1 err 0 hit 1 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 1 state 4 err 0 hit 1 miss 1 ovfl 0}
do_test pager2-2.19 { do_test pager2-2.19 {
pager_pagecount $::p1 pager_pagecount $::p1
} {1} } {1}
do_test pager2-2.21 { do_test pager2-2.21 {
pager_stats $::p1 pager_stats $::p1
} {ref 1 page 1 max 10 size 1 state 1 err 0 hit 1 miss 1 ovfl 0} } {ref 1 page 1 max 10 size 1 state 4 err 0 hit 1 miss 1 ovfl 0}
do_test pager2-2.22 { do_test pager2-2.22 {
page_unref $::g1 page_unref $::g1
} {} } {}
do_test pager2-2.23 { do_test pager2-2.23 {
pager_stats $::p1 pager_stats $::p1
} {ref 0 page 1 max 10 size 1 state 0 err 0 hit 1 miss 1 ovfl 0} } {ref 0 page 1 max 10 size 1 state 4 err 0 hit 1 miss 1 ovfl 0}
do_test pager2-2.24 { do_test pager2-2.24 {
set v [catch { set v [catch {
page_get $::p1 1 page_get $::p1 1
@ -215,14 +215,17 @@ do_test pager2-3.5 {
page_unref $::g(1) page_unref $::g(1)
} {} } {}
for {set i 2} {$i<=20} {incr i} { for {set i 2} {$i<=20} {incr i} {
set page1 [page_get $::p1 1]
do_test pager2-3.6.[expr {$i-1}] [subst { do_test pager2-3.6.[expr {$i-1}] [subst {
set gx \[page_get $::p1 $i\] set gx \[page_get $::p1 $i\]
set v \[page_read \$gx\] set v \[page_read \$gx\]
page_unref \$gx page_unref \$gx
set v set v
}] "Page-$i" }] "Page-$i"
page_unref $page1
} }
for {set i 1} {$i<=20} {incr i} { for {set i 1} {$i<=20} {incr i} {
set page1 [page_get $::p1 1]
regsub -all CNT { regsub -all CNT {
set ::g1 [page_get $::p1 CNT] set ::g1 [page_get $::p1 CNT]
set ::g2 [page_get $::p1 CNT] set ::g2 [page_get $::p1 CNT]
@ -244,6 +247,7 @@ for {set i 1} {$i<=20} {incr i} {
expr {$vy==$::vx} expr {$vy==$::vx}
} $i body; } $i body;
do_test pager2-3.7.$i.3 $body {1} do_test pager2-3.7.$i.3 $body {1}
page_unref $page1
} }
do_test pager2-3.99 { do_test pager2-3.99 {
pager_close $::p1 pager_close $::p1
@ -281,7 +285,7 @@ do_test pager2-4.3 {
} {ref 1} } {ref 1}
do_test pager2-4.4 { do_test pager2-4.4 {
lrange [pager_stats $::p1] 8 9 lrange [pager_stats $::p1] 8 9
} {state 1} } {state 4}
for {set i 1} {$i<20} {incr i} { for {set i 1} {$i<20} {incr i} {
do_test pager2-4.5.$i.0 { do_test pager2-4.5.$i.0 {
@ -396,7 +400,7 @@ breakpoint
do_test pager2-4.5.$i.10 { do_test pager2-4.5.$i.10 {
pager_commit $p1 pager_commit $p1
lrange [pager_stats $p1] 8 9 lrange [pager_stats $p1] 8 9
} {state 1} } {state 4}
} }
do_test pager2-4.99 { do_test pager2-4.99 {

View File

@ -9,7 +9,7 @@
# #
#*********************************************************************** #***********************************************************************
# #
# $Id: permutations.test,v 1.35 2008/10/11 17:04:04 danielk1977 Exp $ # $Id: permutations.test,v 1.36 2008/10/17 18:51:53 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -448,6 +448,24 @@ run_tests "autovacuum_ioerr" -description {
pragma auto_vacuum = 1 pragma auto_vacuum = 1
} -include ioerr.test } -include ioerr.test
# Run tests with an in-memory journal.
#
run_tests "inmemory_journal" -description {
Run tests with an in-memory journal file.
} -presql {
pragma journal_mode = 'memory'
} -exclude {
# Exclude all tests that simulate IO errors.
autovacuum_ioerr2.test incrvacuum_ioerr.test ioerr.test
ioerr.test ioerr2.test ioerr3.test ioerr4.test ioerr5.test
vacuum3.test incrblob_err.test diskfull.test
# Exclude test scripts that use tcl IO to access journal files or count
# the number of fsync() calls.
pager.test exclusive.test jrnlmode.test sync.test misc1.test
journal1.test conflict.test
}
ifcapable mem3 { ifcapable mem3 {
run_tests "memsys3" -description { run_tests "memsys3" -description {
Run tests using the allocator in mem3.c. Run tests using the allocator in mem3.c.

View File

@ -13,7 +13,7 @@
# caused by an ON CONFLICT ROLLBACK clause aborts any other pending # caused by an ON CONFLICT ROLLBACK clause aborts any other pending
# statements. # statements.
# #
# $Id: rollback.test,v 1.9 2008/10/13 14:16:11 drh Exp $ # $Id: rollback.test,v 1.10 2008/10/17 18:51:53 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -81,7 +81,10 @@ do_test rollback-1.9 {
set permutation "" set permutation ""
catch {set permutation $::permutations_test_prefix} catch {set permutation $::permutations_test_prefix}
if {$tcl_platform(platform) == "unix" && $permutation ne "onefile"} { if {$tcl_platform(platform) == "unix"
&& $permutation ne "onefile"
&& $permutation ne "inmemory_journal"
} {
do_test rollback-2.1 { do_test rollback-2.1 {
execsql { execsql {
BEGIN; BEGIN;

View File

@ -247,6 +247,7 @@ foreach file {
vdbe.c vdbe.c
vdbeblob.c vdbeblob.c
journal.c journal.c
memjournal.c
walker.c walker.c
resolve.c resolve.c