modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest_tdb4.c (about) 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 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 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 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 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 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 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 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 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 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 263 static int btVfsSectorSize(bt_file *pFile){ 264 BtFile *p = (BtFile*)pFile; 265 return p->pVfs->xSectorSize(p->pFile); 266 } 267 268 static void btDeref(BtDb *p){ 269 p->nRef--; 270 assert( p->nRef>=0 ); 271 if( p->nRef<=0 ) testFree(p); 272 } 273 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 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 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 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 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 316 static void btVfsShmBarrier(bt_file *pFile){ 317 BtFile *p = (BtFile*)pFile; 318 return p->pVfs->xShmBarrier(p->pFile); 319 } 320 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 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 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 } 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 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 379 static int bt_delete(TestDb *pTestDb, void *pK, int nK){ 380 return bt_write(pTestDb, pK, nK, 0, -1); 381 } 382 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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