tt3_checkpoint.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. ** 2001 September 15
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  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.
  10. **
  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.
  15. **
  16. ** This file contains the implementation of test cases:
  17. **
  18. ** checkpoint_starvation_1
  19. ** checkpoint_starvation_2
  20. */
  21. /*
  22. ** Both test cases involve 1 writer/checkpointer thread and N reader threads.
  23. **
  24. ** Each reader thread performs a series of read transactions, one after
  25. ** another. Each read transaction lasts for 100 ms.
  26. **
  27. ** The writer writes transactions as fast as possible. It uses a callback
  28. ** registered with sqlite3_wal_hook() to try to keep the WAL-size limited to
  29. ** around 50 pages.
  30. **
  31. ** In test case checkpoint_starvation_1, the auto-checkpoint uses
  32. ** SQLITE_CHECKPOINT_PASSIVE. In checkpoint_starvation_2, it uses RESTART.
  33. ** The expectation is that in the first case the WAL file will grow very
  34. ** large, and in the second will be limited to the 50 pages or thereabouts.
  35. ** However, the overall transaction throughput will be lower for
  36. ** checkpoint_starvation_2, as every checkpoint will block for up to 200 ms
  37. ** waiting for readers to clear.
  38. */
  39. /* Frame limit used by the WAL hook for these tests. */
  40. #define CHECKPOINT_STARVATION_FRAMELIMIT 50
  41. /* Duration in ms of each read transaction */
  42. #define CHECKPOINT_STARVATION_READMS 100
  43. struct CheckpointStarvationCtx {
  44. int eMode;
  45. int nMaxFrame;
  46. };
  47. typedef struct CheckpointStarvationCtx CheckpointStarvationCtx;
  48. static int checkpoint_starvation_walhook(
  49. void *pCtx,
  50. sqlite3 *db,
  51. const char *zDb,
  52. int nFrame
  53. ){
  54. CheckpointStarvationCtx *p = (CheckpointStarvationCtx *)pCtx;
  55. if( nFrame>p->nMaxFrame ){
  56. p->nMaxFrame = nFrame;
  57. }
  58. if( nFrame>=CHECKPOINT_STARVATION_FRAMELIMIT ){
  59. sqlite3_wal_checkpoint_v2(db, zDb, p->eMode, 0, 0);
  60. }
  61. return SQLITE_OK;
  62. }
  63. static char *checkpoint_starvation_reader(int iTid, int iArg){
  64. Error err = {0};
  65. Sqlite db = {0};
  66. opendb(&err, &db, "test.db", 0);
  67. while( !timetostop(&err) ){
  68. i64 iCount1, iCount2;
  69. sql_script(&err, &db, "BEGIN");
  70. iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
  71. usleep(CHECKPOINT_STARVATION_READMS*1000);
  72. iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1");
  73. sql_script(&err, &db, "COMMIT");
  74. if( iCount1!=iCount2 ){
  75. test_error(&err, "Isolation failure - %lld %lld", iCount1, iCount2);
  76. }
  77. }
  78. closedb(&err, &db);
  79. print_and_free_err(&err);
  80. return 0;
  81. }
  82. static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){
  83. Error err = {0};
  84. Sqlite db = {0};
  85. Threadset threads = {0};
  86. int nInsert = 0;
  87. int i;
  88. opendb(&err, &db, "test.db", 1);
  89. sql_script(&err, &db,
  90. "PRAGMA page_size = 1024;"
  91. "PRAGMA journal_mode = WAL;"
  92. "CREATE TABLE t1(x);"
  93. );
  94. setstoptime(&err, nMs);
  95. for(i=0; i<4; i++){
  96. launch_thread(&err, &threads, checkpoint_starvation_reader, 0);
  97. usleep(CHECKPOINT_STARVATION_READMS*1000/4);
  98. }
  99. sqlite3_wal_hook(db.db, checkpoint_starvation_walhook, (void *)p);
  100. while( !timetostop(&err) ){
  101. sql_script(&err, &db, "INSERT INTO t1 VALUES(randomblob(1200))");
  102. nInsert++;
  103. }
  104. printf(" Checkpoint mode : %s\n",
  105. p->eMode==SQLITE_CHECKPOINT_PASSIVE ? "PASSIVE" : "RESTART"
  106. );
  107. printf(" Peak WAL : %d frames\n", p->nMaxFrame);
  108. printf(" Transaction count: %d transactions\n", nInsert);
  109. join_all_threads(&err, &threads);
  110. closedb(&err, &db);
  111. print_and_free_err(&err);
  112. }
  113. static void checkpoint_starvation_1(int nMs){
  114. Error err = {0};
  115. CheckpointStarvationCtx ctx = { SQLITE_CHECKPOINT_PASSIVE, 0 };
  116. checkpoint_starvation_main(nMs, &ctx);
  117. if( ctx.nMaxFrame<(CHECKPOINT_STARVATION_FRAMELIMIT*10) ){
  118. test_error(&err, "WAL failed to grow - %d frames", ctx.nMaxFrame);
  119. }
  120. print_and_free_err(&err);
  121. }
  122. static void checkpoint_starvation_2(int nMs){
  123. Error err = {0};
  124. CheckpointStarvationCtx ctx = { SQLITE_CHECKPOINT_RESTART, 0 };
  125. checkpoint_starvation_main(nMs, &ctx);
  126. if( ctx.nMaxFrame>CHECKPOINT_STARVATION_FRAMELIMIT+10 ){
  127. test_error(&err, "WAL grew too large - %d frames", ctx.nMaxFrame);
  128. }
  129. print_and_free_err(&err);
  130. }