aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <Dan Kennedy>2024-09-26 18:02:17 +0000
committerdan <Dan Kennedy>2024-09-26 18:02:17 +0000
commitd0720eee5e19d9d6889b275bdb652e5e0160899c (patch)
tree32883f27d0150749b75d6bf69dd52a2d0720e835 /src
parent8cd30e3f5b6306b8d657e3dd7376763ab10f0279 (diff)
downloadsqlite-d0720eee5e19d9d6889b275bdb652e5e0160899c.tar.gz
sqlite-d0720eee5e19d9d6889b275bdb652e5e0160899c.zip
When possible, avoid taking wal file read-lock 0 in sqlite3_snapshot_get().
FossilOrigin-Name: 34b6ac3d76dbc6819778ec2a0f81cbcdcc0cd1a6303381d97f1c479e4ecdd132
Diffstat (limited to 'src')
-rw-r--r--src/main.c4
-rw-r--r--src/wal.c18
2 files changed, 20 insertions, 2 deletions
diff --git a/src/main.c b/src/main.c
index 6ab09c556..fceb7957b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4963,7 +4963,11 @@ int sqlite3_snapshot_get(
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ i64 dummy = 0;
+ sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy);
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+ sqlite3PagerSnapshotOpen(pPager, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
}
diff --git a/src/wal.c b/src/wal.c
index 89106038b..f4aa663fd 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -541,6 +541,7 @@ struct Wal {
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
+ int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
sqlite3 *db;
@@ -3097,7 +3098,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
SEH_INJECT_FAULT;
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
+ && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0)
#endif
){
/* The WAL has been completely backfilled (or it is empty).
@@ -4497,7 +4498,20 @@ void sqlite3WalSnapshotOpen(
Wal *pWal,
sqlite3_snapshot *pSnapshot
){
- pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){
+ /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In
+ ** this case set the bGetSnapshot flag so that if the call to
+ ** sqlite3_snapshot_get() is about to read transaction on this wal
+ ** file, it does not take read-lock 0 if the wal file has been completely
+ ** checkpointed. Taking read-lock 0 would work, but then it would be
+ ** possible for a subsequent writer to destroy the snapshot even while
+ ** this connection is holding its read-transaction open. This is contrary
+ ** to user expectations, so we avoid it by not taking read-lock 0. */
+ pWal->bGetSnapshot = 1;
+ }else{
+ pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ pWal->bGetSnapshot = 0;
+ }
}
/*