From 2a321c754704cd68f433cf1f0414628d14386003 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 16 Jun 2010 19:04:23 +0000 Subject: [PATCH 01/13] Experimental change: On systems where it is not possible to unlink a file while one or more processes has it open (i.e. not unix), avoid closing the journal file each time the database is unlocked and reopening it at the start of each transaction. FossilOrigin-Name: bede8c8a148fb9be5ffbf38df7fa733e35cc68c3 --- manifest | 20 +++-- manifest.uuid | 2 +- src/pager.c | 37 +++++++-- src/sqlite.h.in | 1 + src/test_vfs.c | 190 ++++++++++++++++++++++++++++++++++++++++----- test/journal2.test | 188 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 400 insertions(+), 38 deletions(-) create mode 100644 test/journal2.test diff --git a/manifest b/manifest index bab89a2a99..8919437c24 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\stest\scases\sto\spager1.test. -D 2010-06-16T12:30:11 +C Experimental\schange:\sOn\ssystems\swhere\sit\sis\snot\spossible\sto\sunlink\sa\sfile\swhile\sone\sor\smore\sprocesses\shas\sit\sopen\s(i.e.\snot\sunix),\savoid\sclosing\sthe\sjournal\sfile\seach\stime\sthe\sdatabase\sis\sunlocked\sand\sreopening\sit\sat\sthe\sstart\sof\seach\stransaction. +D 2010-06-16T19:04:23 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19 F src/os_unix.c ae173c9f6afaa58b2833a1c95c6cd32021755c42 F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138 -F src/pager.c 2964185d4356d0dc159b8340e52d2538d32394e5 +F src/pager.c 133cc49da000b2685a104ed9812084c61bd7e40f F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 @@ -170,7 +170,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714 -F src/sqlite.h.in 46c01e55cea31b91565ae41276c6310ee4032be8 +F src/sqlite.h.in 706e41c4526ed2674fa042ab3b7ba473b20cb141 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 F src/sqliteInt.h 242987ebd2366ea36650a09cdab04a9163c62109 F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3 @@ -209,7 +209,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726 -F src/test_vfs.c 001c34e08748a4a02cd1c2d5531c160a007a84d8 +F src/test_vfs.c 687ba8db7830909955896488a66d3c6b655827f0 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d @@ -466,6 +466,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 +F test/journal2.test 0f867f26c7f30bda2b69dc0e6451caa8fed18ef1 F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849 F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 @@ -822,7 +823,10 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 6c5c04eea1f0e8d61883ee8675c249fbf895dc01 -R d490808417f08b44a0b162eb48b4aec9 +P ad3209572d0e6afe5c8b52313e334509661045e2 +R 55fd31c025a3067f63c5d2afd30242b8 +T *branch * experimental +T *sym-experimental * +T -sym-trunk * U dan -Z 861e5ff117287c588eecf635e107e097 +Z 33e1ea27519902b3169c3c25730a3e25 diff --git a/manifest.uuid b/manifest.uuid index 4d0fbc3ef3..08f76d7826 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ad3209572d0e6afe5c8b52313e334509661045e2 \ No newline at end of file +bede8c8a148fb9be5ffbf38df7fa733e35cc68c3 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 2b102fbea9..46eb7bc636 100644 --- a/src/pager.c +++ b/src/pager.c @@ -336,6 +336,7 @@ struct Pager { u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ + u8 safeJrnlHandle; /* True if jrnl may be held open with no lock */ /* The following block contains those class members that are dynamically ** modified during normal operations. The other variables in this structure @@ -1224,7 +1225,13 @@ static void pager_unlock(Pager *pPager){ ** Otherwise, another connection with journal_mode=delete might ** delete the file out from under us. */ - sqlite3OsClose(pPager->jfd); + if( pPager->safeJrnlHandle==0 + || (pPager->journalMode!=PAGER_JOURNALMODE_TRUNCATE + && pPager->journalMode!=PAGER_JOURNALMODE_PERSIST) + ){ + sqlite3OsClose(pPager->jfd); + } + sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); @@ -3089,6 +3096,7 @@ int sqlite3PagerClose(Pager *pPager){ sqlite3BeginBenignMalloc(); pPager->errCode = 0; pPager->exclusiveMode = 0; + pPager->safeJrnlHandle = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, (pPager->noSync ? 0 : pPager->sync_flags), @@ -3908,17 +3916,22 @@ int sqlite3PagerOpen( */ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3_vfs * const pVfs = pPager->pVfs; - int rc; /* Return code */ - int exists; /* True if a journal file is present */ + int rc = SQLITE_OK; /* Return code */ + int exists = 1; /* True if a journal file is present */ + int jrnlOpen = !!isOpen(pPager->jfd); assert( pPager!=0 ); assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); - assert( !isOpen(pPager->jfd) ); assert( pPager->state <= PAGER_SHARED ); + assert( jrnlOpen==0 + || sqlite3OsDeviceCharacteristics(pPager->jfd)&SQLITE_IOCAP_SAFE_DELETE + ); *pExists = 0; - rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); + if( !jrnlOpen ){ + rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); + } if( rc==SQLITE_OK && exists ){ int locked; /* True if some process holds a RESERVED lock */ @@ -3956,15 +3969,19 @@ static int hasHotJournal(Pager *pPager, int *pExists){ ** If there is, then we consider this journal to be hot. If not, ** it can be ignored. */ - int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; - rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); + if( !jrnlOpen ){ + int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); + } if( rc==SQLITE_OK ){ u8 first = 0; rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } - sqlite3OsClose(pPager->jfd); + if( !jrnlOpen ){ + sqlite3OsClose(pPager->jfd); + } *pExists = (first!=0); }else if( rc==SQLITE_CANTOPEN ){ /* If we cannot open the rollback journal file in order to see if @@ -4490,6 +4507,10 @@ static int pager_open_journal(Pager *pPager){ ); #else rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); + if( rc==SQLITE_OK ){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->jfd); + pPager->safeJrnlHandle = (iDc&SQLITE_IOCAP_SAFE_DELETE)!=0; + } #endif } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 28778f7fc0..093d5b3e71 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -508,6 +508,7 @@ int sqlite3_exec( #define SQLITE_IOCAP_ATOMIC64K 0x00000100 #define SQLITE_IOCAP_SAFE_APPEND 0x00000200 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_SAFE_DELETE 0x00000800 /* ** CAPI3REF: File Locking Levels diff --git a/src/test_vfs.c b/src/test_vfs.c index e94bef7d29..8a0095d87d 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -58,6 +58,9 @@ struct Testvfs { int iIoerrCnt; int ioerr; int nIoerrFail; + + int iDevchar; + int iSectorsize; }; /* @@ -77,7 +80,10 @@ struct Testvfs { #define TESTVFS_OPEN_MASK 0x00000100 #define TESTVFS_SYNC_MASK 0x00000200 #define TESTVFS_DELETE_MASK 0x00000400 -#define TESTVFS_ALL_MASK 0x000007FF +#define TESTVFS_CLOSE_MASK 0x00000800 +#define TESTVFS_WRITE_MASK 0x00001000 +#define TESTVFS_TRUNCATE_MASK 0x00002000 +#define TESTVFS_ALL_MASK 0x00003FFF #define TESTVFS_MAX_PAGES 256 @@ -245,15 +251,23 @@ static void tvfsExecTcl( ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - if( p->pShmId ){ - Tcl_DecrRefCount(p->pShmId); - p->pShmId = 0; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ + tvfsExecTcl(p, "xClose", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + } + + if( pFd->pShmId ){ + Tcl_DecrRefCount(pFd->pShmId); + pFd->pShmId = 0; } if( pFile->pMethods ){ ckfree((char *)pFile->pMethods); } - return sqlite3OsClose(p->pReal); + return sqlite3OsClose(pFd->pReal); } /* @@ -278,16 +292,42 @@ static int tvfsWrite( int iAmt, sqlite_int64 iOfst ){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); + int rc = SQLITE_OK; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ + tvfsExecTcl(p, "xWrite", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + tvfsResultCode(p, &rc); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst); + } + return rc; } /* ** Truncate an tvfs-file. */ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsTruncate(p->pReal, size); + int rc = SQLITE_OK; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ + tvfsExecTcl(p, "xTruncate", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + tvfsResultCode(p, &rc); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3OsTruncate(pFd->pReal, size); + } + return rc; } /* @@ -376,16 +416,24 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ ** Return the sector-size in bytes for an tvfs-file. */ static int tvfsSectorSize(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsSectorSize(p->pReal); + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->iSectorsize>=0 ){ + return p->iSectorsize; + } + return sqlite3OsSectorSize(pFd->pReal); } /* ** Return the device characteristic flags supported by an tvfs-file. */ static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsDeviceCharacteristics(p->pReal); + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->iDevchar>=0 ){ + return p->iDevchar; + } + return sqlite3OsDeviceCharacteristics(pFd->pReal); } /* @@ -782,25 +830,37 @@ static int testvfs_obj_cmd( ){ Testvfs *p = (Testvfs *)cd; - static const char *CMD_strs[] = { - "shm", "delete", "filter", "ioerr", "script", 0 - }; enum DB_enum { - CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT + CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, + CMD_DEVCHAR, CMD_SECTORSIZE + }; + struct TestvfsSubcmd { + char *zName; + enum DB_enum eCmd; + } aSubcmd[] = { + { "shm", CMD_SHM }, + { "delete", CMD_DELETE }, + { "filter", CMD_FILTER }, + { "ioerr", CMD_IOERR }, + { "script", CMD_SCRIPT }, + { "devchar", CMD_DEVCHAR }, + { "sectorsize", CMD_SECTORSIZE }, + { 0, 0 } }; - int i; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } - if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){ + if( Tcl_GetIndexFromObjStruct( + interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i) + ){ return TCL_ERROR; } Tcl_ResetResult(interp); - switch( (enum DB_enum)i ){ + switch( aSubcmd[i].eCmd ){ case CMD_SHM: { Tcl_Obj *pObj; int i; @@ -857,7 +917,10 @@ static int testvfs_obj_cmd( { "xShmMap", TESTVFS_SHMMAP_MASK }, { "xSync", TESTVFS_SYNC_MASK }, { "xDelete", TESTVFS_DELETE_MASK }, + { "xWrite", TESTVFS_WRITE_MASK }, + { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, + { "xClose", TESTVFS_CLOSE_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; @@ -948,6 +1011,89 @@ static int testvfs_obj_cmd( Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); break; } + + case CMD_DEVCHAR: { + struct DeviceFlag { + char *zName; + int iValue; + } aFlag[] = { + { "default", -1 }, + { "atomic", SQLITE_IOCAP_ATOMIC }, + { "atomic512", SQLITE_IOCAP_ATOMIC512 }, + { "atomic1k", SQLITE_IOCAP_ATOMIC1K }, + { "atomic2k", SQLITE_IOCAP_ATOMIC2K }, + { "atomic4k", SQLITE_IOCAP_ATOMIC4K }, + { "atomic8k", SQLITE_IOCAP_ATOMIC8K }, + { "atomic16k", SQLITE_IOCAP_ATOMIC16K }, + { "atomic32k", SQLITE_IOCAP_ATOMIC32K }, + { "atomic64k", SQLITE_IOCAP_ATOMIC64K }, + { "sequential", SQLITE_IOCAP_SEQUENTIAL }, + { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, + { "safe_delete", SQLITE_IOCAP_SAFE_DELETE }, + { 0, 0 } + }; + Tcl_Obj *pRet; + int iFlag; + + if( objc>3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?"); + return TCL_ERROR; + } + if( objc==3 ){ + int j; + int iNew = 0; + Tcl_Obj **flags = 0; + int nFlags = 0; + + if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){ + return TCL_ERROR; + } + + for(j=0; j1 ){ + Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0); + return TCL_ERROR; + } + iNew |= aFlag[idx].iValue; + } + + p->iDevchar = iNew; + } + + pRet = Tcl_NewObj(); + for(iFlag=0; iFlagiDevchar & aFlag[iFlag].iValue ){ + Tcl_ListObjAppendElement( + interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1) + ); + } + } + Tcl_SetObjResult(interp, pRet); + + break; + } + + case CMD_SECTORSIZE: { + if( objc>3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?"); + return TCL_ERROR; + } + if( objc==3 ){ + int iNew = 0; + if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){ + return TCL_ERROR; + } + p->iSectorsize = iNew; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize)); + break; + } } return TCL_OK; @@ -1067,6 +1213,8 @@ static int testvfs_cmd( nByte = sizeof(Testvfs) + strlen(zVfs)+1; p = (Testvfs *)ckalloc(nByte); memset(p, 0, nByte); + p->iDevchar = -1; + p->iSectorsize = -1; /* Create the new object command before querying SQLite for a default VFS ** to use for 'real' IO operations. This is because creating the new VFS diff --git a/test/journal2.test b/test/journal2.test new file mode 100644 index 0000000000..8104299d49 --- /dev/null +++ b/test/journal2.test @@ -0,0 +1,188 @@ +# 2010 June 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/malloc_common.tcl +db close + +set a_string_counter 1 +proc a_string {n} { + global a_string_counter + incr a_string_counter + string range [string repeat "${a_string_counter}." $n] 1 $n +} + +# Create a [testvfs] and install it as the default VFS. Set the device +# characteristics flags to "SAFE_DELETE". +# +testvfs tvfs -default 1 +tvfs devchar safe_delete + +# Set up a hook so that each time a journal file is opened, closed or +# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final +# segment of the journal file-name (i.e. "test.db-journal") are appended to +# global list variable $::oplog. +# +tvfs filter {xOpen xClose xDelete} +tvfs script journal_op_catcher + +proc journal_op_catcher {method filename args} { + + # If global variable ::tvfs_error_on_write is defined, then return an + # IO error to every attempt to modify the file-system. Otherwise, return + # SQLITE_OK. + # + if {[info exists ::tvfs_error_on_write]} { + if {$method == "xDelete" || $method == "xWrite" || $method == "xTruncate"} { + return SQLITE_IOERR + } + return SQLITE_OK + } + + if {[string match *journal* $filename]==0} return + + set f [file tail $filename] + lappend ::oplog $method $f + + if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 } + switch -- $method { + xOpen { + incr ::open_journals($f) +1 + } + xClose { + incr ::open_journals($f) -1 + } + xDelete { + if {$::open_journals($f)>0} { return SQLITE_IOERR } + } + } + + return +} + + +do_test journal2-1.1 { + set ::oplog [list] + sqlite3 db test.db + execsql { CREATE TABLE t1(a, b) } + set ::oplog +} {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal} +do_test journal2-1.2 { + set ::oplog [list] + execsql { + PRAGMA journal_mode = truncate; + INSERT INTO t1 VALUES(1, 2); + } + set ::oplog +} {xOpen test.db-journal} +do_test journal2-1.3 { + set ::oplog [list] + execsql { INSERT INTO t1 VALUES(3, 4) } + set ::oplog +} {} +do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4} + +# Add a second connection. This connection attempts to commit data in +# journal_mode=DELETE mode. When it tries to delete the journal file, +# the VFS layer returns an IO error. +# +do_test journal2-1.5 { + set ::oplog [list] + sqlite3 db2 test.db + execsql { PRAGMA journal_mode = delete } db2 + catchsql { INSERT INTO t1 VALUES(5, 6) } db2 +} {1 {disk I/O error}} +do_test journal2-1.6 { file exists test.db-journal } 1 +do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4} +do_test journal2-1.8 { + execsql { PRAGMA journal_mode = truncate } db2 + execsql { INSERT INTO t1 VALUES(5, 6) } db2 +} {} +do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6} + +# Grow the database until it is reasonably large. Then, from a +# journal_mode=DELETE connection, attempt to commit a large transaction (one +# that involves upgrading to an exclusive lock and writing the database +# before the transaction is committed). +# +do_test journal2-1.10 { + db2 close + db func a_string a_string + execsql { + CREATE TABLE t2(a UNIQUE, b UNIQUE); + INSERT INTO t2 VALUES(a_string(200), a_string(300)); + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 2 + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 4 + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 8 + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 16 + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 32 + INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 64 + } + file size test.db-journal +} {0} +do_test journal2-1.11 { + set sz [expr [file size test.db] / 1024] + expr {$sz>120 && $sz<200} +} 1 + +do_test journal2-1.12 { + sqlite3 db2 test.db + execsql { + PRAGMA cache_size = 10; + BEGIN; + INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2; -- 128 + } db2 +} {} +do_test journal2-1.13 { + tvfs filter {xOpen xClose xDelete xWrite xTruncate} + set ::tvfs_error_on_write 1 + catchsql { COMMIT } db2 +} {1 {disk I/O error}} +db2 close +unset ::tvfs_error_on_write +file copy -force test.db testX.db + +do_test journal2-1.14 { file exists test.db-journal } 1 +do_test journal2-1.15 { + execsql { + SELECT count(*) FROM t2; + PRAGMA integrity_check; + } +} {64 ok} + +# This block checks that in the test case above, connection [db2] really +# did begin writing to the database file before it hit IO errors. If +# this is true, then the copy of the database file made before [db] +# rolled back the hot journal should fail the integrity-check. +# +do_test journal2-1.16 { + set sz [expr [file size testX.db] / 1024] + expr {$sz>240 && $sz<400} +} 1 +do_test journal2-1.17 { + expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"} +} {1} +do_test journal2-1.20 { + sqlite3 db2 testX.db + expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"} +} {0} +do_test journal2-1.21 { + db2 close +} {} + +db close +tvfs delete +finish_test + From b70f82a7a523d432153edf1b9c496eb11463e585 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 17 Jun 2010 11:36:28 +0000 Subject: [PATCH 02/13] Fix bug in journal2.test. FossilOrigin-Name: c1e04f1d4e8575ebc41b5b4403dbfe3f60d578dc --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/journal2.test | 10 +++++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 3746475123..b5533dd304 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\supdates\swith\sexperimental\sbranch. -D 2010-06-17T10:52:07 +C Fix\sbug\sin\sjournal2.test. +D 2010-06-17T11:36:28 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -466,7 +466,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 -F test/journal2.test 92653f42868b32272a9913c767324b0b3992a60b +F test/journal2.test 61c60f287d2d5f4d3d62af0a0d97100c90e055a6 F test/jrnlmode.test cd0c9c5b2555f3d5bb72ed8aa8d0ad16ecf77e7c F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 20133e9ca98f5e6c42051ed3d65e4eb71d5366a5 1ec74591a93e8b27ad3ac739914a48a91972e82c -R 4f7b82137af7b10bc7d2278f04c82c2f +P 9f6ea1de5abab0ca28688e257ddf03c66413cf6e +R 07d7ad85696711a45c0b4b5690681a45 U dan -Z 03dc90f484cb38d112214ba72ea54330 +Z b6a1325b7da2976f7858122f03070f50 diff --git a/manifest.uuid b/manifest.uuid index 200362655a..f33d818d2d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9f6ea1de5abab0ca28688e257ddf03c66413cf6e \ No newline at end of file +c1e04f1d4e8575ebc41b5b4403dbfe3f60d578dc \ No newline at end of file diff --git a/test/journal2.test b/test/journal2.test index ad76a8173f..18c898a28c 100644 --- a/test/journal2.test +++ b/test/journal2.test @@ -47,7 +47,6 @@ proc journal_op_catcher {method filename args} { if {[lsearch {xDelete xWrite xTruncate} $method]>=0} { return SQLITE_IOERR } - return SQLITE_OK } # The rest of this command only deals with xOpen(), xClose() and xDelete() @@ -70,7 +69,7 @@ proc journal_op_catcher {method filename args} { switch -- $method { xOpen { incr ::open_journals($f) +1 } xClose { incr ::open_journals($f) -1 } - xDelete { if {$::open_journals($f)>0} { puts EEE;return SQLITE_IOERR } } + xDelete { if {$::open_journals($f)>0} { return SQLITE_IOERR } } } return "" @@ -220,7 +219,12 @@ ifcapable wal { set ::oplog [list] execsql { PRAGMA journal_mode = WAL } set ::oplog - } {xClose test.db-journal xDelete test.db-journal} + } [list \ + xClose test.db-journal \ + xOpen test.db-journal xClose test.db-journal \ + xOpen test.db-journal xClose test.db-journal \ + xDelete test.db-journal \ + ] db close } From 731bf5bcf87cbbd34a11f73a6d345255f90e7547 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 17 Jun 2010 16:44:21 +0000 Subject: [PATCH 03/13] A different fix to [fc62af4523]. When changing from journal_mode=PERSIST or TRINCATE to some other rollback mode, delete the journal file only if a RESERVED lock can be obtained on the database file first. FossilOrigin-Name: b9b11855e8a9522309dd30e5256bb67d67e1353a --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/pager.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/vdbe.c | 7 ++----- test/journal2.test | 9 ++------- test/jrnlmode.test | 4 ++-- 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index b5533dd304..d5453b91cc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sbug\sin\sjournal2.test. -D 2010-06-17T11:36:28 +C A\sdifferent\sfix\sto\s[fc62af4523].\sWhen\schanging\sfrom\sjournal_mode=PERSIST\sor\sTRINCATE\sto\ssome\sother\srollback\smode,\sdelete\sthe\sjournal\sfile\sonly\sif\sa\sRESERVED\slock\scan\sbe\sobtained\son\sthe\sdatabase\sfile\sfirst. +D 2010-06-17T16:44:22 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19 F src/os_unix.c ae173c9f6afaa58b2833a1c95c6cd32021755c42 F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138 -F src/pager.c 658e5063d2d1661336a1e269e1cc324dfa8a683a +F src/pager.c 5968e0d73febd2e1c9e4e785660bdf49ff2e2cab F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 @@ -217,7 +217,7 @@ F src/update.c 9859f2056c7739a1db0d9774ccb6c2f0cee6d1de F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f -F src/vdbe.c 8a910a19981b8f670f4d67b5b0673459de50ccba +F src/vdbe.c e115585b14d2cc4128cb53a7e42f207750e80f55 F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1 F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d @@ -466,8 +466,8 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 -F test/journal2.test 61c60f287d2d5f4d3d62af0a0d97100c90e055a6 -F test/jrnlmode.test cd0c9c5b2555f3d5bb72ed8aa8d0ad16ecf77e7c +F test/journal2.test 3e98dc6b7486aa7e1ed67ff542e891a978654093 +F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849 F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 9f6ea1de5abab0ca28688e257ddf03c66413cf6e -R 07d7ad85696711a45c0b4b5690681a45 +P c1e04f1d4e8575ebc41b5b4403dbfe3f60d578dc +R c1f8308c51de4402b52d191c23c2aef4 U dan -Z b6a1325b7da2976f7858122f03070f50 +Z 10be27f6ff328697757cba4d76703f36 diff --git a/manifest.uuid b/manifest.uuid index f33d818d2d..aab680823a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1e04f1d4e8575ebc41b5b4403dbfe3f60d578dc \ No newline at end of file +b9b11855e8a9522309dd30e5256bb67d67e1353a \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 8869802c54..a902d70efd 100644 --- a/src/pager.c +++ b/src/pager.c @@ -5898,6 +5898,48 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ /* Change the journal mode. */ pPager->journalMode = (u8)eMode; + + /* When transistioning from TRUNCATE or PERSIST to any other journal + ** mode except WAL (and we are not in locking_mode=EXCLUSIVE) then + ** delete the journal file. + */ + assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); + assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); + assert( (PAGER_JOURNALMODE_DELETE & 5)==0 ); + assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 ); + assert( (PAGER_JOURNALMODE_OFF & 5)==0 ); + assert( (PAGER_JOURNALMODE_WAL & 5)==5 ); + + assert( isOpen(pPager->fd) || pPager->exclusiveMode ); + if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ + + /* In this case we would like to delete the journal file. If it is + ** not possible, then that is not a problem. Deleting the journal file + ** here is an optimization only. + ** + ** Before deleting the journal file, obtain a RESERVED lock on the + ** database file. This ensures that the journal file is not deleted + ** while it is in use by some other client. + */ + int rc = SQLITE_OK; + int state = pPager->state; + if( statestate==PAGER_SHARED ){ + assert( rc==SQLITE_OK ); + rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); + } + if( rc==SQLITE_OK ){ + sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + } + if( rc==SQLITE_OK && state==PAGER_SHARED ){ + sqlite3OsUnlock(pPager->fd, SHARED_LOCK); + }else if( state==PAGER_UNLOCK ){ + pager_unlock(pPager); + } + assert( state==pPager->state ); + } } /* Return the new journal mode */ diff --git a/src/vdbe.c b/src/vdbe.c index 14785d35d5..6803beafd3 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5251,9 +5251,6 @@ case OP_JournalMode: { /* out2-prerelease */ }else if( rc==SQLITE_BUSY && pOp->p5==0 ){ goto abort_due_to_error; } - }else{ - sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_DELETE); - rc = SQLITE_OK; } /* Open a transaction on the database file. Regardless of the journal @@ -5261,8 +5258,7 @@ case OP_JournalMode: { /* out2-prerelease */ */ assert( sqlite3BtreeIsInTrans(pBt)==0 ); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeSetVersion(pBt, - (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); + rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error; } if( rc==SQLITE_BUSY ){ @@ -5274,6 +5270,7 @@ case OP_JournalMode: { /* out2-prerelease */ #endif /* ifndef SQLITE_OMIT_WAL */ eNew = sqlite3PagerSetJournalMode(pPager, eNew); + pOut = &aMem[pOp->p2]; pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = (char *)sqlite3JournalModename(eNew); diff --git a/test/journal2.test b/test/journal2.test index 18c898a28c..20331b8bd1 100644 --- a/test/journal2.test +++ b/test/journal2.test @@ -215,16 +215,11 @@ ifcapable wal { do_test journal2-2.3 { expr {[file size test.db-journal] > 512} } {1} - do_test journal2-2.3 { + do_test journal2-2.4 { set ::oplog [list] execsql { PRAGMA journal_mode = WAL } set ::oplog - } [list \ - xClose test.db-journal \ - xOpen test.db-journal xClose test.db-journal \ - xOpen test.db-journal xClose test.db-journal \ - xDelete test.db-journal \ - ] + } {xClose test.db-journal xDelete test.db-journal} db close } diff --git a/test/jrnlmode.test b/test/jrnlmode.test index 2a6338fc9e..fd3e59f12d 100644 --- a/test/jrnlmode.test +++ b/test/jrnlmode.test @@ -484,7 +484,7 @@ ifcapable pragma { INSERT INTO t4 VALUES(3, 4); } file exists test.db-journal - } {1} + } {0} do_test jrnlmode-6.7 { execsql { COMMIT; @@ -493,7 +493,7 @@ ifcapable pragma { } {1 2 3 4} do_test jrnlmode-6.8 { file exists test.db-journal - } {1} + } {0} do_test jrnlmode-6.9 { execsql { PRAGMA journal_mode = DELETE; From 83acd423a1bca7c95cae4a4c9af918e3ebc00d59 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 18 Jun 2010 11:10:06 +0000 Subject: [PATCH 04/13] Change the implementation of the unix implementation of xAccess() so that it returns 0 (does not exist) to an SQLITE_ACCESS_EXISTS query on a file that exists but is zero bytes in size. FossilOrigin-Name: 077b0e5bcd849130c8df373fc2134c4b44351882 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index f37774487e..b513f79112 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\schange\s[7c3a86b9c7]. -D 2010-06-17T16:44:53 +C Change\sthe\simplementation\sof\sthe\sunix\simplementation\sof\sxAccess()\sso\sthat\sit\sreturns\s0\s(does\snot\sexist)\sto\san\sSQLITE_ACCESS_EXISTS\squery\son\sa\sfile\sthat\sexists\sbut\sis\szero\sbytes\sin\ssize. +D 2010-06-18T11:10:07 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -154,7 +154,7 @@ F src/os.c 9c4a2f82a50306a33907678ec0187b6ad1486bfe F src/os.h d7775504a51e6e0d40315aa427b3e229ff9ff9ca F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19 -F src/os_unix.c ae173c9f6afaa58b2833a1c95c6cd32021755c42 +F src/os_unix.c 2555f00c4c777539c33a2ef0e65f71cff08a6fa0 F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138 F src/pager.c 5968e0d73febd2e1c9e4e785660bdf49ff2e2cab F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P b9b11855e8a9522309dd30e5256bb67d67e1353a 7c3a86b9c7e2a35ce755c32b38e911e79d843fad -R 9b3c0e89ee34bf70754dc9094b410e06 +P bd7bc4e0e28bc749034ff1a9290a69330c5d8ca4 +R 2b113c40a63b7748c0ad882d1483f64f U dan -Z cddd2246fd2d00b78e84c3f7e0542efe +Z 8ecd2203ce71c16c5fd05e7fedfa658b diff --git a/manifest.uuid b/manifest.uuid index 2060936fd0..d97862f3d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bd7bc4e0e28bc749034ff1a9290a69330c5d8ca4 \ No newline at end of file +077b0e5bcd849130c8df373fc2134c4b44351882 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 574f48d189..9966ed6097 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4618,6 +4618,12 @@ static int unixAccess( assert(!"Invalid flags argument"); } *pResOut = (access(zPath, amode)==0); + if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){ + struct stat buf; + if( 0==stat(zPath, &buf) && buf.st_size==0 ){ + *pResOut = 0; + } + } return SQLITE_OK; } From d956efebeaaf7b724c141b765a95a79932b7b538 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 18 Jun 2010 16:13:45 +0000 Subject: [PATCH 05/13] Rearrange some code in OP_JournalMode to avoid incorrect returns from subsequent invocations of "PRAGMA journal_mode" following an IO error. FossilOrigin-Name: ce0a4a9b5f981d066822a9ae63740c91b35bfc60 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbe.c | 11 ++++------- test/walmode.test | 31 ++++++++++++++++--------------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index b513f79112..a2cd06dea2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\simplementation\sof\sthe\sunix\simplementation\sof\sxAccess()\sso\sthat\sit\sreturns\s0\s(does\snot\sexist)\sto\san\sSQLITE_ACCESS_EXISTS\squery\son\sa\sfile\sthat\sexists\sbut\sis\szero\sbytes\sin\ssize. -D 2010-06-18T11:10:07 +C Rearrange\ssome\scode\sin\sOP_JournalMode\sto\savoid\sincorrect\sreturns\sfrom\ssubsequent\sinvocations\sof\s"PRAGMA\sjournal_mode"\sfollowing\san\sIO\serror. +D 2010-06-18T16:13:45 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -217,7 +217,7 @@ F src/update.c 9859f2056c7739a1db0d9774ccb6c2f0cee6d1de F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f -F src/vdbe.c e115585b14d2cc4128cb53a7e42f207750e80f55 +F src/vdbe.c 290d20ed92b560dc0b602ac50b252f9553a2d8e8 F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1 F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d @@ -778,7 +778,7 @@ F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008 F test/walfault.test c2b524299dede269282a0795e11396cc446ca9af F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78 -F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048 +F test/walmode.test b54e2f91f34179c65cab02a6916578617a33eef0 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933 F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P bd7bc4e0e28bc749034ff1a9290a69330c5d8ca4 -R 2b113c40a63b7748c0ad882d1483f64f +P 077b0e5bcd849130c8df373fc2134c4b44351882 +R 54f97d60c6d719c202a2c47c8f5392d5 U dan -Z 8ecd2203ce71c16c5fd05e7fedfa658b +Z fff7f7ea627d7c4a7f85eb236bd967cc diff --git a/manifest.uuid b/manifest.uuid index d97862f3d8..9fc7060ef5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -077b0e5bcd849130c8df373fc2134c4b44351882 \ No newline at end of file +ce0a4a9b5f981d066822a9ae63740c91b35bfc60 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 6803beafd3..aec5712bf0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5248,8 +5248,6 @@ case OP_JournalMode: { /* out2-prerelease */ rc = sqlite3PagerCloseWal(pPager); if( rc==SQLITE_OK ){ sqlite3PagerSetJournalMode(pPager, eNew); - }else if( rc==SQLITE_BUSY && pOp->p5==0 ){ - goto abort_due_to_error; } } @@ -5259,16 +5257,15 @@ case OP_JournalMode: { /* out2-prerelease */ assert( sqlite3BtreeIsInTrans(pBt)==0 ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); - if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error; - } - if( rc==SQLITE_BUSY ){ - eNew = eOld; - rc = SQLITE_OK; } } } #endif /* ifndef SQLITE_OMIT_WAL */ + if( rc ){ + if( rc==SQLITE_BUSY && pOp->p5!=0 ) rc = SQLITE_OK; + eNew = eOld; + } eNew = sqlite3PagerSetJournalMode(pPager, eNew); pOut = &aMem[pOp->p2]; diff --git a/test/walmode.test b/test/walmode.test index 714e0d8189..48979b19c6 100644 --- a/test/walmode.test +++ b/test/walmode.test @@ -124,46 +124,48 @@ do_test walmode-4.5 { # from WAL to rollback mode because a second connection has the database # open. Or from rollback to WAL. # -do_test walmode-4.1 { +do_test walmode-4.6 { sqlite3 db2 test.db execsql { PRAGMA main.journal_mode } db2 } {delete} -do_test walmode-4.2 { +do_test walmode-4.7 { execsql { PRAGMA main.journal_mode = wal } db } {wal} -do_test walmode-4.3 { +do_test walmode-4.8 { execsql { SELECT * FROM t1 } db2 } {1 2} -do_test walmode-4.4 { +do_test walmode-4.9 { catchsql { PRAGMA journal_mode = delete } db } {1 {database is locked}} -do_test walmode-4.5 { +do_test walmode-4.10 { execsql { PRAGMA main.journal_mode } db } {wal} -do_test walmode-4.6 { + +do_test walmode-4.11 { db2 close execsql { PRAGMA journal_mode = delete } db } {delete} -do_test walmode-4.7 { +do_test walmode-4.12 { execsql { PRAGMA main.journal_mode } db } {delete} -do_test walmode-4.8 { +do_test walmode-4.13 { list [file exists test.db-journal] [file exists test.db-wal] } {0 0} -do_test walmode-4.9 { +do_test walmode-4.14 { sqlite3 db2 test.db execsql { BEGIN; SELECT * FROM t1; } db2 } {1 2} -do_test walmode-4.11 { - execsql { PRAGMA main.journal_mode } db -} {delete} -do_test walmode-4.10 { + +do_test walmode-4.16 { execsql { PRAGMA main.journal_mode } db } {delete} +do_test walmode-4.17 { execsql { PRAGMA main.journal_mode } db2 } {delete} + +do_test walmode-4.17 { catchsql { PRAGMA main.journal_mode = wal } db } {1 {database is locked}} -do_test walmode-4.11 { +do_test walmode-4.18 { execsql { PRAGMA main.journal_mode } db } {delete} catch { db close } @@ -180,7 +182,6 @@ do_test walmode-5.1.1 { sqlite3 db :memory: execsql { PRAGMA main.journal_mode } } {memory} -breakpoint do_test walmode-5.1.2 { execsql { PRAGMA main.journal_mode = wal } } {memory} From 1f4cb65a9e76f0be5b07852f05c6b0c24ef72cf7 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 18 Jun 2010 18:59:49 +0000 Subject: [PATCH 06/13] Add tests to pager1.test. FossilOrigin-Name: 582fca89195af54e9668af249691654cfea63d04 --- manifest | 12 +++--- manifest.uuid | 2 +- test/pager1.test | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index a2cd06dea2..5be23c9020 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rearrange\ssome\scode\sin\sOP_JournalMode\sto\savoid\sincorrect\sreturns\sfrom\ssubsequent\sinvocations\sof\s"PRAGMA\sjournal_mode"\sfollowing\san\sIO\serror. -D 2010-06-18T16:13:45 +C Add\stests\sto\spager1.test. +D 2010-06-18T18:59:49 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -534,7 +534,7 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test 60dec408563461f9fbf04d4d301b1b4db23f7525 +F test/pager1.test f2806eeba269efbe0132302b789f9fb4abf62264 F test/pagerfault.test 16e560bc4332d5b089b369d82ae4b65b8805b5eb F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 077b0e5bcd849130c8df373fc2134c4b44351882 -R 54f97d60c6d719c202a2c47c8f5392d5 +P ce0a4a9b5f981d066822a9ae63740c91b35bfc60 +R 43f6c397d741ef10ef5d1aeb6e2ade8c U dan -Z fff7f7ea627d7c4a7f85eb236bd967cc +Z 6cf151c823519ced3c5ca7c23ec3a1bb diff --git a/manifest.uuid b/manifest.uuid index 9fc7060ef5..e5f96cb16d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ce0a4a9b5f981d066822a9ae63740c91b35bfc60 \ No newline at end of file +582fca89195af54e9668af249691654cfea63d04 \ No newline at end of file diff --git a/test/pager1.test b/test/pager1.test index d0caaa9d41..c1a2a5ff27 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -22,6 +22,8 @@ source $testdir/malloc_common.tcl # # pager1-3.*: Savepoint related tests. # +# pager1-4.*: Hot-journal related tests. +# proc do_execsql_test {testname sql result} { uplevel do_test $testname [list "execsql {$sql}"] [list $result] @@ -210,6 +212,99 @@ do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} do_execsql_test pager1-3.6 { COMMIT } {} +testvfs tv -default 1 +foreach code [list { + set s 512 + set sql { PRAGMA synchronous = off } +} { + set s 1024 + set sql { PRAGMA journal_mode = memory } +} { + set s 2048 + tv devchar safe_append +} { + set s 4096 + set sql { PRAGMA journal_mode = WAL } +}] { + eval $code + tv sectorsize $s + + do_test pager1-3.7.$s.1 { + faultsim_delete_and_reopen + execsql $sql + execsql { + PRAGMA cache_size = 10; + CREATE TABLE t1(i INTEGER PRIMARY KEY, j blob); + } + } {} + + set tn 0 + set lowpoint 0 + foreach x { + 70 22 96 59 96 50 22 56 21 16 37 64 43 40 0 38 22 38 55 0 6 + 43 62 32 93 54 18 13 29 45 66 29 25 61 31 53 82 75 25 96 86 10 69 + 2 29 6 60 80 95 42 82 85 50 68 96 90 39 78 69 87 97 48 74 65 43 + x + 86 34 26 50 41 85 58 44 89 22 6 51 45 46 58 32 97 6 1 12 32 2 + 69 39 48 71 33 31 5 58 90 43 24 54 12 9 18 57 4 38 91 42 27 45 + 50 38 56 29 10 0 26 37 83 1 78 15 47 30 75 62 46 29 68 5 30 4 + 27 96 33 95 79 75 56 10 29 70 32 75 52 88 5 36 50 57 46 63 88 65 + x + 44 95 64 20 24 35 69 61 61 2 35 92 42 46 23 98 78 1 38 72 79 35 + 94 37 13 59 5 93 27 58 80 75 58 7 67 13 10 76 84 4 8 70 81 45 + 8 41 98 5 60 26 92 29 91 90 2 62 40 4 5 22 80 15 83 76 52 88 + 29 5 68 73 72 7 54 17 89 32 81 94 51 28 53 71 8 42 54 59 70 79 + x + 35 59 37 22 8 72 10 48 79 6 87 96 59 95 45 56 6 4 86 68 25 28 + 43 75 47 9 53 18 69 51 11 94 86 65 23 87 49 19 20 20 33 14 11 86 + 42 23 8 40 94 55 4 38 52 30 6 25 44 79 57 82 30 87 86 75 40 92 + 29 26 82 91 67 64 15 51 17 11 15 27 32 7 38 1 52 82 26 99 17 18 + 38 13 20 65 91 98 50 81 49 15 94 45 84 35 31 67 13 43 78 3 94 77 + 47 18 96 66 99 77 11 11 70 18 1 29 79 57 59 86 94 34 91 15 24 53 + 61 73 58 46 36 79 90 89 12 0 91 0 86 44 71 83 75 76 97 65 13 80 + 42 39 15 44 90 18 67 69 1 72 17 99 12 72 77 17 3 34 75 59 92 76 + 18 86 60 12 20 98 48 14 12 67 45 44 10 2 5 88 7 45 5 47 45 75 + 19 25 42 62 66 17 94 63 0 53 38 81 26 11 97 33 13 36 81 82 73 26 + 78 90 28 78 26 61 9 74 70 53 17 86 51 90 3 30 99 5 25 44 6 72 + 84 32 74 46 16 44 74 82 84 9 58 90 85 82 53 40 37 + } { + incr tn + set now [db one {SELECT count(i) FROM t1}] + if {$x == "x"} { + execsql { COMMIT ; BEGIN } + set lowpoint $now + do_test pager1.3.7.$s.2.$tn { + sqlite3 db2 test.db + execsql { + SELECT COALESCE(max(i), 0) FROM t1; + PRAGMA integrity_check; + } + } [list $lowpoint ok] + db2 close + } else { + if {$now > $x } { + if { $x>=$lowpoint } { + execsql "ROLLBACK TO sp_$x" + } else { + execsql "DELETE FROM t1 WHERE i>$x" + set lowpoint $x + } + } elseif {$now < $x} { + for {set k $now} {$k < $x} {incr k} { + execsql "SAVEPOINT sp_$k" + execsql { INSERT INTO t1(j) VALUES(randomblob(1500)) } + } + } + do_execsql_test pager1.3.7.$s.2.$tn { + SELECT COALESCE(max(i), 0) FROM t1; + PRAGMA integrity_check; + } [list $x ok] + } + } +} +db close +tv delete + #------------------------------------------------------------------------- # Hot journal rollback related test cases. # From de4996e2ee8662ac7e875c4591bca9115b25f13f Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 19 Jun 2010 11:30:41 +0000 Subject: [PATCH 07/13] Add tests to pager1.test and pagerfault.test. FossilOrigin-Name: 58c0b5bfed8c67cc3f2f4a6784d08c14e652c265 --- manifest | 14 ++--- manifest.uuid | 2 +- test/pager1.test | 80 +++++++++++++++++++++------ test/pagerfault.test | 126 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 195 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 5be23c9020..9af221bb21 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sto\spager1.test. -D 2010-06-18T18:59:49 +C Add\stests\sto\spager1.test\sand\spagerfault.test. +D 2010-06-19T11:30:41 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -534,8 +534,8 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test f2806eeba269efbe0132302b789f9fb4abf62264 -F test/pagerfault.test 16e560bc4332d5b089b369d82ae4b65b8805b5eb +F test/pager1.test d71580a4f358276520192f21fa2be4b8930bce86 +F test/pagerfault.test 424b0bbb3d458d36a94dfec89b05b0eab4d99ac8 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P ce0a4a9b5f981d066822a9ae63740c91b35bfc60 -R 43f6c397d741ef10ef5d1aeb6e2ade8c +P 582fca89195af54e9668af249691654cfea63d04 +R fbd44aafb92e6601ec3f8830a20d8a05 U dan -Z 6cf151c823519ced3c5ca7c23ec3a1bb +Z 2ad8778b11d258070a4981dade837d10 diff --git a/manifest.uuid b/manifest.uuid index e5f96cb16d..9a73ee0908 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -582fca89195af54e9668af249691654cfea63d04 \ No newline at end of file +58c0b5bfed8c67cc3f2f4a6784d08c14e652c265 \ No newline at end of file diff --git a/test/pager1.test b/test/pager1.test index c1a2a5ff27..4ef921e5e4 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -24,6 +24,8 @@ source $testdir/malloc_common.tcl # # pager1-4.*: Hot-journal related tests. # +# pager1-5.*: Cases related to multi-file commits. +# proc do_execsql_test {testname sql result} { uplevel do_test $testname [list "execsql {$sql}"] [list $result] @@ -212,24 +214,33 @@ do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} do_execsql_test pager1-3.6 { COMMIT } {} +set otn 0 testvfs tv -default 1 foreach code [list { set s 512 - set sql { PRAGMA synchronous = off } } { set s 1024 set sql { PRAGMA journal_mode = memory } } { set s 2048 tv devchar safe_append +} { + set s 4096 } { set s 4096 set sql { PRAGMA journal_mode = WAL } +} { + set s 8192 + set sql { PRAGMA synchronous = off } }] { + + incr otn + set sql "" + tv devchar {} eval $code tv sectorsize $s - do_test pager1-3.7.$s.1 { + do_test pager1-3.7.$otn.0 { faultsim_delete_and_reopen execsql $sql execsql { @@ -241,6 +252,8 @@ foreach code [list { set tn 0 set lowpoint 0 foreach x { + 100 x 0 100 + x 70 22 96 59 96 50 22 56 21 16 37 64 43 40 0 38 22 38 55 0 6 43 62 32 93 54 18 13 29 45 66 29 25 61 31 53 82 75 25 96 86 10 69 2 29 6 60 80 95 42 82 85 50 68 96 90 39 78 69 87 97 48 74 65 43 @@ -255,25 +268,13 @@ foreach code [list { 8 41 98 5 60 26 92 29 91 90 2 62 40 4 5 22 80 15 83 76 52 88 29 5 68 73 72 7 54 17 89 32 81 94 51 28 53 71 8 42 54 59 70 79 x - 35 59 37 22 8 72 10 48 79 6 87 96 59 95 45 56 6 4 86 68 25 28 - 43 75 47 9 53 18 69 51 11 94 86 65 23 87 49 19 20 20 33 14 11 86 - 42 23 8 40 94 55 4 38 52 30 6 25 44 79 57 82 30 87 86 75 40 92 - 29 26 82 91 67 64 15 51 17 11 15 27 32 7 38 1 52 82 26 99 17 18 - 38 13 20 65 91 98 50 81 49 15 94 45 84 35 31 67 13 43 78 3 94 77 - 47 18 96 66 99 77 11 11 70 18 1 29 79 57 59 86 94 34 91 15 24 53 - 61 73 58 46 36 79 90 89 12 0 91 0 86 44 71 83 75 76 97 65 13 80 - 42 39 15 44 90 18 67 69 1 72 17 99 12 72 77 17 3 34 75 59 92 76 - 18 86 60 12 20 98 48 14 12 67 45 44 10 2 5 88 7 45 5 47 45 75 - 19 25 42 62 66 17 94 63 0 53 38 81 26 11 97 33 13 36 81 82 73 26 - 78 90 28 78 26 61 9 74 70 53 17 86 51 90 3 30 99 5 25 44 6 72 - 84 32 74 46 16 44 74 82 84 9 58 90 85 82 53 40 37 } { incr tn set now [db one {SELECT count(i) FROM t1}] if {$x == "x"} { execsql { COMMIT ; BEGIN } set lowpoint $now - do_test pager1.3.7.$s.2.$tn { + do_test pager1.3.7.$otn.$tn { sqlite3 db2 test.db execsql { SELECT COALESCE(max(i), 0) FROM t1; @@ -295,7 +296,7 @@ foreach code [list { execsql { INSERT INTO t1(j) VALUES(randomblob(1500)) } } } - do_execsql_test pager1.3.7.$s.2.$tn { + do_execsql_test pager1.3.7.$otn.$tn { SELECT COALESCE(max(i), 0) FROM t1; PRAGMA integrity_check; } [list $x ok] @@ -316,6 +317,10 @@ tv delete # compute) the associated journal is rolled back (and no # xAccess() call to check for the presence of any master # journal file is made). +# +# pager1.4.3.*: Test that the contents of a hot-journal are ignored if the +# page-size or sector-size in the journal header appear to +# be invalid (too large, too small or not a power of 2). # do_test pager1.4.1.1 { faultsim_delete_and_reopen @@ -403,5 +408,48 @@ do_test pager1.4.2.5 { } } {4 ok} +do_test pager1.4.3.1 { + testvfs tstvfs -default 1 + tstvfs filter xSync + tstvfs script xSyncCallback + proc xSyncCallback {method file args} { + set file [file tail $file] + if { 0==[string match *journal $file] } { faultsim_save } + } + faultsim_delete_and_reopen + execsql { + PRAGMA journal_mode = DELETE; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + } + db close + tstvfs delete +} {} + +foreach {tn ofst value result} { + 2 20 31 {1 2 3 4} + 3 20 32 {1 2 3 4} + 4 20 33 {1 2 3 4} + 5 20 65536 {1 2 3 4} + 6 20 131072 {1 2 3 4} + + 7 24 511 {1 2 3 4} + 8 24 513 {1 2 3 4} + 9 24 65536 {1 2 3 4} + + 10 32 65536 {1 2} +} { + do_test pager1.4.3.$tn { + faultsim_restore_and_reopen + hexio_write test.db-journal $ofst [format %.8x $value] + execsql { SELECT * FROM t1 } + } $result +} +db close + +#------------------------------------------------------------------------- +# + finish_test diff --git a/test/pagerfault.test b/test/pagerfault.test index 8dc99e0bc0..ed781b5b59 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -54,11 +54,56 @@ do_faultsim_test pagerfault-1 -prep { } } +#------------------------------------------------------------------------- +# Test fault-injection while rolling back a hot-journal file with a +# page-size different from the current value stored on page 1 of the +# database file. +# +do_test pagerfault-2-pre1 { + testvfs tv -default 1 + tv filter xSync + tv script xSyncCb + proc xSyncCb {filename args} { + if {[string match *journal filename]==0} faultsim_save + } + faultsim_delete_and_reopen + execsql { + PRAGMA page_size = 4096; + BEGIN; + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES('o', 't', 't'); + INSERT INTO abc VALUES('f', 'f', 's'); + INSERT INTO abc SELECT * FROM abc; -- 4 + INSERT INTO abc SELECT * FROM abc; -- 8 + INSERT INTO abc SELECT * FROM abc; -- 16 + INSERT INTO abc SELECT * FROM abc; -- 32 + INSERT INTO abc SELECT * FROM abc; -- 64 + INSERT INTO abc SELECT * FROM abc; -- 128 + INSERT INTO abc SELECT * FROM abc; -- 256 + COMMIT; + PRAGMA page_size = 1024; + VACUUM; + } + db close + tv delete +} {} +do_faultsim_test pagerfault-2 -prep { + faultsim_restore_and_reopen +} -body { + execsql { SELECT * FROM abc } +} -test { + set answer [split [string repeat "ottffs" 128] ""] + faultsim_test_result [list 0 $answer] + faultsim_integrity_check + set res [db eval { SELECT * FROM abc }] + if {$res != $answer} { error "Database content appears incorrect ($res)" } +} -faults oom-transient + #------------------------------------------------------------------------- # Test fault-injection while rolling back hot-journals that were created # as part of a multi-file transaction. # -do_test pagerfault-2-pre1 { +do_test pagerfault-3-pre1 { testvfs tstvfs -default 1 tstvfs filter xDelete tstvfs script xDeleteCallback @@ -96,7 +141,7 @@ do_test pagerfault-2-pre1 { db close tstvfs delete } {} -do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep { +do_faultsim_test pagerfault-3 -faults ioerr-persistent -prep { faultsim_restore_and_reopen } -body { execsql { @@ -107,7 +152,6 @@ do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep { } -test { faultsim_test_result {0 {4 4}} {1 {unable to open database: test.db2}} faultsim_integrity_check - catchsql { ATTACH 'test.db2' AS aux } if {[db one { SELECT count(*) FROM t1 }] != 4 || [db one { SELECT count(*) FROM t2 }] != 4 @@ -116,4 +160,80 @@ do_faultsim_test pagerfault-2 -faults ioerr-persistent -prep { } } +#------------------------------------------------------------------------- +# Test fault-injection as part of a vanilla, no-transaction, INSERT +# statement. +# +do_faultsim_test pagerfault-4 -prep { + faultsim_delete_and_reopen +} -body { + execsql { + CREATE TABLE x(y); + INSERT INTO x VALUES('z'); + SELECT * FROM x; + } +} -test { + faultsim_test_result {0 z} + faultsim_integrity_check +} + +#------------------------------------------------------------------------- +# Test fault-injection as part of a commit when using journal_mode=PERSIST. +# +do_test pagerfault-5-pre1 { + faultsim_delete_and_reopen + db func a_string a_string + execsql { + CREATE TABLE t1(a UNIQUE, b UNIQUE); + INSERT INTO t1 VALUES(a_string(200), a_string(300)); + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + } + faultsim_save_and_close +} {} +do_faultsim_test pagerfault-5.1 -prep { + faultsim_restore_and_reopen + db func a_string a_string + execsql { PRAGMA journal_mode = PERSIST } +} -body { + execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } +} -test { + faultsim_test_result {0 {}} + faultsim_integrity_check +} +do_faultsim_test pagerfault-5.2 -prep { + faultsim_restore_and_reopen + db func a_string a_string + execsql { + PRAGMA journal_mode = PERSIST; + PRAGMA journal_size_limit = 2048; + } +} -body { + execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } +} -test { + faultsim_test_result {0 {}} + faultsim_integrity_check +} + +do_faultsim_test pagerfault-5.3 -prep { + faultsim_restore_and_reopen + db func a_string a_string + file delete -force test2.db test2.db-journal test2.db-wal + execsql { + PRAGMA journal_mode = PERSIST; + ATTACH 'test2.db' AS aux; + PRAGMA aux.journal_mode = PERSIST; + PRAGMA aux.journal_size_limit = 0; + } +} -body { + execsql { + BEGIN; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + CREATE TABLE aux.t2 AS SELECT * FROM t1; + COMMIT; + } +} -test { + faultsim_test_result {0 {}} +} + finish_test From 146ed78b7818b43845ae44d3cbb12c7c80183be5 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 19 Jun 2010 17:26:37 +0000 Subject: [PATCH 08/13] Add tests to pager1.test and pagerfault.test. FossilOrigin-Name: f5df83fd875073eee8e2269e87e2a8c9c7abc981 --- manifest | 18 ++--- manifest.uuid | 2 +- src/test_vfs.c | 75 ++++++++++++++---- test/malloc_common.tcl | 27 +++++++ test/pager1.test | 169 +++++++++++++++++++++++++++++++++++++++++ test/pagerfault.test | 49 +++++++++++- test/permutations.test | 1 + 7 files changed, 317 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 9af221bb21..d122597b86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ C Add\stests\sto\spager1.test\sand\spagerfault.test. -D 2010-06-19T11:30:41 +D 2010-06-19T17:26:37 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -209,7 +209,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726 -F src/test_vfs.c 687ba8db7830909955896488a66d3c6b655827f0 +F src/test_vfs.c abdf6881beac76cbc54d2586cd092b2b4ed3a217 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d @@ -509,7 +509,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 -F test/malloc_common.tcl fbf369eb2828825c5f319c101917aff91ea87556 +F test/malloc_common.tcl 4981dd86adf0d3f25c755ac3a425d6208fda6362 F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 @@ -534,13 +534,13 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test d71580a4f358276520192f21fa2be4b8930bce86 -F test/pagerfault.test 424b0bbb3d458d36a94dfec89b05b0eab4d99ac8 +F test/pager1.test 2842b3567589fc4881928a7febeb9342442ea449 +F test/pagerfault.test 55c7d602eaba7c08312616a4c6482606d50eed6a F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 -F test/permutations.test f044eaba204ff13d530ceb72a22b0ed2c43562ef +F test/permutations.test 97cfca3f7c390fa530c6f5c63d73eb67e5b0cd9d F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 582fca89195af54e9668af249691654cfea63d04 -R fbd44aafb92e6601ec3f8830a20d8a05 +P 58c0b5bfed8c67cc3f2f4a6784d08c14e652c265 +R 86313cbaab41f6821959bc241c636465 U dan -Z 2ad8778b11d258070a4981dade837d10 +Z a6c0e379ae1464c418b51e1bd6121ef1 diff --git a/manifest.uuid b/manifest.uuid index 9a73ee0908..8f8bbb9acb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -58c0b5bfed8c67cc3f2f4a6784d08c14e652c265 \ No newline at end of file +f5df83fd875073eee8e2269e87e2a8c9c7abc981 \ No newline at end of file diff --git a/src/test_vfs.c b/src/test_vfs.c index 8a0095d87d..2d4dad7867 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -59,6 +59,10 @@ struct Testvfs { int ioerr; int nIoerrFail; + int iFullCnt; + int fullerr; + int nFullFail; + int iDevchar; int iSectorsize; }; @@ -193,6 +197,30 @@ static int tvfsResultCode(Testvfs *p, int *pRc){ return 0; } +static int tvfsInjectIoerr(Testvfs *p){ + int ret = 0; + if( p->ioerr ){ + p->iIoerrCnt--; + if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){ + ret = 1; + p->nIoerrFail++; + } + } + return ret; +} + +static int tvfsInjectFullerr(Testvfs *p){ + int ret = 0; + if( p->fullerr ){ + p->iFullCnt--; + if( p->iFullCnt<=0 ){ + ret = 1; + p->nFullFail++; + } + } + return ret; +} + static void tvfsExecTcl( Testvfs *p, @@ -302,6 +330,8 @@ static int tvfsWrite( ); tvfsResultCode(p, &rc); } + + if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst); @@ -365,6 +395,8 @@ static int tvfsSync(sqlite3_file *pFile, int flags){ tvfsResultCode(p, &rc); } + if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; + if( rc==SQLITE_OK ){ rc = sqlite3OsSync(pFd->pReal, flags); } @@ -603,18 +635,6 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut); } -static int tvfsInjectIoerr(Testvfs *p){ - int ret = 0; - if( p->ioerr ){ - p->iIoerrCnt--; - if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){ - ret = 1; - p->nIoerrFail++; - } - } - return ret; -} - static int tvfsShmOpen( sqlite3_file *pFileDes ){ @@ -832,7 +852,7 @@ static int testvfs_obj_cmd( enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, - CMD_DEVCHAR, CMD_SECTORSIZE + CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR }; struct TestvfsSubcmd { char *zName; @@ -842,6 +862,7 @@ static int testvfs_obj_cmd( { "delete", CMD_DELETE }, { "filter", CMD_FILTER }, { "ioerr", CMD_IOERR }, + { "fullerr", CMD_FULLERR }, { "script", CMD_SCRIPT }, { "devchar", CMD_DEVCHAR }, { "sectorsize", CMD_SECTORSIZE }, @@ -978,6 +999,34 @@ static int testvfs_obj_cmd( break; } + /* + ** TESTVFS fullerr ?IFAIL? + ** + ** Where IFAIL is an integer. + */ + case CMD_FULLERR: { + int iRet = p->nFullFail; + + p->nFullFail = 0; + p->fullerr = 0; + p->iFullCnt = 0; + + if( objc==3 ){ + int iCnt; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) ){ + return TCL_ERROR; + } + p->fullerr = (iCnt>0); + p->iFullCnt = iCnt; + }else if( objc!=2 ){ + Tcl_AppendResult(interp, "Bad args", 0); + return TCL_ERROR; + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); + break; + } + /* ** TESTVFS ioerr ?IFAIL PERSIST? ** diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index a24716cd4a..dc68b1b53a 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -49,6 +49,16 @@ set FAULTSIM(ioerr-persistent) [list \ -injecterrlist {{1 {disk I/O error}}} \ ] +# SQLITE_FULL errors (always persistent): +# +set FAULTSIM(full) [list \ + -injectinstall fullerr_injectinstall \ + -injectstart fullerr_injectstart \ + -injectstop fullerr_injectstop \ + -injecterrlist {{1 {database or disk is full}}} \ + -injectuninstall fullerr_injectuninstall \ +] + # Transient and persistent SHM errors: # set FAULTSIM(shmerr-transient) [list \ @@ -177,6 +187,7 @@ proc ioerr_injectstop {} { return $sv } + # The following procs are used as [do_one_faultsim_test] callbacks when # injecting shared-memory related error faults into test cases. # @@ -195,6 +206,22 @@ proc shmerr_injectstop {} { shmfault ioerr 0 0 } +proc fullerr_injectinstall {} { + testvfs shmfault -default true +} +proc fullerr_injectuninstall {} { + catch {db close} + catch {db2 close} + shmfault delete +} +proc fullerr_injectstart {iFail} { + shmfault full $iFail +} +proc fullerr_injectstop {} { + shmfault full 0 +} + + # This command is not called directly. It is used by the # [faultsim_test_result] command created by [do_faultsim_test] and used # by -test scripts. diff --git a/test/pager1.test b/test/pager1.test index 4ef921e5e4..33b5c2ae04 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -26,6 +26,8 @@ source $testdir/malloc_common.tcl # # pager1-5.*: Cases related to multi-file commits. # +# pager1-6.*: Cases related to "PRAGMA max_page_count" +# proc do_execsql_test {testname sql result} { uplevel do_test $testname [list "execsql {$sql}"] [list $result] @@ -221,6 +223,12 @@ foreach code [list { } { set s 1024 set sql { PRAGMA journal_mode = memory } +} { + set s 1024 + set sql { + PRAGMA journal_mode = memory; + PRAGMA locking_mode = exclusive; + } } { set s 2048 tv devchar safe_append @@ -449,7 +457,168 @@ foreach {tn ofst value result} { db close #------------------------------------------------------------------------- +# The following tests deal with multi-file commits. # +# pager1-5.1.*: The case where a multi-file cannot be committed because +# another connection is holding a SHARED lock on one of the +# files. After the SHARED lock is removed, the COMMIT succeeds. +# +# pager1-5.2.*: Multi-file commits with journal_mode=memory. +# +# pager1-5.3.*: Multi-file commits with journal_mode=memory. +# +# pager1-5.4.*: Check that with synchronous=normal, the master-journal file +# name is added to a journal file immediately after the last +# journal record. But with synchronous=full, extra unused space +# is allocated between the last journal record and the +# master-journal file name so that the master-journal file +# name does not lie on the same sector as the last journal file +# record. +# +# pager1-5.5.*: +# +do_test pager1-5.1.1 { + faultsim_delete_and_reopen + execsql { + ATTACH 'test.db2' AS aux; + CREATE TABLE t1(a, b); + CREATE TABLE aux.t2(a, b); + INSERT INTO t1 VALUES(17, 'Lenin'); + INSERT INTO t1 VALUES(22, 'Stalin'); + INSERT INTO t1 VALUES(53, 'Khrushchev'); + } +} {} +do_test pager1-5.1.2 { + execsql { + BEGIN; + INSERT INTO t1 VALUES(64, 'Brezhnev'); + INSERT INTO t2 SELECT * FROM t1; + } + sqlite3 db2 test.db2 + execsql { + BEGIN; + SELECT * FROM t2; + } db2 +} {} +do_test pager1-5.1.3 { + catchsql COMMIT +} {1 {database is locked}} +do_test pager1-5.1.4 { + execsql COMMIT db2 + execsql COMMIT + execsql { SELECT * FROM t2 } db2 +} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev} +do_test pager1-5.1.5 { + db2 close +} {} + +do_test pager1-5.2.1 { + execsql { + PRAGMA journal_mode = memory; + BEGIN; + INSERT INTO t1 VALUES(84, 'Andropov'); + INSERT INTO t2 VALUES(84, 'Andropov'); + COMMIT; + } +} {memory} +do_test pager1-5.3.1 { + execsql { + PRAGMA journal_mode = off; + BEGIN; + INSERT INTO t1 VALUES(85, 'Gorbachev'); + INSERT INTO t2 VALUES(85, 'Gorbachev'); + COMMIT; + } +} {off} + +do_test pager1-5.4.1 { + db close + testvfs tv + sqlite3 db test.db -vfs tv + execsql { ATTACH 'test.db2' AS aux } + + tv filter xDelete + tv script max_journal_size + tv sectorsize 512 + set ::max_journal 0 + proc max_journal_size {method args} { + set sz 0 + catch { set sz [file size test.db-journal] } + if {$sz > $::max_journal} { + set ::max_journal $sz + } + return SQLITE_OK + } + execsql { + PRAGMA journal_mode = DELETE; + PRAGMA synchronous = NORMAL; + BEGIN; + INSERT INTO t1 VALUES(85, 'Gorbachev'); + INSERT INTO t2 VALUES(85, 'Gorbachev'); + COMMIT; + } + set ::max_journal +} [expr 2615+[string length [pwd]]] +do_test pager1-5.4.2 { + set ::max_journal 0 + execsql { + PRAGMA synchronous = full; + BEGIN; + DELETE FROM t1 WHERE b = 'Lenin'; + DELETE FROM t2 WHERE b = 'Lenin'; + COMMIT; + } + set ::max_journal +} [expr 3111+[string length [pwd]]] +db close +tv delete + +do_test pager1-5.5.1 { + sqlite3 db test.db + execsql { + ATTACH 'test.db2' AS aux; + PRAGMA journal_mode = PERSIST; + CREATE TABLE t3(a, b); + INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1; + UPDATE t3 SET b = randomblob(1500); + } + expr [file size test.db-journal] > 15000 +} {1} +do_test pager1-5.5.2 { + execsql { + PRAGMA synchronous = full; + BEGIN; + DELETE FROM t1 WHERE b = 'Stalin'; + DELETE FROM t2 WHERE b = 'Stalin'; + COMMIT; + } + file size test.db-journal +} {0} + + +#------------------------------------------------------------------------- +# The following tests work with "PRAGMA max_page_count" +# +do_test pager1-6.1 { + faultsim_delete_and_reopen + execsql { + PRAGMA max_page_count = 10; + CREATE TABLE t2(a, b); + CREATE TABLE t3(a, b); + CREATE TABLE t4(a, b); + CREATE TABLE t5(a, b); + CREATE TABLE t6(a, b); + CREATE TABLE t7(a, b); + CREATE TABLE t8(a, b); + CREATE TABLE t9(a, b); + CREATE TABLE t10(a, b); + } +} {10} +do_test pager1-6.2 { + catchsql { + CREATE TABLE t11(a, b); + } +} {1 {database or disk is full}} finish_test diff --git a/test/pagerfault.test b/test/pagerfault.test index ed781b5b59..81a62ed7ea 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -179,6 +179,12 @@ do_faultsim_test pagerfault-4 -prep { #------------------------------------------------------------------------- # Test fault-injection as part of a commit when using journal_mode=PERSIST. +# Three different cases: +# +# pagerfault-5.1: With no journal_size_limit configured. +# pagerfault-5.2: With a journal_size_limit configured. +# pagerfault-5.4: Multi-file transaction. One connection has a +# journal_size_limit of 0, the other has no limit. # do_test pagerfault-5-pre1 { faultsim_delete_and_reopen @@ -214,7 +220,6 @@ do_faultsim_test pagerfault-5.2 -prep { faultsim_test_result {0 {}} faultsim_integrity_check } - do_faultsim_test pagerfault-5.3 -prep { faultsim_restore_and_reopen db func a_string a_string @@ -236,4 +241,46 @@ do_faultsim_test pagerfault-5.3 -prep { faultsim_test_result {0 {}} } +# The following was an attempt to get a bitvec malloc to fail. Didn't work. +# +# do_test pagerfault-6-pre1 { +# faultsim_delete_and_reopen +# execsql { +# CREATE TABLE t1(x, y, UNIQUE(x, y)); +# INSERT INTO t1 VALUES(1, randomblob(1501)); +# INSERT INTO t1 VALUES(2, randomblob(1502)); +# INSERT INTO t1 VALUES(3, randomblob(1503)); +# INSERT INTO t1 VALUES(4, randomblob(1504)); +# INSERT INTO t1 +# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; +# INSERT INTO t1 +# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; +# INSERT INTO t1 +# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; +# INSERT INTO t1 +# SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1; +# } +# faultsim_save_and_close +# } {} +# do_faultsim_test pagerfault-6 -prep { +# faultsim_restore_and_reopen +# } -body { +# execsql { +# BEGIN; +# UPDATE t1 SET x=x+4 WHERE x=1; +# SAVEPOINT one; +# UPDATE t1 SET x=x+4 WHERE x=2; +# SAVEPOINT three; +# UPDATE t1 SET x=x+4 WHERE x=3; +# SAVEPOINT four; +# UPDATE t1 SET x=x+4 WHERE x=4; +# RELEASE three; +# COMMIT; +# SELECT DISTINCT x FROM t1; +# } +# } -test { +# faultsim_test_result {0 {5 6 7 8}} +# faultsim_integrity_check +# } + finish_test diff --git a/test/permutations.test b/test/permutations.test index 921df33a47..27f795676a 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -170,6 +170,7 @@ test_suite "coverage-pager" -description { } -files { pager1.test pagerfault.test + journal2.test } From 8ce49d6ac0d238483a411145416187ff3cb15bf3 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 19 Jun 2010 18:12:02 +0000 Subject: [PATCH 09/13] Change the name of IOCAP_SAFE_DELETE to IOCAP_UNDELETABLE_WHEN_OPEN. Have the xDeviceCharacteristics() method of the win32 VFS return this flag. FossilOrigin-Name: 5a5ff4e3e4c707464f227907d0aefb8ef42180dd --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/os_win.c | 2 +- src/pager.c | 8 ++++---- src/sqlite.h.in | 24 ++++++++++++------------ src/test_vfs.c | 26 +++++++++++++------------- test/journal2.test | 2 +- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/manifest b/manifest index d122597b86..a3d01f67df 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sto\spager1.test\sand\spagerfault.test. -D 2010-06-19T17:26:37 +C Change\sthe\sname\sof\sIOCAP_SAFE_DELETE\sto\sIOCAP_UNDELETABLE_WHEN_OPEN.\sHave\sthe\sxDeviceCharacteristics()\smethod\sof\sthe\swin32\sVFS\sreturn\sthis\sflag. +D 2010-06-19T18:12:03 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -155,8 +155,8 @@ F src/os.h d7775504a51e6e0d40315aa427b3e229ff9ff9ca F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19 F src/os_unix.c 2555f00c4c777539c33a2ef0e65f71cff08a6fa0 -F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138 -F src/pager.c 5968e0d73febd2e1c9e4e785660bdf49ff2e2cab +F src/os_win.c 73608839342de32280cb378d3c2fc85a5dd80bd2 +F src/pager.c 6ebb43239ad4ae2c0b0720bbd88a6a84a301bc8a F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 @@ -170,7 +170,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714 -F src/sqlite.h.in 706e41c4526ed2674fa042ab3b7ba473b20cb141 +F src/sqlite.h.in 301476d8556cbb1c5d4bc906370b2dafe4d98a44 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 F src/sqliteInt.h 242987ebd2366ea36650a09cdab04a9163c62109 F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3 @@ -209,7 +209,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726 -F src/test_vfs.c abdf6881beac76cbc54d2586cd092b2b4ed3a217 +F src/test_vfs.c 9ba0bb227f5fa08d7e3533ff21063c5acf13dabb F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d @@ -466,7 +466,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 -F test/journal2.test 3e98dc6b7486aa7e1ed67ff542e891a978654093 +F test/journal2.test a08ea6545d987385e7cbb1d4e7dc2eaacd83b00b F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849 F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 58c0b5bfed8c67cc3f2f4a6784d08c14e652c265 -R 86313cbaab41f6821959bc241c636465 +P f5df83fd875073eee8e2269e87e2a8c9c7abc981 +R 71fe53986b1289fd437e53aa98b15675 U dan -Z a6c0e379ae1464c418b51e1bd6121ef1 +Z aadd8ae68501aa286ffeda96be308372 diff --git a/manifest.uuid b/manifest.uuid index 8f8bbb9acb..dbbc0ae575 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f5df83fd875073eee8e2269e87e2a8c9c7abc981 \ No newline at end of file +5a5ff4e3e4c707464f227907d0aefb8ef42180dd \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index ec62e394c9..24d0e7ca3f 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1151,7 +1151,7 @@ static int winSectorSize(sqlite3_file *id){ */ static int winDeviceCharacteristics(sqlite3_file *id){ UNUSED_PARAMETER(id); - return 0; + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; } /**************************************************************************** diff --git a/src/pager.c b/src/pager.c index a902d70efd..3d16c66f25 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3924,9 +3924,9 @@ static int hasHotJournal(Pager *pPager, int *pExists){ assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); assert( pPager->state <= PAGER_SHARED ); - assert( jrnlOpen==0 - || sqlite3OsDeviceCharacteristics(pPager->jfd)&SQLITE_IOCAP_SAFE_DELETE - ); + assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & + SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN + )); *pExists = 0; if( !jrnlOpen ){ @@ -4509,7 +4509,7 @@ static int pager_open_journal(Pager *pPager){ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); if( rc==SQLITE_OK ){ int iDc = sqlite3OsDeviceCharacteristics(pPager->jfd); - pPager->safeJrnlHandle = (iDc&SQLITE_IOCAP_SAFE_DELETE)!=0; + pPager->safeJrnlHandle = (iDc&SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)!=0; } #endif } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 093d5b3e71..f91f25b3fb 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -497,18 +497,18 @@ int sqlite3_exec( ** information is written to disk in the same order as calls ** to xWrite(). */ -#define SQLITE_IOCAP_ATOMIC 0x00000001 -#define SQLITE_IOCAP_ATOMIC512 0x00000002 -#define SQLITE_IOCAP_ATOMIC1K 0x00000004 -#define SQLITE_IOCAP_ATOMIC2K 0x00000008 -#define SQLITE_IOCAP_ATOMIC4K 0x00000010 -#define SQLITE_IOCAP_ATOMIC8K 0x00000020 -#define SQLITE_IOCAP_ATOMIC16K 0x00000040 -#define SQLITE_IOCAP_ATOMIC32K 0x00000080 -#define SQLITE_IOCAP_ATOMIC64K 0x00000100 -#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 -#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 -#define SQLITE_IOCAP_SAFE_DELETE 0x00000800 +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 /* ** CAPI3REF: File Locking Levels diff --git a/src/test_vfs.c b/src/test_vfs.c index 2d4dad7867..46f3a0630a 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -1066,19 +1066,19 @@ static int testvfs_obj_cmd( char *zName; int iValue; } aFlag[] = { - { "default", -1 }, - { "atomic", SQLITE_IOCAP_ATOMIC }, - { "atomic512", SQLITE_IOCAP_ATOMIC512 }, - { "atomic1k", SQLITE_IOCAP_ATOMIC1K }, - { "atomic2k", SQLITE_IOCAP_ATOMIC2K }, - { "atomic4k", SQLITE_IOCAP_ATOMIC4K }, - { "atomic8k", SQLITE_IOCAP_ATOMIC8K }, - { "atomic16k", SQLITE_IOCAP_ATOMIC16K }, - { "atomic32k", SQLITE_IOCAP_ATOMIC32K }, - { "atomic64k", SQLITE_IOCAP_ATOMIC64K }, - { "sequential", SQLITE_IOCAP_SEQUENTIAL }, - { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, - { "safe_delete", SQLITE_IOCAP_SAFE_DELETE }, + { "default", -1 }, + { "atomic", SQLITE_IOCAP_ATOMIC }, + { "atomic512", SQLITE_IOCAP_ATOMIC512 }, + { "atomic1k", SQLITE_IOCAP_ATOMIC1K }, + { "atomic2k", SQLITE_IOCAP_ATOMIC2K }, + { "atomic4k", SQLITE_IOCAP_ATOMIC4K }, + { "atomic8k", SQLITE_IOCAP_ATOMIC8K }, + { "atomic16k", SQLITE_IOCAP_ATOMIC16K }, + { "atomic32k", SQLITE_IOCAP_ATOMIC32K }, + { "atomic64k", SQLITE_IOCAP_ATOMIC64K }, + { "sequential", SQLITE_IOCAP_SEQUENTIAL }, + { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, + { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN }, { 0, 0 } }; Tcl_Obj *pRet; diff --git a/test/journal2.test b/test/journal2.test index 20331b8bd1..f7145ebdf7 100644 --- a/test/journal2.test +++ b/test/journal2.test @@ -28,7 +28,7 @@ proc a_string {n} { # characteristics flags to "SAFE_DELETE". # testvfs tvfs -default 1 -tvfs devchar safe_delete +tvfs devchar undeletable_when_open # Set up a hook so that each time a journal file is opened, closed or # deleted, the method name ("xOpen", "xClose" or "xDelete") and the final From c548b78310f1899f1d5ebcb95c25768f633a7194 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 19 Jun 2010 19:06:33 +0000 Subject: [PATCH 10/13] Fix an assert() failure that could occur if compiling with OMIT_SHARED_CACHE. FossilOrigin-Name: 3e76a9f2c041a6d36614f540bb89588703d85925 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeblob.c | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index a3d01f67df..dc715a7b25 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sname\sof\sIOCAP_SAFE_DELETE\sto\sIOCAP_UNDELETABLE_WHEN_OPEN.\sHave\sthe\sxDeviceCharacteristics()\smethod\sof\sthe\swin32\sVFS\sreturn\sthis\sflag. -D 2010-06-19T18:12:03 +C Fix\san\sassert()\sfailure\sthat\scould\soccur\sif\scompiling\swith\sOMIT_SHARED_CACHE. +D 2010-06-19T19:06:34 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -222,7 +222,7 @@ F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1 F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d F src/vdbeaux.c 4e96a5169b988a8697d4a417f902277b4152e43e -F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e +F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256 F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f5df83fd875073eee8e2269e87e2a8c9c7abc981 -R 71fe53986b1289fd437e53aa98b15675 +P 5a5ff4e3e4c707464f227907d0aefb8ef42180dd +R 0e23e267b3b82742ffd6ce332fce696f U dan -Z aadd8ae68501aa286ffeda96be308372 +Z 610fee2a443c81bfcb467b2cb6ae3598 diff --git a/manifest.uuid b/manifest.uuid index dbbc0ae575..f0caada5b2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a5ff4e3e4c707464f227907d0aefb8ef42180dd \ No newline at end of file +3e76a9f2c041a6d36614f540bb89588703d85925 \ No newline at end of file diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 829b6de6dd..b2b9f0ed00 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -191,10 +191,14 @@ int sqlite3_blob_open( sqlite3VdbeUsesBtree(v, iDb); /* Configure the OP_TableLock instruction */ +#ifdef SQLITE_OMIT_SHARED_CACHE + sqlite3VdbeChangeToNoop(v, 2, 1); +#else sqlite3VdbeChangeP1(v, 2, iDb); sqlite3VdbeChangeP2(v, 2, pTab->tnum); sqlite3VdbeChangeP3(v, 2, flags); sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); +#endif /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ From 672b41beaacde22782739495fb5bc2e38290d92e Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 21 Jun 2010 05:40:49 +0000 Subject: [PATCH 11/13] Fix jrnlmode2.test so that it works on systems where UNDELETABLE_WHEN_OPEN is defined. FossilOrigin-Name: 59be370e52ec814c45efa6cbac45b6df94661b54 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/jrnlmode2.test | 34 +++++++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index dc715a7b25..f1ca3e28a6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sassert()\sfailure\sthat\scould\soccur\sif\scompiling\swith\sOMIT_SHARED_CACHE. -D 2010-06-19T19:06:34 +C Fix\sjrnlmode2.test\sso\sthat\sit\sworks\son\ssystems\swhere\sUNDELETABLE_WHEN_OPEN\sis\sdefined. +D 2010-06-21T05:40:49 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -468,7 +468,7 @@ F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19 F test/journal2.test a08ea6545d987385e7cbb1d4e7dc2eaacd83b00b F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849 -F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd +F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00 F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 @@ -824,7 +824,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 5a5ff4e3e4c707464f227907d0aefb8ef42180dd -R 0e23e267b3b82742ffd6ce332fce696f +P 3e76a9f2c041a6d36614f540bb89588703d85925 +R b870a455574cea6100e536dd46b8d81b U dan -Z 610fee2a443c81bfcb467b2cb6ae3598 +Z d0b6213f5feedc09ae1f6676dae25d67 diff --git a/manifest.uuid b/manifest.uuid index f0caada5b2..e802654324 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e76a9f2c041a6d36614f540bb89588703d85925 \ No newline at end of file +59be370e52ec814c45efa6cbac45b6df94661b54 \ No newline at end of file diff --git a/test/jrnlmode2.test b/test/jrnlmode2.test index 9a1fe37c3f..dc3bc270b4 100644 --- a/test/jrnlmode2.test +++ b/test/jrnlmode2.test @@ -9,7 +9,6 @@ # #*********************************************************************** # -# $Id: jrnlmode2.test,v 1.6 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -20,10 +19,33 @@ ifcapable {!pager_pragmas} { } #------------------------------------------------------------------------- -# Test overview: +# The tests in this file check that the following two bugs (both now fixed) +# do not reappear. # -# jrnlmode2-1.*: Demonstrate bug #3745 -# jrnlmode2-2.*: Demonstrate bug #3751 +# jrnlmode2-1.*: Demonstrate bug #3745: +# +# In persistent journal mode, if: +# +# * There is a persistent journal in the file-system, AND +# * there exists a connection with a shared lock on the db file, +# +# then a second connection cannot open a read-transaction on the database. +# The reason is because while determining that the persistent-journal is +# not a hot-journal, SQLite currently grabs an exclusive lock on the +# database file. If this fails because another connection has a shared +# lock, then SQLITE_BUSY is returned to the user. +# +# jrnlmode2-2.*: Demonstrate bug #3751: +# +# If a connection is opened in SQLITE_OPEN_READONLY mode, the underlying +# unix file descriptor on the database file is opened in O_RDONLY mode. +# +# When SQLite queries the database file for the schema in order to compile +# the SELECT statement, it sees the empty journal in the file system, it +# attempts to obtain an exclusive lock on the database file (this is a +# bug). The attempt to obtain an exclusive (write) lock on a read-only file +# fails at the OS level. Under unix, fcntl() reports an EBADF - "Bad file +# descriptor" - error. # do_test jrnlmode2-1.1 { @@ -46,6 +68,8 @@ do_test jrnlmode2-1.3 { do_test jrnlmode2-1.4 { execsql { INSERT INTO t1 VALUES(3, 4); + } + execsql { BEGIN; SELECT * FROM t1; } @@ -87,9 +111,9 @@ do_test jrnlmode2-2.4 { } {0 {1 2 3 4 5 6}} do_test jrnlmode2-2.5 { + db close file delete test.db-journal } {} - do_test jrnlmode2-2.6 { sqlite3 db2 test.db -readonly 1 catchsql { SELECT * FROM t1 } db2 From 153eda0aa469406a29a532735afc8bcae0b51a6b Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 21 Jun 2010 07:45:47 +0000 Subject: [PATCH 12/13] Add further pager tests. FossilOrigin-Name: 4104b175a8c3560a7680f3d2b54416821bb2e19d --- manifest | 19 +++-- manifest.uuid | 2 +- test/pager1.test | 182 +++++++++++++++++------------------------ test/pager2.test | 117 ++++++++++++++++++++++++++ test/pagerfault.test | 24 ++++++ test/permutations.test | 1 + test/tester.tcl | 10 +++ 7 files changed, 240 insertions(+), 115 deletions(-) create mode 100644 test/pager2.test diff --git a/manifest b/manifest index 7f2143caf9..231f496cdf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\schange. -D 2010-06-21T06:00:16 +C Add\sfurther\spager\stests. +D 2010-06-21T07:45:47 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -534,13 +534,14 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test 2842b3567589fc4881928a7febeb9342442ea449 -F test/pagerfault.test 55c7d602eaba7c08312616a4c6482606d50eed6a +F test/pager1.test e086d98a5312a7395d579117a1211d9110faffcc +F test/pager2.test ad062a51030dc1e2749f506528db4cc5bae6474c +F test/pagerfault.test e67e9c18bf7b4bb8cc8d458d3a5ecc980f18a225 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 -F test/permutations.test 97cfca3f7c390fa530c6f5c63d73eb67e5b0cd9d +F test/permutations.test 9296368f1d14d9e042f146a804ca38f551d35435 F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea @@ -611,7 +612,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3 F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6 F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 -F test/tester.tcl 7912c3c8768320fd7bcb217637c2f0a607fbbc24 +F test/tester.tcl ab89e8e592ff26e2b65ff3cae9de5f26863ae766 F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca @@ -824,7 +825,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 59be370e52ec814c45efa6cbac45b6df94661b54 822a0283c6bc1c75001f3d1c528a4ff89c6b039c -R cd73ab3d3f6400b82e1db5686eff6200 +P f6d26e07b70965e332b1589804ca938593a5f432 +R 57527134db79eb4730ccc85bc2c2f806 U dan -Z 0c29ece94fc927539688ff52cbe59deb +Z 286faa52a0364bba3d1b0d11286b24cb diff --git a/manifest.uuid b/manifest.uuid index 6b35f2cebc..e246eaf3dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f6d26e07b70965e332b1589804ca938593a5f432 \ No newline at end of file +4104b175a8c3560a7680f3d2b54416821bb2e19d \ No newline at end of file diff --git a/test/pager1.test b/test/pager1.test index 33b5c2ae04..313c0f36e0 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -14,6 +14,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl +source $testdir/wal_common.tcl # # pager1-1.*: Test inter-process locking (clients in multiple processes). @@ -28,13 +29,8 @@ source $testdir/malloc_common.tcl # # pager1-6.*: Cases related to "PRAGMA max_page_count" # - -proc do_execsql_test {testname sql result} { - uplevel do_test $testname [list "execsql {$sql}"] [list $result] -} -proc do_catchsql_test {testname sql result} { - uplevel do_test $testname [list "catchsql {$sql}"] [list $result] -} +# pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE" +# set a_string_counter 1 proc a_string {n} { @@ -216,104 +212,6 @@ do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} do_execsql_test pager1-3.6 { COMMIT } {} -set otn 0 -testvfs tv -default 1 -foreach code [list { - set s 512 -} { - set s 1024 - set sql { PRAGMA journal_mode = memory } -} { - set s 1024 - set sql { - PRAGMA journal_mode = memory; - PRAGMA locking_mode = exclusive; - } -} { - set s 2048 - tv devchar safe_append -} { - set s 4096 -} { - set s 4096 - set sql { PRAGMA journal_mode = WAL } -} { - set s 8192 - set sql { PRAGMA synchronous = off } -}] { - - incr otn - set sql "" - tv devchar {} - eval $code - tv sectorsize $s - - do_test pager1-3.7.$otn.0 { - faultsim_delete_and_reopen - execsql $sql - execsql { - PRAGMA cache_size = 10; - CREATE TABLE t1(i INTEGER PRIMARY KEY, j blob); - } - } {} - - set tn 0 - set lowpoint 0 - foreach x { - 100 x 0 100 - x - 70 22 96 59 96 50 22 56 21 16 37 64 43 40 0 38 22 38 55 0 6 - 43 62 32 93 54 18 13 29 45 66 29 25 61 31 53 82 75 25 96 86 10 69 - 2 29 6 60 80 95 42 82 85 50 68 96 90 39 78 69 87 97 48 74 65 43 - x - 86 34 26 50 41 85 58 44 89 22 6 51 45 46 58 32 97 6 1 12 32 2 - 69 39 48 71 33 31 5 58 90 43 24 54 12 9 18 57 4 38 91 42 27 45 - 50 38 56 29 10 0 26 37 83 1 78 15 47 30 75 62 46 29 68 5 30 4 - 27 96 33 95 79 75 56 10 29 70 32 75 52 88 5 36 50 57 46 63 88 65 - x - 44 95 64 20 24 35 69 61 61 2 35 92 42 46 23 98 78 1 38 72 79 35 - 94 37 13 59 5 93 27 58 80 75 58 7 67 13 10 76 84 4 8 70 81 45 - 8 41 98 5 60 26 92 29 91 90 2 62 40 4 5 22 80 15 83 76 52 88 - 29 5 68 73 72 7 54 17 89 32 81 94 51 28 53 71 8 42 54 59 70 79 - x - } { - incr tn - set now [db one {SELECT count(i) FROM t1}] - if {$x == "x"} { - execsql { COMMIT ; BEGIN } - set lowpoint $now - do_test pager1.3.7.$otn.$tn { - sqlite3 db2 test.db - execsql { - SELECT COALESCE(max(i), 0) FROM t1; - PRAGMA integrity_check; - } - } [list $lowpoint ok] - db2 close - } else { - if {$now > $x } { - if { $x>=$lowpoint } { - execsql "ROLLBACK TO sp_$x" - } else { - execsql "DELETE FROM t1 WHERE i>$x" - set lowpoint $x - } - } elseif {$now < $x} { - for {set k $now} {$k < $x} {incr k} { - execsql "SAVEPOINT sp_$k" - execsql { INSERT INTO t1(j) VALUES(randomblob(1500)) } - } - } - do_execsql_test pager1.3.7.$otn.$tn { - SELECT COALESCE(max(i), 0) FROM t1; - PRAGMA integrity_check; - } [list $x ok] - } - } -} -db close -tv delete - #------------------------------------------------------------------------- # Hot journal rollback related test cases. # @@ -620,5 +518,79 @@ do_test pager1-6.2 { } } {1 {database or disk is full}} + +#------------------------------------------------------------------------- +# The following tests work with "PRAGMA journal_mode=TRUNCATE" and +# "PRAGMA locking_mode=EXCLUSIVE". +# +# Each test is specified with 5 variables. As follows: +# +# $tn: Test Number. Used as part of the [do_test] test names. +# $sql: SQL to execute. +# $res: Expected result of executing $sql. +# $js: The expected size of the journal file, in bytes, after executing +# the SQL script. Or -1 if the journal is not expected to exist. +# $ws: The expected size of the WAL file, in bytes, after executing +# the SQL script. Or -1 if the WAL is not expected to exist. +# +faultsim_delete_and_reopen +foreach {tn sql res js ws} [subst { + + 1 { + CREATE TABLE t1(a, b); + PRAGMA auto_vacuum=OFF; + PRAGMA synchronous=NORMAL; + PRAGMA page_size=1024; + PRAGMA locking_mode=EXCLUSIVE; + PRAGMA journal_mode=TRUNCATE; + INSERT INTO t1 VALUES(1, 2); + } {exclusive truncate} 0 -1 + + 2 { + BEGIN IMMEDIATE; + SELECT * FROM t1; + COMMIT; + } {1 2} 0 -1 + + 3 { + BEGIN; + SELECT * FROM t1; + COMMIT; + } {1 2} 0 -1 + + 4 { PRAGMA journal_mode = WAL } wal -1 -1 + 5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024] + 6 { PRAGMA locking_mode = NORMAL } normal -1 [wal_file_size 1 1024] + 7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024] + + 8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1 + 9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1 + 10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1 + +}] { + do_execsql_test pager1-7.1.$tn.1 $sql $res + catch { set J -1 ; set J [file size test.db-journal] } + catch { set W -1 ; set W [file size test.db-wal] } + do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws] +} + +do_test pager1-8.1 { + faultsim_delete_and_reopen + db close + sqlite3 db :memory: + execsql { + CREATE TABLE x1(x); + INSERT INTO x1 VALUES('Charles'); + INSERT INTO x1 VALUES('James'); + INSERT INTO x1 VALUES('Mary'); + SELECT * FROM x1; + } +} {Charles James Mary} +do_test pager1-8.2 { + db close + sqlite3 db :memory: + catchsql { SELECT * FROM x1 } +} {1 {no such table: x1}} + finish_test diff --git a/test/pager2.test b/test/pager2.test new file mode 100644 index 0000000000..855850f056 --- /dev/null +++ b/test/pager2.test @@ -0,0 +1,117 @@ +# 2010 June 15 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/malloc_common.tcl + +set otn 0 +testvfs tv -default 1 +foreach code [list { + set s 512 +} { + set s 1024 + set sql { PRAGMA journal_mode = memory } +} { + set s 1024 + set sql { + PRAGMA journal_mode = memory; + PRAGMA locking_mode = exclusive; + } +} { + set s 2048 + tv devchar safe_append +} { + set s 4096 +} { + set s 4096 + set sql { PRAGMA journal_mode = WAL } +} { + set s 8192 + set sql { PRAGMA synchronous = off } +}] { + + incr otn + set sql "" + tv devchar {} + eval $code + tv sectorsize $s + + do_test pager2-1.$otn.0 { + faultsim_delete_and_reopen + execsql $sql + execsql { + PRAGMA cache_size = 10; + CREATE TABLE t1(i INTEGER PRIMARY KEY, j blob); + } + } {} + + set tn 0 + set lowpoint 0 + foreach x { + 100 x 0 100 + x + 70 22 96 59 96 50 22 56 21 16 37 64 43 40 0 38 22 38 55 0 6 + 43 62 32 93 54 18 13 29 45 66 29 25 61 31 53 82 75 25 96 86 10 69 + 2 29 6 60 80 95 42 82 85 50 68 96 90 39 78 69 87 97 48 74 65 43 + x + 86 34 26 50 41 85 58 44 89 22 6 51 45 46 58 32 97 6 1 12 32 2 + 69 39 48 71 33 31 5 58 90 43 24 54 12 9 18 57 4 38 91 42 27 45 + 50 38 56 29 10 0 26 37 83 1 78 15 47 30 75 62 46 29 68 5 30 4 + 27 96 33 95 79 75 56 10 29 70 32 75 52 88 5 36 50 57 46 63 88 65 + x + 44 95 64 20 24 35 69 61 61 2 35 92 42 46 23 98 78 1 38 72 79 35 + 94 37 13 59 5 93 27 58 80 75 58 7 67 13 10 76 84 4 8 70 81 45 + 8 41 98 5 60 26 92 29 91 90 2 62 40 4 5 22 80 15 83 76 52 88 + 29 5 68 73 72 7 54 17 89 32 81 94 51 28 53 71 8 42 54 59 70 79 + x + } { + incr tn + set now [db one {SELECT count(i) FROM t1}] + if {$x == "x"} { + execsql { COMMIT ; BEGIN } + set lowpoint $now + do_test pager2.1.$otn.$tn { + sqlite3 db2 test.db + execsql { + SELECT COALESCE(max(i), 0) FROM t1; + PRAGMA integrity_check; + } + } [list $lowpoint ok] + db2 close + } else { + if {$now > $x } { + if { $x>=$lowpoint } { + execsql "ROLLBACK TO sp_$x" + } else { + execsql "DELETE FROM t1 WHERE i>$x" + set lowpoint $x + } + } elseif {$now < $x} { + for {set k $now} {$k < $x} {incr k} { + execsql "SAVEPOINT sp_$k" + execsql { INSERT INTO t1(j) VALUES(randomblob(1500)) } + } + } + do_execsql_test pager2.1.$otn.$tn { + SELECT COALESCE(max(i), 0) FROM t1; + PRAGMA integrity_check; + } [list $x ok] + } + } +} +db close +tv delete + + +finish_test diff --git a/test/pagerfault.test b/test/pagerfault.test index 81a62ed7ea..0af8d51807 100644 --- a/test/pagerfault.test +++ b/test/pagerfault.test @@ -241,6 +241,30 @@ do_faultsim_test pagerfault-5.3 -prep { faultsim_test_result {0 {}} } +#------------------------------------------------------------------------- +# Test fault-injection as part of a commit when using +# journal_mode=TRUNCATE. +# +do_test pagerfault-6-pre1 { + faultsim_delete_and_reopen + db func a_string a_string + execsql { + CREATE TABLE t1(a UNIQUE, b UNIQUE); + INSERT INTO t1 VALUES(a_string(200), a_string(300)); + } + faultsim_save_and_close +} {} +do_faultsim_test pagerfault-6.1 -prep { + faultsim_restore_and_reopen + db func a_string a_string + execsql { PRAGMA journal_mode = TRUNCATE } +} -body { + execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } +} -test { + faultsim_test_result {0 {}} + faultsim_integrity_check +} + # The following was an attempt to get a bitvec malloc to fail. Didn't work. # # do_test pagerfault-6-pre1 { diff --git a/test/permutations.test b/test/permutations.test index 27f795676a..e1846c13ac 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -169,6 +169,7 @@ test_suite "coverage-pager" -description { Coverage tests for file pager.c. } -files { pager1.test + pager2.test pagerfault.test journal2.test } diff --git a/test/tester.tcl b/test/tester.tcl index 625bdcc3ee..d6ce7eac28 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -49,6 +49,8 @@ # crashsql ARGS... # integrity_check TESTNAME ?DB? # do_test TESTNAME SCRIPT EXPECTED +# do_execsql_test TESTNAME SQL EXPECTED +# do_catchsql_test TESTNAME SQL EXPECTED # # Commands providing a lower level interface to the global test counters: # @@ -316,6 +318,14 @@ proc do_test {name cmd expected} { } flush stdout } + +proc do_execsql_test {testname sql result} { + uplevel do_test $testname [list "execsql {$sql}"] [list $result] +} +proc do_catchsql_test {testname sql result} { + uplevel do_test $testname [list "catchsql {$sql}"] [list $result] +} + # Run an SQL script. # Return the number of microseconds per statement. From e08341c664e41bb084a7a95bfb47b90b13868694 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 21 Jun 2010 12:34:29 +0000 Subject: [PATCH 13/13] Change things so that journal2.test works with ENABLE_ATOMIC_WRITE. FossilOrigin-Name: a64d96db09ef2b7651fa4e98d3c7bf3ae5d3fe96 --- manifest | 16 ++--- manifest.uuid | 2 +- src/pager.c | 19 +++--- test/malloc_common.tcl | 6 +- test/pager1.test | 152 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 173 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 231f496cdf..e54d79b686 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sfurther\spager\stests. -D 2010-06-21T07:45:47 +C Change\sthings\sso\sthat\sjournal2.test\sworks\swith\sENABLE_ATOMIC_WRITE. +D 2010-06-21T12:34:30 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19 F src/os_unix.c 5231a75a3799872b1250bc70c0e6a1a5960bc865 F src/os_win.c 73608839342de32280cb378d3c2fc85a5dd80bd2 -F src/pager.c 6ebb43239ad4ae2c0b0720bbd88a6a84a301bc8a +F src/pager.c 9f138b79b47090c1e31efe3d9ea191cc92981643 F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 @@ -509,7 +509,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 -F test/malloc_common.tcl 4981dd86adf0d3f25c755ac3a425d6208fda6362 +F test/malloc_common.tcl 58caffc4be307b56c5b1438b5eba3eb278bd81f5 F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 @@ -534,7 +534,7 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test e086d98a5312a7395d579117a1211d9110faffcc +F test/pager1.test 86d034bf3ffe4e99648714443776440d0555f705 F test/pager2.test ad062a51030dc1e2749f506528db4cc5bae6474c F test/pagerfault.test e67e9c18bf7b4bb8cc8d458d3a5ecc980f18a225 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 @@ -825,7 +825,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f6d26e07b70965e332b1589804ca938593a5f432 -R 57527134db79eb4730ccc85bc2c2f806 +P 4104b175a8c3560a7680f3d2b54416821bb2e19d +R aa81338105a8066f92038016780c9df7 U dan -Z 286faa52a0364bba3d1b0d11286b24cb +Z 4c6c5e973462d689a9ddf24faae3aa9f diff --git a/manifest.uuid b/manifest.uuid index e246eaf3dc..003bedc572 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4104b175a8c3560a7680f3d2b54416821bb2e19d \ No newline at end of file +a64d96db09ef2b7651fa4e98d3c7bf3ae5d3fe96 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 3d16c66f25..a5377d4c3a 100644 --- a/src/pager.c +++ b/src/pager.c @@ -336,7 +336,6 @@ struct Pager { u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ - u8 safeJrnlHandle; /* True if jrnl may be held open with no lock */ /* The following block contains those class members that are dynamically ** modified during normal operations. The other variables in this structure @@ -1220,14 +1219,20 @@ static int pagerUseWal(Pager *pPager){ static void pager_unlock(Pager *pPager){ if( !pPager->exclusiveMode ){ int rc = SQLITE_OK; /* Return code */ + int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):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->safeJrnlHandle==0 - || (pPager->journalMode!=PAGER_JOURNALMODE_TRUNCATE - && pPager->journalMode!=PAGER_JOURNALMODE_PERSIST) + assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 ); + assert( (PAGER_JOURNALMODE_OFF & 5)!=1 ); + assert( (PAGER_JOURNALMODE_WAL & 5)!=1 ); + assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 ); + assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); + assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); + if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN) + || 1!=(pPager->journalMode & 5) ){ sqlite3OsClose(pPager->jfd); } @@ -3096,7 +3101,6 @@ int sqlite3PagerClose(Pager *pPager){ sqlite3BeginBenignMalloc(); pPager->errCode = 0; pPager->exclusiveMode = 0; - pPager->safeJrnlHandle = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, (pPager->noSync ? 0 : pPager->sync_flags), @@ -3123,6 +3127,7 @@ int sqlite3PagerClose(Pager *pPager){ enable_simulated_io_errors(); PAGERTRACE(("CLOSE %d\n", PAGERID(pPager))); IOTRACE(("CLOSE %p\n", pPager)) + sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); @@ -4507,10 +4512,6 @@ static int pager_open_journal(Pager *pPager){ ); #else rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); - if( rc==SQLITE_OK ){ - int iDc = sqlite3OsDeviceCharacteristics(pPager->jfd); - pPager->safeJrnlHandle = (iDc&SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)!=0; - } #endif } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index dc68b1b53a..8202b19aff 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -136,14 +136,14 @@ proc faultsim_save_and_close {} { catch { db close } return "" } -proc faultsim_restore_and_reopen {} { +proc faultsim_restore_and_reopen {{dbfile test.db}} { catch { db close } foreach f [glob -nocomplain test.db*] { file delete -force $f } foreach f2 [glob -nocomplain sv_test.db*] { set f [string range $f2 3 end] file copy -force $f2 $f } - sqlite3 db test.db + sqlite3 db $dbfile sqlite3_extended_result_codes db 1 sqlite3_db_config_lookaside db 0 0 0 } @@ -156,7 +156,7 @@ proc faultsim_integrity_check {{db db}} { proc faultsim_delete_and_reopen {{file test.db}} { catch { db close } foreach f [glob -nocomplain test.db*] { file delete -force $f } - sqlite3 db test.db + sqlite3 db $file } diff --git a/test/pager1.test b/test/pager1.test index 313c0f36e0..f7a821b6d2 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -227,6 +227,13 @@ do_execsql_test pager1-3.6 { COMMIT } {} # pager1.4.3.*: Test that the contents of a hot-journal are ignored if the # page-size or sector-size in the journal header appear to # be invalid (too large, too small or not a power of 2). +# +# pager1.4.4.*: Test hot-journal rollback of journal file with a master +# journal pointer generated in various "PRAGMA synchronous" +# modes. +# +# pager1.4.5.*: Test that hot-journal rollback stops if it encounters a +# journal-record for which the checksum fails. # do_test pager1.4.1.1 { faultsim_delete_and_reopen @@ -354,6 +361,146 @@ foreach {tn ofst value result} { } db close +# Set up a VFS that snapshots the file-system just before a master journal +# file is deleted to commit a multi-file transaction. Specifically, the +# file-system is saved just before the xDelete() call to remove the +# master journal file from the file-system. +# +testvfs tv -default 1 +tv script copy_on_mj_delete +set ::mj_filename_length 0 +proc copy_on_mj_delete {method filename args} { + if {[string match *mj* [file tail $filename]]} { + set ::mj_filename_length [string length $filename] + faultsim_save + } + return SQLITE_OK +} + +set pwd [pwd] +foreach {tn1 tcl} { + 1 { set prefix "test.db" } + 2 { + # This test depends on the underlying VFS being able to open paths + # 512 bytes in length. The idea is to create a hot-journal file that + # contains a master-journal pointer so large that it could contain + # a valid page record (if the file page-size is 512 bytes). So as to + # make sure SQLite doesn't get confused by this. + # + set nPadding [expr 511 - $::mj_filename_length] + + # We cannot just create a really long database file name to open, as + # Linux limits a single component of a path to 255 bytes by default + # (and presumably other systems have limits too). So create a directory + # hierarchy to work in. + # + set dirname "d123456789012345678901234567890/" + set nDir [expr $nPadding / 32] + if { $nDir } { + set p [string repeat $dirname $nDir] + file mkdir $p + cd $p + } + + set padding [string repeat x [expr $nPadding %32]] + set prefix "test.db${padding}" + } +} { + eval $tcl + foreach {tn2 sql} { + o { + PRAGMA main.synchronous=OFF; + PRAGMA aux.synchronous=OFF; + } + o512 { + PRAGMA main.synchronous=OFF; + PRAGMA aux.synchronous=OFF; + PRAGMA main.page_size = 512; + PRAGMA aux.page_size = 512; + } + n { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + } + f { + PRAGMA main.synchronous=FULL; + PRAGMA aux.synchronous=FULL; + } + } { + + set tn "${tn1}.${tn2}" + + # Set up a connection to have two databases, test.db (main) and + # test.db2 (aux). Then run a multi-file transaction on them. The + # VFS will snapshot the file-system just before the master-journal + # file is deleted to commit the transaction. + # + tv filter xDelete + do_test pager1-4.4.$tn.1 { + faultsim_delete_and_reopen $prefix + execsql " + ATTACH '${prefix}2' AS aux; + $sql + CREATE TABLE a(x); + CREATE TABLE aux.b(x); + INSERT INTO a VALUES('double-you'); + INSERT INTO a VALUES('why'); + INSERT INTO a VALUES('zed'); + INSERT INTO b VALUES('won'); + INSERT INTO b VALUES('too'); + INSERT INTO b VALUES('free'); + " + execsql { + BEGIN; + INSERT INTO a SELECT * FROM b WHERE rowid<=3; + INSERT INTO b SELECT * FROM a WHERE rowid<=3; + COMMIT; + } + } {} + tv filter {} + + # Check that the transaction was committed successfully. + # + do_execsql_test pager1-4.4.$tn.2 { + SELECT * FROM a + } {double-you why zed won too free} + do_execsql_test pager1-4.4.$tn.3 { + SELECT * FROM b + } {won too free double-you why zed} + + # Restore the file-system and reopen the databases. Check that it now + # appears that the transaction was not committed (because the file-system + # was restored to the state where it had not been). + # + do_test pager1-4.4.$tn.4 { + faultsim_restore_and_reopen $prefix + execsql "ATTACH '${prefix}2' AS aux" + } {} + do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} + do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} + + # Restore the file-system again. This time, before reopening the databases, + # delete the master-journal file from the file-system. It now appears that + # the transaction was committed (no master-journal file == no rollback). + # + do_test pager1-4.4.$tn.7 { + faultsim_restore_and_reopen $prefix + foreach f [glob ${prefix}-mj*] { file delete -force $f } + execsql "ATTACH '${prefix}2' AS aux" + } {} + do_execsql_test pager1-4.4.$tn.8 { + SELECT * FROM a + } {double-you why zed won too free} + do_execsql_test pager1-4.4.$tn.9 { + SELECT * FROM b + } {won too free double-you why zed} + } + + cd $pwd +} +db close +tv delete + #------------------------------------------------------------------------- # The following tests deal with multi-file commits. # @@ -373,7 +520,10 @@ db close # name does not lie on the same sector as the last journal file # record. # -# pager1-5.5.*: +# pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is +# truncated to zero bytes when a multi-file transaction is +# committed (instead of the first couple of bytes being zeroed). +# # do_test pager1-5.1.1 { faultsim_delete_and_reopen