-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
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
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
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
#include <Windows.h>
# 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)
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) ){
}
}
-#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 */
/* 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;
if( iFrame<=iLast ) break;
}
+ SEH_FREE_ON_ERROR(aFrame, 0);
sqlite3_free(aFrame);
- SEH_FREE_ON_ERROR(0);
}
finished:
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 && i<nSegment; i++){
WalHashLoc sLoc;
}
if( rc!=SQLITE_OK ){
+ SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p);
p = 0;
- SEH_FREE_ON_ERROR(0);
}
*pp = p;
return rc;
}
walcheckpoint_out:
-#ifdef SQLITE_USE_SEH
- assert( pWal->pFree==(void*)pIter );
- pWal->pFree = 0;
-#endif
+ SEH_FREE_ON_ERROR(pIter, 0);
walIteratorFree(pIter);
return rc;
}
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
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;
#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 */
#endif
assert( pWal->ckptLock==0 );
+ assert( pWal->nSehTry>0 );
#ifdef SQLITE_ENABLE_SNAPSHOT
if( pSnapshot ){
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 {
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 */
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 */