From 8c408004394dfa0997feb2f28436a0481f3ce679 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 1 Nov 2010 17:38:24 +0000 Subject: [PATCH] If a database file with the WAL flag set is opened in exclusive-locking mode, use heap memory to store the wal-index instead of shared-memory. FossilOrigin-Name: 8dd5c69198619866923c6053b71899c1fb8c4c67 --- manifest | 41 +++++------- manifest.uuid | 2 +- src/pager.c | 78 +++++++++++++++++----- src/test_vfs.c | 1 + src/wal.c | 60 ++++++++++++++--- src/wal.h | 9 ++- test/pager1.test | 8 +-- test/permutations.test | 2 +- test/tester.tcl | 2 + test/wal2.test | 11 +++- test/walfault.test | 68 +++++++++++++++++++ test/walnoshm.test | 146 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 366 insertions(+), 62 deletions(-) create mode 100644 test/walnoshm.test diff --git a/manifest b/manifest index 147d5a4acc..2590bc11f4 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,5 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA1 - -C Change\sthe\sversion\snumber\sto\s3.7.4. -D 2010-11-01T14:34:31 +C If\sa\sdatabase\sfile\swith\sthe\sWAL\sflag\sset\sis\sopened\sin\sexclusive-locking\smode,\suse\sheap\smemory\sto\sstore\sthe\swal-index\sinstead\sof\sshared-memory. +D 2010-11-01T17:38:25 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2c8cefd962eca0147132c7cf9eaa4bb24c656f3f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -165,7 +162,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_unix.c 00a4a84aba46b61439913bebf0c10d408e42a630 F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad -F src/pager.c d9858b47b216e3bcb0431bd50ef17d070ac0b92c +F src/pager.c c19b0e8d49220825fd382236fbbcb3063c48ce2d F src/pager.h 8167a1e720d0b7a2790079007128e594010220ad F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa @@ -221,7 +218,7 @@ F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0 -F src/test_vfs.c 702e52636113f6b9721da90ef1bf26e07fff414d +F src/test_vfs.c e10fcca756cafa89438311b31522ac1f95bf784b F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852 @@ -238,8 +235,8 @@ F src/vdbeblob.c e0ce3c54cc0c183af2ec67b63a289acf92251df4 F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30 -F src/wal.c 0dc7eb9e907a2c280cdcde876d313e07ea4ad811 -F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c +F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e +F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c d9a31eb3d59466b6c53567c8c9a6c2fe68bbd565 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -569,7 +566,7 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec -F test/pager1.test 12ad20280db1ba25f1f0d7ddebf0971a305d8f80 +F test/pager1.test fa74657dc832f0e21dc3ce60829feaee143296ba F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pagerfault.test 3cd3537bf2efb4baef26c74878718f4a32926da4 @@ -578,7 +575,7 @@ F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 -F test/permutations.test da40da6433f050b50e65a8ae37265ab6c89f876c +F test/permutations.test e54d5fc34708ecb4a67f2a18f7b8719b175a1652 F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea @@ -655,7 +652,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 -F test/tester.tcl b9c732d1228f0daab41bbbeddd6d0861394b23aa +F test/tester.tcl fa48313dcf20f9c6def1af485e284e29100d709e F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca @@ -823,7 +820,7 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d F test/wal.test 70227190e713b3e7eb2a7d5ec3510b66db01f327 -F test/wal2.test 223f3e14d475730af772a7f5862d4bcfa7565c3a +F test/wal2.test c794b8b257af54190bb913678ad3984cbf3311b9 F test/wal3.test 957a5f2a8fe8a6ff01de1a15285ecf2f376fcaf8 F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 F test/wal_common.tcl 895d76138043b86bdccf36494054bdabcf65837b @@ -832,9 +829,10 @@ F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0 F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce F test/walcrash.test e763841551d6b23677ccb419797c1589dcbdbaf5 F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142 -F test/walfault.test 05c470688d742688e455dd56816bd6bcffa298f8 +F test/walfault.test 1211c3c5f35142d93940c709c61fbaf58c3afab6 F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483 F test/walmode.test 22ddccd073c817ac9ead62b88ac446e8dedc7d2c +F test/walnoshm.test 732391f72af2785d2758aaa8f9ae563d6d519b20 F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933 F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c @@ -884,14 +882,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 582db83294599ffd7265d3ab2db2765e7e4fbb8d -R a1ed7a266761633aef3d19047277de6a -U drh -Z 4f48c9a1b8040f4fd58227e590b304c6 ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.6 (GNU/Linux) - -iD8DBQFMzs/6oxKgR168RlERAuCbAJ9uimmTB547wDq4mUtvniDAfA0HTwCeNbhj -lkScdJYDKuse8cKgqrNrUF4= -=7Gng ------END PGP SIGNATURE----- +P db64843b540d23c58fe4de199a7fc40d44900bc4 +R 2b6e847446dd321925fabfa8d797522d +U dan +Z 4b3ff964892084a664463cd0c913ef99 diff --git a/manifest.uuid b/manifest.uuid index faac2fc344..0c247a0a33 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db64843b540d23c58fe4de199a7fc40d44900bc4 \ No newline at end of file +8dd5c69198619866923c6053b71899c1fb8c4c67 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index a1cc4e0500..f748a443ef 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1050,7 +1050,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ static int pagerUnlockDb(Pager *pPager, int eLock){ int rc = SQLITE_OK; - assert( !pPager->exclusiveMode ); + assert( !pPager->exclusiveMode || pPager->eLock==eLock ); assert( eLock==NO_LOCK || eLock==SHARED_LOCK ); assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); if( isOpen(pPager->fd) ){ @@ -6350,7 +6350,8 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_QUERY<0 ); assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 ); - if( eMode>=0 && !pPager->tempFile ){ + assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) ); + if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){ pPager->exclusiveMode = (u8)eMode; } return (int)pPager->exclusiveMode; @@ -6537,9 +6538,61 @@ int sqlite3PagerWalCallback(Pager *pPager){ */ int sqlite3PagerWalSupported(Pager *pPager){ const sqlite3_io_methods *pMethods = pPager->fd->pMethods; - return pMethods->iVersion>=2 && pMethods->xShmMap!=0; + return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap); } +/* +** Attempt to take an exclusive lock on the database file. If a PENDING lock +** is obtained instead, immediately release it. +*/ +static int pagerExclusiveLock(Pager *pPager){ + int rc; /* Return code */ + + assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + /* If the attempt to grab the pending lock failed, release the + ** exclusive lock that may have been obtained instead. */ + pagerUnlockDb(pPager, SHARED_LOCK); + } + + return rc; +} + +/* +** Call sqlite3WalOpen() to open the WAL handle. If the pager is in +** exclusive-locking mode when this function is called, take an EXCLUSIVE +** lock on the database file and use heap-memory to store the wal-index +** in. Otherwise, use the normal shared-memory. +*/ +static int pagerOpenWal(Pager *pPager){ + int rc = SQLITE_OK; + + assert( pPager->pWal==0 && pPager->tempFile==0 ); + assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); + + /* If the pager is already in exclusive-mode, the WAL module will use + ** heap-memory for the wal-index instead of the VFS shared-memory + ** implementation. Take the exclusive lock now, before opening the WAL + ** file, to make sure this is safe. + */ + if( pPager->exclusiveMode ){ + rc = pagerExclusiveLock(pPager); + } + + /* Open the connection to the log file. If this operation fails, + ** (e.g. due to malloc() failure), return an error code. + */ + if( rc==SQLITE_OK ){ + rc = sqlite3WalOpen(pPager->pVfs, + pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal + ); + } + + return rc; +} + + /* ** The caller must be holding a SHARED lock on the database file to call ** this function. @@ -6573,11 +6626,7 @@ int sqlite3PagerOpenWal( /* Close any rollback journal previously open */ sqlite3OsClose(pPager->jfd); - /* Open the connection to the log file. If this operation fails, - ** (e.g. due to malloc() failure), unlock the database file and - ** return an error code. - */ - rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal); + rc = pagerOpenWal(pPager); if( rc==SQLITE_OK ){ pPager->journalMode = PAGER_JOURNALMODE_WAL; pPager->eState = PAGER_OPEN; @@ -6616,8 +6665,7 @@ int sqlite3PagerCloseWal(Pager *pPager){ ); } if( rc==SQLITE_OK && logexists ){ - rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, - pPager->zWal, &pPager->pWal); + rc = pagerOpenWal(pPager); } } @@ -6625,17 +6673,13 @@ int sqlite3PagerCloseWal(Pager *pPager){ ** the database file, the log and log-summary files will be deleted. */ if( rc==SQLITE_OK && pPager->pWal ){ - rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, - (pPager->noSync ? 0 : pPager->sync_flags), - pPager->pageSize, (u8*)pPager->pTmpSpace + (pPager->noSync ? 0 : pPager->sync_flags), + pPager->pageSize, (u8*)pPager->pTmpSpace ); pPager->pWal = 0; - }else{ - /* If we cannot get an EXCLUSIVE lock, downgrade the PENDING lock - ** that we did get back to SHARED. */ - pagerUnlockDb(pPager, SQLITE_LOCK_SHARED); } } return rc; diff --git a/src/test_vfs.c b/src/test_vfs.c index c606cfbe5c..ebe4a576a4 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -26,6 +26,7 @@ ** -default BOOLEAN (True to make the vfs default. Default false) ** -szosfile INTEGER (Value for sqlite3_vfs.szOsFile) ** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname) +** -iversion INTEGER (Value for sqlite3_vfs.iVersion) */ #include "sqlite3.h" diff --git a/src/wal.c b/src/wal.c index f90faa238d..3b217908b7 100644 --- a/src/wal.c +++ b/src/wal.c @@ -428,6 +428,13 @@ struct Wal { #endif }; +/* +** Candidate values for Wal.exclusiveMode. +*/ +#define WAL_NORMAL_MODE 0 +#define WAL_EXCLUSIVE_MODE 1 +#define WAL_HEAPMEMORY_MODE 2 + /* ** Each page of the wal-index mapping contains a hash-table made up of ** an array of HASHTABLE_NSLOT elements of the following type. @@ -514,9 +521,14 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ /* Request a pointer to the required page from the VFS */ if( pWal->apWiData[iPage]==0 ){ - rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, - pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] - ); + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); + if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM; + }else{ + rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, + pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] + ); + } } *ppPage = pWal->apWiData[iPage]; @@ -599,6 +611,12 @@ static void walChecksumBytes( aOut[1] = s2; } +static void walShmBarrier(Wal *pWal){ + if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ + sqlite3OsShmBarrier(pWal->pDbFd); + } +} + /* ** Write the header information in pWal->hdr into the wal-index. ** @@ -613,7 +631,7 @@ static void walIndexWriteHdr(Wal *pWal){ pWal->hdr.iVersion = WALINDEX_MAX_VERSION; walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum); memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr)); - sqlite3OsShmBarrier(pWal->pDbFd); + walShmBarrier(pWal); memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr)); } @@ -1185,7 +1203,15 @@ recovery_error: ** Close an open wal-index. */ static void walIndexClose(Wal *pWal, int isDelete){ - sqlite3OsShmUnmap(pWal->pDbFd, isDelete); + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + int i; + for(i=0; inWiData; i++){ + sqlite3_free((void *)pWal->apWiData[i]); + pWal->apWiData[i] = 0; + } + }else{ + sqlite3OsShmUnmap(pWal->pDbFd, isDelete); + } } /* @@ -1207,6 +1233,7 @@ int sqlite3WalOpen( sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ sqlite3_file *pDbFd, /* The open database file */ const char *zWalName, /* Name of the WAL file */ + int bNoShm, /* True to run in heap-memory mode */ Wal **ppWal /* OUT: Allocated Wal handle */ ){ int rc; /* Return Code */ @@ -1240,6 +1267,7 @@ int sqlite3WalOpen( pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->zWalName = zWalName; + pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); @@ -1673,7 +1701,9 @@ int sqlite3WalClose( */ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ - pWal->exclusiveMode = 1; + if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ + pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; + } rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf); if( rc==SQLITE_OK ){ isDelete = 1; @@ -1729,7 +1759,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ */ aHdr = walIndexHdr(pWal); memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); - sqlite3OsShmBarrier(pWal->pDbFd); + walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ @@ -1930,7 +1960,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** and can be safely ignored. */ rc = walLockShared(pWal, WAL_READ_LOCK(0)); - sqlite3OsShmBarrier(pWal->pDbFd); + walShmBarrier(pWal); if( rc==SQLITE_OK ){ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ /* It is not safe to allow the reader to continue here if frames @@ -2024,7 +2054,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** log-wrap (either of which would require an exclusive lock on ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid. */ - sqlite3OsShmBarrier(pWal->pDbFd); + walShmBarrier(pWal); if( pInfo->aReadMark[mxI]!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ @@ -2667,13 +2697,14 @@ int sqlite3WalCallback(Wal *pWal){ ** on the main database file before invoking this operation. ** ** If op is negative, then do a dry-run of the op==1 case but do -** not actually change anything. The pager uses this to see if it +** not actually change anything. The pager uses this to see if it ** should acquire the database exclusive lock prior to invoking ** the op==1 case. */ int sqlite3WalExclusiveMode(Wal *pWal, int op){ int rc; assert( pWal->writeLock==0 ); + assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 ); /* pWal->readLock is usually set, but might be -1 if there was a ** prior error while attempting to acquire are read-lock. This cannot @@ -2707,4 +2738,13 @@ int sqlite3WalExclusiveMode(Wal *pWal, int op){ return rc; } +/* +** Return true if the argument is non-NULL and the WAL module is using +** heap-memory for the wal-index. Otherwise, if the argument is NULL or the +** WAL module is using shared-memory, return false. +*/ +int sqlite3WalHeapMemory(Wal *pWal){ + return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); +} + #endif /* #ifndef SQLITE_OMIT_WAL */ diff --git a/src/wal.h b/src/wal.h index f20dfa8e17..35f695c88a 100644 --- a/src/wal.h +++ b/src/wal.h @@ -35,6 +35,7 @@ # define sqlite3WalCheckpoint(u,v,w,x) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 +# define sqlite3WalHeapMemory(z) 0 #else #define WAL_SAVEPOINT_NDATA 4 @@ -45,7 +46,7 @@ typedef struct Wal Wal; /* Open and close a connection to a write-ahead log. */ -int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**); +int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**); int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); /* Used by readers to open (lock) and close (unlock) a snapshot. A @@ -102,5 +103,11 @@ int sqlite3WalCallback(Wal *pWal); */ int sqlite3WalExclusiveMode(Wal *pWal, int op); +/* Return true if the argument is non-NULL and the WAL module is using +** heap-memory for the wal-index. Otherwise, if the argument is NULL or the +** WAL module is using shared-memory, return false. +*/ +int sqlite3WalHeapMemory(Wal *pWal); + #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* _WAL_H_ */ diff --git a/test/pager1.test b/test/pager1.test index b09730d529..1e162654fe 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -1107,10 +1107,10 @@ ifcapable wal { 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] + 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 } exclusive -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 diff --git a/test/permutations.test b/test/permutations.test index 83ee11e53c..14cf3abfe6 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -183,7 +183,7 @@ test_suite "coverage-wal" -description { } -files { wal.test wal2.test wal3.test walmode.test walbak.test walhook.test walcrash2.test walcksum.test - walfault.test walbig.test + walfault.test walbig.test walnoshm.test } test_suite "coverage-pager" -description { diff --git a/test/tester.tcl b/test/tester.tcl index 00692ef09f..22586fbd30 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -303,6 +303,8 @@ proc do_test {name cmd expected} { global argv cmdlinearg + fix_testname name + sqlite3_memdebug_settitle $name # if {[llength $argv]==0} { diff --git a/test/wal2.test b/test/wal2.test index 03c0018f49..a62e9b99e6 100644 --- a/test/wal2.test +++ b/test/wal2.test @@ -430,13 +430,16 @@ do_test wal2-6.1.1 { sqlite3 db test.db execsql { Pragma Journal_Mode = Wal; - Pragma Locking_Mode = Exclusive; } -} {wal exclusive} +} {wal} do_test wal2-6.1.2 { execsql { PRAGMA lock_status } } {main unlocked temp closed} do_test wal2-6.1.3 { + execsql { + SELECT * FROM sqlite_master; + Pragma Locking_Mode = Exclusive; + } execsql { BEGIN; CREATE TABLE t1(a, b); @@ -486,6 +489,7 @@ do_test wal2-6.2.2 { do_test wal2-6.2.3 { db close sqlite3 db test.db + execsql { SELECT * FROM sqlite_master } execsql { PRAGMA LOCKING_MODE = EXCLUSIVE } } {exclusive} do_test wal2-6.2.4 { @@ -732,6 +736,7 @@ do_test wal2-6.6.1 { T script lock_control T filter {} sqlite3 db test.db -vfs T + execsql { SELECT * FROM sqlite_master } execsql { PRAGMA locking_mode = exclusive } execsql { INSERT INTO t2 VALUES('V', 'VI') } } {} @@ -755,7 +760,7 @@ do_test wal2-6.6.2 { T filter {} execsql { INSERT INTO t2 VALUES('IX', 'X') } } {} -do_test wal2-6.6.3 { +do_test wal2-6.6.4 { # This time, we have successfully exited exclusive mode. So the second # connection can read the database. sqlite3 db2 test.db -vfs T diff --git a/test/walfault.test b/test/walfault.test index f22a40ecfd..5fd71bc04d 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -446,5 +446,73 @@ do_faultsim_test walfault-12 -prep { faultsim_test_result {0 {}} } +#------------------------------------------------------------------------- +# Test simple recovery, reading and writing a database file using a +# heap-memory wal-index. +# +do_test walfault-13-pre-1 { + faultsim_delete_and_reopen + execsql { + PRAGMA journal_mode = WAL; + PRAGMA wal_autocheckpoint = 0; + BEGIN; + CREATE TABLE abc(a PRIMARY KEY); + INSERT INTO abc VALUES(randomblob(1500)); + INSERT INTO abc VALUES(randomblob(1500)); + COMMIT; + } + faultsim_save_and_close + file delete sv_test.db-shm +} {} + +do_faultsim_test walfault-13.1 -prep { + faultsim_restore_and_reopen +} -body { + db eval { PRAGMA locking_mode = exclusive } + db eval { SELECT count(*) FROM abc } +} -test { + faultsim_test_result {0 2} + if {[file exists test.db-shm]} { error "Not using heap-memory mode" } + faultsim_integrity_check +} + +do_faultsim_test walfault-13.2 -prep { + faultsim_restore_and_reopen + db eval { PRAGMA locking_mode = exclusive } +} -body { + db eval { PRAGMA journal_mode = delete } +} -test { + faultsim_test_result {0 delete} + if {[file exists test.db-shm]} { error "Not using heap-memory mode" } + faultsim_integrity_check +} + +do_test walfault-13-pre-2 { + faultsim_delete_and_reopen + execsql { + BEGIN; + CREATE TABLE abc(a PRIMARY KEY); + INSERT INTO abc VALUES(randomblob(1500)); + INSERT INTO abc VALUES(randomblob(1500)); + COMMIT; + } + faultsim_save_and_close +} {} + +do_faultsim_test walfault-13.3 -prep { + faultsim_restore_and_reopen +} -body { + db eval { + PRAGMA locking_mode = exclusive; + PRAGMA journal_mode = WAL; + INSERT INTO abc VALUES(randomblob(1500)); + } +} -test { + faultsim_test_result {0 {exclusive wal}} + if {[file exists test.db-shm]} { error "Not using heap-memory mode" } + faultsim_integrity_check + set nRow [db eval {SELECT count(*) FROM abc}] + if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } +} finish_test diff --git a/test/walnoshm.test b/test/walnoshm.test new file mode 100644 index 0000000000..a2f1900663 --- /dev/null +++ b/test/walnoshm.test @@ -0,0 +1,146 @@ +# 2010 November 1 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing that WAL databases may be accessed without +# using the xShm primitives if the connection is in exclusive-mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix walnoshm +ifcapable !wal {finish_test ; return } + +db close +testvfs tvfsshm +testvfs tvfs -default 1 -iversion 1 +sqlite3 db test.db + +#-------------------------------------------------------------------------- +# Test that when using a version 1 VFS, a database can only be converted +# to WAL mode after setting locking_mode=EXCLUSIVE. Also, test that if a +# WAL database is opened using heap-memory for the WAL index, the connection +# cannot change back to locking_mode=NORMAL while the database is still in +# WAL mode. +# +do_execsql_test 1.1 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); +} + +do_execsql_test 1.2 { + PRAGMA journal_mode = WAL; + SELECT * FROM t1; +} {delete 1 2} +do_test 1.3 { file exists test.db-wal } {0} + +do_execsql_test 1.4 { + PRAGMA locking_mode = exclusive; + PRAGMA journal_mode = WAL; + SELECT * FROM t1; +} {exclusive wal 1 2} +do_test 1.5 { file exists test.db-wal } {1} + +do_execsql_test 1.6 { INSERT INTO t1 VALUES(3, 4) } + +do_execsql_test 1.7 { + PRAGMA locking_mode = normal; +} {exclusive} +do_execsql_test 1.8 { + PRAGMA journal_mode = delete; + PRAGMA main.locking_mode; +} {delete exclusive} +do_execsql_test 1.9 { + PRAGMA locking_mode = normal; +} {normal} +do_execsql_test 1.10 { + SELECT * FROM t1; +} {1 2 3 4} +do_test 1.11 { file exists test.db-wal } {0} + +#------------------------------------------------------------------------- +# +# 2.1.*: Test that a connection using a version 1 VFS can open a WAL database +# and convert it to rollback mode if it is set to use +# locking_mode=exclusive. +# +# 2.2.*: Test that if the exclusive lock cannot be obtained while attempting +# the above, the operation fails and the WAL file is not opened. +# +do_execsql_test 2.1.1 { + CREATE TABLE t2(x, y); + INSERT INTO t2 VALUES('a', 'b'); + INSERT INTO t2 VALUES('c', 'd'); +} +do_execsql_test 2.1.2 { + PRAGMA locking_mode = exclusive; + PRAGMA journal_mode = WAL; + INSERT INTO t2 VALUES('e', 'f'); + INSERT INTO t2 VALUES('g', 'h'); +} {exclusive wal} + +do_test 2.1.3 { + file copy -force test.db test2.db + file copy -force test.db-wal test2.db-wal + sqlite3 db2 test2.db + catchsql { SELECT * FROM t2 } db2 +} {1 {unable to open database file}} +do_test 2.1.4 { + catchsql { PRAGMA journal_mode = delete } db2 +} {1 {unable to open database file}} +do_test 2.1.5 { + execsql { + PRAGMA locking_mode = exclusive; + PRAGMA journal_mode = delete; + SELECT * FROM t2; + } db2 +} {exclusive delete a b c d e f g h} + +do_test 2.2.1 { + file copy -force test.db test2.db + file copy -force test.db-wal test2.db-wal + sqlite3 db3 test2.db -vfs tvfsshm + sqlite3 db2 test2.db + execsql { SELECT * FROM t2 } db3 +} {a b c d e f g h} + +do_test 2.2.2 { + execsql { PRAGMA locking_mode = exclusive } db2 + catchsql { PRAGMA journal_mode = delete } db2 +} {1 {database is locked}} + +do_test 2.2.3 { + # This is to test that [db2] is not holding a PENDING lock (which can + # happen when an attempt to obtain an EXCLUSIVE lock fails). + sqlite3 db4 test2.db -vfs tvfsshm + execsql { SELECT * FROM t2 } db4 +} {a b c d e f g h} + +do_test 2.2.4 { + catchsql { SELECT * FROM t2 } db2 +} {1 {database is locked}} + +do_test 2.2.5 { + db4 close + sqlite3 db4 test2.db -vfs tvfsshm + execsql { SELECT * FROM t2 } db4 +} {a b c d e f g h} + +do_test 2.2.6 { + db3 close + db4 close + execsql { SELECT * FROM t2 } db2 +} {a b c d e f g h} + +db2 close + + +finish_test +