Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add start of checkpointing code to btree. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
29373a8844687bc9c444338bcf798237 |
User & Date: | dan 2013-10-25 20:20:08.913 |
Context
2013-10-26
| ||
12:44 | Use sqlite4_malloc instead of malloc in test fixture for num check-in: 3f6924e784 user: peterreid tags: trunk | |
2013-10-25
| ||
20:20 | Add start of checkpointing code to btree. check-in: 29373a8844 user: dan tags: trunk | |
02:37 | Fix buffer overread when parsing a UTF16 exponent check-in: 9e61c90be4 user: peterreid tags: trunk | |
Changes
Changes to lsm-test/lsmtest_main.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | void *pVal, int nVal, /* Expected value */ int *pRc /* IN/OUT: Error code */ ){ if( *pRc==0 ){ void *pDbVal; int nDbVal; int rc; rc = tdb_fetch(pDb, pKey, nKey, &pDbVal, &nDbVal); testSetError(rc); if( rc==0 && (nVal!=nDbVal || (nVal>0 && lsm_memcmp(pVal, pDbVal, nVal))) ){ testSetError(1); } } } | > > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | void *pVal, int nVal, /* Expected value */ int *pRc /* IN/OUT: Error code */ ){ if( *pRc==0 ){ void *pDbVal; int nDbVal; int rc; static int nCall = 0; nCall++; rc = tdb_fetch(pDb, pKey, nKey, &pDbVal, &nDbVal); testSetError(rc); if( rc==0 && (nVal!=nDbVal || (nVal>0 && lsm_memcmp(pVal, pDbVal, nVal))) ){ testSetError(1); } } } |
︙ | ︙ |
Changes to src/btInt.h.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* Number of elements in an array object. */ #define array_size(x) (sizeof(x)/sizeof(x[0])) /* Number of read-lock slots in shared memory */ #define BT_NREADER 4 /************************************************************************* ** Interface to bt_pager.c functionality. */ typedef struct BtPage BtPage; typedef struct BtPager BtPager; | > > > > > > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* Number of elements in an array object. */ #define array_size(x) (sizeof(x)/sizeof(x[0])) /* Number of read-lock slots in shared memory */ #define BT_NREADER 4 #ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX # define MAX(a,b) (((a)>(b))?(a):(b)) #endif /************************************************************************* ** Interface to bt_pager.c functionality. */ typedef struct BtPage BtPage; typedef struct BtPager BtPager; |
︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 | int sqlite4BtLogRead(BtLog*, u32 pgno, u8 *aData); int sqlite4BtLogWrite(BtLog*, u32 pgno, u8 *aData, int bCommit); int sqlite4BtLogSnapshotOpen(BtLog*); int sqlite4BtLogSnapshotClose(BtLog*); int sqlite4BtLogSnapshotWritable(BtLog*); int sqlite4BtLogCheckpoint(BtLog*); /* ** End of bt_log.c interface. *************************************************************************/ /************************************************************************* | > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | int sqlite4BtLogRead(BtLog*, u32 pgno, u8 *aData); int sqlite4BtLogWrite(BtLog*, u32 pgno, u8 *aData, int bCommit); int sqlite4BtLogSnapshotOpen(BtLog*); int sqlite4BtLogSnapshotClose(BtLog*); int sqlite4BtLogSnapshotWritable(BtLog*); int sqlite4BtLogSize(BtLog*); int sqlite4BtLogCheckpoint(BtLog*); /* ** End of bt_log.c interface. *************************************************************************/ /************************************************************************* |
︙ | ︙ |
Changes to src/bt_lock.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2013 October 18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* ** 2013 October 18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ #include "sqliteInt.h" #include "btInt.h" #include <string.h> #include <assert.h> #include <stdio.h> #define BT_LOCK_DMS1 0 /* DMS1 */ #define BT_LOCK_DMS2_RW 1 /* DMS2/rw */ |
︙ | ︙ | |||
400 401 402 403 404 405 406 407 | } } sqlite4_mutex_leave(pShared->pClientMutex); *ppOut = pOut; return rc; } | > > > > > > > > | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | } } sqlite4_mutex_leave(pShared->pClientMutex); *ppOut = pOut; return rc; } int sqlite4BtLockCkpt(BtLock *pLock){ return btLockLockop(pLock, BT_LOCK_CKPTER, BT_LOCK_EXCL, 0); } int sqlite4BtLockCkptUnlock(BtLock *pLock){ return btLockLockop(pLock, BT_LOCK_CKPTER, BT_LOCK_UNLOCK, 0); } |
Changes to src/bt_log.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | int padding; u32 aCksum[2]; /* Object checksum */ }; /* ** A single instance of this structure follows the two BtShmHdr structures ** in shared memory. */ struct BtCkptHdr { u32 iFirstRead; /* First uncheckpointed frame */ u32 iFirstRecover; /* First recovery frame */ }; struct BtShm { BtShmHdr hdr1; BtShmHdr hdr2; BtCkptHdr ckpt; | > > > > > > > > > > > > > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | int padding; u32 aCksum[2]; /* Object checksum */ }; /* ** A single instance of this structure follows the two BtShmHdr structures ** in shared memory. ** ** iWalHdr: ** This field encodes two pieces of information: the location of the ** current log file header (slot 0 or slot 1) and the value of the ** BtWalHdr.iCnt field within it (0, 1 or 2). Encoded as: ** ** ((iSlot << 2) + iCnt) ** ** To decode, use: ** ** iSlot = (ckpthdr.iWalHdr >> 2); ** iCnt = (ckpthdr.iWalHdr & 0x03);& 0x03); */ struct BtCkptHdr { u32 iFirstRead; /* First uncheckpointed frame */ u32 iWalHdr; /* Description of current wal header */ u32 iFirstRecover; /* First recovery frame */ }; struct BtShm { BtShmHdr hdr1; BtShmHdr hdr2; BtCkptHdr ckpt; |
︙ | ︙ | |||
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | ** initialize the shared-memory accordingly. */ static int btLogRecover(BtLog *pLog){ bt_env *pVfs = pLog->pLock->pVfs; i64 nByte = 0; /* Size of log file on disk */ int rc; /* Return code */ BtWalHdr *pHdr = 0; /* Read a log file header from the start of the file. */ rc = pVfs->xSize(pLog->pFd, &nByte); if( rc==SQLITE4_OK && nByte>0 ){ BtWalHdr hdr1; rc = btLogReadHeader(pLog, 0, &hdr1); if( rc==SQLITE4_OK ){ BtWalHdr hdr2; rc = btLogReadHeader(pLog, hdr1.nSector, &hdr2); if( rc==SQLITE4_NOTFOUND ){ pHdr = &hdr1; }else if( rc==SQLITE4_OK ){ int aGreater[3] = {1, 2, 0}; pHdr = ((hdr2.iCnt==aGreater[hdr1.iCnt]) ? &hdr2 : &hdr1); } }else if( rc==SQLITE4_NOTFOUND ){ int iOff; for(iOff=256; iOff<=65536 && rc==SQLITE4_NOTFOUND; iOff=iOff*2){ rc = btLogReadHeader(pLog, iOff, &hdr1); } if( rc==SQLITE4_OK ){ pHdr = &hdr1; } } if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_OK; } /* If a header was successfully read from the file, scan the log file ** and populate the shared-memory hash tables. */ if( pHdr ){ u32 iCommit = 0; rc = btLogTraverse(pLog, pHdr, btLogRecoverFrame, (void*)&iCommit); if( rc==SQLITE4_OK && iCommit>0 ){ pLog->snapshot.aLog[4] = 1; pLog->snapshot.aLog[5] = iCommit; rc = btLogHashRollback(pLog, btLogFrameHash(pLog, iCommit), iCommit); } } return rc; | > > > > > > > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | ** initialize the shared-memory accordingly. */ static int btLogRecover(BtLog *pLog){ bt_env *pVfs = pLog->pLock->pVfs; i64 nByte = 0; /* Size of log file on disk */ int rc; /* Return code */ BtWalHdr *pHdr = 0; int iSlot = 0; /* Read a log file header from the start of the file. */ rc = pVfs->xSize(pLog->pFd, &nByte); if( rc==SQLITE4_OK && nByte>0 ){ BtWalHdr hdr1; rc = btLogReadHeader(pLog, 0, &hdr1); if( rc==SQLITE4_OK ){ BtWalHdr hdr2; rc = btLogReadHeader(pLog, hdr1.nSector, &hdr2); if( rc==SQLITE4_NOTFOUND ){ pHdr = &hdr1; }else if( rc==SQLITE4_OK ){ int aGreater[3] = {1, 2, 0}; pHdr = ((hdr2.iCnt==aGreater[hdr1.iCnt]) ? &hdr2 : &hdr1); } iSlot = (pHdr==&hdr2); }else if( rc==SQLITE4_NOTFOUND ){ int iOff; for(iOff=256; iOff<=65536 && rc==SQLITE4_NOTFOUND; iOff=iOff*2){ rc = btLogReadHeader(pLog, iOff, &hdr1); } if( rc==SQLITE4_OK ){ pHdr = &hdr1; iSlot = 1; } } if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_OK; } /* If a header was successfully read from the file, scan the log file ** and populate the shared-memory hash tables. */ if( pHdr ){ u32 iCommit = 0; rc = btLogTraverse(pLog, pHdr, btLogRecoverFrame, (void*)&iCommit); if( rc==SQLITE4_OK && iCommit>0 ){ BtShm *pShm = btLogShm(pLog); pShm->ckpt.iFirstRead = 1; pShm->ckpt.iWalHdr = (iSlot<<2) + pHdr->iCnt; pShm->ckpt.iFirstRecover = 1; pLog->snapshot.aLog[4] = 1; pLog->snapshot.aLog[5] = iCommit; rc = btLogHashRollback(pLog, btLogFrameHash(pLog, iCommit), iCommit); } } return rc; |
︙ | ︙ | |||
548 549 550 551 552 553 554 555 556 557 558 559 560 561 | zWal = sqlite4BtPagerFilename(pPager, BT_PAGERFILE_LOG); rc = pVfs->xOpen(pEnv, pVfs, zWal, 0, &pLog->pFd); if( rc==SQLITE4_OK && bRecover ){ rc = btLogMapShm(pLog, 0); if( rc==SQLITE4_OK ){ btLogZeroSnapshot(pLog); rc = btLogRecover(pLog); } if( rc==SQLITE4_OK ){ rc = btLogUpdateSharedHdr(pLog); } } | > > > > | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | zWal = sqlite4BtPagerFilename(pPager, BT_PAGERFILE_LOG); rc = pVfs->xOpen(pEnv, pVfs, zWal, 0, &pLog->pFd); if( rc==SQLITE4_OK && bRecover ){ rc = btLogMapShm(pLog, 0); if( rc==SQLITE4_OK ){ BtShm *pShm = btLogShm(pLog); memset(pShm, 0, sizeof(BtShm)); pShm->ckpt.iFirstRead = 1; pShm->ckpt.iFirstRecover = 1; btLogZeroSnapshot(pLog); rc = btLogRecover(pLog); } if( rc==SQLITE4_OK ){ rc = btLogUpdateSharedHdr(pLog); } } |
︙ | ︙ | |||
647 648 649 650 651 652 653 654 655 656 657 | ** ** If any other error occurs, an SQLite4 error code is returned. The final ** state of buffer aData[] is undefined in this case. */ int sqlite4BtLogRead(BtLog *pLog, u32 pgno, u8 *aData){ const int pgsz = sqlite4BtPagerPagesize((BtPager*)(pLog->pLock)); int iHash; int rc = SQLITE4_NOTFOUND; u32 iFrame = 0; iHash = btLogFrameHash(pLog, pLog->snapshot.aLog[5]); | > > | | 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 | ** ** If any other error occurs, an SQLite4 error code is returned. The final ** state of buffer aData[] is undefined in this case. */ int sqlite4BtLogRead(BtLog *pLog, u32 pgno, u8 *aData){ const int pgsz = sqlite4BtPagerPagesize((BtPager*)(pLog->pLock)); int iHash; int iHashLast; int rc = SQLITE4_NOTFOUND; u32 iFrame = 0; iHash = btLogFrameHash(pLog, pLog->snapshot.aLog[5]); iHashLast = btLogFrameHash(pLog, pLog->snapshot.aLog[4]); for( ; rc==SQLITE4_NOTFOUND && iHash>=iHashLast && iFrame==0; iHash--){ rc = btLogHashSearch(pLog, iHash, pgno, &iFrame); } if( rc==SQLITE4_OK && iFrame!=0 ){ bt_env *pVfs = pLog->pLock->pVfs; i64 iOff; assert( rc==SQLITE4_OK ); |
︙ | ︙ | |||
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | rc = btLogSnapshot(pLog, &shmhdr); } if( rc==SQLITE4_OK && memcmp(&shmhdr, &pLog->snapshot, sizeof(BtShmHdr)) ){ sqlite4BtLockReaderUnlock(pLog->pLock); rc = SQLITE4_NOTFOUND; } } return rc; } int sqlite4BtLogSnapshotClose(BtLog *pLog){ sqlite4BtLockReaderUnlock(pLog->pLock); return SQLITE4_OK; } int sqlite4BtLogSnapshotWritable(BtLog *pLog){ return 1; } int sqlite4BtLogCheckpoint(BtLog *pLog){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 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 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | rc = btLogSnapshot(pLog, &shmhdr); } if( rc==SQLITE4_OK && memcmp(&shmhdr, &pLog->snapshot, sizeof(BtShmHdr)) ){ sqlite4BtLockReaderUnlock(pLog->pLock); rc = SQLITE4_NOTFOUND; } } if( rc==SQLITE4_OK ){ BtShm *pShm = btLogShm(pLog); u32 iCkpt = pShm->ckpt.iFirstRead; if( iCkpt>pLog->snapshot.aLog[4] ){ pLog->snapshot.aLog[4] = iCkpt; } } return rc; } int sqlite4BtLogSnapshotClose(BtLog *pLog){ sqlite4BtLockReaderUnlock(pLog->pLock); return SQLITE4_OK; } int sqlite4BtLogSnapshotWritable(BtLog *pLog){ return 1; } static void btLogMergeInplace( u32 *aLeft, int nLeft, /* Left hand input array */ u32 *aRight, int nRight, /* Right hand input array */ u32 *aSpace, /* Temporary space */ int *pnOut /* OUT: Size of aLeft[] after merge */ ){ int iLeft = 0; int iRight = 0; int iOut = 0; while( iLeft<nLeft || iRight<nRight ){ u32 v; if( iRight==nRight || (iLeft<nLeft && aLeft[iLeft]<aRight[iRight]) ){ assert( iLeft<nLeft ); v = aLeft[iLeft++]; }else{ assert( iRight<nRight ); v = aRight[iRight++]; } if( v && (iOut==0 || v!=aSpace[iOut-1]) ) aSpace[iOut++] = v; } memcpy(aLeft, aSpace, iOut*sizeof(u32)); memset(&aLeft[iOut], 0, ((nLeft+nRight)-iOut) * sizeof(u32)); *pnOut = iOut; } static void btLogMergeSort( u32 *aPgno, /* Array to sort */ int *pnPgno, /* IN/OUT: Number of entries in aPgno[] */ u32 *aSpace /* Temporary space */ ){ int nMerge; int nPgno = *pnPgno; for(nMerge=1; nMerge<nPgno; nMerge=nMerge*2){ int iLeft; for(iLeft=0; iLeft<nPgno; iLeft+=(nMerge*2)){ u32 *aLeft = &aPgno[iLeft]; int nLeft = MIN(nMerge, nPgno-iLeft); u32 *aRight = &aPgno[iLeft+nMerge]; int nRight = MIN(nMerge, nPgno-iLeft-nLeft); btLogMergeInplace(aLeft, nLeft, aRight, nRight, aSpace, pnPgno); } } } /* ** Parameters iFirst and iLast are frame numbers for frames that are part ** of the current log. This function scans the wal-index from iFirst to ** iLast (inclusive) and records the set of page numbers that occur once. ** This set is sorted in ascending order and returned via the output ** variables *paPgno and *pnPgno. ** */ static int btLogGatherPgno( BtLog *pLog, /* Log module handle */ u32 iFirst, /* First frame to gather pgnos from */ u32 iLast, /* Last frame to gather pgnos from */ u32 **paPgno, /* OUT: s4_malloc'd array of sorted pgno */ int *pnPgno /* OUT: Number of entries in *paPgno */ ){ u32 i; u32 *aPgno; /* Returned array */ u32 *aSpace; /* Temporary space used by merge-sort */ int nMax = (iLast - iFirst) + 1; int rc = SQLITE4_OK; /* Allocate space to collect all page numbers. */ aPgno = (u32*)sqlite4_malloc(pLog->pLock->pEnv, sizeof(u32)*nMax*2); if( aPgno==0 ) rc = btErrorBkpt(SQLITE4_NOMEM); aSpace = &aPgno[nMax]; /* Copy the required page numbers into the allocated array */ for(i=iFirst; rc==SQLITE4_OK && i<=iLast; i++){ u32 *aPage; ht_slot *aHash; u32 iZero; rc = btLogFindHash(pLog, btLogFrameHash(pLog, i), &aHash, &aPage, &iZero); if( rc==SQLITE4_OK ){ aPgno[i-iFirst] = aPage[i-iZero]; } } /* Sort the contents of the array in ascending order. This step also ** eliminates any duplicate page numbers. */ if( rc==SQLITE4_OK ){ btLogMergeSort(aPgno, &nMax, aSpace); *pnPgno = nMax; *paPgno = aPgno; }else{ sqlite4_free(pLog->pLock->pEnv, aPgno); *paPgno = 0; *pnPgno = 0; } return rc; } /* ** Return the number of frames in the log file according to the current ** snapshot. */ int sqlite4BtLogSize(BtLog *pLog){ return (int)pLog->snapshot.aLog[5] - (int)pLog->snapshot.aLog[4]; } int sqlite4BtLogCheckpoint(BtLog *pLog){ BtLock *pLock = pLog->pLock; int rc; /* Take the CHECKPOINTER lock. */ rc = sqlite4BtLockCkpt(pLock); if( rc==SQLITE4_OK ){ const int pgsz = sqlite4BtPagerPagesize((BtPager*)pLock); bt_env *pVfs = pLock->pVfs; bt_file *pFd = pLock->pFd; BtShm *pShm; /* Pointer to shared-memory region */ u32 iFirst; /* First frame to checkpoint */ u32 iLast; /* Last frame to checkpoint */ u32 *aPgno = 0; /* Array of page numbers to checkpoint */ int nPgno; /* Number of entries in aPgno[] */ int i; /* Used to loop through aPgno[] */ u8 *aBuf; /* Buffer to load page data into */ /* Allocate space to load log data into */ aBuf = sqlite4_malloc(pLock->pEnv, pgsz); if( aBuf==0 ) rc = btErrorBkpt(SQLITE4_NOMEM); /* Figure out the set of page numbers stored in the part of the log ** file being checkpointed. Remove any duplicates and sort them in ** ascending order. */ if( rc==SQLITE4_OK ){ pShm = btLogShm(pLog); iFirst = pShm->ckpt.iFirstRead; iLast = pLog->snapshot.aLog[5]; rc = btLogGatherPgno(pLog, iFirst, iLast, &aPgno, &nPgno); } /* Copy data from the log file to the database file. */ for(i=0; rc==SQLITE4_OK && i<nPgno; i++){ u32 pgno = aPgno[i]; rc = sqlite4BtLogRead(pLog, pgno, aBuf); if( rc==SQLITE4_OK ){ i64 iOff = (i64)pgsz * (pgno-1); rc = pVfs->xWrite(pFd, iOff, aBuf, pgsz); } } /* Update the first field of the checkpoint-header. This tells readers ** that they need not consider anything that in the log before this ** point (since the data has already been copied into the database ** file). */ if( rc==SQLITE4_OK ){ pShm->ckpt.iFirstRead = iLast+1; pVfs->xShmBarrier(pLog->pFd); } /* Write a new header into the log file. This tells any future recovery ** where it should start reading the log. Once this new header is synced ** to disk, the space cleared by this checkpoint operation can be ** reused. */ if( rc==SQLITE4_OK ){ int iSlot = ((pShm->ckpt.iWalHdr >> 2) + 1) % 2; i64 iOff; BtWalHdr hdr; BtFrameHdr fhdr; memset(&hdr, 0, sizeof(BtWalHdr)); hdr.iMagic = BT_WAL_MAGIC; hdr.iVersion = BT_WAL_VERSION; hdr.iCnt = (((pShm->ckpt.iWalHdr & 0x03) + 1) % 3); hdr.nSector = pLog->snapshot.nSector; hdr.nPgsz = pgsz; hdr.iFirstFrame = iLast+1; iOff = btLogFrameOffset(pLog, pgsz, iLast); rc = btLogReadData(pLog, iOff, (u8*)&fhdr, sizeof(BtFrameHdr)); if( rc==SQLITE4_OK ){ hdr.iSalt1 = fhdr.aCksum[0]; hdr.iSalt2 = fhdr.aCksum[1]; rc = btLogWriteHeader(pLog, iSlot, &hdr); } if( rc==SQLITE4_OK ){ pShm->ckpt.iWalHdr = (iSlot<<2) + hdr.iCnt; } } /* Update the second field of the checkpoint header. This tells future ** writers that it is now safe to recycle pages before this point ** (assuming all live readers are cleared). */ if( rc==SQLITE4_OK ){ pShm->ckpt.iFirstRecover = iLast+1; pVfs->xShmBarrier(pLog->pFd); } /* Free the buffer and drop the checkpointer lock */ sqlite4_free(pLock->pEnv, aBuf); sqlite4BtLockCkptUnlock(pLog->pLock); } return rc; } |
Changes to src/bt_main.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | /* ** Values that make up the single byte flags field at the start of ** b-tree pages. */ #define BT_PGFLAGS_INTERNAL 0x01 /* True for non-leaf nodes */ | < < < < < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /* ** Values that make up the single byte flags field at the start of ** b-tree pages. */ #define BT_PGFLAGS_INTERNAL 0x01 /* True for non-leaf nodes */ /* #define BT_STDERR_DEBUG 1 */ struct bt_db { sqlite4_env *pEnv; /* SQLite environment */ BtPager *pPager; /* Underlying page-based database */ bt_cursor *pAllCsr; /* List of all open cursors */ }; |
︙ | ︙ |
Changes to src/bt_pager.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <string.h> #include <assert.h> #include <stdio.h> /* By default pages are 1024 bytes in size. */ #define BT_DEFAULT_PGSZ 1024 typedef struct BtPageHash BtPageHash; typedef struct BtDbhdr BtDbhdr; /* ** Hash table for page references currently in memory. Manipulated using ** the following functions: | > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <string.h> #include <assert.h> #include <stdio.h> /* By default pages are 1024 bytes in size. */ #define BT_DEFAULT_PGSZ 1024 /* By default auto-checkpoint is 1000 */ #define BT_DEFAULT_AUTOCKPT 1000 typedef struct BtPageHash BtPageHash; typedef struct BtDbhdr BtDbhdr; /* ** Hash table for page references currently in memory. Manipulated using ** the following functions: |
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | u32 pgsz; /* Page size in bytes */ u32 nPg; /* Number of pages in database */ u32 cookie; /* User cookie value (SQL schema cookie) */ }; /* ** Pager object. */ struct BtPager { BtLock btl; /* Variables shared with bt_lock module */ BtLog *pLog; /* Logging module */ int iTransactionLevel; /* Current transaction level (see bt.h) */ char *zFile; /* Database file name */ int nFile; /* Length of string zFile in bytes */ BtPageHash hash; /* Hash table */ BtPage *pDirty; /* List of all dirty pages */ BtDbhdr dbhdr; | > > > > > > > < | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | u32 pgsz; /* Page size in bytes */ u32 nPg; /* Number of pages in database */ u32 cookie; /* User cookie value (SQL schema cookie) */ }; /* ** Pager object. ** ** nAutoCkpt: ** If a transaction is committed and there are this many frames in the ** log file, automatically run a checkpoint operation. */ struct BtPager { BtLock btl; /* Variables shared with bt_lock module */ BtLog *pLog; /* Logging module */ int iTransactionLevel; /* Current transaction level (see bt.h) */ char *zFile; /* Database file name */ int nFile; /* Length of string zFile in bytes */ BtPageHash hash; /* Hash table */ BtPage *pDirty; /* List of all dirty pages */ int nTotalRef; /* Total number of outstanding page refs */ int nAutoCkpt; /* Auto-checkpoint when log is this large */ int bDoAutoCkpt; /* Do auto-checkpoint after next unlock */ BtDbhdr dbhdr; }; /************************************************************************** ** Interface to BtPageHash object. */ |
︙ | ︙ | |||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 | nByte = sizeof(BtPager) + nExtra; p = (BtPager*)sqlite4_malloc(pEnv, nByte); if( !p ) return btErrorBkpt(SQLITE4_NOMEM); memset(p, 0, nByte); p->btl.pEnv = pEnv; p->btl.pVfs = sqlite4BtEnvDefault(); *pp = p; return SQLITE4_OK; } static void btFreePage(BtPager *p, BtPage *pPg){ if( pPg ){ sqlite4_free(p->btl.pEnv, pPg->aData); | > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | nByte = sizeof(BtPager) + nExtra; p = (BtPager*)sqlite4_malloc(pEnv, nByte); if( !p ) return btErrorBkpt(SQLITE4_NOMEM); memset(p, 0, nByte); p->btl.pEnv = pEnv; p->btl.pVfs = sqlite4BtEnvDefault(); p->nAutoCkpt = BT_DEFAULT_AUTOCKPT; *pp = p; return SQLITE4_OK; } static void btFreePage(BtPager *p, BtPage *pPg){ if( pPg ){ sqlite4_free(p->btl.pEnv, pPg->aData); |
︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 357 358 359 360 | assert( p->iTransactionLevel==0 ); rc = sqlite4BtLogSnapshotClose(p->pLog); /* Purge the page cache. */ assert( p->pDirty==0 ); btPurgeCache(p); return rc; } /* ** Commit the current write transaction to disk. */ static int btCommitTransaction(BtPager *p){ | > > > > > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | assert( p->iTransactionLevel==0 ); rc = sqlite4BtLogSnapshotClose(p->pLog); /* Purge the page cache. */ assert( p->pDirty==0 ); btPurgeCache(p); if( rc==SQLITE4_OK && p->bDoAutoCkpt ){ sqlite4BtLogCheckpoint(p->pLog); } p->bDoAutoCkpt = 0; return rc; } /* ** Commit the current write transaction to disk. */ static int btCommitTransaction(BtPager *p){ |
︙ | ︙ | |||
373 374 375 376 377 378 379 380 381 382 383 384 385 386 | } } p->pDirty = 0; if( rc==SQLITE4_OK ){ rc = p->btl.pVfs->xWrite(p->btl.pFd, 0, (void*)&p->dbhdr, sizeof(BtDbhdr)); } return rc; } static int btLoadPageData(BtPager *p, BtPage *pPg){ int rc; /* Return code */ | > > > > | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | } } p->pDirty = 0; if( rc==SQLITE4_OK ){ rc = p->btl.pVfs->xWrite(p->btl.pFd, 0, (void*)&p->dbhdr, sizeof(BtDbhdr)); } if( p->nAutoCkpt && sqlite4BtLogSize(p->pLog)>=p->nAutoCkpt ){ p->bDoAutoCkpt = 1; } return rc; } static int btLoadPageData(BtPager *p, BtPage *pPg){ int rc; /* Return code */ |
︙ | ︙ | |||
531 532 533 534 535 536 537 | return p->iTransactionLevel; } /* ** Query for the database page size. Requires an open read transaction. */ int sqlite4BtPagerPagesize(BtPager *p){ | | < | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | return p->iTransactionLevel; } /* ** Query for the database page size. Requires an open read transaction. */ int sqlite4BtPagerPagesize(BtPager *p){ /* assert( p->iTransactionLevel>=1 && p->btl.pFd ); */ return (int)p->dbhdr.pgsz; } /* ** Query for the root page number. Requires an open read transaction. */ u32 sqlite4BtPagerRootpgno(BtPager *p){ assert( p->iTransactionLevel>=1 && p->btl.pFd ); return 2; |
︙ | ︙ |
Changes to src/bt_unix.c.
︙ | ︙ | |||
250 251 252 253 254 255 256 | } sqlite4_free(pSqlEnv, zCwd); *pzOut = zOut; return rc; } | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | } sqlite4_free(pSqlEnv, zCwd); *pzOut = zOut; return rc; } static int btPosixOsUnlink(sqlite4_env *pEnv, bt_env *pVfs, const char *zFile){ int prc = unlink(zFile); return prc ? btErrorBkpt(SQLITE4_IOERR) : SQLITE4_OK; } int btPosixOsLock(bt_file *pFile, int iLock, int eType){ int rc = SQLITE4_OK; PosixFile *p = (PosixFile *)pFile; |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
385 386 387 388 389 390 391 | # Delete all files associated with LSM database $file. That is: # # ${file} # ${file}-log # ${file}-shm # proc db_delete {file} { | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | # Delete all files associated with LSM database $file. That is: # # ${file} # ${file}-log # ${file}-shm # proc db_delete {file} { forcedelete $file $file-shm $file-log $file-wal } # Create a test database # proc reset_db {} { catch {db close} db_delete test.db |
︙ | ︙ |