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 |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c43deb33ae5f191ea2e054181759beee |
User & Date: | dan 2010-06-03 12:35:28.000 |
Context
2010-06-03
| ||
16:58 | Add extra tests for removing elements from wal-index hash tables as part of a rollback. (check-in: af3e598ad9 user: dan tags: trunk) | |
12:35 | Delay opening the sub-journal until SQLite actually needs to write data to it. (check-in: c43deb33ae user: dan tags: trunk) | |
12:09 | Remove global variables when compiled with SQLITE_OMIT_WSD (check-in: dd10a547f1 user: drh tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 | 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 ** for all open savepoints before returning. ** ** This function returns SQLITE_OK if everything is successful, an IO ** 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; | > > > > > > > > > > > > > > > > > > > > | < < < > | | | > > > > > > > > > > > | | | > | 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 3436 3437 3438 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 | 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 ** for all open savepoints before returning. ** ** This function returns SQLITE_OK if everything is successful, an IO ** 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); } |
︙ | ︙ | |||
4396 4397 4398 4399 4400 4401 4402 | if( pPg ){ Pager *pPager = pPg->pPager; sqlite3PcacheRelease(pPg); pagerUnlockIfUnused(pPager); } } | < < < < < < < < < < < < < < < < < < < < < | 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 | 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 |
︙ | ︙ | |||
4499 4500 4501 4502 4503 4504 4505 | pPager->needSync = 0; pPager->nRec = 0; pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; rc = writeJournalHdr(pPager); } | < < < | 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 | 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; } |
︙ | ︙ | |||
5465 5466 5467 5468 5469 5470 5471 | } if( pagerUseWal(pPager) ){ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); } pPager->nSavepoint = ii+1; } assert( pPager->nSavepoint==nSavepoint ); | < < < | 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 | } 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 | } set sqlite_open_file_count } {3} do_test stmt-1.5 { execsql COMMIT set sqlite_open_file_count } {1} | | > > > > | | | > > > > | | > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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} proc filecount {testname sql expected} { uplevel [list do_test $testname [subst -nocommand { execsql BEGIN 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 | # 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 { | < | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # 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 { |
︙ | ︙ | |||
105 106 107 108 109 110 111 | PRAGMA journal_mode = WAL; CREATE TABLE abc(a PRIMARY KEY); INSERT INTO abc VALUES(randomblob(1500)); } db close faultsim_save_and_close } {} | < > > | > > < | < | 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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | 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); INSERT INTO t1 VALUES('a', 'b'); PRAGMA wal_checkpoint; 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 { |
︙ | ︙ | |||
175 176 177 178 179 180 181 | SELECT count(*) FROM t1; } } -test { faultsim_test_result {0 16384} faultsim_integrity_check } | > | < | < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | 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 */ |
︙ | ︙ | |||
217 218 219 220 221 222 223 224 225 226 227 228 229 230 | } -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); | > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | } -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); |
︙ | ︙ | |||
242 243 244 245 246 247 248 249 250 251 252 253 254 255 | 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)); } | > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | 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)); } |
︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 | 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)); } | > > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | 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)); } |
︙ | ︙ | |||
324 325 326 327 328 329 330 | # 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. # | | | | | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 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 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | # 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 } } 2 { if {$method == "xShmGet"} { 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; /* 32 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ 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 |