Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add test code to run bt checkpoints in a background thread. Various fixes and tweaks to support this. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
439684c450f121a8657d90624bdc008a |
User & Date: | dan 2013-11-16 20:35:02.535 |
Context
2013-11-20
| ||
19:23 | Combine the bt database and shm headers. check-in: 1512aee6f6 user: dan tags: trunk | |
2013-11-16
| ||
20:35 | Add test code to run bt checkpoints in a background thread. Various fixes and tweaks to support this. check-in: 439684c450 user: dan tags: trunk | |
2013-11-15
| ||
19:18 | Add test file fkey2.test to the list of files used by the "bt" permutation. check-in: 5c2af9e0b7 user: dan tags: trunk | |
Changes
Changes to lsm-test/lsmtest2.c.
︙ | ︙ | |||
458 459 460 461 462 463 464 | int iIns; int testrc = 0; testCaseProgress(i, nIter, testCaseNDot(), &iDot); /* Restore and open the database. */ testRestoreDb(DBNAME, "wal"); | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | int iIns; int testrc = 0; testCaseProgress(i, nIter, testCaseNDot(), &iDot); /* Restore and open the database. */ testRestoreDb(DBNAME, "wal"); testrc = tdb_open("bt safety=2", DBNAME, 0, &pDb); assert( testrc==0 ); /* Insert nInsert records into the database. Crash midway through. */ tdb_bt_prepare_sync_crash(pDb, 1 + (i%(nInsert+2))); for(iIns=0; iIns<nInsert; iIns++){ void *pKey; int nKey; void *pVal; int nVal; |
︙ | ︙ |
Changes to lsm-test/lsmtest3.c.
︙ | ︙ | |||
157 158 159 160 161 162 163 | int rc; int i; CksumDb *pCksum; char *zName; zName = getName(zSystem); testCaseStart(&rc, zName); | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | int rc; int i; CksumDb *pCksum; char *zName; zName = getName(zSystem); testCaseStart(&rc, zName); testFree(zName); pCksum = testCksumArrayNew(pData, 0, nRepeat*100, 100); pDb = 0; rc = tdb_open(zSystem, 0, 1, &pDb); if( pDb && tdb_transaction_support(pDb)==0 ){ testCaseSkip(); goto skip_rollback_test; |
︙ | ︙ | |||
221 222 223 224 225 226 227 | ){ if( *pRc==0 ){ int bRun = 1; if( zPattern ){ char *zName = getName(zSystem); bRun = testGlobMatch(zPattern, zName); | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | ){ if( *pRc==0 ){ int bRun = 1; if( zPattern ){ char *zName = getName(zSystem); bRun = testGlobMatch(zPattern, zName); testFree(zName); } if( bRun ){ DatasourceDefn defn = { TEST_DATASOURCE_RANDOM, 10, 15, 50, 100 }; Datasource *pData = testDatasourceNew(&defn); *pRc = rollback_test_1(zSystem, pData); testDatasourceFree(pData); } } } |
Changes to lsm-test/lsmtest_main.c.
︙ | ︙ | |||
362 363 364 365 366 367 368 | char *zRet; va_copy(copy, ap); nByte = vsnprintf(0, 0, zFormat, copy); va_end(copy); assert( nByte>=0 ); | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | char *zRet; va_copy(copy, ap); nByte = vsnprintf(0, 0, zFormat, copy); va_end(copy); assert( nByte>=0 ); zRet = (char *)testMalloc(nByte+1); vsnprintf(zRet, nByte+1, zFormat, ap); return zRet; } char *testMallocPrintf(const char *zFormat, ...){ va_list ap; char *zRet; |
︙ | ︙ | |||
391 392 393 394 395 396 397 | ** ** * Test code may assume that allocations may not fail. ** * Returned memory is always zeroed. ** ** Allocations made using testMalloc() should be freed using testFree(). */ void *testMalloc(int n){ | | | > | | > > > | > > > > > > > | > > > | > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | ** ** * Test code may assume that allocations may not fail. ** * Returned memory is always zeroed. ** ** Allocations made using testMalloc() should be freed using testFree(). */ void *testMalloc(int n){ u8 *p = (u8*)malloc(n + 8); memset(p, 0, n+8); *(int*)p = n; return (void*)&p[8]; } void *testMallocCopy(void *pCopy, int nByte){ void *pRet = testMalloc(nByte); memcpy(pRet, pCopy, nByte); return pRet; } void *testRealloc(void *ptr, int n){ if( ptr ){ u8 *p = (u8*)ptr - 8; int nOrig = *(int*)p; p = (u8*)realloc(p, n+8); if( nOrig<n ){ memset(&p[8+nOrig], 0, n-nOrig); } *(int*)p = n; return (void*)&p[8]; } return testMalloc(n); } /* ** Free an allocation made by an earlier call to testMalloc(). */ void testFree(void *ptr){ if( ptr ){ u8 *p = (u8*)ptr - 8; memset(p, 0x55, *(int*)p + 8); free(p); } } /* ** String zPattern contains a glob pattern. Return true if zStr matches ** the pattern, or false if it does not. */ int testGlobMatch(const char *zPattern, const char *zStr){ |
︙ | ︙ |
Changes to lsm-test/lsmtest_tdb4.c.
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 | /* ** This file contains the TestDb bt wrapper. */ #include "lsmtest_tdb.h" #include "lsmtest.h" #include <unistd.h> #include "bt.h" typedef struct BtDb BtDb; typedef struct BtFile BtFile; /* ** Each database or log file opened by a database handle is wrapped by ** an object of the following type. */ struct BtFile { BtDb *pBt; /* Database handle that opened this file */ bt_file *pFile; /* File handle belonging to underlying VFS */ int nSectorSize; /* Size of sectors in bytes */ int nSector; /* Allocated size of nSector array */ u8 **apSector; /* Original sector data */ }; /* | > > > > > > > > | 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 | /* ** This file contains the TestDb bt wrapper. */ #include "lsmtest_tdb.h" #include "lsmtest.h" #include <unistd.h> #include "bt.h" #include <pthread.h> typedef struct BtDb BtDb; typedef struct BtFile BtFile; /* Background checkpointer interface (see implementations below). */ typedef struct bt_ckpter bt_ckpter; static int bgc_attach(BtDb *pDb, const char*); static int bgc_detach(BtDb *pDb); /* ** Each database or log file opened by a database handle is wrapped by ** an object of the following type. */ struct BtFile { BtDb *pBt; /* Database handle that opened this file */ bt_env *pVfs; /* Underlying VFS */ bt_file *pFile; /* File handle belonging to underlying VFS */ int nSectorSize; /* Size of sectors in bytes */ int nSector; /* Allocated size of nSector array */ u8 **apSector; /* Original sector data */ }; /* |
︙ | ︙ | |||
40 41 42 43 44 45 46 47 | bt_db *pBt; /* bt database handle */ sqlite4_env *pEnv; /* SQLite environment (for malloc/free) */ bt_env *pVfs; /* Underlying VFS */ /* Space for bt_fetch() results */ u8 *aBuffer; /* Space to store results */ int nBuffer; /* Allocated size of aBuffer[] in bytes */ | > | > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | bt_db *pBt; /* bt database handle */ sqlite4_env *pEnv; /* SQLite environment (for malloc/free) */ bt_env *pVfs; /* Underlying VFS */ /* Space for bt_fetch() results */ u8 *aBuffer; /* Space to store results */ int nBuffer; /* Allocated size of aBuffer[] in bytes */ int nRef; /* Background checkpointer used by mt connections */ bt_ckpter *pCkpter; /* Stuff used for crash test simulation */ BtFile *apFile[2]; /* Database and log files used by pBt */ bt_env env; /* Private VFS for this object */ int nCrashSync; /* Number of syncs until crash (see above) */ int bCrash; /* True once a crash has been simulated */ }; |
︙ | ︙ | |||
80 81 82 83 84 85 86 | p = (BtFile*)testMalloc(sizeof(BtFile)); if( !p ) return SQLITE4_NOMEM; if( flags & BT_OPEN_DATABASE ){ pBt->apFile[0] = p; }else if( flags & BT_OPEN_LOG ){ pBt->apFile[1] = p; } | > | > > | | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | p = (BtFile*)testMalloc(sizeof(BtFile)); if( !p ) return SQLITE4_NOMEM; if( flags & BT_OPEN_DATABASE ){ pBt->apFile[0] = p; }else if( flags & BT_OPEN_LOG ){ pBt->apFile[1] = p; } if( (flags & BT_OPEN_SHARED)==0 ){ p->pBt = pBt; } p->pVfs = pBt->pVfs; rc = pBt->pVfs->xOpen(pEnv, pVfs, zFile, flags, &p->pFile); if( rc!=SQLITE4_OK ){ testFree(p); p = 0; }else{ pBt->nRef++; } *ppFile = (bt_file*)p; return rc; } static int btVfsSize(bt_file *pFile, sqlite4_int64 *piRes){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xSize(p->pFile, piRes); } static int btVfsRead(bt_file *pFile, sqlite4_int64 iOff, void *pBuf, int nBuf){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xRead(p->pFile, iOff, pBuf, nBuf); } static int btFlushSectors(BtFile *p, int iFile){ sqlite4_int64 iSz; int rc; int i; u8 *aTmp = 0; |
︙ | ︙ | |||
199 200 201 202 203 204 205 | } return rc; } static int btVfsWrite(bt_file *pFile, sqlite4_int64 iOff, void *pBuf, int nBuf){ BtFile *p = (BtFile*)pFile; | | | | | | > | | | | | | | | | | > | | > > | > > > | > > | | | | | | | | | > > > | | 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 | } return rc; } static int btVfsWrite(bt_file *pFile, sqlite4_int64 iOff, void *pBuf, int nBuf){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; if( p->pBt && p->pBt->nCrashSync ){ btSaveSectors(p, iOff, nBuf); } return p->pVfs->xWrite(p->pFile, iOff, pBuf, nBuf); } static int btVfsTruncate(bt_file *pFile, sqlite4_int64 iOff){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xTruncate(p->pFile, iOff); } static int btVfsSync(bt_file *pFile){ int rc = SQLITE4_OK; BtFile *p = (BtFile*)pFile; BtDb *pBt = p->pBt; if( pBt ){ if( pBt->bCrash ) return SQLITE4_IOERR; if( pBt->nCrashSync ){ pBt->nCrashSync--; pBt->bCrash = (pBt->nCrashSync==0); if( pBt->bCrash ){ btFlushSectors(pBt->apFile[0], 0); btFlushSectors(pBt->apFile[1], 1); rc = SQLITE4_IOERR; }else{ btFlushSectors(p, 0); } } } if( rc==SQLITE4_OK ){ rc = p->pVfs->xSync(p->pFile); } return rc; } static int btVfsSectorSize(bt_file *pFile){ BtFile *p = (BtFile*)pFile; return p->pVfs->xSectorSize(p->pFile); } static void btDeref(BtDb *p){ p->nRef--; assert( p->nRef>=0 ); if( p->nRef<=0 ) testFree(p); } static int btVfsClose(bt_file *pFile){ BtFile *p = (BtFile*)pFile; BtDb *pBt = p->pBt; int rc; if( pBt ){ btFlushSectors(p, 0); if( p==pBt->apFile[0] ) pBt->apFile[0] = 0; if( p==pBt->apFile[1] ) pBt->apFile[1] = 0; } testFree(p->apSector); rc = p->pVfs->xClose(p->pFile); #if 0 btDeref(p->pBt); #endif testFree(p); return rc; } static int btVfsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){ BtDb *pBt = (BtDb*)pVfs->pVfsCtx; if( pBt->bCrash ) return SQLITE4_IOERR; return pBt->pVfs->xUnlink(pEnv, pBt->pVfs, zFile); } static int btVfsLock(bt_file *pFile, int iLock, int eType){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xLock(p->pFile, iLock, eType); } static int btVfsTestLock(bt_file *pFile, int iLock, int nLock, int eType){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xTestLock(p->pFile, iLock, nLock, eType); } static int btVfsShmMap(bt_file *pFile, int iChunk, int sz, void **ppOut){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xShmMap(p->pFile, iChunk, sz, ppOut); } static void btVfsShmBarrier(bt_file *pFile){ BtFile *p = (BtFile*)pFile; return p->pVfs->xShmBarrier(p->pFile); } static int btVfsShmUnmap(bt_file *pFile, int bDelete){ BtFile *p = (BtFile*)pFile; if( p->pBt && p->pBt->bCrash ) return SQLITE4_IOERR; return p->pVfs->xShmUnmap(p->pFile, bDelete); } static int bt_close(TestDb *pTestDb){ BtDb *p = (BtDb*)pTestDb; int rc = sqlite4BtClose(p->pBt); free(p->aBuffer); if( p->apFile[0] ) p->apFile[0]->pBt = 0; if( p->apFile[1] ) p->apFile[1]->pBt = 0; bgc_detach(p); testFree(p); return rc; } static int btMinTransaction(BtDb *p, int iMin, int *piLevel){ int iLevel; int rc = SQLITE4_OK; |
︙ | ︙ | |||
590 591 592 593 594 595 596 | } if( *p ) return SQLITE4_ERROR; *piVal = i; return SQLITE4_OK; } | | | > > > > | | > | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | } if( *p ) return SQLITE4_ERROR; *piVal = i; return SQLITE4_OK; } static int testBtConfigure(bt_db *db, const char *zCfg, int *pbMt){ int rc = SQLITE4_OK; if( zCfg ){ struct CfgParam { const char *zParam; int eParam; } aParam[] = { { "safety", BT_CONTROL_SAFETY }, { "autockpt", BT_CONTROL_AUTOCKPT }, { "multiproc", BT_CONTROL_MULTIPROC }, { "mt", -1 } }; const char *z = zCfg; int n = strlen(z); char *aSpace; const char *zOpt; const char *zArg; aSpace = (char*)testMalloc(n+2); while( 0==testParseOption(&z, &zOpt, &zArg, aSpace) ){ int i; int iVal; rc = testArgSelect(aParam, "param", zOpt, &i); if( rc!=SQLITE4_OK ) break; rc = testParseInt(zArg, &iVal); if( rc!=SQLITE4_OK ) break; if( aParam[i].eParam<0 ){ *pbMt = iVal; }else{ rc = sqlite4BtControl(db, aParam[i].eParam, (void*)&iVal); if( rc!=SQLITE4_OK ) break; } } testFree(aSpace); } return rc; } |
︙ | ︙ | |||
660 661 662 663 664 665 666 667 668 669 670 671 672 673 | unlink(zFilename); unlink(zLog); sqlite3_free(zLog); } rc = sqlite4BtNew(pEnv, 0, &pBt); if( rc==SQLITE4_OK ){ p = (BtDb*)testMalloc(sizeof(BtDb)); p->base.pMethods = &SqlMethods; p->pBt = pBt; p->pEnv = pEnv; p->nRef = 1; p->env.pVfsCtx = (void*)p; | > > | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | unlink(zFilename); unlink(zLog); sqlite3_free(zLog); } rc = sqlite4BtNew(pEnv, 0, &pBt); if( rc==SQLITE4_OK ){ int mt = 0; /* True for multi-threaded connection */ p = (BtDb*)testMalloc(sizeof(BtDb)); p->base.pMethods = &SqlMethods; p->pBt = pBt; p->pEnv = pEnv; p->nRef = 1; p->env.pVfsCtx = (void*)p; |
︙ | ︙ | |||
686 687 688 689 690 691 692 | p->env.xShmMap = btVfsShmMap; p->env.xShmBarrier = btVfsShmBarrier; p->env.xShmUnmap = btVfsShmUnmap; sqlite4BtControl(pBt, BT_CONTROL_GETVFS, (void*)&p->pVfs); sqlite4BtControl(pBt, BT_CONTROL_SETVFS, (void*)&p->env); | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | p->env.xShmMap = btVfsShmMap; p->env.xShmBarrier = btVfsShmBarrier; p->env.xShmUnmap = btVfsShmUnmap; sqlite4BtControl(pBt, BT_CONTROL_GETVFS, (void*)&p->pVfs); sqlite4BtControl(pBt, BT_CONTROL_SETVFS, (void*)&p->env); rc = testBtConfigure(pBt, zSpec, &mt); if( rc==SQLITE4_OK ){ rc = sqlite4BtOpen(pBt, zFilename); } if( rc==SQLITE4_OK && mt ){ int nAuto = 0; rc = bgc_attach(p, zSpec); sqlite4BtControl(pBt, BT_CONTROL_AUTOCKPT, (void*)&nAuto); } } if( rc!=SQLITE4_OK && p ){ bt_close(&p->base); } *ppDb = &p->base; return rc; } void tdb_bt_prepare_sync_crash(TestDb *pTestDb, int iSync){ BtDb *p = (BtDb*)pTestDb; assert( pTestDb->pMethods->xClose==bt_close ); assert( p->bCrash==0 ); p->nCrashSync = iSync; } /************************************************************************* ** Beginning of code for background checkpointer. */ struct bt_ckpter { sqlite4_buffer file; /* File name */ sqlite4_buffer spec; /* Options */ int nLogsize; /* Minimum log size to checkpoint */ int nRef; /* Number of clients */ int bDoWork; /* Set by client threads */ pthread_t ckpter_thread; /* Checkpointer thread */ pthread_cond_t ckpter_cond; /* Condition var the ckpter waits on */ pthread_mutex_t ckpter_mutex; /* Mutex used with ckpter_cond */ bt_ckpter *pNext; /* Next object in list at gBgc.pCkpter */ }; static struct GlobalBackgroundCheckpointer { bt_ckpter *pCkpter; /* Linked list of checkpointers */ } gBgc; static void *bgc_main(void *pArg){ BtDb *pDb = 0; int rc; int mt; bt_ckpter *pCkpter = (bt_ckpter*)pArg; rc = test_bt_open("", (char*)pCkpter->file.p, 0, (TestDb**)&pDb); assert( rc==SQLITE4_OK ); rc = testBtConfigure(pDb->pBt, (char*)pCkpter->spec.p, &mt); while( pCkpter->nRef>0 ){ bt_db *db = pDb->pBt; int nLog = 0; sqlite4BtBegin(db, 1); sqlite4BtCommit(db, 0); sqlite4BtControl(db, BT_CONTROL_LOGSIZE, (void*)&nLog); if( nLog>=pCkpter->nLogsize ){ int rc; bt_checkpoint ckpt; memset(&ckpt, 0, sizeof(bt_checkpoint)); ckpt.nFrameBuffer = nLog/2; rc = sqlite4BtControl(db, BT_CONTROL_CHECKPOINT, (void*)&ckpt); assert( rc==SQLITE4_OK ); sqlite4BtControl(db, BT_CONTROL_LOGSIZE, (void*)&nLog); } /* The thread will wake up when it is signaled either because another ** thread has created some work for this one or because the connection ** is being closed. */ pthread_mutex_lock(&pCkpter->ckpter_mutex); if( pCkpter->bDoWork==0 ){ pthread_cond_wait(&pCkpter->ckpter_cond, &pCkpter->ckpter_mutex); } pCkpter->bDoWork = 0; pthread_mutex_unlock(&pCkpter->ckpter_mutex); } if( pDb ) bt_close((TestDb*)pDb); return 0; } static void bgc_logsize_cb(void *pCtx, int nLogsize){ bt_ckpter *p = (bt_ckpter*)pCtx; if( nLogsize>=p->nLogsize ){ pthread_mutex_lock(&p->ckpter_mutex); p->bDoWork = 1; pthread_cond_signal(&p->ckpter_cond); pthread_mutex_unlock(&p->ckpter_mutex); } } static int bgc_attach(BtDb *pDb, const char *zSpec){ int rc; int n; bt_info info; bt_ckpter *pCkpter; /* Figure out the full path to the database opened by handle pDb. */ info.eType = BT_INFO_FILENAME; info.pgno = 0; sqlite4_buffer_init(&info.output, 0); rc = sqlite4BtControl(pDb->pBt, BT_CONTROL_INFO, (void*)&info); if( rc!=SQLITE4_OK ) return rc; sqlite4_mutex_enter(sqlite4_mutex_alloc(pDb->pEnv, SQLITE4_MUTEX_STATIC_KV)); /* Search for an existing bt_ckpter object. */ n = info.output.n; for(pCkpter=gBgc.pCkpter; pCkpter; pCkpter=pCkpter->pNext){ if( n==pCkpter->file.n && 0==memcmp(info.output.p, pCkpter->file.p, n) ){ break; } } /* Failed to find a suitable checkpointer. Create a new one. */ if( pCkpter==0 ){ bt_logsizecb cb; pCkpter = testMalloc(sizeof(bt_ckpter)); memcpy(&pCkpter->file, &info.output, sizeof(sqlite4_buffer)); info.output.p = 0; pCkpter->pNext = gBgc.pCkpter; pCkpter->nLogsize = 1000; gBgc.pCkpter = pCkpter; pCkpter->nRef = 1; sqlite4_buffer_init(&pCkpter->spec, 0); rc = sqlite4_buffer_set(&pCkpter->spec, zSpec, strlen(zSpec)+1); assert( rc==SQLITE4_OK ); /* Kick off the checkpointer thread. */ if( rc==0 ) rc = pthread_cond_init(&pCkpter->ckpter_cond, 0); if( rc==0 ) rc = pthread_mutex_init(&pCkpter->ckpter_mutex, 0); if( rc==0 ){ rc = pthread_create(&pCkpter->ckpter_thread, 0, bgc_main, (void*)pCkpter); } assert( rc==0 ); /* todo: Fix this */ /* Set up the logsize callback for the client thread */ cb.pCtx = (void*)pCkpter; cb.xLogsize = bgc_logsize_cb; sqlite4BtControl(pDb->pBt, BT_CONTROL_LOGSIZECB, (void*)&cb); }else{ pCkpter->nRef++; } /* Assuming a checkpointer was encountered or effected, attach the ** connection to it. */ if( pCkpter ){ pDb->pCkpter = pCkpter; } sqlite4_mutex_leave(sqlite4_mutex_alloc(pDb->pEnv, SQLITE4_MUTEX_STATIC_KV)); sqlite4_buffer_clear(&info.output); return rc; } static int bgc_detach(BtDb *pDb){ int rc = SQLITE4_OK; bt_ckpter *pCkpter = pDb->pCkpter; if( pCkpter ){ int bShutdown = 0; /* True if this is the last reference */ sqlite4_mutex_enter(sqlite4_mutex_alloc(pDb->pEnv,SQLITE4_MUTEX_STATIC_KV)); pCkpter->nRef--; if( pCkpter->nRef==0 ){ bt_ckpter **pp; *pp = pCkpter->pNext; for(pp=&gBgc.pCkpter; *pp!=pCkpter; pp=&((*pp)->pNext)); bShutdown = 1; } sqlite4_mutex_leave(sqlite4_mutex_alloc(pDb->pEnv,SQLITE4_MUTEX_STATIC_KV)); if( bShutdown ){ void *pDummy; /* Signal the checkpointer thread. */ pthread_mutex_lock(&pCkpter->ckpter_mutex); pCkpter->bDoWork = 1; pthread_cond_signal(&pCkpter->ckpter_cond); pthread_mutex_unlock(&pCkpter->ckpter_mutex); /* Join the checkpointer thread. */ pthread_join(pCkpter->ckpter_thread, &pDummy); pthread_cond_destroy(&pCkpter->ckpter_cond); pthread_mutex_destroy(&pCkpter->ckpter_mutex); sqlite4_buffer_clear(&pCkpter->file); sqlite4_buffer_clear(&pCkpter->spec); testFree(pCkpter); } pDb->pCkpter = 0; } return rc; } /* ** End of background checkpointer. *************************************************************************/ |
Changes to lsm-test/sqltest.c.
︙ | ︙ | |||
143 144 145 146 147 148 149 | if( nByte>sizeof(aBlob) ) nByte = sizeof(aBlob); testPrngArray(iSeed, (unsigned int *)aBlob, (nByte+3)/4); sqlite4_result_blob(ctx, aBlob, nByte, SQLITE4_TRANSIENT, 0); } static void install_rblob_function4(sqlite4 *db){ testPrngInit(); | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | if( nByte>sizeof(aBlob) ) nByte = sizeof(aBlob); testPrngArray(iSeed, (unsigned int *)aBlob, (nByte+3)/4); sqlite4_result_blob(ctx, aBlob, nByte, SQLITE4_TRANSIENT, 0); } static void install_rblob_function4(sqlite4 *db){ testPrngInit(); sqlite4_create_function(db, "rblob", 3, 0, rblobFunc4, 0, 0, 0); } /* sqlite3 implementation */ static void rblobFunc3(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ unsigned char aBlob[1000]; int iSeed = sqlite3_value_int(apArg[0]); |
︙ | ︙ | |||
207 208 209 210 211 212 213 | if( nRange>0 ){ iVal = iVal % nRange; } sqlite4_result_int(ctx, iVal); } static void install_rint_function4(sqlite4 *db){ testPrngInit(); | | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | if( nRange>0 ){ iVal = iVal % nRange; } sqlite4_result_int(ctx, iVal); } static void install_rint_function4(sqlite4 *db){ testPrngInit(); sqlite4_create_function(db, "rint", 2, 0, rintFunc4, 0, 0, 0); } /* ** End of rint() implementations. *************************************************************************/ /************************************************************************* ** Integer query functions for sqlite3 and src4. |
︙ | ︙ | |||
272 273 274 275 276 277 278 | install_rblob_function4(db); zCreateTbl = create_schema_sql(nIdx); zInsert = create_insert_sql(nIdx); /* Create the db schema and prepare the INSERT statement */ | | | | | | | 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 | install_rblob_function4(db); zCreateTbl = create_schema_sql(nIdx); zInsert = create_insert_sql(nIdx); /* Create the db schema and prepare the INSERT statement */ EXPLODE( sqlite4_exec(db, zCreateTbl, 0, 0) ); EXPLODE( sqlite4_prepare(db, zInsert, -1, &pInsert, 0) ); /* Run the test */ testTimeInit(); for(i=0; i<nRow; i++){ if( (i % nRowPerTrans)==0 ){ if( i!=0 ) EXPLODE( sqlite4_exec(db, "COMMIT", 0, 0) ); EXPLODE( sqlite4_exec(db, "BEGIN", 0, 0) ); } sqlite4_bind_int(pInsert, 1, i); sqlite4_step(pInsert); EXPLODE( sqlite4_reset(pInsert) ); } EXPLODE( sqlite4_exec(db, "COMMIT", 0, 0) ); /* Free all the stuff allocated above */ sqlite4_finalize(pInsert); sqlite4_free(0, zCreateTbl); sqlite4_free(0, zInsert); sqlite4_close(db, 0); nMs = testTimeGet(); /* Print out the time taken by the test */ printf("%.3f seconds\n", (double)nMs / 1000.0); return 0; } static int do_insert1_test3( |
︙ | ︙ | |||
452 453 454 455 456 457 458 | /* Create the db schema and prepare the INSERT statement */ zSelect = create_select_sql(iIdx); EXPLODE( sqlite4_prepare(db, zSelect, -1, &pSelect, 0) ); testTimeInit(); for(i=0; i<nRow; i++){ if( (i % nRowPerTrans)==0 ){ | | | | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | /* Create the db schema and prepare the INSERT statement */ zSelect = create_select_sql(iIdx); EXPLODE( sqlite4_prepare(db, zSelect, -1, &pSelect, 0) ); testTimeInit(); for(i=0; i<nRow; i++){ if( (i % nRowPerTrans)==0 ){ if( i!=0 ) EXPLODE( sqlite4_exec(db, "COMMIT", 0, 0) ); EXPLODE( sqlite4_exec(db, "BEGIN", 0, 0) ); } sqlite4_bind_int(pSelect, 1, (i*211)%nTblRow); EXPLODE( SQLITE_ROW!=sqlite4_step(pSelect) ); EXPLODE( sqlite4_reset(pSelect) ); } EXPLODE( sqlite4_exec(db, "COMMIT", 0, 0) ); nMs = testTimeGet(); sqlite4_finalize(pSelect); sqlite4_close(db, 0); sqlite4_free(0, zSelect); printf("%.3f seconds\n", (double)nMs / 1000.0); return 0; } static int do_select1_test3( const char *zFile, |
︙ | ︙ | |||
649 650 651 652 653 654 655 | rc = sqlite4_open(0, zFile, &p->db); if( rc!=SQLITE4_OK ){ sqlite4_free(0, p); p = 0; }else{ install_rint_function4(p->db); if( zConfig ) { | | | 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | rc = sqlite4_open(0, zFile, &p->db); if( rc!=SQLITE4_OK ){ sqlite4_free(0, p); p = 0; }else{ install_rint_function4(p->db); if( zConfig ) { rc = sqlite4_exec(p->db, zConfig, 0, 0); } } *pp = (SqlDatabase *)p; } return rc; } |
︙ | ︙ | |||
680 681 682 683 684 685 686 | SqlStmt *pSql; SqlStmt *pNext; for(pSql=pDb->pSqlStmt; pSql; pSql=pNext){ pNext = pSql->pNext; sqlite4_finalize((sqlite4_stmt *)pSql->pStmt); sqlite4_free(0, pSql); } | | | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | SqlStmt *pSql; SqlStmt *pNext; for(pSql=pDb->pSqlStmt; pSql; pSql=pNext){ pNext = pSql->pNext; sqlite4_finalize((sqlite4_stmt *)pSql->pStmt); sqlite4_free(0, pSql); } sqlite4_close(p->db, 0); sqlite4_free(0, p); } } static int exec_sql(SqlDatabase *pDb, const char *zSql, const char *zBind, ...){ int rc = 0; void *pNewStmt = 0; |
︙ | ︙ |
Changes to src/bt.h.
︙ | ︙ | |||
162 163 164 165 166 167 168 | ** The third argument is interpreted as a pointer to type (int). The ** value pointer to is set to the number of uncheckpointed frames ** that stored in the log file according to the snapshot used by the ** most recently completed transaction or checkpoint operation. ** ** BT_CONTROL_MULTIPROC: ** The third argument is interpreted as a pointer to type (int). | | > > > > | | | | | | | > > > > > > > > > > > > > > > > > | 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 | ** The third argument is interpreted as a pointer to type (int). The ** value pointer to is set to the number of uncheckpointed frames ** that stored in the log file according to the snapshot used by the ** most recently completed transaction or checkpoint operation. ** ** BT_CONTROL_MULTIPROC: ** The third argument is interpreted as a pointer to type (int). ** ** BT_CONTROL_LOGSIZECB: ** ** BT_CONTROL_CHECKPOINT: ** */ #define BT_CONTROL_INFO 7706389 #define BT_CONTROL_SETVFS 7706390 #define BT_CONTROL_GETVFS 7706391 #define BT_CONTROL_SAFETY 7706392 #define BT_CONTROL_AUTOCKPT 7706393 #define BT_CONTROL_LOGSIZE 7706394 #define BT_CONTROL_MULTIPROC 7706395 #define BT_CONTROL_LOGSIZECB 7706396 #define BT_CONTROL_CHECKPOINT 7706397 int sqlite4BtControl(bt_db*, int op, void *pArg); #define BT_SAFETY_OFF 0 #define BT_SAFETY_NORMAL 1 #define BT_SAFETY_FULL 2 typedef struct bt_info bt_info; struct bt_info { int eType; unsigned int pgno; sqlite4_buffer output; }; #define BT_INFO_PAGEDUMP 1 #define BT_INFO_FILENAME 2 typedef struct bt_logsizecb bt_logsizecb; struct bt_logsizecb { void *pCtx; /* A copy of this is passed to xLogsize() */ void (*xLogsize)(void*, int); /* Callback function */ }; typedef struct bt_checkpoint bt_checkpoint; struct bt_checkpoint { int nFrameBuffer; /* Minimum number of frames to leave in log */ int nCkpt; /* OUT: Number of frames checkpointed */ }; /* ** File-system interface. */ typedef struct bt_env bt_env; typedef struct bt_file bt_file; |
︙ | ︙ | |||
218 219 220 221 222 223 224 | }; /* ** Flags for xOpen */ #define BT_OPEN_DATABASE 0x0001 #define BT_OPEN_LOG 0x0002 | > | | 239 240 241 242 243 244 245 246 247 248 249 | }; /* ** Flags for xOpen */ #define BT_OPEN_DATABASE 0x0001 #define BT_OPEN_LOG 0x0002 #define BT_OPEN_SHARED 0x0004 #define BT_OPEN_READONLY 0x0008 |
Changes to src/btInt.h.
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 | void sqlite4BtPagerSetEnv(BtPager*, bt_env*); void sqlite4BtPagerSetSafety(BtPager*, int*); void sqlite4BtPagerSetAutockpt(BtPager*, int*); void sqlite4BtPagerLogsize(BtPager*, int*); void sqlite4BtPagerMultiproc(BtPager *pPager, int *piVal); /* ** End of bt_pager.c interface. *************************************************************************/ /************************************************************************* ** File-system interface. | > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | void sqlite4BtPagerSetEnv(BtPager*, bt_env*); void sqlite4BtPagerSetSafety(BtPager*, int*); void sqlite4BtPagerSetAutockpt(BtPager*, int*); void sqlite4BtPagerLogsize(BtPager*, int*); void sqlite4BtPagerMultiproc(BtPager *pPager, int *piVal); void sqlite4BtPagerLogsizeCb(BtPager *pPager, bt_logsizecb*); int sqlite4BtPagerCheckpoint(BtPager *pPager, bt_checkpoint*); /* ** End of bt_pager.c interface. *************************************************************************/ /************************************************************************* ** File-system interface. |
︙ | ︙ |
Changes to src/bt_lock.c.
︙ | ︙ | |||
316 317 318 319 320 321 322 | if( rc==SQLITE4_OK ){ sqlite4_mutex_enter(pShared->pClientMutex); /* If this is a multi-process connection and the shared file-handle ** has not yet been opened, open it now. Under the cover of the ** client-mutex. */ if( pShared->pFile==0 && pShared->bMultiProc ){ | > | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | if( rc==SQLITE4_OK ){ sqlite4_mutex_enter(pShared->pClientMutex); /* If this is a multi-process connection and the shared file-handle ** has not yet been opened, open it now. Under the cover of the ** client-mutex. */ if( pShared->pFile==0 && pShared->bMultiProc ){ int flags = BT_OPEN_SHARED; rc = pVfs->xOpen(pEnv, pVfs, pShared->zName, flags, &pShared->pFile); } if( rc==SQLITE4_OK ){ if( pShared->pBtFile ){ p->pBtFile = pShared->pBtFile; pShared->pBtFile = p->pBtFile->pNext; p->pBtFile->pNext = 0; |
︙ | ︙ |
Changes to src/bt_main.c.
︙ | ︙ | |||
2468 2469 2470 2471 2472 2473 2474 | return sqlite4BtPagerSetCookie(db->pPager, iVal); } int sqlite4BtGetCookie(bt_db *db, unsigned int *piVal){ return sqlite4BtPagerGetCookie(db->pPager, piVal); } | | | | < > > > > > > > > > > > > > > > > > > > > > > > > > | 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 | return sqlite4BtPagerSetCookie(db->pPager, iVal); } int sqlite4BtGetCookie(bt_db *db, unsigned int *piVal){ return sqlite4BtPagerGetCookie(db->pPager, piVal); } static int btControlInfo(bt_db *db, bt_info *pInfo){ int rc = SQLITE4_OK; switch( pInfo->eType ){ case BT_INFO_PAGEDUMP: { int iTrans = sqlite4BtTransactionLevel(db); if( iTrans==0 ) rc = sqlite4BtBegin(db, 1); if( rc==SQLITE4_OK ){ BtPage *pPg = 0; rc = sqlite4BtPageGet(db->pPager, pInfo->pgno, &pPg); if( rc==SQLITE4_OK ){ u8 *aData; int nData; aData = sqlite4BtPageData(pPg); nData = sqlite4BtPagerPagesize(db->pPager); btPageToAscii(pInfo->pgno, aData, nData, &pInfo->output); sqlite4_buffer_append(&pInfo->output, "", 1); sqlite4BtPageRelease(pPg); } if( iTrans==0 ) rc = sqlite4BtCommit(db, 0); } break; } case BT_INFO_FILENAME: { const char *zFile; zFile = sqlite4BtPagerFilename(db->pPager, BT_PAGERFILE_DATABASE); rc = sqlite4_buffer_set(&pInfo->output, zFile, strlen(zFile)+1); break; } default: { rc = SQLITE4_ERROR; break; } } return rc; } int sqlite4BtControl(bt_db *db, int op, void *pArg){ int rc = SQLITE4_OK; switch( op ){ case BT_CONTROL_INFO: { bt_info *pInfo = (bt_info*)pArg; rc = btControlInfo(db, pInfo); break; } case BT_CONTROL_GETVFS: { *((bt_env**)pArg) = sqlite4BtPagerGetEnv(db->pPager); break; } case BT_CONTROL_SETVFS: { |
︙ | ︙ | |||
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 | } case BT_CONTROL_MULTIPROC: { int *pInt = (int*)pArg; sqlite4BtPagerMultiproc(db->pPager, pInt); break; } } return rc; } | > > > > > > > > > > > > | 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 | } case BT_CONTROL_MULTIPROC: { int *pInt = (int*)pArg; sqlite4BtPagerMultiproc(db->pPager, pInt); break; } case BT_CONTROL_LOGSIZECB: { bt_logsizecb *p = (bt_logsizecb*)pArg; sqlite4BtPagerLogsizeCb(db->pPager, p); break; } case BT_CONTROL_CHECKPOINT: { bt_logsizecb *p = (bt_checkpoint*)pArg; rc = sqlite4BtPagerCheckpoint(db->pPager, p); break; } } return rc; } |
Changes to src/bt_pager.c.
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | BtPage *pDirty; /* List of all dirty pages */ int nTotalRef; /* Total number of outstanding page refs */ int bDoAutoCkpt; /* Do auto-checkpoint after next unlock */ BtSavepoint *aSavepoint; /* Savepoint array */ int nSavepoint; /* Number of entries in aSavepoint array */ int pgsz; /* Page size in bytes */ int nPg; /* Number of pages currently in db file */ }; /************************************************************************** ** Interface to BtPageHash object. */ | > > > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | BtPage *pDirty; /* List of all dirty pages */ int nTotalRef; /* Total number of outstanding page refs */ int bDoAutoCkpt; /* Do auto-checkpoint after next unlock */ BtSavepoint *aSavepoint; /* Savepoint array */ int nSavepoint; /* Number of entries in aSavepoint array */ int pgsz; /* Page size in bytes */ int nPg; /* Number of pages currently in db file */ void *pLogsizeCtx; /* A copy of this is passed to xLogsize() */ void (*xLogsize)(void*, int); /* Log-size Callback function */ }; /************************************************************************** ** Interface to BtPageHash object. */ |
︙ | ︙ | |||
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | } /* ** Commit the current write transaction to disk. */ static int btCommitTransaction(BtPager *p){ int rc = SQLITE4_OK; BtPage *pPg; BtPage *pNext; assert( p->iTransactionLevel>=2 ); btCloseSavepoints(p, 2, 0); for(pPg=p->pDirty; pPg; pPg=pNext){ pNext = pPg->pNextDirty; pPg->flags &= ~(BT_PAGE_DIRTY); pPg->pNextDirty = 0; if( rc==SQLITE4_OK ){ int nPg = ((pNext==0) ? p->nPg : 0); rc = sqlite4BtLogWrite(p->pLog, pPg->pgno, pPg->aData, nPg); } } p->pDirty = 0; sqlite4BtLogSnapshotEndWrite(p->pLog); | > | > > > > > | 535 536 537 538 539 540 541 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 | } /* ** Commit the current write transaction to disk. */ static int btCommitTransaction(BtPager *p){ int rc = SQLITE4_OK; int nLogsize; /* Number of frames in log after commit */ BtPage *pPg; BtPage *pNext; assert( p->iTransactionLevel>=2 ); btCloseSavepoints(p, 2, 0); for(pPg=p->pDirty; pPg; pPg=pNext){ pNext = pPg->pNextDirty; pPg->flags &= ~(BT_PAGE_DIRTY); pPg->pNextDirty = 0; if( rc==SQLITE4_OK ){ int nPg = ((pNext==0) ? p->nPg : 0); rc = sqlite4BtLogWrite(p->pLog, pPg->pgno, pPg->aData, nPg); } } p->pDirty = 0; sqlite4BtLogSnapshotEndWrite(p->pLog); nLogsize = sqlite4BtLogSize(p->pLog); if( p->btl.nAutoCkpt && nLogsize>=p->btl.nAutoCkpt ){ p->bDoAutoCkpt = 1; } if( p->xLogsize ){ p->xLogsize(p->pLogsizeCtx, nLogsize); } return rc; } static int btLoadPageData(BtPager *p, BtPage *pPg){ int rc; /* Return code */ |
︙ | ︙ | |||
954 955 956 957 958 959 960 961 962 963 964 965 966 967 | void sqlite4BtPagerMultiproc(BtPager *pPager, int *piVal){ if( *piVal==0 || *piVal==1 ){ pPager->btl.bRequestMultiProc = *piVal; } *piVal = pPager->btl.bRequestMultiProc; } #ifndef NDEBUG int sqlite4BtPagerRefcount(BtPager *p){ return p->nTotalRef; } #endif | > > > > > > > > > > > | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 | void sqlite4BtPagerMultiproc(BtPager *pPager, int *piVal){ if( *piVal==0 || *piVal==1 ){ pPager->btl.bRequestMultiProc = *piVal; } *piVal = pPager->btl.bRequestMultiProc; } void sqlite4BtPagerLogsizeCb(BtPager *pPager, bt_logsizecb *p){ pPager->xLogsize = p->xLogsize; pPager->pLogsizeCtx = p->pCtx; } int sqlite4BtPagerCheckpoint(BtPager *pPager, bt_checkpoint *pCkpt){ int rc; rc = sqlite4BtLogCheckpoint(pPager->pLog, pCkpt->nFrameBuffer); return rc; } #ifndef NDEBUG int sqlite4BtPagerRefcount(BtPager *p){ return p->nTotalRef; } #endif |