Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Combine the bt database and shm headers. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1512aee6f68f507882b8a2a35722d636 |
User & Date: | dan 2013-11-20 19:23:35.619 |
Context
2013-11-21
| ||
18:46 | Add code to free pages and blocks. check-in: 1a0d07f113 user: dan tags: trunk | |
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 | |
Changes
Changes to src/btInt.h.
︙ | ︙ | |||
35 36 37 38 39 40 41 | #ifndef MAX # define MAX(a,b) (((a)>(b))?(a):(b)) #endif /* By default pages are 1024 bytes in size. */ #define BT_DEFAULT_PGSZ 1024 | < < < < < < < < < < < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #ifndef MAX # define MAX(a,b) (((a)>(b))?(a):(b)) #endif /* By default pages are 1024 bytes in size. */ #define BT_DEFAULT_PGSZ 1024 /************************************************************************* ** Interface to bt_pager.c functionality. */ typedef struct BtPage BtPage; typedef struct BtPager BtPager; /* |
︙ | ︙ |
Changes to src/bt_log.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | #define BT_WAL_MAGIC 0xBEE1CA62 #define BT_WAL_VERSION 0x00000001 /* Wrap the log around if there is a block of this many free frames at ** the start of the file. */ #define BT_NWRAPLOG 100 | | > | | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #define BT_WAL_MAGIC 0xBEE1CA62 #define BT_WAL_VERSION 0x00000001 /* Wrap the log around if there is a block of this many free frames at ** the start of the file. */ #define BT_NWRAPLOG 100 typedef struct BtCkptHdr BtCkptHdr; typedef struct BtDbHdrCksum BtDbHdrCksum; typedef struct BtFrameHdr BtFrameHdr; typedef struct BtShm BtShm; typedef struct BtShmHdr BtShmHdr; typedef struct BtWalHdr BtWalHdr; /* ** WAL file header. All u32 fields are stored in big-endian order on ** disk. A single WAL file may contain two of these headers - one at ** byte offset 0 and the other at offset <sector-size> (the start of ** the second disk sector in the file, according to the xSectorSize ** VFS method). |
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | u32 pgno; /* Page number of this frame */ u32 iNext; /* Next frame pointer */ u32 nPg; /* For commit frames, size of db file */ u32 aCksum[2]; /* Frame checksum */ }; #define BT_FRAME_COMMIT 0x80000000 /* ** Shared memory header. Shared memory begins with two copies of ** this structure. All fields are stored in machine byte-order. */ struct BtShmHdr { u32 aLog[6]; /* First/last frames for each log region */ int nSector; /* Sector size assumed for WAL file */ int iHashSide; /* Hash table side for region (c) of log */ u32 aFrameCksum[2]; /* Checksum of previous frame */ u32 iNextFrame; /* Location to write next log frame to */ | > > > > > > > > > | < < < < > | 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 101 102 103 104 105 106 107 108 109 110 | u32 pgno; /* Page number of this frame */ u32 iNext; /* Next frame pointer */ u32 nPg; /* For commit frames, size of db file */ u32 aCksum[2]; /* Frame checksum */ }; #define BT_FRAME_COMMIT 0x80000000 /* ** A database header with checksum fields. */ struct BtDbHdrCksum { BtDbHdr hdr; u32 aCksum[2]; }; /* ** Shared memory header. Shared memory begins with two copies of ** this structure. All fields are stored in machine byte-order. */ struct BtShmHdr { u32 aLog[6]; /* First/last frames for each log region */ int nSector; /* Sector size assumed for WAL file */ int iHashSide; /* Hash table side for region (c) of log */ u32 aFrameCksum[2]; /* Checksum of previous frame */ u32 iNextFrame; /* Location to write next log frame to */ BtDbHdr dbhdr; /* Cached db-header values */ u32 padding; u32 aCksum[2]; /* Object checksum */ }; /* ** A single instance of this structure follows the two BtShmHdr structures ** in shared memory. ** |
︙ | ︙ | |||
288 289 290 291 292 293 294 | assert( aLog[2]==0 || pHdr->iNextFrame<aLog[2] || pHdr->iNextFrame>aLog[3] ); assert( aLog[4]==0 || pHdr->iNextFrame<aLog[4] || pHdr->iNextFrame>aLog[5] ); } #else #define btDebugCheckSnapshot(x) #endif | < < < < < < < | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | assert( aLog[2]==0 || pHdr->iNextFrame<aLog[2] || pHdr->iNextFrame>aLog[3] ); assert( aLog[4]==0 || pHdr->iNextFrame<aLog[4] || pHdr->iNextFrame>aLog[5] ); } #else #define btDebugCheckSnapshot(x) #endif #ifndef NDEBUG static void btDebugLogSafepoint(BtLock *pLock, u32 iSafe){ #if BT_PAGE_DEBUG static int nCall = 0; fprintf(stderr, "%d:%d: checkpoint safepoint=%d\n", pLock->iDebugId, nCall++, (int)iSafe ); |
︙ | ︙ | |||
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | fflush(stderr); #endif } #endif #ifndef NDEBUG #include <ctype.h> static void binToStr(u8 *pIn, int nIn, u8 *pOut, int nOut){ int i; int nCopy = MIN(nIn, (nOut-1)); for(i=0; i<nCopy; i++){ if( isprint(pIn[i]) ){ pOut[i] = pIn[i]; }else{ pOut[i] = '.'; } } pOut[i] = '\0'; } void sqlite4BtDebugKV( BtLock *pLock, const char *zStr, u8 *pK, int nK, u8 *pV, int nV ){ #if BT_VAL_DEBUG u8 aKBuf[40]; u8 aVBuf[40]; static int nCall = 0; | > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | fflush(stderr); #endif } #endif #ifndef NDEBUG #include <ctype.h> #if BT_VAL_DEBUG static void binToStr(u8 *pIn, int nIn, u8 *pOut, int nOut){ int i; int nCopy = MIN(nIn, (nOut-1)); for(i=0; i<nCopy; i++){ if( isprint(pIn[i]) ){ pOut[i] = pIn[i]; }else{ pOut[i] = '.'; } } pOut[i] = '\0'; } #endif void sqlite4BtDebugKV( BtLock *pLock, const char *zStr, u8 *pK, int nK, u8 *pV, int nV ){ #if BT_VAL_DEBUG u8 aKBuf[40]; u8 aVBuf[40]; static int nCall = 0; |
︙ | ︙ | |||
755 756 757 758 759 760 761 | btLogHashInsert(pLog, pHdr->pgno, iFrame); if( pHdr->nPg!=0 ){ FrameRecoverCtx *pFRC = (FrameRecoverCtx*)pCtx; pFRC->iLast = iFrame; pFRC->iNextFrame = pHdr->iNext; memcpy(pLog->snapshot.aFrameCksum, pHdr->aCksum, sizeof(pHdr->aCksum)); | | | 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | btLogHashInsert(pLog, pHdr->pgno, iFrame); if( pHdr->nPg!=0 ){ FrameRecoverCtx *pFRC = (FrameRecoverCtx*)pCtx; pFRC->iLast = iFrame; pFRC->iNextFrame = pHdr->iNext; memcpy(pLog->snapshot.aFrameCksum, pHdr->aCksum, sizeof(pHdr->aCksum)); pLog->snapshot.dbhdr.nPg = pHdr->nPg; } #if 0 fprintf(stderr, "recovered frame=%d pgno=%d\n", iFrame, pHdr->pgno); fflush(stderr); #endif return 0; |
︙ | ︙ | |||
800 801 802 803 804 805 806 | } } aLog[5] = iLast; return btLogHashRollback(pLog, btLogFrameHash(pLog, iLast), iLast); } | | > > | | | > > | > > | < | | < | | > | | 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 | } } aLog[5] = iLast; return btLogHashRollback(pLog, btLogFrameHash(pLog, iLast), iLast); } static int btLogReadDbhdr(BtLog *pLog, BtDbHdr *pHdr){ BtLock *p = pLog->pLock; int rc; /* Return code */ i64 nByte; /* Size of database file in byte */ rc = p->pVfs->xSize(p->pFd, &nByte); if( rc==SQLITE4_OK && nByte>0 ){ BtDbHdrCksum hdr; rc = p->pVfs->xRead(p->pFd, 0, &hdr, sizeof(BtDbHdrCksum)); if( rc==SQLITE4_OK ){ u32 aCksum[2]; btLogChecksum(1, (u8*)&hdr, offsetof(BtDbHdrCksum, aCksum), 0, aCksum); if( aCksum[0]==hdr.aCksum[0] && aCksum[1]==hdr.aCksum[1] ){ memcpy(pHdr, &hdr, sizeof(BtDbHdr)); return SQLITE4_OK; } } } memset(pHdr, 0, sizeof(BtDbHdr)); pHdr->pgsz = BT_DEFAULT_PGSZ; pHdr->nPg = 1; pHdr->iRoot = 2; return rc; } static int btLogUpdateDbhdr(BtLog *pLog, u8 *aData){ BtDbHdrCksum hdr; memcpy(&hdr.hdr, &pLog->snapshot.dbhdr, sizeof(BtDbHdr)); btLogChecksum(1, (u8*)&hdr, offsetof(BtDbHdrCksum, aCksum), 0, hdr.aCksum); assert( hdr.hdr.iRoot=2 ); assert( hdr.hdr.pgsz>0 ); memcpy(aData, &hdr, sizeof(BtDbHdrCksum)); return SQLITE4_OK; } /* ** Run log recovery. In other words, read the log file from disk and |
︙ | ︙ | |||
900 901 902 903 904 905 906 | /* One or more transactions were recovered from the log file. */ BtShm *pShm = btLogShm(pLog); pShm->ckpt.iWalHdr = (iSlot<<2) + pHdr->iCnt; pShm->ckpt.iFirstRead = pHdr->iFirstFrame; pShm->ckpt.iFirstRecover = pHdr->iFirstFrame; rc = btLogRollbackRecovery(pLog, &ctx); pLog->snapshot.iNextFrame = ctx.iNextFrame; | | < | < < < | 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 | /* One or more transactions were recovered from the log file. */ BtShm *pShm = btLogShm(pLog); pShm->ckpt.iWalHdr = (iSlot<<2) + pHdr->iCnt; pShm->ckpt.iFirstRead = pHdr->iFirstFrame; pShm->ckpt.iFirstRecover = pHdr->iFirstFrame; rc = btLogRollbackRecovery(pLog, &ctx); pLog->snapshot.iNextFrame = ctx.iNextFrame; pLog->snapshot.dbhdr.pgsz = pHdr->nPgsz; assert( pShm->ckpt.iFirstRead>0 ); } } if( rc==SQLITE4_OK && ctx.iLast==0 ){ /* No transactions were recovered from the log file. */ btLogZeroSnapshot(pLog); /* Read the database file header to obtail values required ** by the snapshot. */ rc = btLogReadDbhdr(pLog, &pLog->snapshot.dbhdr); } if( rc==SQLITE4_OK ){ btDebugTopology( pLog->pLock, "recovered", pLog->snapshot.iHashSide, pLog->snapshot.aLog ); } |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | /* Update the wal index hash tables with the (pgno -> iFrame) record. ** If this is a commit frame, update the nPg field as well. */ if( rc==SQLITE4_OK ){ if( iFrame==1 ){ pLog->snapshot.iHashSide = (pLog->snapshot.iHashSide+1) % 2; } | | | 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | /* Update the wal index hash tables with the (pgno -> iFrame) record. ** If this is a commit frame, update the nPg field as well. */ if( rc==SQLITE4_OK ){ if( iFrame==1 ){ pLog->snapshot.iHashSide = (pLog->snapshot.iHashSide+1) % 2; } if( nPg ) pLog->snapshot.dbhdr.nPg = nPg; rc = btLogHashInsert(pLog, pgno, iFrame); } /* Update the private copy of the shm-header */ btDebugCheckSnapshot(&pLog->snapshot); BtShmHdr hdr; |
︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 | } /* If this is a commit frame and the size of the database has changed, ** ensure that the log file contains at least one copy of page 1 written ** since the last checkpoint. This is required as a future checkpoint ** will need to update the nPg field in the database header located on ** page 1. */ | | | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 | } /* If this is a commit frame and the size of the database has changed, ** ensure that the log file contains at least one copy of page 1 written ** since the last checkpoint. This is required as a future checkpoint ** will need to update the nPg field in the database header located on ** page 1. */ if( nPg && nPg!=pLog->snapshot.dbhdr.nPg ){ BtPager *pPager = (BtPager *)(pLog->pLock); BtPage *pOne = 0; rc = sqlite4BtPageGet(pPager, 1, &pOne); if( rc==SQLITE4_OK ){ rc = sqlite4BtLogWrite(pLog, 1, sqlite4BtPageData(pOne), 0); sqlite4BtPageRelease(pOne); } |
︙ | ︙ | |||
1732 1733 1734 1735 1736 1737 1738 | 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 */ u32 iFirstRead; /* First frame not checkpointed */ rc = btLogSnapshot(pLog, &pLog->snapshot); | | | 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 | 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 */ u32 iFirstRead; /* First frame not checkpointed */ rc = btLogSnapshot(pLog, &pLog->snapshot); pgsz = pLog->snapshot.dbhdr.pgsz; if( rc==SQLITE4_OK ){ /* Allocate space to load log data into */ aBuf = sqlite4_malloc(pLock->pEnv, pgsz); if( aBuf==0 ) rc = btErrorBkpt(SQLITE4_NOMEM); } |
︙ | ︙ | |||
1838 1839 1840 1841 1842 1843 1844 | return rc; } /* ** Return the database page size in bytes. */ int sqlite4BtLogPagesize(BtLog *pLog){ | | | | | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 | return rc; } /* ** Return the database page size in bytes. */ int sqlite4BtLogPagesize(BtLog *pLog){ return pLog->snapshot.dbhdr.pgsz; } /* ** Return the number of pages in the database at last commit. */ int sqlite4BtLogPagecount(BtLog *pLog){ return (pLog->snapshot.dbhdr.nPg==1 ? 2 : pLog->snapshot.dbhdr.nPg); } /* ** Return the current value of the user cookie. */ u32 sqlite4BtLogCookie(BtLog *pLog){ return pLog->snapshot.dbhdr.iCookie; } /* ** Set the value of the user cookie. */ int sqlite4BtLogSetCookie(BtLog *pLog, u32 iCookie){ BtPager *pPager = (BtPager *)(pLog->pLock); BtPage *pOne = 0; int rc; rc = sqlite4BtPageGet(pPager, 1, &pOne); if( rc==SQLITE4_OK ){ rc = sqlite4BtPageWrite(pOne); } if( rc==SQLITE4_OK ){ pLog->snapshot.dbhdr.iCookie = iCookie; btLogUpdateDbhdr(pLog, sqlite4BtPageData(pOne)); } sqlite4BtPageRelease(pOne); return rc; } |