Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Various fixes for test cases. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6b27bf40697aaedf2a2e1e67f29cb9e2 |
User & Date: | dan 2013-02-25 17:18:20.565 |
Context
2013-02-25
| ||
17:49 | Fix a legacy test case that uses zeroblob(). check-in: 22d65927b3 user: dan tags: trunk | |
17:18 | Various fixes for test cases. check-in: 6b27bf4069 user: dan tags: trunk | |
16:36 | File Format Change Modify the key encoding so that final BLOBs are entered byte-for-byte with no terminator. check-in: 3b2515079a user: drh tags: trunk | |
Changes
Changes to main.mk.
︙ | ︙ | |||
487 488 489 490 491 492 493 | TESTFIXTURE_PREREQ = $(TESTSRC) $(TESTSRC2) TESTFIXTURE_PREREQ += $(TOP)/src/tclsqlite.c TESTFIXTURE_PREREQ += libsqlite4.a testfixture$(EXE): $(TESTFIXTURE_PREREQ) $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | TESTFIXTURE_PREREQ = $(TESTSRC) $(TESTSRC2) TESTFIXTURE_PREREQ += $(TOP)/src/tclsqlite.c TESTFIXTURE_PREREQ += libsqlite4.a testfixture$(EXE): $(TESTFIXTURE_PREREQ) $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ -o testfixture$(EXE) $(LIBTCL) libsqlite4.a $(THREADLIB) amalgamation-testfixture$(EXE): sqlite4.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite4.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) fts3-testfixture$(EXE): sqlite4.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c |
︙ | ︙ |
Changes to src/fts5func.c.
︙ | ︙ | |||
542 543 544 545 546 547 548 549 550 551 552 553 554 555 | iOff += nShift; mask = mask >> nShift; pSnip->iOff = iOff; pSnip->hlmask = mask; } static void fts5Snippet(sqlite4_context *pCtx, int nArg, sqlite4_value **apArg){ Snippet aSnip[4]; int nSnip; int iCol = -1; int nToken = -15; int rc; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | iOff += nShift; mask = mask >> nShift; pSnip->iOff = iOff; pSnip->hlmask = mask; } /* ** Parameter aSnip points to an array of nSnip Snippet objects, where nSnip ** is less than or equal to 4. This function sorts the array in place in ** ascending order of Snippet.iCol and Snippet.iOff. */ static void fts5SnippetSort(Snippet *aSnip, int nSnip){ Snippet aTmp[4]; int i; assert( nSnip<=4 && nSnip>=1 ); for(i=0; i<nSnip; i++){ int iBest = -1; int iTry; for(iTry=0; iTry<nSnip; iTry++){ Snippet *pTry = &aSnip[iTry]; if( pTry->iCol>=0 && (iBest<0 || pTry->iCol<aSnip[iBest].iCol || (pTry->iCol==aSnip[iBest].iCol && pTry->iOff<aSnip[iBest].iOff) )){ iBest = iTry; } } assert( iBest>=0 ); memcpy(&aTmp[i], &aSnip[iBest], sizeof(Snippet)); aSnip[iBest].iCol = -1; } memcpy(aSnip, aTmp, sizeof(Snippet)*nSnip); } static void fts5Snippet(sqlite4_context *pCtx, int nArg, sqlite4_value **apArg){ Snippet aSnip[4]; int nSnip; int iCol = -1; int nToken = -15; int rc; |
︙ | ︙ | |||
579 580 581 582 583 584 585 586 587 588 589 590 591 592 | memset(aSnip, 0, sizeof(aSnip)); for(i=0; rc==SQLITE4_OK && i<nSnip; i++){ rc = fts5BestSnippet(pCtx, iCol, &mask, nTok, &aSnip[i]); } if( mask==0 || nSnip==4 ){ SnippetText text = {0, 0, 0}; for(i=0; rc==SQLITE4_OK && i<nSnip; i++){ int nSz; rc = sqlite4_mi_size(pCtx, aSnip[i].iCol, -1, &nSz); if( rc==SQLITE4_OK ){ fts5SnippetImprove(pCtx, nTok, nSz, &aSnip[i]); rc = fts5SnippetText( pCtx, &aSnip[i], &text, nTok, zStart, zEnd, zEllipses | > | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | memset(aSnip, 0, sizeof(aSnip)); for(i=0; rc==SQLITE4_OK && i<nSnip; i++){ rc = fts5BestSnippet(pCtx, iCol, &mask, nTok, &aSnip[i]); } if( mask==0 || nSnip==4 ){ SnippetText text = {0, 0, 0}; fts5SnippetSort(aSnip, nSnip); for(i=0; rc==SQLITE4_OK && i<nSnip; i++){ int nSz; rc = sqlite4_mi_size(pCtx, aSnip[i].iCol, -1, &nSz); if( rc==SQLITE4_OK ){ fts5SnippetImprove(pCtx, nTok, nSz, &aSnip[i]); rc = fts5SnippetText( pCtx, &aSnip[i], &text, nTok, zStart, zEnd, zEllipses |
︙ | ︙ |
Changes to src/lsm_main.c.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 149 150 151 | if( rc!=LSM_OK ){ lsmFree(pEnv, zAlloc); zAlloc = 0; } *pzAbs = zAlloc; return rc; } /* ** Open a new connection to database zFilename. */ int lsm_open(lsm_db *pDb, const char *zFilename){ int rc; | > > > > > > > > > > > > > > > > > > > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | if( rc!=LSM_OK ){ lsmFree(pEnv, zAlloc); zAlloc = 0; } *pzAbs = zAlloc; return rc; } /* ** Check that the bits in the db->mLock mask are consistent with the ** value stored in db->iRwclient. An assert shall fail otherwise. */ static void assertRwclientLockValue(lsm_db *db){ #ifndef NDEBUG u64 msk; /* Mask of mLock bits for RWCLIENT locks */ u64 rwclient = 0; /* Bit corresponding to db->iRwclient */ if( db->iRwclient>=0 ){ rwclient = ((u64)1 << (LSM_LOCK_RWCLIENT(db->iRwclient)-1)); } msk = ((u64)1 << (LSM_LOCK_RWCLIENT(LSM_LOCK_NRWCLIENT)-1)) - 1; msk -= (((u64)1 << (LSM_LOCK_RWCLIENT(0)-1)) - 1); assert( (db->mLock & msk)==rwclient ); #endif } /* ** Open a new connection to database zFilename. */ int lsm_open(lsm_db *pDb, const char *zFilename){ int rc; |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 | if( rc==LSM_OK && LSM_OK==(rc = lsmCheckpointLoad(pDb, 0)) ){ lsmFsSetPageSize(pDb->pFS, lsmCheckpointPgsz(pDb->aSnapshot)); lsmFsSetBlockSize(pDb->pFS, lsmCheckpointBlksz(pDb->aSnapshot)); } } lsmFree(pDb->pEnv, zFull); } assert( pDb->bReadonly==0 || pDb->bReadonly==1 ); assert( rc!=LSM_OK || (pDb->pShmhdr==0)==(pDb->bReadonly==1) ); return rc; } | > < > > | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | if( rc==LSM_OK && LSM_OK==(rc = lsmCheckpointLoad(pDb, 0)) ){ lsmFsSetPageSize(pDb->pFS, lsmCheckpointPgsz(pDb->aSnapshot)); lsmFsSetBlockSize(pDb->pFS, lsmCheckpointBlksz(pDb->aSnapshot)); } } lsmFree(pDb->pEnv, zFull); assertRwclientLockValue(pDb); } assert( pDb->bReadonly==0 || pDb->bReadonly==1 ); assert( rc!=LSM_OK || (pDb->pShmhdr==0)==(pDb->bReadonly==1) ); return rc; } int lsm_close(lsm_db *pDb){ int rc = LSM_OK; if( pDb ){ assert_db_state(pDb); if( pDb->pCsr || pDb->nTransOpen ){ rc = LSM_MISUSE_BKPT; }else{ lsmFreeSnapshot(pDb->pEnv, pDb->pClient); pDb->pClient = 0; assertRwclientLockValue(pDb); lsmDbDatabaseRelease(pDb); lsmLogClose(pDb); lsmFsClose(pDb->pFS); assert( pDb->mLock==0 ); /* Invoke any destructors registered for the compression or |
︙ | ︙ |
Changes to src/lsm_shared.c.
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 | } } } } if( pDb->iRwclient>=0 ){ lsmShmLock(pDb, LSM_LOCK_RWCLIENT(pDb->iRwclient), LSM_LOCK_UNLOCK, 0); } lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); } pDb->pShmhdr = 0; } | > | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | } } } } if( pDb->iRwclient>=0 ){ lsmShmLock(pDb, LSM_LOCK_RWCLIENT(pDb->iRwclient), LSM_LOCK_UNLOCK, 0); pDb->iRwclient = -1; } lsmShmLock(pDb, LSM_LOCK_DMS2, LSM_LOCK_UNLOCK, 0); lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); } pDb->pShmhdr = 0; } |
︙ | ︙ | |||
397 398 399 400 401 402 403 404 405 406 407 408 409 410 | if( rc2!=LSM_BUSY ){ rc = rc2; break; } } } lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); return rc; } static int dbOpenSharedFd(lsm_env *pEnv, Database *p, int bRoOk){ int rc; rc = lsmEnvOpen(pEnv, p->zName, 0, &p->pFile); | > | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | if( rc2!=LSM_BUSY ){ rc = rc2; break; } } } lsmShmLock(pDb, LSM_LOCK_DMS1, LSM_LOCK_UNLOCK, 0); return rc; } static int dbOpenSharedFd(lsm_env *pEnv, Database *p, int bRoOk){ int rc; rc = lsmEnvOpen(pEnv, p->zName, 0, &p->pFile); |
︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 | case LSM_LOCK_SHARED: if( nExcl ){ rc = LSM_BUSY; }else{ if( nShared==0 ){ rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_SHARED); } | > | | > > | > | 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | case LSM_LOCK_SHARED: if( nExcl ){ rc = LSM_BUSY; }else{ if( nShared==0 ){ rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_SHARED); } if( rc==LSM_OK ){ db->mLock |= ms; db->mLock &= ~me; } } break; default: assert( eOp==LSM_LOCK_EXCL ); if( nExcl || nShared ){ rc = LSM_BUSY; }else{ rc = lockSharedFile(db->pEnv, p, iLock, LSM_LOCK_EXCL); if( rc==LSM_OK ){ db->mLock |= (me|ms); } } break; } lsmMutexLeave(db->pEnv, p->pClientMutex); } |
︙ | ︙ |
Changes to test/ckpt1.test.
︙ | ︙ | |||
72 73 74 75 76 77 78 | INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 4K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 8K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 16K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 32K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 64K } do_test 3.2 { | < > | | 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 | INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 4K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 8K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 16K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 32K INSERT INTO t1 SELECT randstr(100,100), randstr(100,100) FROM t1; -- 64K } do_test 3.2 { sqlite4_lsm_work db main -nmerge 1 -npage 1000000 execsql { SELECT count(*) FROM t1 } } {65536} do_test 3.3 { db close sqlite4 db test.db execsql { SELECT count(*) FROM t1 } } {65536} do_test 3.4 { execsql { INSERT INTO t1 VALUES(randstr(100,100), randstr(100,100)) } db close sqlite4 db test.db sqlite4_lsm_work db main -nmerge 1 -npage 1000000 execsql { SELECT count(*) FROM t1 } } {65537} finish_test |
Changes to test/csr1.test.
︙ | ︙ | |||
73 74 75 76 77 78 79 | # tree to be flushed to disk, # populate_db_2 do_execsql_test 3.1 { BEGIN; INSERT INTO t1 VALUES(10, randstr(910, 910)); } | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | # tree to be flushed to disk, # populate_db_2 do_execsql_test 3.1 { BEGIN; INSERT INTO t1 VALUES(10, randstr(910, 910)); } do_test 3.2 { sqlite4_lsm_config db main autoflush } 1024 do_test 3.3 { sqlite4_lsm_config db main autoflush 4 } 4 do_test 3.4 { set res [list] db eval { SELECT a, length(b) AS l FROM t1 } { lappend res $a $l # The following commit will flush the in-memory tree to disk. if {$a == 5} { db eval COMMIT } |
︙ | ︙ |
Changes to test/log3.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | do_test 1.7 { sqlite4_lsm_config db main safety } {2} do_test 1.8 { sqlite4_lsm_config db main safety 3 } {2} do_test 1.9 { sqlite4_lsm_config db main safety } {2} #------------------------------------------------------------------------- reset_db do_test 2.0 { sqlite4_lsm_config db main safety 2 } {2} | < | | | 32 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 | do_test 1.7 { sqlite4_lsm_config db main safety } {2} do_test 1.8 { sqlite4_lsm_config db main safety 3 } {2} do_test 1.9 { sqlite4_lsm_config db main safety } {2} #------------------------------------------------------------------------- reset_db do_test 2.0 { sqlite4_lsm_config db main safety 2 } {2} do_execsql_test 2.2 { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); } {} do_filesize_test 2.3 0 1024 do_execsql_test 2.4 { BEGIN; INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); COMMIT; } {} do_filesize_test 2.5 0 2048 do_test 2.6 { optimize_db } {} do_execsql_test 2.7 { INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)) } do_test 2.8 { sqlite4_lsm_checkpoint db main } {} do_test 2.9 { sqlite4_lsm_info db main log-structure } {0 0 0 0 2560 3072} for {set i 1} {$i <= 6} {incr i} { do_execsql_test 2.10.$i.1 { INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); } do_execsql_test 2.10.$i.2 { SELECT count(*) FROM t1 } [expr 8 + $i] do_recover_test 2.10.$i.3 { SELECT count(*) FROM t1 } [expr 8 + $i] } do_test 2.11 { sqlite4_lsm_info db main log-structure } {0 0 0 0 2560 6144} finish_test |
Changes to test/lsm1.test.
︙ | ︙ | |||
86 87 88 89 90 91 92 | db write ccc three db write ddd four db write eee five db write fff six reopen db delete_range a bbb reopen | < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | db write ccc three db write ddd four db write eee five db write fff six reopen db delete_range a bbb reopen db work 10 } {1} do_contents_test 2.2 { {bbb two} {ccc three} {ddd four} {eee five} {fff six} } #------------------------------------------------------------------------- |
︙ | ︙ | |||
115 116 117 118 119 120 121 | } {1} do_test 3.2 { db write bx seven reopen db delete_range aaa bx reopen | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | } {1} do_test 3.2 { db write bx seven reopen db delete_range aaa bx reopen db work 2 10 } {1} do_contents_test 3.3 { {aaa one} {bx seven} {ccc three} {ddd four} {eee five} {fff six} } do_test 3.4 { fetch ddd } four |
︙ | ︙ |
Changes to test/lsm3.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 | } else { set locked {0 {}} } # Open a single-process connection to the database from an external # process (if $tn==1, otherwise open it from within the current # process). code2 { sqlite4 db2 file:test.db?lsm_multiple_processes=0 } # Try to open some other connections to the database file, both in multi # and single process mode. If ($tn==1), then all such attempts fail. Or, # if ($tn==2), they all succeed. do_test $tn.1 { catch { db close } | > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | } else { set locked {0 {}} } # Open a single-process connection to the database from an external # process (if $tn==1, otherwise open it from within the current # process). breakpoint code2 { sqlite4 db2 file:test.db?lsm_multiple_processes=0 } # Try to open some other connections to the database file, both in multi # and single process mode. If ($tn==1), then all such attempts fail. Or, # if ($tn==2), they all succeed. do_test $tn.1 { catch { db close } |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
131 132 133 134 135 136 137 | # lappend ::testsuitelist xxx test_suite "src4" -prefix "" -description { } -files { simple.test simple2.test log3.test | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | # lappend ::testsuitelist xxx test_suite "src4" -prefix "" -description { } -files { simple.test simple2.test log3.test lsm1.test lsm2.test lsm3.test lsm4.test lsm5.test csr1.test ckpt1.test mc1.test fts5expr1.test fts5query1.test fts5rnd1.test fts5create.test fts5snippet.test aggerror.test |
︙ | ︙ |
Changes to test/simple.test.
︙ | ︙ | |||
83 84 85 86 87 88 89 | do_execsql_test 3.1 { CREATE TABLE t1(k PRIMARY KEY, v UNIQUE) } do_execsql_test 3.2 { SELECT * FROM sqlite_master } { table t1 t1 2 {CREATE TABLE t1(k PRIMARY KEY, v UNIQUE)} | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | do_execsql_test 3.1 { CREATE TABLE t1(k PRIMARY KEY, v UNIQUE) } do_execsql_test 3.2 { SELECT * FROM sqlite_master } { table t1 t1 2 {CREATE TABLE t1(k PRIMARY KEY, v UNIQUE)} index sqlite_t1_unique2 t1 3 {} } #explain { INSERT INTO t1 VALUES('one', '111') } #execsql { PRAGMA vdbe_trace = 1 } #execsql { PRAGMA kv_trace = 1 } # do_execsql_test 3.3 { INSERT INTO t1 VALUES('one', '111') } {} |
︙ | ︙ | |||
123 124 125 126 127 128 129 | do_execsql_test 5.1 { CREATE TABLE t1(k, v UNIQUE) } do_execsql_test 5.2 { CREATE INDEX i1 ON t1(v) } do_execsql_test 5.3 { SELECT * FROM sqlite_master } { table t1 t1 3 {CREATE TABLE t1(k, v UNIQUE)} | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | do_execsql_test 5.1 { CREATE TABLE t1(k, v UNIQUE) } do_execsql_test 5.2 { CREATE INDEX i1 ON t1(v) } do_execsql_test 5.3 { SELECT * FROM sqlite_master } { table t1 t1 3 {CREATE TABLE t1(k, v UNIQUE)} index sqlite_t1_unique1 t1 2 {} index i1 t1 4 {CREATE INDEX i1 ON t1(v)} } do_execsql_test 5.3 { INSERT INTO t1 VALUES('one', '111') } {} do_execsql_test 5.4 { SELECT * FROM t1 } {one 111} do_execsql_test 5.5 { PRAGMA integrity_check } {ok} |
︙ | ︙ |
Changes to test/test_lsm.c.
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | return LSM_OK; } static void testCompressNoopFree(void *pCtx){ } /* ** End of compression routines "noop". *************************************************************************/ /* ** TCLCMD: sqlite4_lsm_config DB DBNAME PARAM ... */ static int test_sqlite4_lsm_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < | < | < < < < < | < | < < < < | | < | > | | > | | < | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 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 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 299 300 301 302 303 304 305 306 307 308 309 310 311 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 | return LSM_OK; } static void testCompressNoopFree(void *pCtx){ } /* ** End of compression routines "noop". *************************************************************************/ static int testConfigureSetCompression( Tcl_Interp *interp, lsm_db *db, Tcl_Obj *pCmp, unsigned int iId ){ struct CompressionScheme { const char *zName; lsm_compress cmp; } aCmp[] = { { "encrypt", { 0, 43, testCompressEncBound, testCompressEncCompress, testCompressEncUncompress, testCompressEncFree } }, { "rle", { 0, 44, testCompressRleBound, testCompressRleCompress, testCompressRleUncompress, testCompressRleFree } }, { "noop", { 0, 45, testCompressNoopBound, testCompressNoopCompress, testCompressNoopUncompress, testCompressNoopFree } }, { 0, {0, 0, 0, 0, 0, 0} } }; int iOpt; int rc; if( interp ){ rc = Tcl_GetIndexFromObjStruct( interp, pCmp, aCmp, sizeof(aCmp[0]), "scheme", 0, &iOpt ); if( rc!=TCL_OK ) return rc; }else{ int nOpt = sizeof(aCmp)/sizeof(aCmp[0]); for(iOpt=0; iOpt<nOpt; iOpt++){ if( iId==aCmp[iOpt].cmp.iId ) break; } if( iOpt==nOpt ) return 0; } rc = lsm_config(db, LSM_CONFIG_SET_COMPRESSION, &aCmp[iOpt].cmp); return rc; } static int testCompressFactory(void *pCtx, lsm_db *db, unsigned int iId){ return testConfigureSetCompression(0, db, 0, iId); } static int testConfigureSetFactory( Tcl_Interp *interp, lsm_db *db, Tcl_Obj *pArg ){ lsm_compress_factory aFactory[2] = { { 0, 0, 0 }, { 0, testCompressFactory, 0 }, }; int bArg = 0; int rc; rc = Tcl_GetBooleanFromObj(interp, pArg, &bArg); if( rc!=TCL_OK ) return rc; assert( bArg==1 || bArg==0 ); rc = lsm_config(db, LSM_CONFIG_SET_COMPRESSION_FACTORY, &aFactory[bArg]); return rc; } /* ** Array apObj[] is an array of nObj Tcl objects intended to be transformed ** into lsm_config() calls on database db. ** ** Each pair of objects in the array is treated as a key/value pair used ** as arguments to a single lsm_config() call. If there are an even number ** of objects in the array, then the interpreter result is set to the output ** value of the final lsm_config() call. Or, if there are an odd number of ** objects in the array, the final object is treated as the key for a ** read-only call to lsm_config(), the return value of which is used as ** the interpreter result. For example, the following: ** ** { safety 1 mmap 0 use_log } ** ** Results in a sequence of calls similar to: ** ** iVal = 1; lsm_config(db, LSM_CONFIG_SAFETY, &iVal); ** iVal = 0; lsm_config(db, LSM_CONFIG_MMAP, &iVal); ** iVal = -1; lsm_config(db, LSM_CONFIG_USE_LOG, &iVal); ** Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); */ static int testConfigureLsm( Tcl_Interp *interp, lsm_db *db, int nObj, Tcl_Obj *const* apObj ){ struct Lsmconfig { const char *zOpt; int eOpt; int bInteger; } aConfig[] = { { "autoflush", LSM_CONFIG_AUTOFLUSH, 1 }, { "page_size", LSM_CONFIG_PAGE_SIZE, 1 }, { "block_size", LSM_CONFIG_BLOCK_SIZE, 1 }, { "safety", LSM_CONFIG_SAFETY, 1 }, { "autowork", LSM_CONFIG_AUTOWORK, 1 }, { "autocheckpoint", LSM_CONFIG_AUTOCHECKPOINT, 1 }, { "mmap", LSM_CONFIG_MMAP, 1 }, { "use_log", LSM_CONFIG_USE_LOG, 1 }, { "automerge", LSM_CONFIG_AUTOMERGE, 1 }, { "max_freelist", LSM_CONFIG_MAX_FREELIST, 1 }, { "multi_proc", LSM_CONFIG_MULTIPLE_PROCESSES, 1 }, { "set_compression", LSM_CONFIG_SET_COMPRESSION, 0 }, { "set_compression_factory", LSM_CONFIG_SET_COMPRESSION_FACTORY, 0 }, { "readonly", LSM_CONFIG_READONLY, 1 }, { 0, 0, 0 } }; int i; int rc = TCL_OK; for(i=0; rc==TCL_OK && i<nObj; i+=2){ int iOpt; rc = Tcl_GetIndexFromObjStruct( interp, apObj[i], aConfig, sizeof(aConfig[0]), "option", 0, &iOpt ); if( rc==TCL_OK ){ if( i==(nObj-1) ){ Tcl_ResetResult(interp); if( aConfig[iOpt].bInteger ){ int iVal = -1; lsm_config(db, aConfig[iOpt].eOpt, &iVal); Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); } }else{ if( aConfig[iOpt].eOpt==LSM_CONFIG_SET_COMPRESSION ){ rc = testConfigureSetCompression(interp, db, apObj[i+1], 0); } else if( aConfig[iOpt].eOpt==LSM_CONFIG_SET_COMPRESSION_FACTORY ){ rc = testConfigureSetFactory(interp, db, apObj[i+1]); } else { int iVal; rc = Tcl_GetIntFromObj(interp, apObj[i+1], &iVal); if( rc==TCL_OK ){ lsm_config(db, aConfig[iOpt].eOpt, &iVal); } Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); } } } } return rc; } /* ** TCLCMD: sqlite4_lsm_config DB DBNAME PARAM ... */ static int test_sqlite4_lsm_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zDb; /* objv[1] as a string */ const char *zName; /* objv[2] as a string */ int rc; sqlite4 *db; lsm_db *pLsm; /* Process arguments. Return early if there is a problem. */ if( objc!=4 && objc!=5 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME PARAM ?VALUE?"); return TCL_ERROR; } zDb = Tcl_GetString(objv[1]); zName = Tcl_GetString(objv[2]); rc = getDbPointer(interp, zDb, &db); if( rc==TCL_OK ){ rc = sqlite4_kvstore_control(db, zName, SQLITE4_KVCTRL_LSM_HANDLE, &pLsm); if( rc!=SQLITE4_OK ){ Tcl_SetResult(interp, (char *)sqlite4TestErrorName(rc), TCL_STATIC); rc = TCL_ERROR; } } if( rc==SQLITE4_OK ){ testConfigureLsm(interp, pLsm, objc-3, &objv[3]); } return rc; } /* ** TCLCMD: sqlite4_lsm_info DB DBNAME PARAM */ static int test_sqlite4_lsm_info( void * clientData, |
︙ | ︙ | |||
364 365 366 367 368 369 370 | return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } typedef struct TclLsmCursor TclLsmCursor; typedef struct TclLsm TclLsm; struct TclLsm { lsm_db *db; }; |
︙ | ︙ | |||
882 883 884 885 886 887 888 | case 9: assert( 0==strcmp(aCmd[9].zCmd, "flush") ); { rc = lsm_flush(p->db); return test_lsm_error(interp, "lsm_flush", rc); } case 10: assert( 0==strcmp(aCmd[10].zCmd, "config") ); { | > > > | > > | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 | case 9: assert( 0==strcmp(aCmd[9].zCmd, "flush") ); { rc = lsm_flush(p->db); return test_lsm_error(interp, "lsm_flush", rc); } case 10: assert( 0==strcmp(aCmd[10].zCmd, "config") ); { Tcl_Obj **apObj; int nObj; if( TCL_OK==Tcl_ListObjGetElements(interp, objv[2], &nObj, &apObj) ){ return testConfigureLsm(interp, p->db, nObj, apObj); } return TCL_ERROR; } case 11: assert( 0==strcmp(aCmd[11].zCmd, "checkpoint") ); { rc = lsm_checkpoint(p->db, 0); return test_lsm_error(interp, "lsm_checkpoint", rc); } |
︙ | ︙ | |||
940 941 942 943 944 945 946 | if( rc!=LSM_OK ){ test_lsm_del((void *)p); test_lsm_error(interp, "lsm_new", rc); return TCL_ERROR; } if( objc==4 ){ | > > > > | > | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | if( rc!=LSM_OK ){ test_lsm_del((void *)p); test_lsm_error(interp, "lsm_new", rc); return TCL_ERROR; } if( objc==4 ){ Tcl_Obj **apObj; int nObj; rc = Tcl_ListObjGetElements(interp, objv[3], &nObj, &apObj); if( rc==TCL_OK ){ rc = testConfigureLsm(interp, p->db, nObj, apObj); } if( rc!=TCL_OK ){ test_lsm_del((void *)p); return rc; } } lsm_config_log(p->db, xLog, 0); |
︙ | ︙ | |||
968 969 970 971 972 973 974 | int SqlitetestLsm_Init(Tcl_Interp *interp){ struct SyscallCmd { const char *zName; Tcl_ObjCmdProc *xCmd; } aCmd[] = { { "sqlite4_lsm_work", test_sqlite4_lsm_work }, { "sqlite4_lsm_checkpoint", test_sqlite4_lsm_checkpoint }, | < | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 | int SqlitetestLsm_Init(Tcl_Interp *interp){ struct SyscallCmd { const char *zName; Tcl_ObjCmdProc *xCmd; } aCmd[] = { { "sqlite4_lsm_work", test_sqlite4_lsm_work }, { "sqlite4_lsm_checkpoint", test_sqlite4_lsm_checkpoint }, { "sqlite4_lsm_info", test_sqlite4_lsm_info }, { "sqlite4_lsm_config", test_sqlite4_lsm_config }, { "lsm_open", test_lsm_open }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xCmd, 0, 0); } return TCL_OK; } |
Changes to test/tester.tcl.
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | # Flush the in-memory tree to disk and merge all runs together into # a single b-tree structure. Because this annihilates all delete keys, # the next rowid allocated for each table with an IPK will be as expected # by SQLite 3 tests. # proc optimize_db {} { #catch { | > | > > > | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 | # Flush the in-memory tree to disk and merge all runs together into # a single b-tree structure. Because this annihilates all delete keys, # the next rowid allocated for each table with an IPK will be as expected # by SQLite 3 tests. # proc optimize_db {} { #catch { set af [sqlite4_lsm_config db main autoflush] sqlite4_lsm_config db main autoflush 0 db eval { BEGIN EXCLUSIVE; COMMIT; } sqlite4_lsm_config db main autoflush $af sqlite4_lsm_work db main -nmerge 1 -npage 100000 sqlite4_lsm_checkpoint db main #} return "" } |
︙ | ︙ |
Changes to www/lsm.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <title>LSM Design Overview</title> <nowiki> <div id=start_of_toc></div> <a href=#summary style=text-decoration:none>1. Summary </a><br> <a href=#locks style=text-decoration:none>2. Locks </a><br> <a href=#database_connect_and_disconnect_operations style=text-decoration:none>3. Database Connect and Disconnect Operations</a><br> <a href=#read-write_clients style=text-decoration:none>3.1. Read-write clients</a><br> <a href=#read-only_clients style=text-decoration:none>3.2. Read-only clients</a><br> <a href=#data_structures style=text-decoration:none>4. Data Structures </a><br> <a href=#database_file style=text-decoration:none>4.1. Database file</a><br> <a href=#sorted_runs style=text-decoration:none>4.1.1. Sorted Runs</a><br> <a href=#levels style=text-decoration:none>4.1.2. Levels</a><br> <a href=#snapshots style=text-decoration:none>4.1.3. Snapshots</a><br> <a href=#in-memory_tree style=text-decoration:none>4.2. In-Memory Tree</a><br> <a href=#memory_allocation style=text-decoration:none>4.2.1. Memory Allocation</a><br> <a href=#header_fields style=text-decoration:none>4.2.2. Header Fields</a><br> <a href=#other_shared-memory_fields style=text-decoration:none>4.3. Other Shared-Memory Fields</a><br> <a href=#log_file style=text-decoration:none>4.4. Log file</a><br> <a href=#database_operations style=text-decoration:none>5. Database Operations </a><br> <a href=#reading style=text-decoration:none>5.1. Reading</a><br> <a href=#writing style=text-decoration:none>5.2. Writing</a><br> | > < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <title>LSM Design Overview</title> <nowiki> <div id=start_of_toc></div> <a href=#summary style=text-decoration:none>1. Summary </a><br> <a href=#locks style=text-decoration:none>2. Locks </a><br> <a href=#database_connect_and_disconnect_operations style=text-decoration:none>3. Database Connect and Disconnect Operations</a><br> <a href=#read-write_clients style=text-decoration:none>3.1. Read-write clients</a><br> <a href=#read-only_clients style=text-decoration:none>3.2. Read-only clients</a><br> <a href=#data_structures style=text-decoration:none>4. Data Structures </a><br> <a href=#database_file style=text-decoration:none>4.1. Database file</a><br> <a href=#sorted_runs style=text-decoration:none>4.1.1. Sorted Runs</a><br> <a href=#levels style=text-decoration:none>4.1.2. Levels</a><br> <a href=#snapshots style=text-decoration:none>4.1.3. Snapshots</a><br> <a href=#in-memory_tree style=text-decoration:none>4.2. In-Memory Tree</a><br> <a href=#memory_allocation style=text-decoration:none>4.2.1. Memory Allocation</a><br> <a href=#header_fields style=text-decoration:none>4.2.2. Header Fields</a><br> <a href=#other_shared-memory_fields style=text-decoration:none>4.3. Other Shared-Memory Fields</a><br> <a href=#log_file style=text-decoration:none>4.4. Log file</a><br> <a href=#database_operations style=text-decoration:none>5. Database Operations </a><br> <a href=#reading style=text-decoration:none>5.1. Reading</a><br> <a href=#writing style=text-decoration:none>5.2. Writing</a><br> <a href=#working style=text-decoration:none>5.3. Working</a><br> <a href=#free-block_list_management style=text-decoration:none>5.3.1. Free-block list management</a><br> <a href=#checkpoint_operations style=text-decoration:none>5.4. Checkpoint Operations</a><br> <div id=end_of_toc></div> <h1 id=summary>1. Summary </h1> |
︙ | ︙ | |||
701 702 703 704 705 706 707 | <li> Sweep the shared-memory area to rebuild the linked list of chunks so that it is consistent with the current tree-header. <li> Clear the writer flag. </ol> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | <li> Sweep the shared-memory area to rebuild the linked list of chunks so that it is consistent with the current tree-header. <li> Clear the writer flag. </ol> <h2 id=working>5.3. Working</h2> <p> Working is similar to writing. The difference is that a "writer" modifies the in-memory tree. A "worker" modifies the contents of the database file. <ol> |
︙ | ︙ | |||
841 842 843 844 845 846 847 848 849 850 851 | <li> Sync the database file again. <li> Update the shared-memory variable to indicate the meta-page written in step 5. <li> Drop the CHECKPOINTER lock. </ol> | > > | 778 779 780 781 782 783 784 785 786 787 788 789 790 | <li> Sync the database file again. <li> Update the shared-memory variable to indicate the meta-page written in step 5. <li> Drop the CHECKPOINTER lock. </ol> |