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