1
2 /*
3 ** This file contains the TestDb bt wrapper.
4 */
5
6 #include "lsmtest_tdb.h"
7 #include "lsmtest.h"
8 #include <unistd.h>
9 #include "bt.h"
10
11 #include <pthread.h>
12
13 typedef struct BtDb BtDb;
14 typedef struct BtFile BtFile;
15
16 /* Background checkpointer interface (see implementations below). */
17 typedef struct bt_ckpter bt_ckpter;
18 static int bgc_attach(BtDb *pDb, const char*);
19 static int bgc_detach(BtDb *pDb);
20
21 /*
22 ** Each database or log file opened by a database handle is wrapped by
23 ** an object of the following type.
24 */
25 struct BtFile {
26 BtDb *pBt; /* Database handle that opened this file */
27 bt_env *pVfs; /* Underlying VFS */
28 bt_file *pFile; /* File handle belonging to underlying VFS */
29 int nSectorSize; /* Size of sectors in bytes */
30 int nSector; /* Allocated size of nSector array */
31 u8 **apSector; /* Original sector data */
32 };
33
34 /*
35 ** nCrashSync:
36 ** If this value is non-zero, then a "crash-test" is running. If
37 ** nCrashSync==1, then the crash is simulated during the very next
38 ** call to the xSync() VFS method (on either the db or log file).
39 ** If nCrashSync==2, the following call to xSync(), and so on.
40 **
41 ** bCrash:
42 ** After a crash is simulated, this variable is set. Any subsequent
43 ** attempts to write to a file or modify the file system in any way
44 ** fail once this is set. All the caller can do is close the connection.
45 **
46 ** bFastInsert:
47 ** If this variable is set to true, then a BT_CONTROL_FAST_INSERT_OP
48 ** control is issued before each callto BtReplace() or BtCsrOpen().
49 */
50 struct BtDb {
51 TestDb base; /* Base class */
52 bt_db *pBt; /* bt database handle */
53 sqlite4_env *pEnv; /* SQLite environment (for malloc/free) */
54 bt_env *pVfs; /* Underlying VFS */
55 int bFastInsert; /* True to use fast-insert */
56
57 /* Space for bt_fetch() results */
58 u8 *aBuffer; /* Space to store results */
59 int nBuffer; /* Allocated size of aBuffer[] in bytes */
60 int nRef;
61
62 /* Background checkpointer used by mt connections */
63 bt_ckpter *pCkpter;
64
65 /* Stuff used for crash test simulation */
66 BtFile *apFile[2]; /* Database and log files used by pBt */
67 bt_env env; /* Private VFS for this object */
68 int nCrashSync; /* Number of syncs until crash (see above) */
69 int bCrash; /* True once a crash has been simulated */
70 };
71
btVfsFullpath(sqlite4_env * pEnv,bt_env * pVfs,const char * z,char ** pzOut)72 static int btVfsFullpath(
73 sqlite4_env *pEnv,
74 bt_env *pVfs,
75 const char *z,
76 char **pzOut
77 ){
78 BtDb *pBt = (BtDb*)pVfs->pVfsCtx;
79 if( pBt->bCrash ) return SQLITE4_IOERR;
80 return pBt->pVfs->xFullpath(pEnv, pBt->pVfs, z, pzOut);
81 }
82
btVfsOpen(sqlite4_env * pEnv,bt_env * pVfs,const char * zFile,int flags,bt_file ** ppFile)83 static int btVfsOpen(
84 sqlite4_env *pEnv,
85 bt_env *pVfs,
86 const char *zFile,
87 int flags, bt_file **ppFile
88 ){
89 BtFile *p;
90 BtDb *pBt = (BtDb*)pVfs->pVfsCtx;
91 int rc;
92
93 if( pBt->bCrash ) return SQLITE4_IOERR;
94
95 p = (BtFile*)testMalloc(sizeof(BtFile));
96 if( !p ) return SQLITE4_NOMEM;
97 if( flags & BT_OPEN_DATABASE ){
98 pBt->apFile[0] = p;
99 }else if( flags & BT_OPEN_LOG ){
100 pBt->apFile[1] = p;
101 }
102 if( (flags & BT_OPEN_SHARED)==0 ){
103 p->pBt = pBt;
104 }
105 p->pVfs = pBt->pVfs;
106
107 rc = pBt->pVfs->xOpen(pEnv, pVfs, zFile, flags, &p->pFile);
108 if( rc!=SQLITE4_OK ){
109 testFree(p);
110 p = 0;
111 }else{
112 pBt->nRef++;
113 }
114
115 *ppFile = (bt_file*)p;
116 return rc;
117 }
118
btVfsSize(bt_file * pFile,sqlite4_int64 * piRes)119 static int btVfsSize(bt_file *pFile, sqlite4_int64 *piRes){
120 BtFile *p = (BtFile*)pFile;
121 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
122 return p->pVfs->xSize(p->pFile, piRes);
123 }
124
btVfsRead(bt_file * pFile,sqlite4_int64 iOff,void * pBuf,int nBuf)125 static int btVfsRead(bt_file *pFile, sqlite4_int64 iOff, void *pBuf, int nBuf){
126 BtFile *p = (BtFile*)pFile;
127 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
128 return p->pVfs->xRead(p->pFile, iOff, pBuf, nBuf);
129 }
130
btFlushSectors(BtFile * p,int iFile)131 static int btFlushSectors(BtFile *p, int iFile){
132 sqlite4_int64 iSz;
133 int rc;
134 int i;
135 u8 *aTmp = 0;
136
137 rc = p->pBt->pVfs->xSize(p->pFile, &iSz);
138 for(i=0; rc==SQLITE4_OK && i<p->nSector; i++){
139 if( p->pBt->bCrash && p->apSector[i] ){
140
141 /* The system is simulating a crash. There are three choices for
142 ** this sector:
143 **
144 ** 1) Leave it as it is (simulating a successful write),
145 ** 2) Restore the original data (simulating a lost write),
146 ** 3) Populate the disk sector with garbage data.
147 */
148 sqlite4_int64 iSOff = p->nSectorSize*i;
149 int nWrite = MIN(p->nSectorSize, iSz - iSOff);
150
151 if( nWrite ){
152 u8 *aWrite = 0;
153 int iOpt = (testPrngValue(i) % 3) + 1;
154 if( iOpt==1 ){
155 aWrite = p->apSector[i];
156 }else if( iOpt==3 ){
157 if( aTmp==0 ) aTmp = testMalloc(p->nSectorSize);
158 aWrite = aTmp;
159 testPrngArray(i*13, (u32*)aWrite, nWrite/sizeof(u32));
160 }
161
162 #if 0
163 fprintf(stderr, "handle sector %d of %s with %s\n", i,
164 iFile==0 ? "db" : "log",
165 iOpt==1 ? "rollback" : iOpt==2 ? "write" : "omit"
166 );
167 fflush(stderr);
168 #endif
169
170 if( aWrite ){
171 rc = p->pBt->pVfs->xWrite(p->pFile, iSOff, aWrite, nWrite);
172 }
173 }
174 }
175 testFree(p->apSector[i]);
176 p->apSector[i] = 0;
177 }
178
179 testFree(aTmp);
180 return rc;
181 }
182
btSaveSectors(BtFile * p,sqlite4_int64 iOff,int nBuf)183 static int btSaveSectors(BtFile *p, sqlite4_int64 iOff, int nBuf){
184 int rc;
185 sqlite4_int64 iSz; /* Size of file on disk */
186 int iFirst; /* First sector affected */
187 int iSector; /* Current sector */
188 int iLast; /* Last sector affected */
189
190 if( p->nSectorSize==0 ){
191 p->nSectorSize = p->pBt->pVfs->xSectorSize(p->pFile);
192 if( p->nSectorSize<512 ) p->nSectorSize = 512;
193 }
194 iLast = (iOff+nBuf-1) / p->nSectorSize;
195 iFirst = iOff / p->nSectorSize;
196
197 rc = p->pBt->pVfs->xSize(p->pFile, &iSz);
198 for(iSector=iFirst; rc==SQLITE4_OK && iSector<=iLast; iSector++){
199 int nRead;
200 sqlite4_int64 iSOff = iSector * p->nSectorSize;
201 u8 *aBuf = testMalloc(p->nSectorSize);
202 nRead = MIN(p->nSectorSize, (iSz - iSOff));
203 if( nRead>0 ){
204 rc = p->pBt->pVfs->xRead(p->pFile, iSOff, aBuf, nRead);
205 }
206
207 while( rc==SQLITE4_OK && iSector>=p->nSector ){
208 int nNew = p->nSector + 32;
209 u8 **apNew = (u8**)testMalloc(nNew * sizeof(u8*));
210 memcpy(apNew, p->apSector, p->nSector*sizeof(u8*));
211 testFree(p->apSector);
212 p->apSector = apNew;
213 p->nSector = nNew;
214 }
215
216 p->apSector[iSector] = aBuf;
217 }
218
219 return rc;
220 }
221
btVfsWrite(bt_file * pFile,sqlite4_int64 iOff,void * pBuf,int nBuf)222 static int btVfsWrite(bt_file *pFile, sqlite4_int64 iOff, void *pBuf, int nBuf){
223 BtFile *p = (BtFile*)pFile;
224 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
225 if( p->pBt && p->pBt->nCrashSync ){
226 btSaveSectors(p, iOff, nBuf);
227 }
228 return p->pVfs->xWrite(p->pFile, iOff, pBuf, nBuf);
229 }
230
btVfsTruncate(bt_file * pFile,sqlite4_int64 iOff)231 static int btVfsTruncate(bt_file *pFile, sqlite4_int64 iOff){
232 BtFile *p = (BtFile*)pFile;
233 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
234 return p->pVfs->xTruncate(p->pFile, iOff);
235 }
236
btVfsSync(bt_file * pFile)237 static int btVfsSync(bt_file *pFile){
238 int rc = SQLITE4_OK;
239 BtFile *p = (BtFile*)pFile;
240 BtDb *pBt = p->pBt;
241
242 if( pBt ){
243 if( pBt->bCrash ) return SQLITE4_IOERR;
244 if( pBt->nCrashSync ){
245 pBt->nCrashSync--;
246 pBt->bCrash = (pBt->nCrashSync==0);
247 if( pBt->bCrash ){
248 btFlushSectors(pBt->apFile[0], 0);
249 btFlushSectors(pBt->apFile[1], 1);
250 rc = SQLITE4_IOERR;
251 }else{
252 btFlushSectors(p, 0);
253 }
254 }
255 }
256
257 if( rc==SQLITE4_OK ){
258 rc = p->pVfs->xSync(p->pFile);
259 }
260 return rc;
261 }
262
btVfsSectorSize(bt_file * pFile)263 static int btVfsSectorSize(bt_file *pFile){
264 BtFile *p = (BtFile*)pFile;
265 return p->pVfs->xSectorSize(p->pFile);
266 }
267
btDeref(BtDb * p)268 static void btDeref(BtDb *p){
269 p->nRef--;
270 assert( p->nRef>=0 );
271 if( p->nRef<=0 ) testFree(p);
272 }
273
btVfsClose(bt_file * pFile)274 static int btVfsClose(bt_file *pFile){
275 BtFile *p = (BtFile*)pFile;
276 BtDb *pBt = p->pBt;
277 int rc;
278 if( pBt ){
279 btFlushSectors(p, 0);
280 if( p==pBt->apFile[0] ) pBt->apFile[0] = 0;
281 if( p==pBt->apFile[1] ) pBt->apFile[1] = 0;
282 }
283 testFree(p->apSector);
284 rc = p->pVfs->xClose(p->pFile);
285 #if 0
286 btDeref(p->pBt);
287 #endif
288 testFree(p);
289 return rc;
290 }
291
btVfsUnlink(sqlite4_env * pEnv,bt_env * pVfs,const char * zFile)292 static int btVfsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){
293 BtDb *pBt = (BtDb*)pVfs->pVfsCtx;
294 if( pBt->bCrash ) return SQLITE4_IOERR;
295 return pBt->pVfs->xUnlink(pEnv, pBt->pVfs, zFile);
296 }
297
btVfsLock(bt_file * pFile,int iLock,int eType)298 static int btVfsLock(bt_file *pFile, int iLock, int eType){
299 BtFile *p = (BtFile*)pFile;
300 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
301 return p->pVfs->xLock(p->pFile, iLock, eType);
302 }
303
btVfsTestLock(bt_file * pFile,int iLock,int nLock,int eType)304 static int btVfsTestLock(bt_file *pFile, int iLock, int nLock, int eType){
305 BtFile *p = (BtFile*)pFile;
306 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
307 return p->pVfs->xTestLock(p->pFile, iLock, nLock, eType);
308 }
309
btVfsShmMap(bt_file * pFile,int iChunk,int sz,void ** ppOut)310 static int btVfsShmMap(bt_file *pFile, int iChunk, int sz, void **ppOut){
311 BtFile *p = (BtFile*)pFile;
312 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
313 return p->pVfs->xShmMap(p->pFile, iChunk, sz, ppOut);
314 }
315
btVfsShmBarrier(bt_file * pFile)316 static void btVfsShmBarrier(bt_file *pFile){
317 BtFile *p = (BtFile*)pFile;
318 return p->pVfs->xShmBarrier(p->pFile);
319 }
320
btVfsShmUnmap(bt_file * pFile,int bDelete)321 static int btVfsShmUnmap(bt_file *pFile, int bDelete){
322 BtFile *p = (BtFile*)pFile;
323 if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR;
324 return p->pVfs->xShmUnmap(p->pFile, bDelete);
325 }
326
bt_close(TestDb * pTestDb)327 static int bt_close(TestDb *pTestDb){
328 BtDb *p = (BtDb*)pTestDb;
329 int rc = sqlite4BtClose(p->pBt);
330 free(p->aBuffer);
331 if( p->apFile[0] ) p->apFile[0]->pBt = 0;
332 if( p->apFile[1] ) p->apFile[1]->pBt = 0;
333 bgc_detach(p);
334 testFree(p);
335 return rc;
336 }
337
btMinTransaction(BtDb * p,int iMin,int * piLevel)338 static int btMinTransaction(BtDb *p, int iMin, int *piLevel){
339 int iLevel;
340 int rc = SQLITE4_OK;
341
342 iLevel = sqlite4BtTransactionLevel(p->pBt);
343 if( iLevel<iMin ){
344 rc = sqlite4BtBegin(p->pBt, iMin);
345 *piLevel = iLevel;
346 }else{
347 *piLevel = -1;
348 }
349
350 return rc;
351 }
btRestoreTransaction(BtDb * p,int iLevel,int rcin)352 static int btRestoreTransaction(BtDb *p, int iLevel, int rcin){
353 int rc = rcin;
354 if( iLevel>=0 ){
355 if( rc==SQLITE4_OK ){
356 rc = sqlite4BtCommit(p->pBt, iLevel);
357 }else{
358 sqlite4BtRollback(p->pBt, iLevel);
359 }
360 assert( iLevel==sqlite4BtTransactionLevel(p->pBt) );
361 }
362 return rc;
363 }
364
bt_write(TestDb * pTestDb,void * pK,int nK,void * pV,int nV)365 static int bt_write(TestDb *pTestDb, void *pK, int nK, void *pV, int nV){
366 BtDb *p = (BtDb*)pTestDb;
367 int iLevel;
368 int rc;
369
370 rc = btMinTransaction(p, 2, &iLevel);
371 if( rc==SQLITE4_OK ){
372 if( p->bFastInsert ) sqlite4BtControl(p->pBt, BT_CONTROL_FAST_INSERT_OP, 0);
373 rc = sqlite4BtReplace(p->pBt, pK, nK, pV, nV);
374 rc = btRestoreTransaction(p, iLevel, rc);
375 }
376 return rc;
377 }
378
bt_delete(TestDb * pTestDb,void * pK,int nK)379 static int bt_delete(TestDb *pTestDb, void *pK, int nK){
380 return bt_write(pTestDb, pK, nK, 0, -1);
381 }
382
bt_delete_range(TestDb * pTestDb,void * pKey1,int nKey1,void * pKey2,int nKey2)383 static int bt_delete_range(
384 TestDb *pTestDb,
385 void *pKey1, int nKey1,
386 void *pKey2, int nKey2
387 ){
388 BtDb *p = (BtDb*)pTestDb;
389 bt_cursor *pCsr = 0;
390 int rc = SQLITE4_OK;
391 int iLevel;
392
393 rc = btMinTransaction(p, 2, &iLevel);
394 if( rc==SQLITE4_OK ){
395 if( p->bFastInsert ) sqlite4BtControl(p->pBt, BT_CONTROL_FAST_INSERT_OP, 0);
396 rc = sqlite4BtCsrOpen(p->pBt, 0, &pCsr);
397 }
398 while( rc==SQLITE4_OK ){
399 const void *pK;
400 int n;
401 int nCmp;
402 int res;
403
404 rc = sqlite4BtCsrSeek(pCsr, pKey1, nKey1, BT_SEEK_GE);
405 if( rc==SQLITE4_INEXACT ) rc = SQLITE4_OK;
406 if( rc!=SQLITE4_OK ) break;
407
408 rc = sqlite4BtCsrKey(pCsr, &pK, &n);
409 if( rc!=SQLITE4_OK ) break;
410
411 nCmp = MIN(n, nKey1);
412 res = memcmp(pKey1, pK, nCmp);
413 assert( res<0 || (res==0 && nKey1<=n) );
414 if( res==0 && nKey1==n ){
415 rc = sqlite4BtCsrNext(pCsr);
416 if( rc!=SQLITE4_OK ) break;
417 rc = sqlite4BtCsrKey(pCsr, &pK, &n);
418 if( rc!=SQLITE4_OK ) break;
419 }
420
421 nCmp = MIN(n, nKey2);
422 res = memcmp(pKey2, pK, nCmp);
423 if( res<0 || (res==0 && nKey2<=n) ) break;
424
425 rc = sqlite4BtDelete(pCsr);
426 }
427 if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_OK;
428
429 sqlite4BtCsrClose(pCsr);
430
431 rc = btRestoreTransaction(p, iLevel, rc);
432 return rc;
433 }
434
bt_fetch(TestDb * pTestDb,void * pK,int nK,void ** ppVal,int * pnVal)435 static int bt_fetch(
436 TestDb *pTestDb,
437 void *pK, int nK,
438 void **ppVal, int *pnVal
439 ){
440 BtDb *p = (BtDb*)pTestDb;
441 bt_cursor *pCsr = 0;
442 int iLevel;
443 int rc = SQLITE4_OK;
444
445 iLevel = sqlite4BtTransactionLevel(p->pBt);
446 if( iLevel==0 ){
447 rc = sqlite4BtBegin(p->pBt, 1);
448 if( rc!=SQLITE4_OK ) return rc;
449 }
450
451 if( p->bFastInsert ) sqlite4BtControl(p->pBt, BT_CONTROL_FAST_INSERT_OP, 0);
452 rc = sqlite4BtCsrOpen(p->pBt, 0, &pCsr);
453 if( rc==SQLITE4_OK ){
454 rc = sqlite4BtCsrSeek(pCsr, pK, nK, BT_SEEK_EQ);
455 if( rc==SQLITE4_OK ){
456 const void *pV = 0;
457 int nV = 0;
458 rc = sqlite4BtCsrData(pCsr, 0, -1, &pV, &nV);
459 if( rc==SQLITE4_OK ){
460 if( nV>p->nBuffer ){
461 free(p->aBuffer);
462 p->aBuffer = (u8*)malloc(nV*2);
463 p->nBuffer = nV*2;
464 }
465 memcpy(p->aBuffer, pV, nV);
466 *pnVal = nV;
467 *ppVal = (void*)(p->aBuffer);
468 }
469
470 }else if( rc==SQLITE4_INEXACT || rc==SQLITE4_NOTFOUND ){
471 *ppVal = 0;
472 *pnVal = -1;
473 rc = SQLITE4_OK;
474 }
475 sqlite4BtCsrClose(pCsr);
476 }
477
478 if( iLevel==0 ) sqlite4BtCommit(p->pBt, 0);
479 return rc;
480 }
481
bt_scan(TestDb * pTestDb,void * pCtx,int bReverse,void * pFirst,int nFirst,void * pLast,int nLast,void (* xCallback)(void *,void *,int,void *,int))482 static int bt_scan(
483 TestDb *pTestDb,
484 void *pCtx,
485 int bReverse,
486 void *pFirst, int nFirst,
487 void *pLast, int nLast,
488 void (*xCallback)(void *, void *, int , void *, int)
489 ){
490 BtDb *p = (BtDb*)pTestDb;
491 bt_cursor *pCsr = 0;
492 int rc;
493 int iLevel;
494
495 rc = btMinTransaction(p, 1, &iLevel);
496
497 if( rc==SQLITE4_OK ){
498 if( p->bFastInsert ) sqlite4BtControl(p->pBt, BT_CONTROL_FAST_INSERT_OP, 0);
499 rc = sqlite4BtCsrOpen(p->pBt, 0, &pCsr);
500 }
501 if( rc==SQLITE4_OK ){
502 if( bReverse ){
503 if( pLast ){
504 rc = sqlite4BtCsrSeek(pCsr, pLast, nLast, BT_SEEK_LE);
505 }else{
506 rc = sqlite4BtCsrLast(pCsr);
507 }
508 }else{
509 rc = sqlite4BtCsrSeek(pCsr, pFirst, nFirst, BT_SEEK_GE);
510 }
511 if( rc==SQLITE4_INEXACT ) rc = SQLITE4_OK;
512
513 while( rc==SQLITE4_OK ){
514 const void *pK = 0; int nK = 0;
515 const void *pV = 0; int nV = 0;
516
517 rc = sqlite4BtCsrKey(pCsr, &pK, &nK);
518 if( rc==SQLITE4_OK ){
519 rc = sqlite4BtCsrData(pCsr, 0, -1, &pV, &nV);
520 }
521
522 if( rc!=SQLITE4_OK ) break;
523 if( bReverse ){
524 if( pFirst ){
525 int res;
526 int nCmp = MIN(nK, nFirst);
527 res = memcmp(pFirst, pK, nCmp);
528 if( res>0 || (res==0 && nK<nFirst) ) break;
529 }
530 }else{
531 if( pLast ){
532 int res;
533 int nCmp = MIN(nK, nLast);
534 res = memcmp(pLast, pK, nCmp);
535 if( res<0 || (res==0 && nK>nLast) ) break;
536 }
537 }
538
539 xCallback(pCtx, (void*)pK, nK, (void*)pV, nV);
540 if( bReverse ){
541 rc = sqlite4BtCsrPrev(pCsr);
542 }else{
543 rc = sqlite4BtCsrNext(pCsr);
544 }
545 }
546 if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_OK;
547
548 sqlite4BtCsrClose(pCsr);
549 }
550
551 rc = btRestoreTransaction(p, iLevel, rc);
552 return rc;
553 }
554
bt_begin(TestDb * pTestDb,int iLvl)555 static int bt_begin(TestDb *pTestDb, int iLvl){
556 BtDb *p = (BtDb*)pTestDb;
557 int rc = sqlite4BtBegin(p->pBt, iLvl);
558 return rc;
559 }
560
bt_commit(TestDb * pTestDb,int iLvl)561 static int bt_commit(TestDb *pTestDb, int iLvl){
562 BtDb *p = (BtDb*)pTestDb;
563 int rc = sqlite4BtCommit(p->pBt, iLvl);
564 return rc;
565 }
566
bt_rollback(TestDb * pTestDb,int iLvl)567 static int bt_rollback(TestDb *pTestDb, int iLvl){
568 BtDb *p = (BtDb*)pTestDb;
569 int rc = sqlite4BtRollback(p->pBt, iLvl);
570 return rc;
571 }
572
testParseOption(const char ** pzIn,const char ** pzOpt,const char ** pzArg,char * pSpace)573 static int testParseOption(
574 const char **pzIn, /* IN/OUT: pointer to next option */
575 const char **pzOpt, /* OUT: nul-terminated option name */
576 const char **pzArg, /* OUT: nul-terminated option argument */
577 char *pSpace /* Temporary space for output params */
578 ){
579 const char *p = *pzIn;
580 const char *pStart;
581 int n;
582
583 char *pOut = pSpace;
584
585 while( *p==' ' ) p++;
586 pStart = p;
587 while( *p && *p!='=' ) p++;
588 if( *p==0 ) return 1;
589
590 n = (p - pStart);
591 memcpy(pOut, pStart, n);
592 *pzOpt = pOut;
593 pOut += n;
594 *pOut++ = '\0';
595
596 p++;
597 pStart = p;
598 while( *p && *p!=' ' ) p++;
599 n = (p - pStart);
600
601 memcpy(pOut, pStart, n);
602 *pzArg = pOut;
603 pOut += n;
604 *pOut++ = '\0';
605
606 *pzIn = p;
607 return 0;
608 }
609
testParseInt(const char * z,int * piVal)610 static int testParseInt(const char *z, int *piVal){
611 int i = 0;
612 const char *p = z;
613
614 while( *p>='0' && *p<='9' ){
615 i = i*10 + (*p - '0');
616 p++;
617 }
618 if( *p=='K' || *p=='k' ){
619 i = i * 1024;
620 p++;
621 }else if( *p=='M' || *p=='m' ){
622 i = i * 1024 * 1024;
623 p++;
624 }
625
626 if( *p ) return SQLITE4_ERROR;
627 *piVal = i;
628 return SQLITE4_OK;
629 }
630
testBtConfigure(BtDb * pDb,const char * zCfg,int * pbMt)631 static int testBtConfigure(BtDb *pDb, const char *zCfg, int *pbMt){
632 int rc = SQLITE4_OK;
633
634 if( zCfg ){
635 struct CfgParam {
636 const char *zParam;
637 int eParam;
638 } aParam[] = {
639 { "safety", BT_CONTROL_SAFETY },
640 { "autockpt", BT_CONTROL_AUTOCKPT },
641 { "multiproc", BT_CONTROL_MULTIPROC },
642 { "blksz", BT_CONTROL_BLKSZ },
643 { "pagesz", BT_CONTROL_PAGESZ },
644 { "mt", -1 },
645 { "fastinsert", -2 },
646 { 0, 0 }
647 };
648 const char *z = zCfg;
649 int n = strlen(z);
650 char *aSpace;
651 const char *zOpt;
652 const char *zArg;
653
654 aSpace = (char*)testMalloc(n+2);
655 while( rc==SQLITE4_OK && 0==testParseOption(&z, &zOpt, &zArg, aSpace) ){
656 int i;
657 int iVal;
658 rc = testArgSelect(aParam, "param", zOpt, &i);
659 if( rc!=SQLITE4_OK ) break;
660
661 rc = testParseInt(zArg, &iVal);
662 if( rc!=SQLITE4_OK ) break;
663
664 switch( aParam[i].eParam ){
665 case -1:
666 *pbMt = iVal;
667 break;
668 case -2:
669 pDb->bFastInsert = 1;
670 break;
671 default:
672 rc = sqlite4BtControl(pDb->pBt, aParam[i].eParam, (void*)&iVal);
673 break;
674 }
675 }
676 testFree(aSpace);
677 }
678
679 return rc;
680 }
681
682
test_bt_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)683 int test_bt_open(
684 const char *zSpec,
685 const char *zFilename,
686 int bClear,
687 TestDb **ppDb
688 ){
689
690 static const DatabaseMethods SqlMethods = {
691 bt_close,
692 bt_write,
693 bt_delete,
694 bt_delete_range,
695 bt_fetch,
696 bt_scan,
697 bt_begin,
698 bt_commit,
699 bt_rollback
700 };
701 BtDb *p = 0;
702 bt_db *pBt = 0;
703 int rc;
704 sqlite4_env *pEnv = sqlite4_env_default();
705
706 if( bClear && zFilename && zFilename[0] ){
707 char *zLog = sqlite3_mprintf("%s-wal", zFilename);
708 unlink(zFilename);
709 unlink(zLog);
710 sqlite3_free(zLog);
711 }
712
713 rc = sqlite4BtNew(pEnv, 0, &pBt);
714 if( rc==SQLITE4_OK ){
715 int mt = 0; /* True for multi-threaded connection */
716
717 p = (BtDb*)testMalloc(sizeof(BtDb));
718 p->base.pMethods = &SqlMethods;
719 p->pBt = pBt;
720 p->pEnv = pEnv;
721 p->nRef = 1;
722
723 p->env.pVfsCtx = (void*)p;
724 p->env.xFullpath = btVfsFullpath;
725 p->env.xOpen = btVfsOpen;
726 p->env.xSize = btVfsSize;
727 p->env.xRead = btVfsRead;
728 p->env.xWrite = btVfsWrite;
729 p->env.xTruncate = btVfsTruncate;
730 p->env.xSync = btVfsSync;
731 p->env.xSectorSize = btVfsSectorSize;
732 p->env.xClose = btVfsClose;
733 p->env.xUnlink = btVfsUnlink;
734 p->env.xLock = btVfsLock;
735 p->env.xTestLock = btVfsTestLock;
736 p->env.xShmMap = btVfsShmMap;
737 p->env.xShmBarrier = btVfsShmBarrier;
738 p->env.xShmUnmap = btVfsShmUnmap;
739
740 sqlite4BtControl(pBt, BT_CONTROL_GETVFS, (void*)&p->pVfs);
741 sqlite4BtControl(pBt, BT_CONTROL_SETVFS, (void*)&p->env);
742
743 rc = testBtConfigure(p, zSpec, &mt);
744 if( rc==SQLITE4_OK ){
745 rc = sqlite4BtOpen(pBt, zFilename);
746 }
747
748 if( rc==SQLITE4_OK && mt ){
749 int nAuto = 0;
750 rc = bgc_attach(p, zSpec);
751 sqlite4BtControl(pBt, BT_CONTROL_AUTOCKPT, (void*)&nAuto);
752 }
753 }
754
755 if( rc!=SQLITE4_OK && p ){
756 bt_close(&p->base);
757 }
758
759 *ppDb = &p->base;
760 return rc;
761 }
762
test_fbt_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)763 int test_fbt_open(
764 const char *zSpec,
765 const char *zFilename,
766 int bClear,
767 TestDb **ppDb
768 ){
769 return test_bt_open("fast=1", zFilename, bClear, ppDb);
770 }
771
test_fbts_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)772 int test_fbts_open(
773 const char *zSpec,
774 const char *zFilename,
775 int bClear,
776 TestDb **ppDb
777 ){
778 return test_bt_open("fast=1 blksz=32K pagesz=512", zFilename, bClear, ppDb);
779 }
780
781
tdb_bt_prepare_sync_crash(TestDb * pTestDb,int iSync)782 void tdb_bt_prepare_sync_crash(TestDb *pTestDb, int iSync){
783 BtDb *p = (BtDb*)pTestDb;
784 assert( pTestDb->pMethods->xClose==bt_close );
785 assert( p->bCrash==0 );
786 p->nCrashSync = iSync;
787 }
788
tdb_bt(TestDb * pDb)789 bt_db *tdb_bt(TestDb *pDb){
790 if( pDb->pMethods->xClose==bt_close ){
791 return ((BtDb *)pDb)->pBt;
792 }
793 return 0;
794 }
795
796 /*************************************************************************
797 ** Beginning of code for background checkpointer.
798 */
799
800 struct bt_ckpter {
801 sqlite4_buffer file; /* File name */
802 sqlite4_buffer spec; /* Options */
803 int nLogsize; /* Minimum log size to checkpoint */
804 int nRef; /* Number of clients */
805
806 int bDoWork; /* Set by client threads */
807 pthread_t ckpter_thread; /* Checkpointer thread */
808 pthread_cond_t ckpter_cond; /* Condition var the ckpter waits on */
809 pthread_mutex_t ckpter_mutex; /* Mutex used with ckpter_cond */
810
811 bt_ckpter *pNext; /* Next object in list at gBgc.pCkpter */
812 };
813
814 static struct GlobalBackgroundCheckpointer {
815 bt_ckpter *pCkpter; /* Linked list of checkpointers */
816 } gBgc;
817
bgc_main(void * pArg)818 static void *bgc_main(void *pArg){
819 BtDb *pDb = 0;
820 int rc;
821 int mt;
822 bt_ckpter *pCkpter = (bt_ckpter*)pArg;
823
824 rc = test_bt_open("", (char*)pCkpter->file.p, 0, (TestDb**)&pDb);
825 assert( rc==SQLITE4_OK );
826 rc = testBtConfigure(pDb, (char*)pCkpter->spec.p, &mt);
827
828 while( pCkpter->nRef>0 ){
829 bt_db *db = pDb->pBt;
830 int nLog = 0;
831
832 sqlite4BtBegin(db, 1);
833 sqlite4BtCommit(db, 0);
834 sqlite4BtControl(db, BT_CONTROL_LOGSIZE, (void*)&nLog);
835
836 if( nLog>=pCkpter->nLogsize ){
837 int rc;
838 bt_checkpoint ckpt;
839 memset(&ckpt, 0, sizeof(bt_checkpoint));
840 ckpt.nFrameBuffer = nLog/2;
841 rc = sqlite4BtControl(db, BT_CONTROL_CHECKPOINT, (void*)&ckpt);
842 assert( rc==SQLITE4_OK );
843 sqlite4BtControl(db, BT_CONTROL_LOGSIZE, (void*)&nLog);
844 }
845
846 /* The thread will wake up when it is signaled either because another
847 ** thread has created some work for this one or because the connection
848 ** is being closed. */
849 pthread_mutex_lock(&pCkpter->ckpter_mutex);
850 if( pCkpter->bDoWork==0 ){
851 pthread_cond_wait(&pCkpter->ckpter_cond, &pCkpter->ckpter_mutex);
852 }
853 pCkpter->bDoWork = 0;
854 pthread_mutex_unlock(&pCkpter->ckpter_mutex);
855 }
856
857 if( pDb ) bt_close((TestDb*)pDb);
858 return 0;
859 }
860
bgc_logsize_cb(void * pCtx,int nLogsize)861 static void bgc_logsize_cb(void *pCtx, int nLogsize){
862 bt_ckpter *p = (bt_ckpter*)pCtx;
863 if( nLogsize>=p->nLogsize ){
864 pthread_mutex_lock(&p->ckpter_mutex);
865 p->bDoWork = 1;
866 pthread_cond_signal(&p->ckpter_cond);
867 pthread_mutex_unlock(&p->ckpter_mutex);
868 }
869 }
870
bgc_attach(BtDb * pDb,const char * zSpec)871 static int bgc_attach(BtDb *pDb, const char *zSpec){
872 int rc;
873 int n;
874 bt_info info;
875 bt_ckpter *pCkpter;
876
877 /* Figure out the full path to the database opened by handle pDb. */
878 info.eType = BT_INFO_FILENAME;
879 info.pgno = 0;
880 sqlite4_buffer_init(&info.output, 0);
881 rc = sqlite4BtControl(pDb->pBt, BT_CONTROL_INFO, (void*)&info);
882 if( rc!=SQLITE4_OK ) return rc;
883
884 sqlite4_mutex_enter(sqlite4_mutex_alloc(pDb->pEnv, SQLITE4_MUTEX_STATIC_KV));
885
886 /* Search for an existing bt_ckpter object. */
887 n = info.output.n;
888 for(pCkpter=gBgc.pCkpter; pCkpter; pCkpter=pCkpter->pNext){
889 if( n==pCkpter->file.n && 0==memcmp(info.output.p, pCkpter->file.p, n) ){
890 break;
891 }
892 }
893
894 /* Failed to find a suitable checkpointer. Create a new one. */
895 if( pCkpter==0 ){
896 bt_logsizecb cb;
897
898 pCkpter = testMalloc(sizeof(bt_ckpter));
899 memcpy(&pCkpter->file, &info.output, sizeof(sqlite4_buffer));
900 info.output.p = 0;
901 pCkpter->pNext = gBgc.pCkpter;
902 pCkpter->nLogsize = 1000;
903 gBgc.pCkpter = pCkpter;
904 pCkpter->nRef = 1;
905
906 sqlite4_buffer_init(&pCkpter->spec, 0);
907 rc = sqlite4_buffer_set(&pCkpter->spec, zSpec, strlen(zSpec)+1);
908 assert( rc==SQLITE4_OK );
909
910 /* Kick off the checkpointer thread. */
911 if( rc==0 ) rc = pthread_cond_init(&pCkpter->ckpter_cond, 0);
912 if( rc==0 ) rc = pthread_mutex_init(&pCkpter->ckpter_mutex, 0);
913 if( rc==0 ){
914 rc = pthread_create(&pCkpter->ckpter_thread, 0, bgc_main, (void*)pCkpter);
915 }
916 assert( rc==0 ); /* todo: Fix this */
917
918 /* Set up the logsize callback for the client thread */
919 cb.pCtx = (void*)pCkpter;
920 cb.xLogsize = bgc_logsize_cb;
921 sqlite4BtControl(pDb->pBt, BT_CONTROL_LOGSIZECB, (void*)&cb);
922 }else{
923 pCkpter->nRef++;
924 }
925
926 /* Assuming a checkpointer was encountered or effected, attach the
927 ** connection to it. */
928 if( pCkpter ){
929 pDb->pCkpter = pCkpter;
930 }
931
932 sqlite4_mutex_leave(sqlite4_mutex_alloc(pDb->pEnv, SQLITE4_MUTEX_STATIC_KV));
933 sqlite4_buffer_clear(&info.output);
934 return rc;
935 }
936
bgc_detach(BtDb * pDb)937 static int bgc_detach(BtDb *pDb){
938 int rc = SQLITE4_OK;
939 bt_ckpter *pCkpter = pDb->pCkpter;
940 if( pCkpter ){
941 int bShutdown = 0; /* True if this is the last reference */
942
943 sqlite4_mutex_enter(sqlite4_mutex_alloc(pDb->pEnv,SQLITE4_MUTEX_STATIC_KV));
944 pCkpter->nRef--;
945 if( pCkpter->nRef==0 ){
946 bt_ckpter **pp;
947
948 *pp = pCkpter->pNext;
949 for(pp=&gBgc.pCkpter; *pp!=pCkpter; pp=&((*pp)->pNext));
950 bShutdown = 1;
951 }
952 sqlite4_mutex_leave(sqlite4_mutex_alloc(pDb->pEnv,SQLITE4_MUTEX_STATIC_KV));
953
954 if( bShutdown ){
955 void *pDummy;
956
957 /* Signal the checkpointer thread. */
958 pthread_mutex_lock(&pCkpter->ckpter_mutex);
959 pCkpter->bDoWork = 1;
960 pthread_cond_signal(&pCkpter->ckpter_cond);
961 pthread_mutex_unlock(&pCkpter->ckpter_mutex);
962
963 /* Join the checkpointer thread. */
964 pthread_join(pCkpter->ckpter_thread, &pDummy);
965 pthread_cond_destroy(&pCkpter->ckpter_cond);
966 pthread_mutex_destroy(&pCkpter->ckpter_mutex);
967
968 sqlite4_buffer_clear(&pCkpter->file);
969 sqlite4_buffer_clear(&pCkpter->spec);
970 testFree(pCkpter);
971 }
972
973 pDb->pCkpter = 0;
974 }
975 return rc;
976 }
977
978 /*
979 ** End of background checkpointer.
980 *************************************************************************/
981
982
983