/ Check-in [c43deb33]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Delay opening the sub-journal until SQLite actually needs to write data to it.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c43deb33ae5f191ea2e054181759beeeb9ea71bf
User & Date: dan 2010-06-03 12:35:28
Context
2010-06-03
16:58
Add extra tests for removing elements from wal-index hash tables as part of a rollback. check-in: af3e598a user: dan tags: trunk
12:35
Delay opening the sub-journal until SQLite actually needs to write data to it. check-in: c43deb33 user: dan tags: trunk
12:09
Remove global variables when compiled with SQLITE_OMIT_WSD check-in: dd10a547 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

3402
3403
3404
3405
3406
3407
3408




















3409
3410
3411
3412
3413
3414
3415
....
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430



3431
3432
3433
3434
3435
3436
3437











3438
3439
3440

3441
3442
3443
3444
3445
3446
3447
....
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
....
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
....
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
    pList->pageHash = pager_pagehash(pList);
#endif
    pList = pList->pDirty;
  }

  return rc;
}





















/*
** Append a record of the current state of page pPg to the sub-journal. 
** It is the callers responsibility to use subjRequiresPage() to check 
** that it is really required before calling this function.
**
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
................................................................................
** error code if the attempt to write to the sub-journal fails, or 
** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
** bitvec.
*/
static int subjournalPage(PgHdr *pPg){
  int rc = SQLITE_OK;
  Pager *pPager = pPg->pPager;
  if( isOpen(pPager->sjfd) ){
    void *pData = pPg->pData;
    i64 offset = pPager->nSubRec*(4+pPager->pageSize);
    char *pData2;




    CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
    PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
  
    assert( pagerUseWal(pPager) 
         || pageInJournal(pPg) 
         || pPg->pgno>pPager->dbOrigSize 
    );











    rc = write32bits(pPager->sjfd, offset, pPg->pgno);
    if( rc==SQLITE_OK ){
      rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);

    }
  }
  if( rc==SQLITE_OK ){
    pPager->nSubRec++;
    assert( pPager->nSavepoint>0 );
    rc = addToSavepointBitvecs(pPager, pPg->pgno);
  }
................................................................................
  if( pPg ){
    Pager *pPager = pPg->pPager;
    sqlite3PcacheRelease(pPg);
    pagerUnlockIfUnused(pPager);
  }
}

/*
** If the main journal file has already been opened, ensure that the
** sub-journal file is open too. If the main journal is not open,
** this function is a no-op.
**
** SQLITE_OK is returned if everything goes according to plan. 
** An SQLITE_IOERR_XXX error code is returned if a call to 
** sqlite3OsOpen() fails.
*/
static int openSubJournal(Pager *pPager){
  int rc = SQLITE_OK;
  if( (pagerUseWal(pPager) || isOpen(pPager->jfd)) && !isOpen(pPager->sjfd) ){
    if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
      sqlite3MemJournalOpen(pPager->sjfd);
    }else{
      rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
    }
  }
  return rc;
}

/*
** This function is called at the start of every write transaction.
** There must already be a RESERVED or EXCLUSIVE lock on the database 
** file when this routine is called.
**
** Open the journal file for pager pPager and write a journal header
** to the start of it. If there are active savepoints, open the sub-journal
................................................................................
    pPager->needSync = 0;
    pPager->nRec = 0;
    pPager->journalOff = 0;
    pPager->setMaster = 0;
    pPager->journalHdr = 0;
    rc = writeJournalHdr(pPager);
  }
  if( rc==SQLITE_OK && pPager->nSavepoint ){
    rc = openSubJournal(pPager);
  }

  if( rc!=SQLITE_OK ){
    sqlite3BitvecDestroy(pPager->pInJournal);
    pPager->pInJournal = 0;
  }
  return rc;
}
................................................................................
      }
      if( pagerUseWal(pPager) ){
        sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
      }
      pPager->nSavepoint = ii+1;
    }
    assert( pPager->nSavepoint==nSavepoint );

    /* Open the sub-journal, if it is not already opened. */
    rc = openSubJournal(pPager);
    assertTruncateConstraint(pPager);
  }

  return rc;
}

/*







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
<
<
<

>
>
>
|
<
<




>
>
>
>
>
>
>
>
>
>
>
|
|
|
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<







 







<
<
<







3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
....
3439
3440
3441
3442
3443
3444
3445
3446



3447
3448
3449
3450
3451


3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
....
4426
4427
4428
4429
4430
4431
4432





















4433
4434
4435
4436
4437
4438
4439
....
4508
4509
4510
4511
4512
4513
4514



4515
4516
4517
4518
4519
4520
4521
....
5471
5472
5473
5474
5475
5476
5477



5478
5479
5480
5481
5482
5483
5484
    pList->pageHash = pager_pagehash(pList);
#endif
    pList = pList->pDirty;
  }

  return rc;
}

/*
** Ensure that the sub-journal file is open. If it is already open, this 
** function is a no-op.
**
** SQLITE_OK is returned if everything goes according to plan. An 
** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen() 
** fails.
*/
static int openSubJournal(Pager *pPager){
  int rc = SQLITE_OK;
  if( !isOpen(pPager->sjfd) ){
    if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
      sqlite3MemJournalOpen(pPager->sjfd);
    }else{
      rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
    }
  }
  return rc;
}

/*
** Append a record of the current state of page pPg to the sub-journal. 
** It is the callers responsibility to use subjRequiresPage() to check 
** that it is really required before calling this function.
**
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
................................................................................
** error code if the attempt to write to the sub-journal fails, or 
** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
** bitvec.
*/
static int subjournalPage(PgHdr *pPg){
  int rc = SQLITE_OK;
  Pager *pPager = pPg->pPager;
  if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){




    /* Open the sub-journal, if it has not already been opened */
    assert( pPager->useJournal );
    assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
    assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );


    assert( pagerUseWal(pPager) 
         || pageInJournal(pPg) 
         || pPg->pgno>pPager->dbOrigSize 
    );
    rc = openSubJournal(pPager);

    /* If the sub-journal was opened successfully (or was already open),
    ** write the journal record into the file.  */
    if( rc==SQLITE_OK ){
      void *pData = pPg->pData;
      i64 offset = pPager->nSubRec*(4+pPager->pageSize);
      char *pData2;
  
      CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
      PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
      if( rc==SQLITE_OK ){
        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
      }
    }
  }
  if( rc==SQLITE_OK ){
    pPager->nSubRec++;
    assert( pPager->nSavepoint>0 );
    rc = addToSavepointBitvecs(pPager, pPg->pgno);
  }
................................................................................
  if( pPg ){
    Pager *pPager = pPg->pPager;
    sqlite3PcacheRelease(pPg);
    pagerUnlockIfUnused(pPager);
  }
}






















/*
** This function is called at the start of every write transaction.
** There must already be a RESERVED or EXCLUSIVE lock on the database 
** file when this routine is called.
**
** Open the journal file for pager pPager and write a journal header
** to the start of it. If there are active savepoints, open the sub-journal
................................................................................
    pPager->needSync = 0;
    pPager->nRec = 0;
    pPager->journalOff = 0;
    pPager->setMaster = 0;
    pPager->journalHdr = 0;
    rc = writeJournalHdr(pPager);
  }




  if( rc!=SQLITE_OK ){
    sqlite3BitvecDestroy(pPager->pInJournal);
    pPager->pInJournal = 0;
  }
  return rc;
}
................................................................................
      }
      if( pagerUseWal(pPager) ){
        sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
      }
      pPager->nSavepoint = ii+1;
    }
    assert( pPager->nSavepoint==nSavepoint );



    assertTruncateConstraint(pPager);
  }

  return rc;
}

/*

Changes to test/stmt.test.

46
47
48
49
50
51
52
53
54
55
56
57
58




59
60
61
62
63
64
65
..
69
70
71
72
73
74
75
76
77
78




79
80
81
82

83


84
85
  }
  set sqlite_open_file_count
} {3}
do_test stmt-1.5 {
  execsql COMMIT
  set sqlite_open_file_count
} {1}
do_test stmt-1.6 {
  execsql {
    BEGIN;
      INSERT INTO t1 SELECT a+2, b+2 FROM t1;
  }
  set sqlite_open_file_count




} {3}
do_test stmt-1.7 {
  execsql COMMIT
  set sqlite_open_file_count
} {1}


................................................................................
    execsql { $sql }
    set ret [set sqlite_open_file_count]
    execsql ROLLBACK
    set ret
  }] $expected]
}

filecount stmt-2.1 { INSERT INTO t1 VALUES(5, 5)  } 2
filecount stmt-2.2 { REPLACE INTO t1 VALUES(5, 5) } 2
filecount stmt-2.3 { INSERT INTO t1 SELECT 5, 5   } 3





do_test stmt-2.4 {
  execsql { CREATE INDEX i1 ON t1(b) }
} {}

filecount stmt-2.5 { REPLACE INTO t1 VALUES(5, 5) } 3



finish_test







|





>
>
>
>







 







|
|
|
>
>
>
>

|


>
|
>
>


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  }
  set sqlite_open_file_count
} {3}
do_test stmt-1.5 {
  execsql COMMIT
  set sqlite_open_file_count
} {1}
do_test stmt-1.6.1 {
  execsql {
    BEGIN;
      INSERT INTO t1 SELECT a+2, b+2 FROM t1;
  }
  set sqlite_open_file_count
} {2}
do_test stmt-1.6.2 {
  execsql { INSERT INTO t1 SELECT a+4, b+4 FROM t1 }
  set sqlite_open_file_count
} {3}
do_test stmt-1.7 {
  execsql COMMIT
  set sqlite_open_file_count
} {1}


................................................................................
    execsql { $sql }
    set ret [set sqlite_open_file_count]
    execsql ROLLBACK
    set ret
  }] $expected]
}

filecount stmt-2.1 { INSERT INTO t1 VALUES(9, 9)  } 2
filecount stmt-2.2 { REPLACE INTO t1 VALUES(9, 9) } 2
filecount stmt-2.3 { INSERT INTO t1 SELECT 9, 9   } 2
filecount stmt-2.4 { 
    INSERT INTO t1 SELECT 9, 9;
    INSERT INTO t1 SELECT 10, 10;
} 3

do_test stmt-2.5 {
  execsql { CREATE INDEX i1 ON t1(b) }
} {}
filecount stmt-2.6 { 
  REPLACE INTO t1 VALUES(5, 5);
  REPLACE INTO t1 VALUES(5, 5); 
} 3

finish_test

Changes to test/tempdb.test.

70
71
72
73
74
75
76

77
78
79
80
81
82
83
do_test tempdb-2.2 {
  execsql {
    CREATE TABLE t1 (a PRIMARY KEY, b, c);
    CREATE TABLE t2 (a, b, c);
    BEGIN;
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);

      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + (0==$jrnl_in_memory) + (0==$subj_in_memory)]
do_test tempdb-2.3 {
  execsql {







>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
do_test tempdb-2.2 {
  execsql {
    CREATE TABLE t1 (a PRIMARY KEY, b, c);
    CREATE TABLE t2 (a, b, c);
    BEGIN;
      INSERT INTO t1 VALUES(1, 2, 3);
      INSERT INTO t1 VALUES(4, 5, 6);
      INSERT INTO t2 VALUES(7, 8, 9);
      INSERT INTO t2 SELECT * FROM t1;
  }
  catchsql { INSERT INTO t1 SELECT * FROM t2 }
  set sqlite_open_file_count
} [expr 1 + (0==$jrnl_in_memory) + (0==$subj_in_memory)]
do_test tempdb-2.3 {
  execsql {

Changes to test/walfault.test.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124


125
126
127
128
129
130
131
...
134
135
136
137
138
139
140


141
142
143
144
145
146
147
148
149
150
151
...
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189
190
191
192
193
...
217
218
219
220
221
222
223


224
225
226
227
228
229
230
...
242
243
244
245
246
247
248


249
250
251
252
253
254
255
...
275
276
277
278
279
280
281


282
283
284
285
286
287
288
...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# This test case, walfault-1-*, simulates faults while executing a
#
#   PRAGMA journal_mode = WAL;
#
# statement immediately after creating a new database.
#
do_test walfault-1-pre-1 {
  db close
  file delete -force test.db test.db-wal test.db-journal
  faultsim_save_and_close
} {}
do_faultsim_test walfault-1 -prep {
  faultsim_restore_and_reopen
} -body {
  db eval { PRAGMA main.journal_mode = WAL }
} -test {
................................................................................
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(1500));
  }
  db close
  faultsim_save_and_close
} {}

do_faultsim_test walfault-3 -prep {
  faultsim_restore_and_reopen
} -body {
  db eval {
    DELETE FROM abc;
    PRAGMA wal_checkpoint;
  }
} -test {
  faultsim_test_result {0 {}}
}

file delete -force test.db test.db-wal test.db-journal


faultsim_save_and_close
do_faultsim_test walfault-4 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a PRIMARY KEY, b);
................................................................................
    SELECT * FROM t1;
  }
} -test {
  faultsim_test_result {0 {wal a b}}
  faultsim_integrity_check
} 



do_test walfault-5-pre-1 {
  catch { db close }
  file delete -force test.db test.db-wal test.db-journal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
  }
  faultsim_save_and_close
} {}
do_faultsim_test walfault-5 -faults shmerr* -prep {
................................................................................
    SELECT count(*) FROM t1;
  }
} -test {
  faultsim_test_result {0 16384}
  faultsim_integrity_check
}



do_test walfault-6-pre-1 {
  catch { db close }
  file delete -force test.db test.db-wal test.db-journal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
    BEGIN;
      INSERT INTO t1 VALUES(randomblob(400));           /* 1 */
................................................................................
} -test {
  faultsim_test_result {0 16384}
  faultsim_integrity_check
  set n [db one {SELECT count(*) FROM t1}]
  if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
}



do_test walfault-7-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
................................................................................
  execsql { SELECT count(*) FROM t1 }
} -test {
  faultsim_test_result {0 4}
  set n [db one {SELECT count(*) FROM t1}]
  if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
}



do_test walfault-8-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(900));
  }
................................................................................
  catch { db eval ROLLBACK }
  faultsim_integrity_check

  set n [db one {SELECT count(*) FROM abc}]
  if {$n != 1} { error "Incorrect number of rows: $n" }
}



do_test walfault-9-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(900));
  }
................................................................................
#   3. If the mapping obtained in (2) is not large enough to cover the
#      entire wal-index, call xShmGet(nReq) to get a larger mapping.
#   4. Do the checkpoint.
#   5. Release the lock and mapping.
#
# This test case tests the outcome of an IO error in step 2.
#
proc shmfault_vfs_cb_6 {method args} {
  switch -- $::shm_state {
    0 { return SQLITE_OK }
    1 {
      if {$method == "xShmGet"} {
        set ::wal_index [tvfs shm [lindex $args 0]]
        tvfs shm [lindex $args 0] [string range $::wal_index 0 65535]
        set ::shm_state 2
................................................................................
        tvfs shm [lindex $args 0] $::wal_index
        return SQLITE_IOERR
      }
    }
  }
  return SQLITE_OK
}
do_test walfault-shm-6.1 {
  set ::shm_state 0
  testvfs tvfs 
  tvfs script shmfault_vfs_cb_6

  sqlite3 db  test.db -vfs tvfs
  sqlite3 db2 test.db -vfs tvfs

  execsql {
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(randomblob(900));
  }
} {wal 0}
do_test walfault-shm-6.2 {
  execsql {
    PRAGMA wal_autocheckpoint = 0;
    BEGIN;
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 2 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 4 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 8 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 16 */
................................................................................
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 2048 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 4096 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 8192 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 16384 */
    COMMIT;
  } db2
} {0}
do_test walfault-shm-6.3 {
  set ::shm_state 1
  catchsql { PRAGMA wal_checkpoint } db2
} {1 {disk I/O error}}
set ::shm_state 0
db close
db2 close
tvfs delete
unset -nocomplain ::wal_index ::shm_state

finish_test








|
<







 







<











|
>
>







 







>
>

<
<
|







 







>
|

<
|
<







 







>
>







 







>
>







 







>
>







 







|







 







|


|











|







 







|











23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
...
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
134
135
136
137
138
139
140
141
142
143


144
145
146
147
148
149
150
151
...
175
176
177
178
179
180
181
182
183
184

185

186
187
188
189
190
191
192
...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# This test case, walfault-1-*, simulates faults while executing a
#
#   PRAGMA journal_mode = WAL;
#
# statement immediately after creating a new database.
#
do_test walfault-1-pre-1 {
  faultsim_delete_and_reopen

  faultsim_save_and_close
} {}
do_faultsim_test walfault-1 -prep {
  faultsim_restore_and_reopen
} -body {
  db eval { PRAGMA main.journal_mode = WAL }
} -test {
................................................................................
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(1500));
  }
  db close
  faultsim_save_and_close
} {}

do_faultsim_test walfault-3 -prep {
  faultsim_restore_and_reopen
} -body {
  db eval {
    DELETE FROM abc;
    PRAGMA wal_checkpoint;
  }
} -test {
  faultsim_test_result {0 {}}
}

#--------------------------------------------------------------------------
#
faultsim_delete_and_reopen
faultsim_save_and_close
do_faultsim_test walfault-4 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a PRIMARY KEY, b);
................................................................................
    SELECT * FROM t1;
  }
} -test {
  faultsim_test_result {0 {wal a b}}
  faultsim_integrity_check
} 

#--------------------------------------------------------------------------
#
do_test walfault-5-pre-1 {


  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
  }
  faultsim_save_and_close
} {}
do_faultsim_test walfault-5 -faults shmerr* -prep {
................................................................................
    SELECT count(*) FROM t1;
  }
} -test {
  faultsim_test_result {0 16384}
  faultsim_integrity_check
}

#--------------------------------------------------------------------------
#
do_test walfault-6-pre-1 {

  faultsim_delete_and_reopen

  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
    BEGIN;
      INSERT INTO t1 VALUES(randomblob(400));           /* 1 */
................................................................................
} -test {
  faultsim_test_result {0 16384}
  faultsim_integrity_check
  set n [db one {SELECT count(*) FROM t1}]
  if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
}

#--------------------------------------------------------------------------
#
do_test walfault-7-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
................................................................................
  execsql { SELECT count(*) FROM t1 }
} -test {
  faultsim_test_result {0 4}
  set n [db one {SELECT count(*) FROM t1}]
  if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
}

#--------------------------------------------------------------------------
#
do_test walfault-8-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(900));
  }
................................................................................
  catch { db eval ROLLBACK }
  faultsim_integrity_check

  set n [db one {SELECT count(*) FROM abc}]
  if {$n != 1} { error "Incorrect number of rows: $n" }
}

#--------------------------------------------------------------------------
#
do_test walfault-9-pre-1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE abc(a PRIMARY KEY);
    INSERT INTO abc VALUES(randomblob(900));
  }
................................................................................
#   3. If the mapping obtained in (2) is not large enough to cover the
#      entire wal-index, call xShmGet(nReq) to get a larger mapping.
#   4. Do the checkpoint.
#   5. Release the lock and mapping.
#
# This test case tests the outcome of an IO error in step 2.
#
proc walfault_10_vfs_cb {method args} {
  switch -- $::shm_state {
    0 { return SQLITE_OK }
    1 {
      if {$method == "xShmGet"} {
        set ::wal_index [tvfs shm [lindex $args 0]]
        tvfs shm [lindex $args 0] [string range $::wal_index 0 65535]
        set ::shm_state 2
................................................................................
        tvfs shm [lindex $args 0] $::wal_index
        return SQLITE_IOERR
      }
    }
  }
  return SQLITE_OK
}
do_test walfault-10.1 {
  set ::shm_state 0
  testvfs tvfs 
  tvfs script walfault_10_vfs_cb

  sqlite3 db  test.db -vfs tvfs
  sqlite3 db2 test.db -vfs tvfs

  execsql {
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(randomblob(900));
  }
} {wal 0}
do_test walfault-10.2 {
  execsql {
    PRAGMA wal_autocheckpoint = 0;
    BEGIN;
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 2 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 4 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 8 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 16 */
................................................................................
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 2048 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 4096 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 8192 */
      INSERT INTO t1 SELECT randomblob(900) FROM t1;    /* 16384 */
    COMMIT;
  } db2
} {0}
do_test walfault-10.3 {
  set ::shm_state 1
  catchsql { PRAGMA wal_checkpoint } db2
} {1 {disk I/O error}}
set ::shm_state 0
db close
db2 close
tvfs delete
unset -nocomplain ::wal_index ::shm_state

finish_test