4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** This file is part of the test program "threadtest3". Despite being a C
13 ** file it is not compiled separately, but included by threadtest3.c using
14 ** the #include directive normally used with header files.
16 ** This file contains the implementation of test cases:
18 ** checkpoint_starvation_1
19 ** checkpoint_starvation_2
23 ** Both test cases involve 1 writer/checkpointer thread and N reader threads.
25 ** Each reader thread performs a series of read transactions, one after
26 ** another. Each read transaction lasts for 100 ms.
28 ** The writer writes transactions as fast as possible. It uses a callback
29 ** registered with sqlite3_wal_hook() to try to keep the WAL-size limited to
32 ** In test case checkpoint_starvation_1, the auto-checkpoint uses
33 ** SQLITE_CHECKPOINT_PASSIVE. In checkpoint_starvation_2, it uses RESTART.
34 ** The expectation is that in the first case the WAL file will grow very
35 ** large, and in the second will be limited to the 50 pages or thereabouts.
36 ** However, the overall transaction throughput will be lower for
37 ** checkpoint_starvation_2, as every checkpoint will block for up to 200 ms
38 ** waiting for readers to clear.
41 /* Frame limit used by the WAL hook for these tests. */
42 #define CHECKPOINT_STARVATION_FRAMELIMIT 50
44 /* Duration in ms of each read transaction */
45 #define CHECKPOINT_STARVATION_READMS 100
47 struct CheckpointStarvationCtx
{
51 typedef struct CheckpointStarvationCtx CheckpointStarvationCtx
;
53 static int checkpoint_starvation_walhook(
59 CheckpointStarvationCtx
*p
= (CheckpointStarvationCtx
*)pCtx
;
60 if( nFrame
>p
->nMaxFrame
){
61 p
->nMaxFrame
= nFrame
;
63 if( nFrame
>=CHECKPOINT_STARVATION_FRAMELIMIT
){
64 sqlite3_wal_checkpoint_v2(db
, zDb
, p
->eMode
, 0, 0);
69 static char *checkpoint_starvation_reader(int iTid
, void *pArg
){
73 opendb(&err
, &db
, "test.db", 0);
74 while( !timetostop(&err
) ){
76 sql_script(&err
, &db
, "BEGIN");
77 iCount1
= execsql_i64(&err
, &db
, "SELECT count(x) FROM t1");
78 usleep(CHECKPOINT_STARVATION_READMS
*1000);
79 iCount2
= execsql_i64(&err
, &db
, "SELECT count(x) FROM t1");
80 sql_script(&err
, &db
, "COMMIT");
82 if( iCount1
!=iCount2
){
83 test_error(&err
, "Isolation failure - %lld %lld", iCount1
, iCount2
);
88 print_and_free_err(&err
);
92 static void checkpoint_starvation_main(int nMs
, CheckpointStarvationCtx
*p
){
95 Threadset threads
= {0};
99 opendb(&err
, &db
, "test.db", 1);
100 sql_script(&err
, &db
,
101 "PRAGMA page_size = 1024;"
102 "PRAGMA journal_mode = WAL;"
103 "CREATE TABLE t1(x);"
106 setstoptime(&err
, nMs
);
109 launch_thread(&err
, &threads
, checkpoint_starvation_reader
, 0);
110 usleep(CHECKPOINT_STARVATION_READMS
*1000/4);
113 sqlite3_wal_hook(db
.db
, checkpoint_starvation_walhook
, (void *)p
);
114 while( !timetostop(&err
) ){
115 sql_script(&err
, &db
, "INSERT INTO t1 VALUES(randomblob(1200))");
119 printf(" Checkpoint mode : %s\n",
120 p
->eMode
==SQLITE_CHECKPOINT_PASSIVE
? "PASSIVE" : "RESTART"
122 printf(" Peak WAL : %d frames\n", p
->nMaxFrame
);
123 printf(" Transaction count: %d transactions\n", nInsert
);
125 join_all_threads(&err
, &threads
);
127 print_and_free_err(&err
);
130 static void checkpoint_starvation_1(int nMs
){
132 CheckpointStarvationCtx ctx
= { SQLITE_CHECKPOINT_PASSIVE
, 0 };
133 checkpoint_starvation_main(nMs
, &ctx
);
134 if( ctx
.nMaxFrame
<(CHECKPOINT_STARVATION_FRAMELIMIT
*10) ){
135 test_error(&err
, "WAL failed to grow - %d frames", ctx
.nMaxFrame
);
137 print_and_free_err(&err
);
140 static void checkpoint_starvation_2(int nMs
){
142 CheckpointStarvationCtx ctx
= { SQLITE_CHECKPOINT_RESTART
, 0 };
143 checkpoint_starvation_main(nMs
, &ctx
);
144 if( ctx
.nMaxFrame
>CHECKPOINT_STARVATION_FRAMELIMIT
+10 ){
145 test_error(&err
, "WAL grew too large - %d frames", ctx
.nMaxFrame
);
147 print_and_free_err(&err
);