diff --git a/manifest b/manifest index a3c3624cf6..d417bb139e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\son\sthis\sbranch\scausing\scheckpoints\sthat\sdo\snot\sproceed\sbecause\sthey\scan't\sget\sthe\sCHECKPOINT\slock\sto\sreturn\sincorrect\soutput\svalues. -D 2021-08-20T11:50:12.817 +C Add\ssome\sassert()\sstatements\sand\sfix\ssmall\sissues\swith\scode\son\sthis\sbranch. +D 2021-08-20T16:19:19.544 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -628,7 +628,7 @@ F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb7 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c F src/vtab.c 88404ac1517903b3eb2abe256772ee95bb09f81ac0a17e13afe5d467df4de4ee F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 42c64a0c198c0610a4f54158faff9ad8b0f3f390cb03c1a69692dc70f886b711 +F src/wal.c d47742fa0d58fa622416cfd105b4b309f39006f30d903e02db2f48236f3d83d7 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c 7342becedf3f8a26f9817f08436bdf8b56ad69af83705f6b9320a0ad3092c2ac F src/where.c 99b6e13664a7bd9a553c554978d0e253066995dade621f44cffa8928c8b493b5 @@ -1921,7 +1921,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 840e0a14ebc4a85d4ede0223287d4c1e4465e9f20c3c43bfc74775dddec1fa8f -R 97abf4da384cedc02121f231f21869ab +P 5a98820c3d20766813bb4b0da23247ac90f380c07827ff13b61d5b606d8311aa +R eab33be79c818813f4366ae19768ee1d U dan -Z 53bdf1f79fced94468e78efd135afd05 +Z 8887602c0a0185b63b60ad6538fd96e1 diff --git a/manifest.uuid b/manifest.uuid index 827b32b4dd..4034ae736f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a98820c3d20766813bb4b0da23247ac90f380c07827ff13b61d5b606d8311aa \ No newline at end of file +bd9b373b177a71f5eaeb7ce8dd1dc755b34951ee1376c24652418bb329bfcb45 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index e17d3959b0..f6c2d86df8 100644 --- a/src/wal.c +++ b/src/wal.c @@ -528,10 +528,10 @@ struct Wal { u32 iReCksum; /* On commit, recalculate checksums from here */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ -#ifdef SQLITE_USE_SEH # ifdef SQLITE_DEBUG int nSehTry; /* Number of nested SEH_TRY{} blocks */ # endif +#ifdef SQLITE_USE_SEH u32 lockMask; /* Mask of locks held */ void *pFree; /* Pointer to sqlite3_free() if exception thrown */ #endif @@ -622,9 +622,12 @@ struct WalIterator { #include # define SEH_TRY __try { \ - assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); TESTONLY(pWal->nSehTry++); + assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \ + TESTONLY(pWal->nSehTry++); -# define SEH_EXCEPT(X) TESTONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 ); \ +# define SEH_EXCEPT(X) \ + TESTONLY(pWal->nSehTry--); \ + assert( pWal->nSehTry==0 ); \ } __except( sehExceptionFilter(pWal, GetExceptionCode()) ){ X } # define SEH_INJECT_FAULT sehInjectFault(pWal) @@ -643,6 +646,12 @@ static int sehExceptionFilter(Wal *pWal, int eCode){ return EXCEPTION_CONTINUE_SEARCH; } +/* +** If one is configured, invoke the xTestCallback callback with 650 as +** the argument. If it returns true, throw the same exception that is +** thrown by the system if the *-shm file mapping is accessed after it +** has been invalidated. +*/ static void sehInjectFault(Wal *pWal){ assert( pWal->nSehTry>0 ); if( sqlite3FaultSim(650) ){ @@ -650,13 +659,27 @@ static void sehInjectFault(Wal *pWal){ } } -#define SEH_FREE_ON_ERROR(X) pWal->pFree = X +/* +** There are two ways to use this macro. To set a pointer to be freed +** if an exception is thrown: +** +** SEH_FREE_ON_ERROR(0, pPtr); +** +** and to cancel the same: +** +** SEH_FREE_ON_ERROR(pPtr, 0); +** +** In the first case, there must not already be a pointer registered to +** be freed. In the second case, pPtr must be the registered pointer. +*/ +#define SEH_FREE_ON_ERROR(X,Y) \ + assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y #else -# define SEH_TRY -# define SEH_EXCEPT(X) -# define SEH_INJECT_FAULT -# define SEH_FREE_ON_ERROR(X) +# define SEH_TRY TESTONLY(pWal->nSehTry++); +# define SEH_EXCEPT(X) TESTONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 ); +# define SEH_INJECT_FAULT assert( pWal->nSehTry>0 ); +# define SEH_FREE_ON_ERROR(X,Y) #endif /* ifdef SQLITE_USE_SEH */ @@ -1369,7 +1392,7 @@ static int walIndexRecover(Wal *pWal){ /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ); - SEH_FREE_ON_ERROR(aFrame); + SEH_FREE_ON_ERROR(0, aFrame); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; @@ -1447,8 +1470,8 @@ static int walIndexRecover(Wal *pWal){ if( iFrame<=iLast ) break; } + SEH_FREE_ON_ERROR(aFrame, 0); sqlite3_free(aFrame); - SEH_FREE_ON_ERROR(0); } finished: @@ -1867,7 +1890,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ memset(p, 0, nByte); p->nSegment = nSegment; aTmp = (ht_slot*)&(((u8*)p)[nByte]); - SEH_FREE_ON_ERROR(p); + SEH_FREE_ON_ERROR(0, p); for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && ipFree==(void*)pIter ); - pWal->pFree = 0; -#endif + SEH_FREE_ON_ERROR(pIter, 0); walIteratorFree(pIter); return rc; } @@ -2306,9 +2326,7 @@ int sqlite3WalClose( if( pWal ){ int isDelete = 0; /* True to unlink wal and wal-index files */ -#ifdef SQLITE_USE_SEH - assert( pWal->lockMask==0 ); -#endif + assert( walAssertLockmask(pWal) ); /* If an EXCLUSIVE lock can be obtained on the database file (using the ** ordinary, rollback-mode locking methods, this guarantees that the @@ -3020,6 +3038,13 @@ static int walHandleException(Wal *pWal){ return SQLITE_IOERR; } +/* +** Assert that the Wal.lockMask mask, which indicates the locks held +** by the connenction, is consistent with the Wal.readLock, Wal.writeLock +** and Wal.ckptLock variables. To be used as: +** +** assert( walAssertLockmask(pWal) ); +*/ static int walAssertLockmask(Wal *pWal){ if( pWal->exclusiveMode==0 ){ static const int S = 1; @@ -3134,18 +3159,8 @@ int sqlite3WalSnapshotRecover(Wal *pWal){ #endif /* SQLITE_ENABLE_SNAPSHOT */ /* -** Begin a read transaction on the database. -** -** This routine used to be called sqlite3OpenSnapshot() and with good reason: -** it takes a snapshot of the state of the WAL and wal-index for the current -** instant in time. The current thread will continue to use this snapshot. -** Other threads might append new content to the WAL and wal-index but -** that extra content is ignored by the current thread. -** -** If the database contents have changes since the previous read -** transaction, then *pChanged is set to 1 before returning. The -** Pager layer will use this to know that its cache is stale and -** needs to be flushed. +** This function does the work of sqlite3WalBeginReadTransaction() (see +** below). That function simply calls this one inside an SEH_TRY{...} block. */ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ @@ -3157,6 +3172,7 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ #endif assert( pWal->ckptLock==0 ); + assert( pWal->nSehTry>0 ); #ifdef SQLITE_ENABLE_SNAPSHOT if( pSnapshot ){ @@ -3251,6 +3267,20 @@ static int walBeginReadTransaction(Wal *pWal, int *pChanged){ return rc; } +/* +** Begin a read transaction on the database. +** +** This routine used to be called sqlite3OpenSnapshot() and with good reason: +** it takes a snapshot of the state of the WAL and wal-index for the current +** instant in time. The current thread will continue to use this snapshot. +** Other threads might append new content to the WAL and wal-index but +** that extra content is ignored by the current thread. +** +** If the database contents have changes since the previous read +** transaction, then *pChanged is set to 1 before returning. The +** Pager layer will use this to know that its cache is stale and +** needs to be flushed. +*/ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; SEH_TRY { @@ -3380,6 +3410,17 @@ static int walFindFrame( return SQLITE_OK; } +/* +** Search the wal file for page pgno. If found, set *piRead to the frame that +** contains the page. Otherwise, if pgno is not in the wal file, set *piRead +** to zero. +** +** Return SQLITE_OK if successful, or an error code if an error occurs. If an +** error does occur, the final value of *piRead is undefined. +** +** The difference between this function and walFindFrame() is that this +** function wraps walFindFrame() in an SEH_TRY{...} block. +*/ int sqlite3WalFindFrame( Wal *pWal, /* WAL handle */ Pgno pgno, /* Database page number to read data for */ @@ -4002,6 +4043,13 @@ static int walFrames( return rc; } +/* +** Write a set of frames to the log. The caller must hold the write-lock +** on the log file (obtained using sqlite3WalBeginWriteTransaction()). +** +** The difference between this function and walFrames() is that this +** function wraps walFrames() in an SEH_TRY{...} block. +*/ int sqlite3WalFrames( Wal *pWal, /* Wal handle to write to */ int szPage, /* Database page-size in bytes */