Skip to content

Commit b4cf7ef

Browse files
committed
libsql-sqlite3: Add libsql_wal_checkpoint_seq_count() API
This adds libsql_wal_checkpoint_seq_count() API function for determining the checkpoint sequence counter of a database WAL.
1 parent 0c5b83f commit b4cf7ef

File tree

7 files changed

+86
-0
lines changed

7 files changed

+86
-0
lines changed

libsql-sqlite3/doc/libsql_extensions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ The libSQL has the following WAL API functions, which are useful for
362362
syncing the WAL between databases:
363363
364364
* `libsql_wal_disable_checkpoint` -- Disable checkpointing, including on database close.
365+
* `libsql_wal_checkpoint_seq_count` -- Return the checkpoint sequence number of the WAL.
365366
* `libsql_wal_frame_count` -- Get the number of frames in the WAL.
366367
* `libsql_wal_get_frame` -- Get a frame from the WAL.
367368
* `libsql_wal_insert_begin` -- Begin WAL insertion.

libsql-sqlite3/src/main.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,30 @@ int libsql_wal_disable_checkpoint(sqlite3 *db) {
24492449
return SQLITE_OK;
24502450
}
24512451

2452+
/*
2453+
** Return the checkpoint sequence counter of the given database.
2454+
*/
2455+
int libsql_wal_checkpoint_seq_count(sqlite3 *db, unsigned int *pnCkpt) {
2456+
int rc = SQLITE_OK;
2457+
Pager *pPager;
2458+
2459+
#ifdef SQLITE_OMIT_WAL
2460+
*pnFrame = 0;
2461+
return SQLITE_OK;
2462+
#else
2463+
#ifdef SQLITE_ENABLE_API_ARMOR
2464+
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
2465+
#endif
2466+
2467+
sqlite3_mutex_enter(db->mutex);
2468+
pPager = sqlite3BtreePager(db->aDb[0].pBt);
2469+
rc = sqlite3PagerWalCheckpointSeqCount(pPager, pnCkpt);
2470+
sqlite3Error(db, rc);
2471+
sqlite3_mutex_leave(db->mutex);
2472+
return rc;
2473+
#endif
2474+
}
2475+
24522476
/*
24532477
** Return the number of frames in the WAL of the given database.
24542478
*/

libsql-sqlite3/src/pager.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7771,6 +7771,18 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
77717771
return rc;
77727772
}
77737773

7774+
/**
7775+
** Return the current checkpoint generation in the WAL file.
7776+
**/
7777+
int sqlite3PagerWalCheckpointSeqCount(Pager *pPager, unsigned int *pnCkpt){
7778+
if( pagerUseWal(pPager) ){
7779+
return pPager->wal->methods.xCheckpointSeqCount(pPager->wal->pData, pnCkpt);
7780+
} else {
7781+
*pnCkpt = 0;
7782+
return SQLITE_OK;
7783+
}
7784+
}
7785+
77747786
/**
77757787
** Return the number of frames in the WAL file.
77767788
**

libsql-sqlite3/src/sqlite.h.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10564,6 +10564,15 @@ void *libsql_close_hook(sqlite3 *db, void (*xClose)(void *pCtx, sqlite3 *db), vo
1056410564
*/
1056510565
int libsql_wal_disable_checkpoint(sqlite3 *db);
1056610566

10567+
/*
10568+
** CAPI3REF: Get the checkpoint sequence counter of the WAL file
10569+
** METHOD: sqlite3
10570+
**
10571+
** ^The [libsql_wal_checkpoint_seq_count(D,P)] interface returns the checkpoint sequence counter
10572+
** of the WAL file for [database connection] D into *P.
10573+
*/
10574+
int libsql_wal_checkpoint_seq_count(sqlite3 *db, unsigned int *pnCkpt);
10575+
1056710576
/*
1056810577
** CAPI3REF: Get the number of frames in the WAL file
1056910578
** METHOD: sqlite3

libsql-sqlite3/src/test_walapi.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,34 @@ void test_sync_while_reading() {
145145
cmp_data(db_primary, db_backup);
146146
}
147147

148+
// This test case writes to a local database, force checkpoint, and then
149+
//verifies that checkpoint sequence number incremented, and the WAL is
150+
//truncated.
151+
static void test_checkpoint(void) {
152+
sqlite3 *db_primary;
153+
unsigned int max_frame, ckpt_seq;
154+
155+
open_db("primary_test_checkpoint.db", &db_primary);
156+
157+
ensure(sqlite3_exec(db_primary, "CREATE TABLE t (x)", 0, 0, 0) == SQLITE_OK, "failed to insert data\n");
158+
ensure(sqlite3_exec(db_primary, "INSERT INTO t VALUES (randomblob(4 * 1024))", 0, 0, 0) == SQLITE_OK, "failed to insert data\n");
159+
ensure(sqlite3_exec(db_primary, "INSERT INTO t VALUES (randomblob(1 * 1024))", 0, 0, 0) == SQLITE_OK, "failed to insert data\n");
160+
ensure(sqlite3_exec(db_primary, "INSERT INTO t VALUES (randomblob(1 * 1024))", 0, 0, 0) == SQLITE_OK, "failed to insert data\n");
161+
162+
ensure(libsql_wal_checkpoint_seq_count(db_primary, &ckpt_seq) == SQLITE_OK, "failed to get checkpoint sequence count: %s\n", sqlite3_errmsg(db_primary));
163+
assert(ckpt_seq == 0);
164+
ensure(libsql_wal_frame_count(db_primary, &max_frame) == SQLITE_OK, "failed to get frames count: %s\n", sqlite3_errmsg(db_primary));
165+
assert(max_frame == 7);
166+
167+
// force checkpoint
168+
ensure(sqlite3_wal_checkpoint_v2(db_primary, NULL, SQLITE_CHECKPOINT_TRUNCATE, NULL, NULL) == SQLITE_OK, "failed to checkpoint: %s\n", sqlite3_errmsg(db_primary));
169+
170+
ensure(libsql_wal_checkpoint_seq_count(db_primary, &ckpt_seq) == SQLITE_OK, "failed to get checkpoint sequence count: %s\n", sqlite3_errmsg(db_primary));
171+
assert(ckpt_seq == 1);
172+
ensure(libsql_wal_frame_count(db_primary, &max_frame) == SQLITE_OK, "failed to get frames count: %s\n", sqlite3_errmsg(db_primary));
173+
assert(max_frame == 0);
174+
}
175+
148176
int main(int argc, char *argv[])
149177
{
150178
test_huge_payload();
@@ -156,5 +184,8 @@ int main(int argc, char *argv[])
156184
test_sync_while_reading();
157185
printf("============= OK test_sync_while_reading\n");
158186

187+
test_checkpoint();
188+
printf("============= OK test_checkpoint\n");
189+
159190
return 0;
160191
}

libsql-sqlite3/src/wal.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4024,6 +4024,11 @@ static int walFrames(
40244024
return rc;
40254025
}
40264026

4027+
int sqlite3WalCheckpointSeqCount(Wal *pWal, unsigned int *pnCkpt){
4028+
*pnCkpt = pWal->nCkpt;
4029+
return SQLITE_OK;
4030+
}
4031+
40274032
int sqlite3WalFrameCount(Wal *pWal, int locked, unsigned int *pnFrames){
40284033
int rc = SQLITE_OK;
40294034
if( locked==0 ) {
@@ -4543,6 +4548,7 @@ static int sqlite3WalOpen(
45434548
out->methods.xUndo = (int (*)(wal_impl *, int (*)(void *, unsigned int), void *))sqlite3WalUndo;
45444549
out->methods.xSavepoint = (void (*)(wal_impl *, unsigned int *))sqlite3WalSavepoint;
45454550
out->methods.xSavepointUndo = (int (*)(wal_impl *, unsigned int *))sqlite3WalSavepointUndo;
4551+
out->methods.xCheckpointSeqCount = (int (*)(wal_impl *, unsigned int *))sqlite3WalCheckpointSeqCount;
45464552
out->methods.xFrameCount = (int (*)(wal_impl *, int, unsigned int *))sqlite3WalFrameCount;
45474553
out->methods.xFrames = (int (*)(wal_impl *, int, libsql_pghdr *, unsigned int, int, int, int *))sqlite3WalFrames;
45484554
out->methods.xCheckpoint = (int (*)(wal_impl *, sqlite3 *, int, int (*)(void *), void *, int, int, unsigned char *, int *, int *, int (*)(void*, int, const unsigned char*, int, int, int), void*))sqlite3WalCheckpoint;

libsql-sqlite3/src/wal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ typedef struct libsql_wal_methods {
7676
** response to a ROLLBACK TO command. */
7777
int (*xSavepointUndo)(wal_impl* pWal, unsigned int *aWalData);
7878

79+
/* Return the current checkpoint generation in the WAL file. */
80+
int (*xCheckpointSeqCount)(wal_impl* pWal, unsigned int *pnCkpt);
81+
7982
/* Return the number of frames in the WAL */
8083
int (*xFrameCount)(wal_impl* pWal, int, unsigned int *);
8184

0 commit comments

Comments
 (0)