Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add extra coverage test cases for wal.c. No changes to production code. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
f9d4ae0e8cc5d32c52eb78799f7959dd |
User & Date: | dan 2010-06-05 11:53:34.000 |
Context
2010-06-05
| ||
14:42 | Mark a condition in wal.c as ALWAYS(). (check-in: 3fe0cc784a user: dan tags: trunk) | |
11:53 | Add extra coverage test cases for wal.c. No changes to production code. (check-in: f9d4ae0e8c user: dan tags: trunk) | |
2010-06-04
| ||
18:38 | Clarify an assert in sqlite3WalExclusiveMode(). (check-in: 255850699d user: dan tags: trunk) | |
Changes
Changes to src/test_vfs.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | */ struct TestvfsFile { sqlite3_file base; /* Base class. Must be first */ sqlite3_vfs *pVfs; /* The VFS */ const char *zFilename; /* Filename as passed to xOpen() */ sqlite3_file *pReal; /* The real, underlying file descriptor */ Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */ TestvfsBuffer *pShm; /* Shared memory buffer */ }; /* ** An instance of this structure is allocated for each VFS created. The ** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite ** is set to point to it. | > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | */ struct TestvfsFile { sqlite3_file base; /* Base class. Must be first */ sqlite3_vfs *pVfs; /* The VFS */ const char *zFilename; /* Filename as passed to xOpen() */ sqlite3_file *pReal; /* The real, underlying file descriptor */ Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */ TestvfsBuffer *pShm; /* Shared memory buffer */ u32 excllock; /* Mask of exclusive locks */ u32 sharedlock; /* Mask of shared locks */ TestvfsFile *pNext; /* Next handle opened on the same file */ }; /* ** An instance of this structure is allocated for each VFS created. The ** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite ** is set to point to it. |
︙ | ︙ | |||
73 74 75 76 77 78 79 | #define TESTVFS_SHMCLOSE_MASK 0x00000040 #define TESTVFS_OPEN_MASK 0x00000080 #define TESTVFS_SYNC_MASK 0x00000100 #define TESTVFS_ALL_MASK 0x000001FF /* | | > > | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #define TESTVFS_SHMCLOSE_MASK 0x00000040 #define TESTVFS_OPEN_MASK 0x00000080 #define TESTVFS_SYNC_MASK 0x00000100 #define TESTVFS_ALL_MASK 0x000001FF /* ** A shared-memory buffer. There is one of these objects for each shared ** memory region opened by clients. If two clients open the same file, ** there are two TestvfsFile structures but only one TestvfsBuffer structure. */ struct TestvfsBuffer { char *zFile; /* Associated file name */ int n; /* Size of allocated buffer in bytes */ u8 *a; /* Buffer allocated using ckalloc() */ TestvfsFile *pFile; /* List of open handles */ TestvfsBuffer *pNext; /* Next in linked list of all buffers */ }; #define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent) #define TESTVFS_MAX_ARGS 12 |
︙ | ︙ | |||
569 570 571 572 573 574 575 | Testvfs *p; int rc = SQLITE_OK; /* Return code */ TestvfsBuffer *pBuffer; /* Buffer to open connection to */ TestvfsFile *pFd; /* The testvfs file structure */ pFd = (TestvfsFile*)pFileDes; p = (Testvfs *)pFd->pVfs->pAppData; | | | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | Testvfs *p; int rc = SQLITE_OK; /* Return code */ TestvfsBuffer *pBuffer; /* Buffer to open connection to */ TestvfsFile *pFd; /* The testvfs file structure */ pFd = (TestvfsFile*)pFileDes; p = (Testvfs *)pFd->pVfs->pAppData; assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 ); /* Evaluate the Tcl script: ** ** SCRIPT xShmOpen FILENAME */ Tcl_ResetResult(p->interp); if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){ |
︙ | ︙ | |||
603 604 605 606 607 608 609 | pBuffer->zFile = (char *)&pBuffer[1]; strcpy(pBuffer->zFile, pFd->zFilename); pBuffer->pNext = p->pBuffer; p->pBuffer = pBuffer; } /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ | > | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 | pBuffer->zFile = (char *)&pBuffer[1]; strcpy(pBuffer->zFile, pFd->zFilename); pBuffer->pNext = p->pBuffer; p->pBuffer = pBuffer; } /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ pFd->pNext = pBuffer->pFile; pBuffer->pFile = pFd; pFd->pShm = pBuffer; return SQLITE_OK; } static int tvfsShmSize( sqlite3_file *pFile, int reqSize, |
︙ | ︙ | |||
709 710 711 712 713 714 715 716 717 718 719 720 721 722 | ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } return rc; } static void tvfsShmBarrier(sqlite3_file *pFile){ TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); | > > > > > > > > > > > > > > > > > > > > > > > > | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK ){ int isLock = (flags & SQLITE_SHM_LOCK); int isExcl = (flags & SQLITE_SHM_EXCLUSIVE); u32 mask = (((1<<n)-1) << ofst); if( isLock ){ TestvfsFile *p2; for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){ if( p2==pFd ) continue; if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){ rc = SQLITE_BUSY; break; } } if( rc==SQLITE_OK ){ if( isExcl ) pFd->excllock |= mask; if( !isExcl ) pFd->sharedlock |= mask; } }else{ if( isExcl ) pFd->excllock &= (~mask); if( !isExcl ) pFd->sharedlock &= (~mask); } } return rc; } static void tvfsShmBarrier(sqlite3_file *pFile){ TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
︙ | ︙ | |||
731 732 733 734 735 736 737 738 739 | sqlite3_file *pFile, int deleteFlag ){ int rc = SQLITE_OK; TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); TestvfsBuffer *pBuffer = pFd->pShm; assert( pFd->pShmId && pFd->pShm ); | > < < < > > > | | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | sqlite3_file *pFile, int deleteFlag ){ int rc = SQLITE_OK; TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); TestvfsBuffer *pBuffer = pFd->pShm; TestvfsFile **ppFd; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmClose", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 ); tvfsResultCode(p, &rc); } for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext)); assert( (*ppFd)==pFd ); *ppFd = pFd->pNext; if( pBuffer->pFile==0 ){ TestvfsBuffer **pp; for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext)); *pp = (*pp)->pNext; ckfree((char *)pBuffer->a); ckfree((char *)pBuffer); } pFd->pShm = 0; |
︙ | ︙ |
Changes to test/wal3.test.
︙ | ︙ | |||
312 313 314 315 316 317 318 319 320 321 322 | } do_test wal3-4.4 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } } {1 {locking protocol}} db close T delete | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > | > > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 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 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | } do_test wal3-4.4 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } } {1 {locking protocol}} db close T delete #------------------------------------------------------------------------- # Only one client may run recovery at a time. Test this mechanism. # # When client-2 tries to open a read transaction while client-1 is # running recovery, it fails to obtain a lock on an aReadMark[] slot # (because they are all locked by recovery). It then tries to obtain # a shared lock on the RECOVER lock to see if there really is a # recovery running or not. # # This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR # being returned when client-2 attempts a shared lock on the RECOVER byte. # # An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An # SQLITE_IOERR should be returned to the caller. # do_test wal3-5.1 { faultsim_delete_and_reopen execsql { PRAGMA journal_mode = WAL; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } faultsim_save_and_close } {} testvfs T -default 1 T script method_callback proc method_callback {method args} { if {$method == "xShmBarrier"} { incr ::barrier_count if {$::barrier_count == 1} { # This code is executed within the xShmBarrier() callback invoked # by the client running recovery as part of writing the recovered # wal-index header. If a second client attempts to access the # database now, it reads a corrupt (partially written) wal-index # header. But it cannot even get that far, as the first client # is still holding all the locks (recovery takes an exclusive lock # on *all* db locks, preventing access by any other client). # # If global variable ::wal3_do_lockfailure is non-zero, then set # things up so that an IO error occurs within an xShmLock() callback # made by the second client (aka [db2]). # sqlite3 db2 test.db if { $::wal3_do_lockfailure } { T filter xShmLock } set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ] T filter {} db2 close } } if {$method == "xShmLock"} { foreach {file handle spec} $args break if { $spec == "2 1 lock shared" } { return SQLITE_IOERR } } return SQLITE_OK } # Test a normal SQLITE_BUSY return. # T filter xShmBarrier set testrc "" set testmsg "" set barrier_count 0 set wal3_do_lockfailure 0 do_test wal3-5.2 { faultsim_restore_and_reopen execsql { SELECT * FROM t1 } } {1 2 3 4} do_test wal3-5.3 { list $::testrc $::testmsg } {1 {database is locked}} db close # Test an SQLITE_IOERR return. # T filter xShmBarrier set barrier_count 0 set wal3_do_lockfailure 1 set testrc "" set testmsg "" do_test wal3-5.4 { faultsim_restore_and_reopen execsql { SELECT * FROM t1 } } {1 2 3 4} do_test wal3-5.5 { list $::testrc $::testmsg } {1 {disk I/O error}} db close T delete #------------------------------------------------------------------------- # When opening a read-transaction on a database # finish_test |
Changes to test/walfault.test.
︙ | ︙ | |||
317 318 319 320 321 322 323 324 325 326 | faultsim_integrity_check catch { db eval { ROLLBACK TO spoint } } catch { db eval { COMMIT } } set n [db one {SELECT count(*) FROM abc}] if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 317 318 319 320 321 322 323 324 325 326 327 328 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 | faultsim_integrity_check catch { db eval { ROLLBACK TO spoint } } catch { db eval { COMMIT } } set n [db one {SELECT count(*) FROM abc}] if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } } do_test walfault-10-pre1 { faultsim_delete_and_reopen execsql { PRAGMA journal_mode = WAL; PRAGMA wal_checkpoint = 0; CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB); CREATE INDEX zzzz ON z(zzz); INSERT INTO z VALUES(NULL, randomblob(800)); INSERT INTO z VALUES(NULL, randomblob(800)); INSERT INTO z SELECT NULL, randomblob(800) FROM z; INSERT INTO z SELECT NULL, randomblob(800) FROM z; INSERT INTO z SELECT NULL, randomblob(800) FROM z; INSERT INTO z SELECT NULL, randomblob(800) FROM z; INSERT INTO z SELECT NULL, randomblob(800) FROM z; } faultsim_save_and_close } {} do_faultsim_test walfault-10 -prep { faultsim_restore_and_reopen execsql { PRAGMA cache_size = 10; BEGIN; UPDATE z SET zzz = randomblob(799); } set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1] sqlite3_step $::stmt } -body { execsql { INSERT INTO z VALUES(NULL, NULL) } } -test { sqlite3_finalize $::stmt faultsim_integrity_check faultsim_test_result {0 {}} catch { db eval { ROLLBACK } } faultsim_integrity_check set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}] if {$n != "64 51200"} { error "Incorrect data: $n" } } finish_test |