Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Further test cases for pager1.test and pagerfault.test. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
bfd563c4714d86805fa09ce9f4f807e5 |
User & Date: | dan 2010-06-25 19:09:48.000 |
Context
2010-06-26
| ||
15:42 | When synchronous=NORMAL, use the same journal file format as with synchronous=FULL (i.e. multiple journal headers within the one journal). Fix for [d11f09d36e]. (check-in: 2eaf5ee0d9 user: dan tags: trunk) | |
2010-06-25
| ||
19:09 | Further test cases for pager1.test and pagerfault.test. (check-in: bfd563c471 user: dan tags: trunk) | |
16:34 | Reduce the average (but not maximum) size of the allocations made as part of a checkpoint. (check-in: 4a7fd91b7a user: dan tags: trunk) | |
Changes
Changes to src/test_vfs.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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. */ struct Testvfs { char *zName; /* Name of this VFS */ sqlite3_vfs *pParent; /* The VFS to use for file IO */ sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */ Tcl_Interp *interp; /* Interpreter to run script in */ Tcl_Obj *pScript; /* Script to execute */ int nScript; /* Number of elements in array apScript */ Tcl_Obj **apScript; /* Array version of pScript */ TestvfsBuffer *pBuffer; /* List of shared buffers */ int isNoshm; | > > > > > > > > > > > | > > > > > < > | 33 34 35 36 37 38 39 40 41 42 43 44 45 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 | 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 */ }; #define FAULT_INJECT_NONE 0 #define FAULT_INJECT_TRANSIENT 1 #define FAULT_INJECT_PERSISTENT 2 typedef struct TestFaultInject TestFaultInject; struct TestFaultInject { int iCnt; /* Remaining calls before fault injection */ int eFault; /* A FAULT_INJECT_* value */ int nFail; /* Number of faults injected */ }; /* ** 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. */ struct Testvfs { char *zName; /* Name of this VFS */ sqlite3_vfs *pParent; /* The VFS to use for file IO */ sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */ Tcl_Interp *interp; /* Interpreter to run script in */ Tcl_Obj *pScript; /* Script to execute */ int nScript; /* Number of elements in array apScript */ Tcl_Obj **apScript; /* Array version of pScript */ TestvfsBuffer *pBuffer; /* List of shared buffers */ int isNoshm; int mask; /* Mask controlling [script] and [ioerr] */ TestFaultInject ioerr_err; TestFaultInject full_err; TestFaultInject cantopen_err; #if 0 int iIoerrCnt; int ioerr; int nIoerrFail; int iFullCnt; int fullerr; int nFullFail; #endif int iDevchar; int iSectorsize; }; /* ** The Testvfs.mask variable is set to a combination of the following. |
︙ | ︙ | |||
83 84 85 86 87 88 89 | #define TESTVFS_OPEN_MASK 0x00000100 #define TESTVFS_SYNC_MASK 0x00000200 #define TESTVFS_DELETE_MASK 0x00000400 #define TESTVFS_CLOSE_MASK 0x00000800 #define TESTVFS_WRITE_MASK 0x00001000 #define TESTVFS_TRUNCATE_MASK 0x00002000 | > | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #define TESTVFS_OPEN_MASK 0x00000100 #define TESTVFS_SYNC_MASK 0x00000200 #define TESTVFS_DELETE_MASK 0x00000400 #define TESTVFS_CLOSE_MASK 0x00000800 #define TESTVFS_WRITE_MASK 0x00001000 #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_ALL_MASK 0x00007FFF #define TESTVFS_MAX_PAGES 1024 /* ** 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, |
︙ | ︙ | |||
193 194 195 196 197 198 199 | return 1; } } return 0; } | | | | | | > | < < | < < < | | > | > > > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | return 1; } } return 0; } static int tvfsInjectFault(TestFaultInject *p){ int ret = 0; if( p->eFault ){ p->iCnt--; if( p->iCnt==0 || (p->iCnt<0 && p->eFault==FAULT_INJECT_PERSISTENT ) ){ ret = 1; p->nFail++; } } return ret; } static int tvfsInjectIoerr(Testvfs *p){ return tvfsInjectFault(&p->ioerr_err); } static int tvfsInjectFullerr(Testvfs *p){ return tvfsInjectFault(&p->full_err); } static int tvfsInjectCantopenerr(Testvfs *p){ return tvfsInjectFault(&p->cantopen_err); } static void tvfsExecTcl( Testvfs *p, const char *zMethod, Tcl_Obj *arg1, |
︙ | ︙ | |||
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ pId = Tcl_GetObjResult(p->interp); } } if( !pId ){ pId = Tcl_NewStringObj("anon", -1); } Tcl_IncrRefCount(pId); pFd->pShmId = pId; Tcl_ResetResult(p->interp); rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags); if( pFd->pReal->pMethods ){ sqlite3_io_methods *pMethods; pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods)); memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods)); if( ((Testvfs *)pVfs->pAppData)->isNoshm ){ | > > > > > > | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ pId = Tcl_GetObjResult(p->interp); } } if( (p->mask&TESTVFS_OPEN_MASK) && tvfsInjectIoerr(p) ) return SQLITE_IOERR; if( tvfsInjectCantopenerr(p) ) return SQLITE_CANTOPEN; if( tvfsInjectFullerr(p) ) return SQLITE_FULL; if( !pId ){ pId = Tcl_NewStringObj("anon", -1); } Tcl_IncrRefCount(pId); pFd->pShmId = pId; Tcl_ResetResult(p->interp); rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags); if( pFd->pReal->pMethods ){ sqlite3_io_methods *pMethods; pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods)); memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods)); if( ((Testvfs *)pVfs->pAppData)->isNoshm ){ |
︙ | ︙ | |||
564 565 566 567 568 569 570 571 572 573 574 575 576 577 | */ static int tvfsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut); } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (DEVSYM_MAX_PATHNAME+1) bytes. | > > > > > > > > > > > > > > > > > > > | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | */ static int tvfsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ Testvfs *p = (Testvfs *)pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){ int rc; char *zArg = 0; if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS"; if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE"; if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ"; tvfsExecTcl(p, "xAccess", Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0 ); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ Tcl_Interp *interp = p->interp; if( TCL_OK==Tcl_GetBooleanFromObj(0, Tcl_GetObjResult(interp), pResOut) ){ return SQLITE_OK; } } } return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut); } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (DEVSYM_MAX_PATHNAME+1) bytes. |
︙ | ︙ | |||
853 854 855 856 857 858 859 | int objc, Tcl_Obj *CONST objv[] ){ Testvfs *p = (Testvfs *)cd; enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, | | | | | | | > | | | | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | int objc, Tcl_Obj *CONST objv[] ){ Testvfs *p = (Testvfs *)cd; enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR }; struct TestvfsSubcmd { char *zName; enum DB_enum eCmd; } aSubcmd[] = { { "shm", CMD_SHM }, { "delete", CMD_DELETE }, { "filter", CMD_FILTER }, { "ioerr", CMD_IOERR }, { "fullerr", CMD_FULLERR }, { "cantopenerr", CMD_CANTOPENERR }, { "script", CMD_SCRIPT }, { "devchar", CMD_DEVCHAR }, { "sectorsize", CMD_SECTORSIZE }, { 0, 0 } }; int i; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; |
︙ | ︙ | |||
946 947 948 949 950 951 952 953 954 955 956 957 958 959 | { "xShmMap", TESTVFS_SHMMAP_MASK }, { "xSync", TESTVFS_SYNC_MASK }, { "xDelete", TESTVFS_DELETE_MASK }, { "xWrite", TESTVFS_WRITE_MASK }, { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int i; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); | > | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | { "xShmMap", TESTVFS_SHMMAP_MASK }, { "xSync", TESTVFS_SYNC_MASK }, { "xDelete", TESTVFS_DELETE_MASK }, { "xWrite", TESTVFS_WRITE_MASK }, { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, { "xAccess", TESTVFS_ACCESS_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int i; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | Tcl_ResetResult(interp); if( p->pScript ) Tcl_SetObjResult(interp, p->pScript); break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > > | > > > > > > > | | | | | | | 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 | Tcl_ResetResult(interp); if( p->pScript ) Tcl_SetObjResult(interp, p->pScript); break; } /* ** TESTVFS ioerr ?IFAIL PERSIST? ** ** Where IFAIL is an integer and PERSIST is boolean. */ case CMD_CANTOPENERR: case CMD_IOERR: case CMD_FULLERR: { TestFaultInject *pTest; int iRet; switch( aSubcmd[i].eCmd ){ case CMD_IOERR: pTest = &p->ioerr_err; break; case CMD_FULLERR: pTest = &p->full_err; break; case CMD_CANTOPENERR: pTest = &p->cantopen_err; break; default: assert(0); } iRet = pTest->nFail; pTest->nFail = 0; pTest->eFault = 0; pTest->iCnt = 0; if( objc==4 ){ int iCnt, iPersist; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) || TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist) ){ return TCL_ERROR; } pTest->eFault = iPersist?FAULT_INJECT_PERSISTENT:FAULT_INJECT_TRANSIENT; pTest->iCnt = iCnt; }else if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CNT PERSIST?"); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); break; } case CMD_DELETE: { |
︙ | ︙ |
Changes to test/malloc_common.tcl.
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | -injectinstall shmerr_injectinstall \ -injectstart {shmerr_injectstart 1} \ -injectstop shmerr_injectstop \ -injecterrlist {{1 {disk I/O error}}} \ -injectuninstall shmerr_injectuninstall \ ] #-------------------------------------------------------------------------- # Usage do_faultsim_test NAME ?OPTIONS...? # # -faults List of fault types to simulate. # | > > > > > > > > > > > > > > > > > | 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 97 98 99 100 101 102 | -injectinstall shmerr_injectinstall \ -injectstart {shmerr_injectstart 1} \ -injectstop shmerr_injectstop \ -injecterrlist {{1 {disk I/O error}}} \ -injectuninstall shmerr_injectuninstall \ ] # Transient and persistent CANTOPEN errors: # set FAULTSIM(cantopen-transient) [list \ -injectinstall cantopen_injectinstall \ -injectstart {cantopen_injectstart 0} \ -injectstop cantopen_injectstop \ -injecterrlist {{1 {unable to open database file}}} \ -injectuninstall cantopen_injectuninstall \ ] set FAULTSIM(cantopen-persistent) [list \ -injectinstall cantopen_injectinstall \ -injectstart {cantopen_injectstart 1} \ -injectstop cantopen_injectstop \ -injecterrlist {{1 {unable to open database file}}} \ -injectuninstall cantopen_injectuninstall \ ] #-------------------------------------------------------------------------- # Usage do_faultsim_test NAME ?OPTIONS...? # # -faults List of fault types to simulate. # |
︙ | ︙ | |||
199 200 201 202 203 204 205 | catch {db2 close} shmfault delete } proc shmerr_injectstart {persist iFail} { shmfault ioerr $iFail $persist } proc shmerr_injectstop {} { | | | > > > > > > > > > > > > | > > > > > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | catch {db2 close} shmfault delete } proc shmerr_injectstart {persist iFail} { shmfault ioerr $iFail $persist } proc shmerr_injectstop {} { shmfault ioerr } # The following procs are used as [do_one_faultsim_test] callbacks when # injecting SQLITE_FULL error faults into test cases. # proc fullerr_injectinstall {} { testvfs shmfault -default true } proc fullerr_injectuninstall {} { catch {db close} catch {db2 close} shmfault delete } proc fullerr_injectstart {iFail} { shmfault full $iFail 1 } proc fullerr_injectstop {} { shmfault full } # The following procs are used as [do_one_faultsim_test] callbacks when # injecting SQLITE_CANTOPEN error faults into test cases. # proc cantopen_injectinstall {} { testvfs shmfault -default true } proc cantopen_injectuninstall {} { catch {db close} catch {db2 close} shmfault delete } proc cantopen_injectstart {persist iFail} { shmfault cantopen $iFail $persist } proc cantopen_injectstop {} { shmfault cantopen } # This command is not called directly. It is used by the # [faultsim_test_result] command created by [do_faultsim_test] and used # by -test scripts. # proc faultsim_test_result_int {args} { |
︙ | ︙ |
Changes to test/pager1.test.
︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 | } {truncate ok} do_test pager1-11.4 { db2 close file size test.db-journal } {0} breakpoint do_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | } {truncate ok} do_test pager1-11.4 { db2 close file size test.db-journal } {0} breakpoint do_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32} db close tv delete #------------------------------------------------------------------------- # Test "PRAGMA page_size" # foreach pagesize { 512 1024 2048 4096 8192 16384 32768 } { faultsim_delete_and_reopen do_test pager1-12.$pagesize.1 { sqlite3 db2 test.db execsql " PRAGMA page_size = $pagesize; CREATE VIEW v AS SELECT * FROM sqlite_master; " db2 file size test.db } $pagesize do_test pager1-12.$pagesize.2 { sqlite3 db2 test.db execsql { SELECT count(*) FROM v; PRAGMA main.page_size; } db2 } [list 1 $pagesize] do_test pager1-12.$pagesize.3 { execsql { SELECT count(*) FROM v; PRAGMA main.page_size; } } [list 1 $pagesize] db2 close } finish_test |
Changes to test/pagerfault.test.
︙ | ︙ | |||
242 243 244 245 246 247 248 | faultsim_integrity_check set res "" set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }] if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"} } | < > > > > > > > > > > > > > > > > > > > > > > > > > | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | faultsim_integrity_check set res "" set rc [catch { set res [db one { PRAGMA aux.integrity_check }] }] if {$rc!=0 || $res != "ok"} {error "integrity-check problem:$rc $res"} } #------------------------------------------------------------------------- # Test fault-injection as part of a commit when using # journal_mode=TRUNCATE. # do_test pagerfault-6-pre1 { faultsim_delete_and_reopen db func a_string a_string execsql { CREATE TABLE t1(a UNIQUE, b UNIQUE); INSERT INTO t1 VALUES(a_string(200), a_string(300)); } faultsim_save_and_close } {} do_faultsim_test pagerfault-6.1 -prep { faultsim_restore_and_reopen db func a_string a_string execsql { PRAGMA journal_mode = TRUNCATE } } -body { execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } } -test { faultsim_test_result {0 {}} faultsim_integrity_check } # The unix vfs xAccess() method considers a file zero bytes in size to # "not exist". This proc overrides that behaviour so that a zero length # file is considered to exist. # proc xAccess {method filename op args} { if {$op != "SQLITE_ACCESS_EXISTS"} { return "" } return [file exists $filename] } do_faultsim_test pagerfault-6.2 -faults cantopen-* -prep { shmfault filter xAccess shmfault script xAccess faultsim_restore_and_reopen db func a_string a_string execsql { PRAGMA journal_mode = TRUNCATE } } -body { execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 } } -test { faultsim_test_result {0 {}} faultsim_integrity_check } # The following was an attempt to get a bitvec malloc to fail. Didn't work. |
︙ | ︙ |