From b3175389c7e1a0eb6e724a8cdbd91b1c7894fc64 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 17 Oct 2008 18:51:52 +0000 Subject: [PATCH] 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 --- main.mk | 2 + manifest | 38 +-- manifest.uuid | 2 +- src/pager.c | 681 ++++++++++++++++++++--------------------- src/pager.h | 3 +- src/pcache.c | 76 +---- src/pcache.h | 9 +- src/pragma.c | 11 +- src/sqliteInt.h | 6 +- test/jrnlmode.test | 17 +- test/pager.test | 4 +- test/pager2.test | 36 ++- test/permutations.test | 20 +- test/rollback.test | 7 +- tool/mksqlite3c.tcl | 1 + 15 files changed, 422 insertions(+), 491 deletions(-) diff --git a/main.mk b/main.mk index 423f429aee..ee8d2d0064 100644 --- a/main.mk +++ b/main.mk @@ -57,6 +57,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \ func.o global.o hash.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 \ + memjournal.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 \ pager.o parse.o pcache.o pragma.o prepare.o printf.o \ @@ -104,6 +105,7 @@ SRC = \ $(TOP)/src/mem4.c \ $(TOP)/src/mem5.c \ $(TOP)/src/mem6.c \ + $(TOP)/src/memjournal.c \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ diff --git a/manifest b/manifest index 8a99e9a0d1..860104d4eb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sdocumentation.\s\sTicket\s#3447.\s(CVS\s5829) -D 2008-10-17T15:10:37 +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-17T18:51:52 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 2014e5a4010ad5ebbcaedff98240b3d14ee83838 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -79,7 +79,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210 -F main.mk 725b8b0ee2c1a7e53adb172984c43165eca61be1 +F main.mk c0baa7e57584ce3666a854015ad8743c5fe38dec F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -138,12 +138,12 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60 F src/os_os2.c 24221ff5ab20cf3472e3ec7eec595f759de55298 F src/os_unix.c 5e3b3c9a54546249c1317cff5343e965192f7f2b F src/os_win.c 13bed718f62d64031b17bb3685adcf994dbf0232 -F src/pager.c d98f56128e849083f2f612196efebd982c491fea -F src/pager.h 9c1917be28fff58118e1fe0ddbc7adfb8dd4f44d +F src/pager.c fd11076a5a2f46a831688f036f03c57bd730dff5 +F src/pager.h 4a57b219c0765fe1870238064e3f46e4eb2cf5af F src/parse.y f4620f42b5e0141e20243b5f963d0fc9c180ab9b -F src/pcache.c f8d7beceba164a34441ac37e88abb3a404f968a7 -F src/pcache.h 974d8ba609c7069af7c050cd3de698cadd090405 -F src/pragma.c f0f48d0d50e9d8fa785178fc2410244c06f6a287 +F src/pcache.c 5b80676e664019c1ebc8356cc25332dd69da6269 +F src/pcache.h 2caf2deb6cbaa75c423b8b96fc1411069ee77c75 +F src/pragma.c 10d61f211d819acd97174a41acc56394bd5bde7e F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51 @@ -152,7 +152,7 @@ F src/select.c d910d7350df0d918e22286c5bfd39d4ea68ec813 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/sqlite.h.in ee95eeed2196e5fa98fdad007301b8d5d3733b6d F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 -F src/sqliteInt.h 69ad0023756cc738d2a5f9def8a0b21d90350667 +F src/sqliteInt.h e5e3909f565fb020a820ccce11abca040902f075 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 @@ -393,7 +393,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 -F test/jrnlmode.test 54469696db41e185a37aed3b3848998cca4e0c37 +F test/jrnlmode.test c2e8212a6f6d32f8fd8f869b93553154eaf2244c F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test 18ead86c8a87ade949a1d5658f6dc4bb111d1b02 F test/like.test fef924922828d5a2a5bff80b9bdd9ff57a1ca500 @@ -450,14 +450,14 @@ F test/nan.test c627d79b3d36ea892563fd67584b3e8a18f0618a F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df -F test/pager.test 1e1832795e9e07a359c959ffdddcf7275a88f54c -F test/pager2.test 070983b89a308adaba525a2f9c1ba0592c72fa3d +F test/pager.test fd3f5009985728ef7bf0dfe32a1bbc112e6895c5 +F test/pager2.test d84c59ae4a803e03d19d72cbb5b14c71850c6163 F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f F test/pcache2.test e2260293e892190be65de89526dbc4f92c8b5a7c -F test/permutations.test a80a319ed2e825fa828af086d322b47fc9d9c664 +F test/permutations.test 3f24cf55e9646b138a6980f78f18190f318af9a3 F test/pragma.test 583937903d01cad823ae195573d90c02ea945717 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef @@ -467,7 +467,7 @@ F test/quick.test 70695607082b3e1ca54023b2c856991604b07703 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/rollback.test d67022e8f99fdb1f115de7e8ea65139263b4bd40 +F test/rollback.test 1f70ab4301d8d105d41438a436cad1fc8897f5e5 F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6 @@ -633,7 +633,7 @@ F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/mkkeywordhash.c c219ee2b8b5b8e7011cccfa1caec62d9812e82e7 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c.tcl 8aff2d49beb7d94a63841e86f3ffd4770e5054aa +F tool/mksqlite3c.tcl ab98a8321f292b4871e362bb4435be234993d46b F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87 F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -648,7 +648,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 8065a92f705dfa04863ba4a828f5bd2803901be8 -R 4bd0b87e5fdde7ed86abc759091ffc21 -U drh -Z 9251407651b2b71ae84b77628eaaa866 +P 5ce2ddffea807d45318619cc9e259a99dfa14346 +R d3d208ea9f507cd99d0a55a9424ad33c +U danielk1977 +Z e1e732a777069a84074d19c41d686a93 diff --git a/manifest.uuid b/manifest.uuid index 801027e17b..48f94588a2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5ce2ddffea807d45318619cc9e259a99dfa14346 \ No newline at end of file +39ebf01addf9d0867daafd06a38719e725128f9c \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 900aa1618d..6932ab96df 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** 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 #include "sqliteInt.h" @@ -309,11 +309,7 @@ static const unsigned char aJournalMagic[] = { */ static int pageInStatement(PgHdr *pPg){ Pager *pPager = pPg->pPager; - if( MEMDB ){ - return pPg->apSave[1]!=0; - }else{ - return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno); - } + return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno); } /* @@ -470,7 +466,7 @@ static u32 pager_set_pagehash(PgHdr *pPage){ #define CHECK_PAGE(x) checkPage(x) static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; - assert( !pPg->pageHash || pPager->errCode || MEMDB + assert( !pPg->pageHash || pPager->errCode || (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. */ assert(pPager->fd->pMethods||pPager->noSync); - if( (pPager->noSync) + if( (pPager->noSync) || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); @@ -796,7 +792,8 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ u32 cksum = 0; 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; len = strlen(zMaster); @@ -880,50 +877,46 @@ static void pager_reset(Pager *pPager){ */ static void pager_unlock(Pager *pPager){ if( !pPager->exclusiveMode ){ - if( !MEMDB ){ - int rc = osUnlock(pPager->fd, NO_LOCK); - if( rc ) pPager->errCode = rc; - pPager->dbSize = -1; - IOTRACE(("UNLOCK %p\n", pPager)) + int rc = osUnlock(pPager->fd, NO_LOCK); + if( rc ) pPager->errCode = rc; + pPager->dbSize = -1; + IOTRACE(("UNLOCK %p\n", pPager)) - /* Always close the journal file when dropping the database lock. - ** Otherwise, another connection with journal_mode=delete might - ** delete the file out from under us. - */ - if( pPager->journalOpen ){ - sqlite3OsClose(pPager->jfd); - pPager->journalOpen = 0; - sqlite3BitvecDestroy(pPager->pInJournal); - pPager->pInJournal = 0; - sqlite3BitvecDestroy(pPager->pAlwaysRollback); - 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; - } + /* Always close the journal file when dropping the database lock. + ** Otherwise, another connection with journal_mode=delete might + ** delete the file out from under us. + */ + if( pPager->journalOpen ){ + sqlite3OsClose(pPager->jfd); + pPager->journalOpen = 0; + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; + sqlite3BitvecDestroy(pPager->pAlwaysRollback); + pPager->pAlwaysRollback = 0; } - if( !MEMDB || pPager->errCode==SQLITE_OK ){ - pPager->state = PAGER_UNLOCK; - pPager->changeCountDone = 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; } + + 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){ int rc = SQLITE_OK; int rc2 = SQLITE_OK; - assert( !MEMDB ); if( pPager->statestmtOpen = 0; } 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 ){ pPager->journalOff = 0; pPager->journalStarted = 0; @@ -1017,7 +1016,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ pPager->setMaster = 0; pPager->needSync = 0; /* lruListSetFirstSynced(pPager); */ - pPager->dbSize = -1; + if( !MEMDB ){ + pPager->dbSize = -1; + } pPager->dbModified = 0; return (rc==SQLITE_OK?rc2:rc); @@ -1667,7 +1668,7 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS 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->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL); if( pPager->noSync ) pPager->needSync = 0; @@ -1741,12 +1742,18 @@ int sqlite3PagerOpen( int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; - int journalFileSize = sqlite3JournalSize(pVfs); + int journalFileSize; int pcacheSize = sqlite3PcacheSize(); int szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; char *zPathname = 0; int nPathname = 0; + if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){ + journalFileSize = sqlite3JournalSize(pVfs); + }else{ + journalFileSize = sqlite3MemJournalSize(); + } + /* The default return is a NULL pointer */ *ppPager = 0; @@ -1764,7 +1771,6 @@ int sqlite3PagerOpen( if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zPathname[0] = 0; - useJournal = 0; }else #endif { @@ -1782,7 +1788,8 @@ int sqlite3PagerOpen( sizeof(*pPager) + /* Pager structure */ pcacheSize + /* PCache object */ 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 */ ); if( !pPager ){ @@ -1793,9 +1800,9 @@ int sqlite3PagerOpen( pPtr = ((u8 *)&pPager[1]) + pcacheSize; pPager->vfsFlags = vfsFlags; pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0]; - pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1]; - pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*2]; - pPager->zFilename = (char*)&pPtr[pVfs->szOsFile*2+journalFileSize]; + pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile]; + pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile+journalFileSize]; + pPager->zFilename = (char*)&pPtr[pVfs->szOsFile+2*journalFileSize]; pPager->zDirectory = &pPager->zFilename[nPathname+1]; pPager->zJournal = &pPager->zDirectory[nPathname+1]; pPager->pVfs = pVfs; @@ -1845,10 +1852,14 @@ int sqlite3PagerOpen( } } } - }else if( !memDb ){ + }else{ /* If a temporary file is requested, it is not opened immediately. ** In this case we accept the default page size and delay actually ** 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; pPager->state = PAGER_EXCLUSIVE; @@ -1920,9 +1931,10 @@ int sqlite3PagerOpen( /* pPager->pLast = 0; */ pPager->nExtra = nExtra; pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT; - assert(pPager->fd->pMethods||memDb||tempFile); - if( !memDb ){ - setSectorSize(pPager); + assert(pPager->fd->pMethods||tempFile); + setSectorSize(pPager); + if( memDb ){ + pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->pBusyHandler = 0; */ /* 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 rc = SQLITE_OK; memset(pDest, 0, N); - assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); + assert(pPager->fd->pMethods||pPager->tempFile); if( pPager->fd->pMethods ){ IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) 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 ); /* 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 ){ rc = SQLITE_OK; @@ -2161,25 +2173,19 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ */ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ int rc = SQLITE_OK; - assert( pPager->state>=PAGER_SHARED || MEMDB ); - + assert( pPager->state>=PAGER_SHARED ); sqlite3PagerPagecount(pPager, 0); if( pPager->errCode ){ rc = pPager->errCode; }else if( nPage<(unsigned)pPager->dbSize ){ - if( MEMDB ){ - pPager->dbSize = nPage; - pager_truncate_cache(pPager); - }else{ - rc = syncJournal(pPager); - if( rc==SQLITE_OK ){ - /* Get an exclusive lock on the database before truncating. */ - rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); - } - if( rc==SQLITE_OK ){ - rc = pager_truncate(pPager, nPage); - } + rc = syncJournal(pPager); + if( rc==SQLITE_OK ){ + /* Get an exclusive lock on the database before truncating. */ + 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->exclusiveMode = 0; pager_reset(pPager); - pagerUnlockAndRollback(pPager); + if( !MEMDB ){ + pagerUnlockAndRollback(pPager); + } enable_simulated_io_errors(); sqlite3EndBenignMalloc(); 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.) */ if( pPager->needSync ){ - if( !pPager->tempFile ){ + assert( !pPager->tempFile ); + if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); assert( pPager->journalOpen ); @@ -2439,6 +2448,7 @@ static int pagerStress(void *p, PgHdr *pPg){ if( pPg->flags&PGHDR_NEED_SYNC ){ rc = syncJournal(pPager); if( rc==SQLITE_OK && pPager->fullSync && + !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) && !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ pPager->nRec = 0; @@ -2572,140 +2582,139 @@ static int pagerSharedLock(Pager *pPager){ if( pPager->state==PAGER_UNLOCK || isErrorReset ){ sqlite3_vfs *pVfs = pPager->pVfs; - if( !MEMDB ){ - int isHotJournal; - assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); - if( !pPager->noReadlock ){ - 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 ); + assert( !MEMDB ); + int isHotJournal; + assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); + if( !pPager->noReadlock ){ + rc = pager_wait_on_lock(pPager, SHARED_LOCK); + if( rc!=SQLITE_OK ){ + assert( pPager->state==PAGER_UNLOCK ); + return pager_error(pPager, rc); } - - /* 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. + 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( !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 ){ - 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( pPager->statefd, 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( pPager->statefd, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ rc = pager_error(pPager, rc); goto failed; } - assert(pPager->state==PAGER_SHARED || - (pPager->exclusiveMode && pPager->state>PAGER_SHARED) - ); + 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 ){ + 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 ){ - /* 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; + if( pPager->dbSize>0 ){ + IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); + if( rc!=SQLITE_OK ){ goto failed; } + }else{ + memset(dbFileVers, 0, sizeof(dbFileVers)); + } - if( pPager->dbSize>0 ){ - IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); - 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); - } + if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ + pager_reset(pPager); } } assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED ); @@ -2808,7 +2817,7 @@ int sqlite3PagerAcquire( assert( pPager->state==PAGER_UNLOCK || sqlite3PcacheRefCount(pPager->pPCache)>0 - || pgno==1 + || pgno==1 ); /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page @@ -2845,7 +2854,6 @@ int sqlite3PagerAcquire( PAGER_INCR(pPager->nMiss); pPg->pPager = pPager; if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){ - assert( !MEMDB ); pPg->flags |= PGHDR_IN_JOURNAL; } 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 rc; - assert( !MEMDB ); assert( pPager->state>=PAGER_RESERVED ); assert( pPager->useJournal ); assert( pPager->pInJournal==0 ); @@ -2965,13 +2972,18 @@ static int pager_open_journal(Pager *pPager){ }else{ flags |= (SQLITE_OPEN_MAIN_JOURNAL); } + if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ + sqlite3MemJournalOpen(pPager->jfd); + rc = SQLITE_OK; + }else{ #ifdef SQLITE_ENABLE_ATOMIC_WRITE - rc = sqlite3JournalOpen( - pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) - ); + rc = sqlite3JournalOpen( + pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) + ); #else - rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); #endif + } assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); pPager->journalOff = 0; pPager->setMaster = 0; @@ -3046,28 +3058,24 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ assert( pPager->pInJournal==0 ); + assert( !MEMDB ); sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL); - if( MEMDB ){ - pPager->state = PAGER_EXCLUSIVE; - pPager->origDbSize = pPager->dbSize; - }else{ - rc = sqlite3OsLock(pPager->fd, RESERVED_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); + rc = sqlite3OsLock(pPager->fd, RESERVED_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); + } }else if( pPager->journalOpen && pPager->journalOff==0 ){ /* This happens when the pager was in exclusive-access mode the last ** 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 ** 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( MEMDB ){ - PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); - rc = sqlite3PcachePreserve(pPg, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - }else{ - u32 cksum; - char *pData2; + u32 cksum; + char *pData2; - /* We should never write to the journal file the page that - ** contains the database locks. The following assert verifies - ** that we do not. */ - assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); - pData2 = CODEC2(pPager, pData, pPg->pgno, 7); - cksum = pager_cksum(pPager, (u8*)pData2); - rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, - pPager->journalOff + 4); - pPager->journalOff += pPager->pageSize+4; - } - if( rc==SQLITE_OK ){ - rc = write32bits(pPager->jfd, pPager->journalOff, cksum); - pPager->journalOff += 4; - } - IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, - pPager->journalOff, pPager->pageSize)); - PAGER_INCR(sqlite3_pager_writej_count); - PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", - PAGERID(pPager), pPg->pgno, - ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)); + /* We should never write to the journal file the page that + ** contains the database locks. The following assert verifies + ** that we do not. */ + assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); + pData2 = CODEC2(pPager, pData, pPg->pgno, 7); + cksum = pager_cksum(pPager, (u8*)pData2); + rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, + pPager->journalOff + 4); + pPager->journalOff += pPager->pageSize+4; + } + if( rc==SQLITE_OK ){ + rc = write32bits(pPager->jfd, pPager->journalOff, cksum); + pPager->journalOff += 4; + } + IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, + pPager->journalOff, pPager->pageSize)); + PAGER_INCR(sqlite3_pager_writej_count); + PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", + PAGERID(pPager), pPg->pgno, + ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)); - /* An error has occured writing to the journal file. The - ** transaction will be rolled back by the layer above. - */ - if( rc!=SQLITE_OK ){ - return rc; - } + /* An error has occured writing to the journal file. The + ** transaction will be rolled back by the layer above. + */ + if( rc!=SQLITE_OK ){ + return rc; + } - pPager->nRec++; - assert( pPager->pInJournal!=0 ); - sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); - if( !pPager->noSync ){ - pPg->flags |= PGHDR_NEED_SYNC; - } - if( pPager->stmtInUse ){ - sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); - } + pPager->nRec++; + assert( pPager->pInJournal!=0 ); + sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); + if( !pPager->noSync ){ + pPg->flags |= PGHDR_NEED_SYNC; + } + if( pPager->stmtInUse ){ + sqlite3BitvecSet(pPager->pInStmt, pPg->pgno); } }else{ if( !pPager->journalStarted && !pPager->noSync ){ @@ -3269,27 +3269,19 @@ static int pager_write(PgHdr *pPg){ ){ assert( (pPg->flags&PGHDR_IN_JOURNAL) || (int)pPg->pgno>pPager->origDbSize ); - if( MEMDB ){ - rc = sqlite3PcachePreserve(pPg, 1); - if( rc!=SQLITE_OK ){ - return rc; - } - 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); + 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); } } @@ -3298,7 +3290,7 @@ static int pager_write(PgHdr *pPg){ assert( pPager->state>=PAGER_SHARED ); if( pPager->dbSize<(int)pPg->pgno ){ pPager->dbSize = pPg->pgno; - if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ + if( pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ pPager->dbSize++; } } @@ -3322,7 +3314,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); - if( !MEMDB && nPagePerSector>1 ){ + if( nPagePerSector>1 ){ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ 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 ** header to be written between the pages journaled by this function. */ + assert( !MEMDB ); assert( pPager->doNotSync==0 ); pPager->doNotSync = 1; @@ -3439,7 +3432,7 @@ int sqlite3PagerDontWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; int rc; - if( MEMDB || pPg->pgno>pPager->origDbSize ){ + if( pPg->pgno>pPager->origDbSize ){ return SQLITE_OK; } if( pPager->pAlwaysRollback==0 ){ @@ -3500,7 +3493,6 @@ void sqlite3PagerDontRollback(DbPage *pPg){ ){ return; } - assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */ #ifdef SQLITE_SECURE_DELETE if( (pPg->flags & PGHDR_IN_JOURNAL)!=0 || (int)pPg->pgno>pPager->origDbSize ){ @@ -3792,16 +3784,9 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ return SQLITE_OK; } PAGERTRACE2("COMMIT %d\n", PAGERID(pPager)); - if( MEMDB ){ - sqlite3PcacheCommit(pPager->pPCache, 0); - sqlite3PcacheCleanAll(pPager->pPCache); - 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); - } + assert( pPager->state==PAGER_SYNCED || MEMDB || !pPager->dirtyCache ); + rc = pager_end_transaction(pPager, pPager->setMaster); + rc = pager_error(pPager, rc); return rc; } @@ -3820,16 +3805,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int sqlite3PagerRollback(Pager *pPager){ int rc = SQLITE_OK; PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); - if( MEMDB ){ - 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 ){ + if( !pPager->dirtyCache || !pPager->journalOpen ){ rc = pager_end_transaction(pPager, pPager->setMaster); }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ if( pPager->state>=PAGER_EXCLUSIVE ){ @@ -3848,7 +3824,9 @@ int sqlite3PagerRollback(Pager *pPager){ 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 ** 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->dbSize>=0 ); PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager)); - if( MEMDB ){ - pPager->stmtInUse = 1; - pPager->stmtSize = pPager->dbSize; - return SQLITE_OK; - } if( !pPager->journalOpen ){ pPager->stmtAutoopen = 1; return SQLITE_OK; @@ -3939,9 +3912,13 @@ static int pagerStmtBegin(Pager *pPager){ pPager->stmtHdrOff = 0; pPager->stmtCksum = pPager->cksumInit; if( !pPager->stmtOpen ){ - rc = sqlite3PagerOpentemp(pPager, pPager->stfd, SQLITE_OPEN_SUBJOURNAL); - if( rc ){ - goto stmt_begin_failed; + if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ + sqlite3MemJournalOpen(pPager->stfd); + }else{ + rc = sqlite3PagerOpentemp(pPager, pPager->stfd, SQLITE_OPEN_SUBJOURNAL); + if( rc ){ + goto stmt_begin_failed; + } } pPager->stmtOpen = 1; pPager->stmtNRec = 0; @@ -3968,14 +3945,13 @@ int sqlite3PagerStmtBegin(Pager *pPager){ int sqlite3PagerStmtCommit(Pager *pPager){ if( pPager->stmtInUse ){ PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); - if( !MEMDB ){ - sqlite3BitvecDestroy(pPager->pInStmt); - pPager->pInStmt = 0; - }else{ - sqlite3PcacheCommit(pPager->pPCache, 1); - } + sqlite3BitvecDestroy(pPager->pInStmt); + pPager->pInStmt = 0; pPager->stmtNRec = 0; pPager->stmtInUse = 0; + if( sqlite3IsMemJournal(pPager->stfd) ){ + sqlite3OsTruncate(pPager->stfd, 0); + } } pPager->stmtAutoopen = 0; return SQLITE_OK; @@ -3988,14 +3964,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){ int rc; if( pPager->stmtInUse ){ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); - if( MEMDB ){ - sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter); - pPager->dbSize = pPager->stmtSize; - pager_truncate_cache(pPager); - rc = SQLITE_OK; - }else{ - rc = pager_stmt_playback(pPager); - } + rc = pager_stmt_playback(pPager); sqlite3PagerStmtCommit(pPager); }else{ rc = SQLITE_OK; @@ -4124,7 +4093,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); } if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){ - assert( !MEMDB ); pPg->flags |= PGHDR_IN_JOURNAL; } @@ -4233,16 +4201,19 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ ** journal-mode. */ int sqlite3PagerJournalMode(Pager *pPager, int eMode){ - assert( eMode==PAGER_JOURNALMODE_QUERY - || eMode==PAGER_JOURNALMODE_DELETE - || eMode==PAGER_JOURNALMODE_TRUNCATE - || eMode==PAGER_JOURNALMODE_PERSIST - || eMode==PAGER_JOURNALMODE_OFF ); - assert( PAGER_JOURNALMODE_QUERY<0 ); - if( eMode>=0 ){ - pPager->journalMode = eMode; - }else{ - assert( eMode==PAGER_JOURNALMODE_QUERY ); + if( !MEMDB ){ + assert( eMode==PAGER_JOURNALMODE_QUERY + || eMode==PAGER_JOURNALMODE_DELETE + || eMode==PAGER_JOURNALMODE_TRUNCATE + || eMode==PAGER_JOURNALMODE_PERSIST + || eMode==PAGER_JOURNALMODE_OFF + || eMode==PAGER_JOURNALMODE_MEMORY ); + assert( PAGER_JOURNALMODE_QUERY<0 ); + if( eMode>=0 ){ + pPager->journalMode = eMode; + }else{ + assert( eMode==PAGER_JOURNALMODE_QUERY ); + } } return (int)pPager->journalMode; } diff --git a/src/pager.h b/src/pager.h index accf049e9d..822b62b18a 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,7 +13,7 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** 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_ @@ -66,6 +66,7 @@ typedef struct PgHdr DbPage; #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #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 diff --git a/src/pcache.c b/src/pcache.c index f55049eb58..a3a1d50577 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,7 +11,7 @@ ************************************************************************* ** 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" @@ -491,8 +491,6 @@ static void pcachePageFree(PgHdr *p){ if( p->pCache->bPurgeable ){ pcache_g.nCurrentPage--; } - pcacheFree(p->apSave[0]); - pcacheFree(p->apSave[1]); pcacheFree(p); } @@ -813,7 +811,6 @@ void sqlite3PcacheMakeDirty(PgHdr *p){ static void pcacheMakeClean(PgHdr *p){ PCache *pCache = p->pCache; - assert( p->apSave[0]==0 && p->apSave[1]==0 ); assert( p->flags & PGHDR_DIRTY ); pcacheRemoveFromList(&pCache->pDirty, p); pcacheAddToList(&pCache->pClean, p); @@ -844,7 +841,6 @@ void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; pcacheEnterMutex(); while( (p = pCache->pDirty)!=0 ){ - assert( p->apSave[0]==0 && p->apSave[1]==0 ); pcacheRemoveFromList(&pCache->pDirty, p); p->flags &= ~PGHDR_DIRTY; pcacheAddToList(&pCache->pClean, p); @@ -869,10 +865,6 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ pcacheRemoveFromHash(p); p->pgno = newPgno; if( newPgno==0 ){ - pcacheFree(p->apSave[0]); - pcacheFree(p->apSave[1]); - p->apSave[0] = 0; - p->apSave[1] = 0; if( (p->flags & PGHDR_DIRTY) ){ pcacheMakeClean(p); } @@ -970,72 +962,6 @@ void sqlite3PcacheClose(PCache *pCache){ 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 /* diff --git a/src/pcache.h b/src/pcache.h index 835fee9189..152d9e6cd5 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -12,7 +12,7 @@ ** This header file defines the interface that the sqlite page cache ** 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_ @@ -40,7 +40,7 @@ struct PgHdr { */ i16 nRef; /* Number of users of 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 ** 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 */ 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 */ PgHdr *sqlite3PcacheDirtyList(PCache*); diff --git a/src/pragma.c b/src/pragma.c index 5a35099609..e8cfc52cc7 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** 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 @@ -455,11 +455,13 @@ void sqlite3Pragma( /* ** 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 ){ int eMode; - static char * const azModeName[] = {"delete", "persist", "off", "truncate"}; + static char * const azModeName[] = { + "delete", "persist", "off", "truncate", "memory" + }; if( zRight==0 ){ eMode = PAGER_JOURNALMODE_QUERY; @@ -503,7 +505,8 @@ void sqlite3Pragma( assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_PERSIST - || eMode==PAGER_JOURNALMODE_OFF ); + || eMode==PAGER_JOURNALMODE_OFF + || eMode==PAGER_JOURNALMODE_MEMORY ); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", P4_STATIC); sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e4ef1d0b69..405a5eb970 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** 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_ #define _SQLITEINT_H_ @@ -2505,6 +2505,10 @@ int sqlite3FindInIndex(Parse *, Expr *, int*); #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) #endif +void sqlite3MemJournalOpen(sqlite3_file *); +int sqlite3MemJournalSize(); +int sqlite3IsMemJournal(sqlite3_file *); + #if SQLITE_MAX_EXPR_DEPTH>0 void sqlite3ExprSetHeight(Parse *pParse, Expr *p); int sqlite3SelectExprHeight(Select *); diff --git a/test/jrnlmode.test b/test/jrnlmode.test index 6383299883..29317220f6 100644 --- a/test/jrnlmode.test +++ b/test/jrnlmode.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The focus # 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] source $testdir/tester.tcl @@ -95,7 +95,7 @@ ifcapable attach { PRAGMA main.journal_mode; PRAGMA aux1.journal_mode; } - } {persist persist} + } {persist memory} do_test jrnlmode-1.10 { execsql { PRAGMA main.journal_mode = OFF; @@ -105,7 +105,7 @@ ifcapable attach { PRAGMA temp.journal_mode; PRAGMA aux1.journal_mode; } - } {off persist persist} + } {off persist memory} do_test jrnlmode-1.11 { execsql { PRAGMA journal_mode; @@ -120,8 +120,9 @@ ifcapable attach { PRAGMA aux1.journal_mode; PRAGMA aux2.journal_mode; } - } {off persist persist} + } {off memory memory} do_test jrnlmode-1.11 { + # The journal-mode used by in-memory databases cannot be changed. execsql { PRAGMA aux1.journal_mode = DELETE; } @@ -130,7 +131,7 @@ ifcapable attach { PRAGMA aux1.journal_mode; PRAGMA aux2.journal_mode; } - } {off delete persist} + } {off memory memory} do_test jrnlmode-1.12 { execsql { PRAGMA journal_mode = delete; @@ -141,7 +142,7 @@ ifcapable attach { PRAGMA aux1.journal_mode; PRAGMA aux2.journal_mode; } - } {delete delete delete delete} + } {delete delete memory memory} do_test jrnlmode-1.13 { execsql { ATTACH ':memory:' as aux3; @@ -153,7 +154,7 @@ ifcapable attach { PRAGMA aux2.journal_mode; PRAGMA aux3.journal_mode; } - } {delete delete delete delete delete} + } {delete delete memory memory memory} do_test jrnlmode-1.14 { execsql { PRAGMA journal_mode = TRUNCATE; @@ -165,7 +166,7 @@ ifcapable attach { PRAGMA aux2.journal_mode; PRAGMA aux3.journal_mode; } - } {truncate truncate truncate truncate truncate} + } {truncate truncate memory memory memory} do_test jrnlmode-1.99 { execsql { diff --git a/test/pager.test b/test/pager.test index 3b199c4b43..32265a5211 100644 --- a/test/pager.test +++ b/test/pager.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # 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] @@ -415,12 +415,14 @@ ifcapable memorydb { pager_truncate $::p2 5 } {} do_test pager-4.6.3 { + set page1 [page_get $::p2 1] for {set i 1} {$i<5} {incr i} { set p [page_get $::p2 $i] page_write $p "Page $i" pager_commit $::p2 page_unref $p } + page_unref $page1 # pager_truncate $::p2 3 } {} do_test pager-4.6.4 { diff --git a/test/pager2.test b/test/pager2.test index 5b65785a61..c20c355661 100644 --- a/test/pager2.test +++ b/test/pager2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # 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] @@ -33,13 +33,13 @@ do_test pager2-1.0 { } {0} do_test pager2-1.1 { 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 { pager_pagecount $::p1 } {0} do_test pager2-1.3 { 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 { pager_close $::p1 } {} @@ -62,7 +62,7 @@ do_test pager2-2.3.1 { } {} do_test pager2-2.3.2 { 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 { set v [catch { set ::g1 [page_get $::p1 1] @@ -72,7 +72,7 @@ do_test pager2-2.3.3 { } {0} do_test pager2-2.3.3 { 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 { set ::gx [page_lookup $::p1 1] page_unref $::gx @@ -80,22 +80,22 @@ do_test pager2-2.3.4 { } {1} do_test pager2-2.3.5 { 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 { expr {$::g1==$::gx} } {1} do_test pager2-2.3.7 { 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 { 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 { pager_pagecount $::p1 } {0} do_test pager2-2.6 { 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 { page_number $::g1 } {1} @@ -107,7 +107,7 @@ do_test pager2-2.9 { } {} do_test pager2-2.10 { 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 { set ::g1 [page_get $::p1 1] expr {$::g1!=0} @@ -117,7 +117,7 @@ do_test pager2-2.12 { } {1} do_test pager2-2.13 { 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 { set v [catch { page_write $::g1 "Page-One" @@ -138,19 +138,19 @@ do_test pager2-2.17 { } {0 {}} do_test pager2-2.20 { 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 { pager_pagecount $::p1 } {1} do_test pager2-2.21 { 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 { page_unref $::g1 } {} do_test pager2-2.23 { 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 { set v [catch { page_get $::p1 1 @@ -215,14 +215,17 @@ do_test pager2-3.5 { page_unref $::g(1) } {} for {set i 2} {$i<=20} {incr i} { + set page1 [page_get $::p1 1] do_test pager2-3.6.[expr {$i-1}] [subst { set gx \[page_get $::p1 $i\] set v \[page_read \$gx\] page_unref \$gx set v }] "Page-$i" + page_unref $page1 } for {set i 1} {$i<=20} {incr i} { + set page1 [page_get $::p1 1] regsub -all CNT { set ::g1 [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} } $i body; do_test pager2-3.7.$i.3 $body {1} + page_unref $page1 } do_test pager2-3.99 { pager_close $::p1 @@ -281,7 +285,7 @@ do_test pager2-4.3 { } {ref 1} do_test pager2-4.4 { lrange [pager_stats $::p1] 8 9 -} {state 1} +} {state 4} for {set i 1} {$i<20} {incr i} { do_test pager2-4.5.$i.0 { @@ -396,7 +400,7 @@ breakpoint do_test pager2-4.5.$i.10 { pager_commit $p1 lrange [pager_stats $p1] 8 9 - } {state 1} + } {state 4} } do_test pager2-4.99 { diff --git a/test/permutations.test b/test/permutations.test index 2abf67199a..b459cd0a7f 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -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] source $testdir/tester.tcl @@ -448,6 +448,24 @@ run_tests "autovacuum_ioerr" -description { pragma auto_vacuum = 1 } -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 { run_tests "memsys3" -description { Run tests using the allocator in mem3.c. diff --git a/test/rollback.test b/test/rollback.test index 54fdcb2026..b526a62a05 100644 --- a/test/rollback.test +++ b/test/rollback.test @@ -13,7 +13,7 @@ # caused by an ON CONFLICT ROLLBACK clause aborts any other pending # 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] source $testdir/tester.tcl @@ -81,7 +81,10 @@ do_test rollback-1.9 { set permutation "" 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 { execsql { BEGIN; diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 1dd54e4a04..9678c20a7e 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -247,6 +247,7 @@ foreach file { vdbe.c vdbeblob.c journal.c + memjournal.c walker.c resolve.c