diff --git a/manifest b/manifest index f8e4eb3aaf..413de553c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fix\s#3077:\suse\sfull\sversion\sin\spkg-config\sfiles\s(CVS\s5746) -D 2008-09-29T00:11:22 +C Instead\sof\sstoring\sa\spointer\sto\sthe\sparent\spage\sin\sthe\sMemPage\sstructure,\shave\seach\sB-Tree\scursor\skeep\strack\sof\sthe\sancestry\sof\sthe\scurrent\spage.\s(CVS\s5747) +D 2008-09-29T11:49:48 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in e4ab842f9a64ef61d57093539a8aab76b12810db F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -99,9 +99,9 @@ F src/attach.c db3f4a60538733c1e4dcb9d0217a6e0d6ccd615b F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53 -F src/btree.c 850d7ede7fe58f8bfad78131278ceff83817abf5 +F src/btree.c 8fc7c0bd577e0e8850d95b0f8d927c983e53deab F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107 -F src/btreeInt.h e36f77e6621d671beb19ae581af1eba116cdfdc4 +F src/btreeInt.h a9388a5e5998cec0b79c2024e6740d12d094ad17 F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe F src/callback.c 7a40fd44da3eb89e7f6eff30aa6f940c45d73a97 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c @@ -137,11 +137,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60 F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0 F src/os_unix.c f33b69d8a85372b270fe37ee664a4c2140a5217d F src/os_win.c 3209dc0ed734291764393ea8d534ba0d8696a540 -F src/pager.c 6426902ba983ce6872fcec20ba72796a79d6cead -F src/pager.h 30e71f447ecbcfef707bb72cc813ce37ab5a2bc9 +F src/pager.c 44eba010e81dcc9b772401b90d6a1c61ec24345b +F src/pager.h 9c1917be28fff58118e1fe0ddbc7adfb8dd4f44d F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8 -F src/pcache.c 52108517c38bcf023f3977085a66aacb520a5385 -F src/pcache.h 0b6871e820159629915e8688b5c67a81a203773f +F src/pcache.c f8d7beceba164a34441ac37e88abb3a404f968a7 +F src/pcache.h 28d9ce2d66909db1f01652586450b62b64793093 F src/pragma.c 0b1c2d2a241dd79a7361bbeb8ff575a9e9d7cd71 F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d @@ -157,7 +157,7 @@ F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 F src/tclsqlite.c 6a7eeff5afd8f5f10fcb7fd7806e56c725dd2b07 F src/test1.c c4de690aad182606e5914f6f3c8f43869fbdaaa8 -F src/test2.c eaa77124786649eedf47d3c5e94d8070c0da228f +F src/test2.c 897528183edf2839c2a3c991d415905db56f1240 F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406 F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288 @@ -167,7 +167,7 @@ F src/test8.c 3637439424d0d21ff2dcf9b015c30fcc1e7bcb24 F src/test9.c 904ebe0ed1472d6bad17a81e2ecbfc20017dc237 F src/test_async.c 45024094ed7cf780c5d5dccda645145f95cf78ef F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad -F src/test_btree.c 8d5b835054f1dd15992e09864a8bc04386bab701 +F src/test_btree.c d7b8716544611c323860370ee364e897c861f1b0 F src/test_config.c db72e95bafdd53c05ceb8735f833cc5dc1f48782 F src/test_devsym.c 802d10e65b4217208cb47059b84adf46318bcdf4 F src/test_func.c a55c4d5479ff2eb5c0a22d4d88e9528ab59c953b @@ -253,7 +253,7 @@ F test/colmeta.test 087c42997754b8c648819832241daf724f813322 F test/colname.test 0f05fea3e5c9260ece53117ad400657515c34280 F test/conflict.test bb29b052c60a1f7eb6382be77902061d1f305318 F test/corrupt.test 5bcf7a986358123b8055dfa64b45fc2fb54dcaa9 -F test/corrupt2.test 08fb049fdf4f72902ff39b1c609e7c1c2e985d8b +F test/corrupt2.test b83f690753525ddac4a9c96e6ba11886ddaf24ea F test/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32 F test/corrupt4.test acdb01afaedf529004b70e55de1a6f5a05ae7fff F test/corrupt5.test 7796d5bdfe155ed824cee9dff371f49da237cfe0 @@ -637,7 +637,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 7c561f2e9264de676c1028943f6c3d06542fd802 -R 02a6492d8d58a0069722b4e87a758448 -U vapier -Z f2828935781c5b8b7b8d7e5f72f7da88 +P efe095e0cb8e0f8a11fd9cc321ec83b556458bf2 +R a0f3c37847099f2dcfb6efb98a6a77ac +U danielk1977 +Z 079550270237333fc6211bd885a42871 diff --git a/manifest.uuid b/manifest.uuid index 2f2779978f..b57fb3d6a6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -efe095e0cb8e0f8a11fd9cc321ec83b556458bf2 \ No newline at end of file +40425e93421286cca1965d7a5769084526210c7a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9e105326b7..2b0b386db4 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.517 2008/09/26 17:31:55 danielk1977 Exp $ +** $Id: btree.c,v 1.518 2008/09/29 11:49:48 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -301,7 +301,7 @@ static int saveCursorPosition(BtCursor *pCur){ ** table, then malloc space for and store the pCur->nKey bytes of key ** data. */ - if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ + if( rc==SQLITE_OK && 0==pCur->apPage[0]->intKey){ void *pKey = sqlite3Malloc(pCur->nKey); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); @@ -314,11 +314,15 @@ static int saveCursorPosition(BtCursor *pCur){ rc = SQLITE_NOMEM; } } - assert( !pCur->pPage->intKey || !pCur->pKey ); + assert( !pCur->apPage[0]->intKey || !pCur->pKey ); if( rc==SQLITE_OK ){ - releasePage(pCur->pPage); - pCur->pPage = 0; + int i; + for(i=0; i<=pCur->iPage; i++){ + releasePage(pCur->apPage[i]); + pCur->apPage[i] = 0; + } + pCur->iPage = -1; pCur->eState = CURSOR_REQUIRESEEK; } @@ -908,50 +912,32 @@ static int decodeFlags(MemPage *pPage, int flagByte){ /* ** Initialize the auxiliary information for a disk block. ** -** The pParent parameter must be a pointer to the MemPage which -** is the parent of the page being initialized. The root of a -** BTree has no parent and so for that page, pParent==NULL. -** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ -int sqlite3BtreeInitPage( - MemPage *pPage, /* The page to be initialized */ - MemPage *pParent /* The parent. Might be NULL */ -){ - int pc; /* Address of a freeblock within pPage->aData[] */ - int hdr; /* Offset to beginning of page header */ - u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ - int usableSize; /* Amount of usable space on each page */ - int cellOffset; /* Offset from start of page to first cell pointer */ - int nFree; /* Number of unused bytes on the page */ - int top; /* First byte of the cell content area */ +int sqlite3BtreeInitPage(MemPage *pPage){ - pBt = pPage->pBt; - assert( pBt!=0 ); - assert( pParent==0 || pParent->pBt==pBt ); - assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pPage->pBt!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); - if( pPage==pParent ){ - return SQLITE_CORRUPT_BKPT; - } - if( (pPage->pParent!=pParent) - && (pPage->pParent!=0 || pPage->isInit==PAGE_ISINIT_FULL) ){ - /* The parent page should never change unless the file is corrupt */ - return SQLITE_CORRUPT_BKPT; - } - if( pPage->isInit==PAGE_ISINIT_FULL ) return SQLITE_OK; - if( pParent!=0 ){ - pPage->pParent = pParent; - sqlite3PagerRef(pParent->pDbPage); - } - if( pPage->isInit==PAGE_ISINIT_NONE ){ + + if( !pPage->isInit ){ + int pc; /* Address of a freeblock within pPage->aData[] */ + int hdr; /* Offset to beginning of page header */ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + int usableSize; /* Amount of usable space on each page */ + int cellOffset; /* Offset from start of page to first cell pointer */ + int nFree; /* Number of unused bytes on the page */ + int top; /* First byte of the cell content area */ + + pBt = pPage->pBt; + hdr = pPage->hdrOffset; data = pPage->aData; if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; @@ -967,10 +953,6 @@ int sqlite3BtreeInitPage( /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; } - if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){ - /* All pages must have at least one cell, except for root pages */ - return SQLITE_CORRUPT_BKPT; - } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); @@ -995,7 +977,6 @@ int sqlite3BtreeInitPage( /* Free space cannot exceed total page size */ return SQLITE_CORRUPT_BKPT; } - } #if 0 /* Check that all the offsets in the cell offset array are within range. @@ -1017,7 +998,8 @@ int sqlite3BtreeInitPage( } #endif - pPage->isInit = PAGE_ISINIT_FULL; + pPage->isInit = 1; + } return SQLITE_OK; } @@ -1051,7 +1033,7 @@ static void zeroPage(MemPage *pPage, int flags){ pPage->maskPage = pBt->pageSize - 1; pPage->idxShift = 0; pPage->nCell = 0; - pPage->isInit = PAGE_ISINIT_FULL; + pPage->isInit = 1; } @@ -1115,15 +1097,13 @@ static int pagerPagecount(Pager *pPager){ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ - MemPage **ppPage, /* Write the page pointer here */ - MemPage *pParent /* Parent of the page */ + MemPage **ppPage /* Write the page pointer here */ ){ int rc; DbPage *pDbPage; MemPage *pPage; assert( sqlite3_mutex_held(pBt->mutex) ); - assert( !pParent || pParent->isInit==PAGE_ISINIT_FULL ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } @@ -1147,14 +1127,8 @@ static int getAndInitPage( if( rc ) return rc; pPage = *ppPage; } - if( pPage->isInit!=PAGE_ISINIT_FULL ){ - rc = sqlite3BtreeInitPage(pPage, pParent); - }else if( pParent && (pPage==pParent || pPage->pParent!=pParent) ){ - /* This condition indicates a loop in the b-tree structure (the scenario - ** where database corruption has caused a page to be a direct or - ** indirect descendant of itself). - */ - rc = SQLITE_CORRUPT_BKPT; + if( !pPage->isInit ){ + rc = sqlite3BtreeInitPage(pPage); } if( rc!=SQLITE_OK ){ releasePage(pPage); @@ -1178,30 +1152,6 @@ static void releasePage(MemPage *pPage){ } } -/* -** This routine is called when the reference count for a page -** reaches zero. We need to unref the pParent pointer when that -** happens. -*/ -static void pageDestructor(DbPage *pData){ - MemPage *pPage; - pPage = (MemPage *)sqlite3PagerGetExtra(pData); - if( pPage ){ - assert( pPage->isInit!=PAGE_ISINIT_FULL - || sqlite3_mutex_held(pPage->pBt->mutex) - ); - if( pPage->pParent ){ - MemPage *pParent = pPage->pParent; - assert( pParent->pBt==pPage->pBt ); - pPage->pParent = 0; - releasePage(pParent); - } - if( pPage->isInit==PAGE_ISINIT_FULL ){ - pPage->isInit = PAGE_ISINIT_DATA; - } - } -} - /* ** During a rollback, when the pager reloads information into the cache ** so that the cache is restored to its original state at the start of @@ -1213,12 +1163,12 @@ static void pageDestructor(DbPage *pData){ static void pageReinit(DbPage *pData){ MemPage *pPage; pPage = (MemPage *)sqlite3PagerGetExtra(pData); - if( pPage->isInit==PAGE_ISINIT_FULL ){ + if( pPage->isInit ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; - sqlite3BtreeInitPage(pPage, pPage->pParent); - }else if( pPage->isInit==PAGE_ISINIT_DATA ){ - pPage->isInit = 0; + if( sqlite3PagerPageRefcount(pData)>0 ){ + sqlite3BtreeInitPage(pPage); + } } } @@ -1344,7 +1294,7 @@ int sqlite3BtreeOpen( } pBt->busyHdr.xFunc = sqlite3BtreeInvokeBusyHandler; pBt->busyHdr.pArg = pBt; - rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, pageDestructor, + rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, EXTRA_SIZE, flags, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); @@ -2092,7 +2042,7 @@ static int setChildPtrmaps(MemPage *pPage){ Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - rc = sqlite3BtreeInitPage(pPage, pPage->pParent); + rc = sqlite3BtreeInitPage(pPage); if( rc!=SQLITE_OK ){ goto set_child_ptrmaps_out; } @@ -2151,7 +2101,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ int i; int nCell; - sqlite3BtreeInitPage(pPage, 0); + sqlite3BtreeInitPage(pPage); nCell = pPage->nCell; for(i=0; ipgnoRoot, &pCur->pPage, 0); + rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); if( rc!=SQLITE_OK ){ goto create_cursor_exception; } @@ -2869,7 +2822,7 @@ static int btreeCursor( return SQLITE_OK; create_cursor_exception: - releasePage(pCur->pPage); + releasePage(pCur->apPage[0]); unlockBtreeIfUnused(pBt); return rc; } @@ -2900,6 +2853,7 @@ int sqlite3BtreeCursorSize(){ int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ + int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); pBt->db = pBtree->db; @@ -2912,7 +2866,9 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ if( pCur->pNext ){ pCur->pNext->pPrev = pCur->pPrev; } - releasePage(pCur->pPage); + for(i=0; i<=pCur->iPage; i++){ + releasePage(pCur->apPage[i]); + } unlockBtreeIfUnused(pBt); invalidateOverflowCache(pCur); /* sqlite3_free(pCur); */ @@ -2926,12 +2882,13 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** The temporary cursor is not on the cursor list for the Btree. */ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ + int i; assert( cursorHoldsMutex(pCur) ); - memcpy(pTempCur, pCur, sizeof(*pCur)); + memcpy(pTempCur, pCur, sizeof(BtCursor)); pTempCur->pNext = 0; pTempCur->pPrev = 0; - if( pTempCur->pPage ){ - sqlite3PagerRef(pTempCur->pPage->pDbPage); + for(i=0; i<=pTempCur->iPage; i++){ + sqlite3PagerRef(pTempCur->apPage[i]->pDbPage); } } @@ -2940,9 +2897,10 @@ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ ** function above. */ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ + int i; assert( cursorHoldsMutex(pCur) ); - if( pCur->pPage ){ - sqlite3PagerUnref(pCur->pPage->pDbPage); + for(i=0; i<=pCur->iPage; i++){ + sqlite3PagerUnref(pCur->apPage[i]->pDbPage); } } @@ -2964,8 +2922,9 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; + int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info); + sqlite3BtreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else @@ -2975,7 +2934,8 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ /* Use a real function in MSVC to work around bugs in that compiler. */ static void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ - sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); + int iPage = pCur->iPage; + sqlite3BtreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); pCur->validNKey = 1; }else{ assertCellInfo(pCur); @@ -2983,12 +2943,13 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ } #else /* if not _MSC_VER */ /* Use a macro in all other compilers so that the function is inlined */ -#define getCellInfo(pCur) \ - if( pCur->info.nSize==0 ){ \ - sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); \ - pCur->validNKey = 1; \ - }else{ \ - assertCellInfo(pCur); \ +#define getCellInfo(pCur) \ + if( pCur->info.nSize==0 ){ \ + int iPage = pCur->iPage; \ + sqlite3BtreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ + pCur->validNKey = 1; \ + }else{ \ + assertCellInfo(pCur); \ } #endif /* _MSC_VER */ @@ -3201,12 +3162,12 @@ static int accessPayload( int rc = SQLITE_OK; u32 nKey; int iIdx = 0; - MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */ - BtShared *pBt; /* Btree this cursor belongs to */ + MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ + BtShared *pBt; /* Btree this cursor belongs to */ assert( pPage ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->idx>=0 && pCur->idxnCell ); + assert( pCur->aiIdx[pCur->iPage]nCell ); assert( offset>=0 ); assert( cursorHoldsMutex(pCur) ); @@ -3339,12 +3300,11 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); - assert( pCur->pPage!=0 ); - if( pCur->pPage->intKey ){ + assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); + if( pCur->apPage[0]->intKey ){ return SQLITE_CORRUPT_BKPT; } - assert( pCur->pPage->intKey==0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0); } return rc; @@ -3372,8 +3332,8 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); - assert( pCur->pPage!=0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); + assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); rc = accessPayload(pCur, offset, amt, pBuf, 1, 0); } return rc; @@ -3408,11 +3368,11 @@ static const unsigned char *fetchPayload( u32 nKey; int nLocal; - assert( pCur!=0 && pCur->pPage!=0 ); + assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( cursorHoldsMutex(pCur) ); - pPage = pCur->pPage; - assert( pCur->idx>=0 && pCur->idxnCell ); + pPage = pCur->apPage[pCur->iPage]; + assert( pCur->aiIdx[pCur->iPage]nCell ); getCellInfo(pCur); aPayload = pCur->info.pCell; aPayload += pCur->info.nHeader; @@ -3471,20 +3431,23 @@ const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ */ static int moveToChild(BtCursor *pCur, u32 newPgno){ int rc; + int i = pCur->iPage; MemPage *pNewPage; - MemPage *pOldPage; BtShared *pBt = pCur->pBt; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); + assert( pCur->iPageiPage>=(BTCURSOR_MAX_DEPTH-1) ){ + return SQLITE_CORRUPT_BKPT; + } + rc = getAndInitPage(pBt, newPgno, &pNewPage); if( rc ) return rc; - pNewPage->idxParent = pCur->idx; - pOldPage = pCur->pPage; - pOldPage->idxShift = 0; - releasePage(pOldPage); - pCur->pPage = pNewPage; - pCur->idx = 0; + pCur->apPage[i]->idxShift = 0; + pCur->apPage[i+1] = pNewPage; + pCur->aiIdx[i+1] = 0; + pCur->iPage++; + pCur->info.nSize = 0; pCur->validNKey = 0; if( pNewPage->nCell<1 ){ @@ -3493,26 +3456,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ return SQLITE_OK; } -/* -** Return true if the page is the virtual root of its table. -** -** The virtual root page is the root page for most tables. But -** for the table rooted on page 1, sometime the real root page -** is empty except for the right-pointer. In such cases the -** virtual root page is the page that the right-pointer of page -** 1 is pointing to. -*/ -int sqlite3BtreeIsRootPage(MemPage *pPage){ - MemPage *pParent; - - assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - pParent = pPage->pParent; - if( pParent==0 ) return 1; - if( pParent->pgno>1 ) return 0; - if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1; - return 0; -} - /* ** Move the cursor up to the parent page. ** @@ -3522,26 +3465,16 @@ int sqlite3BtreeIsRootPage(MemPage *pPage){ ** the largest cell index. */ void sqlite3BtreeMoveToParent(BtCursor *pCur){ - MemPage *pParent; - MemPage *pPage; - int idxParent; - assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - pPage = pCur->pPage; - assert( pPage!=0 ); - assert( !sqlite3BtreeIsRootPage(pPage) ); - pParent = pPage->pParent; - assert( pParent!=0 ); - assert( pPage->pDbPage->nRef>0 ); - idxParent = pPage->idxParent; - sqlite3PagerRef(pParent->pDbPage); - releasePage(pPage); - pCur->pPage = pParent; + assert( pCur->iPage>0 ); + assert( pCur->apPage[pCur->iPage] ); + + releasePage(pCur->apPage[pCur->iPage]); + pCur->iPage--; pCur->info.nSize = 0; pCur->validNKey = 0; - assert( pParent->idxShift==0 ); - pCur->idx = idxParent; + assert( pCur->apPage[pCur->iPage]->idxShift==0 ); } /* @@ -3563,38 +3496,29 @@ static int moveToRoot(BtCursor *pCur){ } clearCursorPosition(pCur); } - pRoot = pCur->pPage; - if( pRoot && pRoot->isInit ){ - /* If the page the cursor is currently pointing to is fully initialized, - ** then the root page can be found by following the MemPage.pParent - ** pointers. This is faster than requesting a reference to the root - ** page from the pager layer. - */ - while( pRoot->pParent ){ - assert( pRoot->isInit==PAGE_ISINIT_FULL ); - pRoot = pRoot->pParent; - } - assert( pRoot->isInit==PAGE_ISINIT_FULL ); - if( pRoot!=pCur->pPage ){ - sqlite3PagerRef(pRoot->pDbPage); - releasePage(pCur->pPage); - pCur->pPage = pRoot; + + if( pCur->iPage>=0 ){ + int i; + for(i=1; i<=pCur->iPage; i++){ + releasePage(pCur->apPage[i]); } }else{ if( - SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) + SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0])) ){ pCur->eState = CURSOR_INVALID; return rc; } - releasePage(pCur->pPage); - pCur->pPage = pRoot; } - assert( pCur->pPage->pgno==pCur->pgnoRoot ); - pCur->idx = 0; + + pRoot = pCur->apPage[0]; + assert( pRoot->pgno==pCur->pgnoRoot ); + pCur->iPage = 0; + pCur->aiIdx[0] = 0; pCur->info.nSize = 0; pCur->atLast = 0; pCur->validNKey = 0; + if( pRoot->nCell==0 && !pRoot->leaf ){ Pgno subpage; assert( pRoot->pgno==1 ); @@ -3602,8 +3526,9 @@ static int moveToRoot(BtCursor *pCur){ assert( subpage>0 ); pCur->eState = CURSOR_VALID; rc = moveToChild(pCur, subpage); + }else{ + pCur->eState = ((pRoot->nCell>0)?CURSOR_VALID:CURSOR_INVALID); } - pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID); return rc; } @@ -3621,9 +3546,9 @@ static int moveToLeftmost(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ - assert( pCur->idx>=0 && pCur->idxnCell ); - pgno = get4byte(findCell(pPage, pCur->idx)); + while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + assert( pCur->aiIdx[pCur->iPage]nCell ); + pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); rc = moveToChild(pCur, pgno); } return rc; @@ -3646,13 +3571,13 @@ static int moveToRightmost(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ + while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - pCur->idx = pPage->nCell; + pCur->aiIdx[pCur->iPage] = pPage->nCell; rc = moveToChild(pCur, pgno); } if( rc==SQLITE_OK ){ - pCur->idx = pPage->nCell - 1; + pCur->aiIdx[pCur->iPage] = pPage->nCell-1; pCur->info.nSize = 0; pCur->validNKey = 0; } @@ -3671,11 +3596,11 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pPage->nCell==0 ); + assert( pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; rc = SQLITE_OK; }else{ - assert( pCur->pPage->nCell>0 ); + assert( pCur->apPage[pCur->iPage]->nCell>0 ); *pRes = 0; rc = moveToLeftmost(pCur); } @@ -3695,7 +3620,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->pPage->nCell==0 ); + assert( pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; }else{ assert( pCur->eState==CURSOR_VALID ); @@ -3749,7 +3674,9 @@ int sqlite3BtreeMovetoUnpacked( /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->pPage->intKey ){ + if( pCur->eState==CURSOR_VALID && pCur->validNKey + && pCur->apPage[0]->intKey + ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; @@ -3764,18 +3691,18 @@ int sqlite3BtreeMovetoUnpacked( if( rc ){ return rc; } - assert( pCur->pPage ); - assert( pCur->pPage->isInit==PAGE_ISINIT_FULL ); + assert( pCur->apPage[pCur->iPage] ); + assert( pCur->apPage[pCur->iPage]->isInit ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; - assert( pCur->pPage->nCell==0 ); + assert( pCur->apPage[pCur->iPage]->nCell==0 ); return SQLITE_OK; } - assert( pCur->pPage->intKey || pIdxKey ); + assert( pCur->apPage[0]->intKey || pIdxKey ); for(;;){ int lwr, upr; Pgno chldPg; - MemPage *pPage = pCur->pPage; + MemPage *pPage = pCur->apPage[pCur->iPage]; int c = -1; /* pRes return if table is empty must be -1 */ lwr = 0; upr = pPage->nCell-1; @@ -3784,18 +3711,19 @@ int sqlite3BtreeMovetoUnpacked( goto moveto_finish; } if( biasRight ){ - pCur->idx = upr; + pCur->aiIdx[pCur->iPage] = upr; }else{ - pCur->idx = (upr+lwr)/2; + pCur->aiIdx[pCur->iPage] = (upr+lwr)/2; } if( lwr<=upr ) for(;;){ void *pCellKey; i64 nCellKey; + int idx = pCur->aiIdx[pCur->iPage]; pCur->info.nSize = 0; pCur->validNKey = 1; if( pPage->intKey ){ u8 *pCell; - pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; + pCell = findCell(pPage, idx) + pPage->childPtrSize; if( pPage->hasData ){ u32 dummy; pCell += getVarint32(pCell, dummy); @@ -3830,7 +3758,7 @@ int sqlite3BtreeMovetoUnpacked( if( c==0 ){ pCur->info.nKey = nCellKey; if( pPage->intKey && !pPage->leaf ){ - lwr = pCur->idx; + lwr = idx; upr = lwr - 1; break; }else{ @@ -3840,18 +3768,18 @@ int sqlite3BtreeMovetoUnpacked( } } if( c<0 ){ - lwr = pCur->idx+1; + lwr = idx+1; }else{ - upr = pCur->idx-1; + upr = idx-1; } if( lwr>upr ){ pCur->info.nKey = nCellKey; break; } - pCur->idx = (lwr+upr)/2; + pCur->aiIdx[pCur->iPage] = (lwr+upr)/2; } assert( lwr==upr+1 ); - assert( pPage->isInit==PAGE_ISINIT_FULL ); + assert( pPage->isInit ); if( pPage->leaf ){ chldPg = 0; }else if( lwr>=pPage->nCell ){ @@ -3860,12 +3788,12 @@ int sqlite3BtreeMovetoUnpacked( chldPg = get4byte(findCell(pPage, lwr)); } if( chldPg==0 ){ - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); if( pRes ) *pRes = c; rc = SQLITE_OK; goto moveto_finish; } - pCur->idx = lwr; + pCur->aiIdx[pCur->iPage] = lwr; pCur->info.nSize = 0; pCur->validNKey = 0; rc = moveToChild(pCur, chldPg); @@ -3937,6 +3865,7 @@ sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){ */ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ int rc; + int idx; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); @@ -3945,7 +3874,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ return rc; } assert( pRes!=0 ); - pPage = pCur->pPage; if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; @@ -3957,13 +3885,14 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ } pCur->skip = 0; - assert( pPage->isInit==PAGE_ISINIT_FULL ); - assert( pCur->idxnCell ); + pPage = pCur->apPage[pCur->iPage]; + idx = ++pCur->aiIdx[pCur->iPage]; + assert( pPage->isInit ); + assert( idx<=pPage->nCell ); - pCur->idx++; pCur->info.nSize = 0; pCur->validNKey = 0; - if( pCur->idx>=pPage->nCell ){ + if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; @@ -3972,14 +3901,14 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ return rc; } do{ - if( sqlite3BtreeIsRootPage(pPage) ){ + if( pCur->iPage==0 ){ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } sqlite3BtreeMoveToParent(pCur); - pPage = pCur->pPage; - }while( pCur->idx>=pPage->nCell ); + pPage = pCur->apPage[pCur->iPage]; + }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); *pRes = 0; if( pPage->intKey ){ rc = sqlite3BtreeNext(pCur, pRes); @@ -4005,7 +3934,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ */ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ int rc; - Pgno pgno; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); @@ -4025,29 +3953,29 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ } pCur->skip = 0; - pPage = pCur->pPage; - assert( pPage->isInit==PAGE_ISINIT_FULL ); - assert( pCur->idx>=0 ); + pPage = pCur->apPage[pCur->iPage]; + assert( pPage->isInit ); if( !pPage->leaf ){ - pgno = get4byte( findCell(pPage, pCur->idx) ); - rc = moveToChild(pCur, pgno); + int idx = pCur->aiIdx[pCur->iPage]; + rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ){ return rc; } rc = moveToRightmost(pCur); }else{ - while( pCur->idx==0 ){ - if( sqlite3BtreeIsRootPage(pPage) ){ + while( pCur->aiIdx[pCur->iPage]==0 ){ + if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; *pRes = 1; return SQLITE_OK; } sqlite3BtreeMoveToParent(pCur); - pPage = pCur->pPage; } - pCur->idx--; pCur->info.nSize = 0; pCur->validNKey = 0; + + pCur->aiIdx[pCur->iPage]--; + pPage = pCur->apPage[pCur->iPage]; if( pPage->intKey && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, pRes); }else{ @@ -4317,12 +4245,9 @@ static int allocateBtreePage( end_allocate_page: releasePage(pTrunk); releasePage(pPrevTrunk); - if( rc==SQLITE_OK ){ - if( (*ppPage)->isInit==PAGE_ISINIT_FULL ){ - releasePage(*ppPage); - return SQLITE_CORRUPT_BKPT; - } - (*ppPage)->isInit = 0; + if( rc==SQLITE_OK && sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){ + releasePage(*ppPage); + return SQLITE_CORRUPT_BKPT; } return rc; } @@ -4341,8 +4266,6 @@ static int freePage(MemPage *pPage){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno>1 ); pPage->isInit = 0; - releasePage(pPage->pParent); - pPage->pParent = 0; /* Increment the free page count on pPage1 */ rc = sqlite3PagerWrite(pPage1->pDbPage); @@ -4613,28 +4536,7 @@ static int reparentPage( int idx, /* Index of child page pgno in pNewParent */ int updatePtrmap /* If true, update pointer-map for pgno */ ){ - MemPage *pThis; DbPage *pDbPage; - - assert( sqlite3_mutex_held(pBt->mutex) ); - assert( pNewParent!=0 ); - if( pgno==0 ) return SQLITE_OK; - assert( pBt->pPager!=0 ); - pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); - if( pDbPage ){ - pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage); - if( pThis->isInit==PAGE_ISINIT_FULL ){ - assert( pThis->aData==sqlite3PagerGetData(pDbPage) ); - if( pThis->pParent!=pNewParent ){ - if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage); - pThis->pParent = pNewParent; - sqlite3PagerRef(pNewParent->pDbPage); - } - pThis->idxParent = idx; - } - sqlite3PagerUnref(pDbPage); - } - if( ISAUTOVACUUM && updatePtrmap ){ return ptrmapPut(pBt, pgno, PTRMAP_BTREE, pNewParent->pgno); } @@ -4884,7 +4786,7 @@ static void assemblePage( #define NB (NN*2+1) /* Total pages involved in the balance */ /* Forward reference */ -static int balance(MemPage*, int); +static int balance(BtCursor*, int); #ifndef SQLITE_OMIT_QUICKBALANCE /* @@ -4904,13 +4806,15 @@ static int balance(MemPage*, int); ** pParent is its parent. pPage must have a single overflow entry ** which is also the right-most entry on the page. */ -static int balance_quick(MemPage *pPage, MemPage *pParent){ +static int balance_quick(BtCursor *pCur){ int rc; MemPage *pNew = 0; Pgno pgnoNew; u8 *pCell; u16 szCell; CellInfo info; + MemPage *pPage = pCur->apPage[pCur->iPage]; + MemPage *pParent = pCur->apPage[pCur->iPage-1]; BtShared *pBt = pPage->pBt; int parentIdx = pParent->nCell; /* pParent new divider cell index */ int parentSize; /* Size of new divider cell */ @@ -4930,8 +4834,10 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ pPage->nOverflow = 0; /* Set the parent of the newly allocated page to pParent. */ +#if 0 pNew->pParent = pParent; sqlite3PagerRef(pParent->pDbPage); +#endif /* pPage is currently the right-child of pParent. Change this ** so that the right-child is the new page allocated above and @@ -4986,14 +4892,15 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ ** the page data and contents of MemPage are consistent. */ pPage->isInit = 0; - sqlite3BtreeInitPage(pPage, pPage->pParent); - sqlite3PagerUnref(pPage->pParent->pDbPage); + sqlite3BtreeInitPage(pPage); /* If everything else succeeded, balance the parent page, in ** case the divider cell inserted caused it to become overfull. */ if( rc==SQLITE_OK ){ - rc = balance(pParent, 0); + releasePage(pPage); + pCur->iPage--; + rc = balance(pCur, 0); } return rc; } @@ -5028,7 +4935,8 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ ** in a corrupted state. So if this routine fails, the database should ** be rolled back. */ -static int balance_nonroot(MemPage *pPage){ +static int balance_nonroot(BtCursor *pCur){ + MemPage *pPage; /* The over or underfull page to balance */ MemPage *pParent; /* The parent of pPage */ BtShared *pBt; /* The whole database */ int nCell = 0; /* Number of cells in apCell[] */ @@ -5063,15 +4971,17 @@ static int balance_nonroot(MemPage *pPage){ u8 *aSpace2 = 0; /* Space for overflow dividers cells after balance */ u8 *aFrom = 0; + pPage = pCur->apPage[pCur->iPage]; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* ** Find the parent page. */ - assert( pPage->isInit==PAGE_ISINIT_FULL ); + assert( pCur->iPage>0 ); + assert( pPage->isInit ); assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); pBt = pPage->pBt; - pParent = pPage->pParent; + pParent = pCur->apPage[pCur->iPage-1]; assert( pParent ); if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){ return rc; @@ -5092,7 +5002,7 @@ static int balance_nonroot(MemPage *pPage){ pPage->intKey && pPage->nOverflow==1 && pPage->aOvfl[0].idx==pPage->nCell && - pPage->pParent->pgno!=1 && + pParent->pgno!=1 && get4byte(&pParent->aData[pParent->hdrOffset+8])==pPage->pgno ){ assert( pPage->intKey ); @@ -5100,7 +5010,7 @@ static int balance_nonroot(MemPage *pPage){ ** TODO: Check the siblings to the left of pPage. It may be that ** they are not full and no new page is required. */ - return balance_quick(pPage, pParent); + return balance_quick(pCur); } #endif @@ -5125,7 +5035,7 @@ static int balance_nonroot(MemPage *pPage){ assert( idxnCell || get4byte(&pParent->aData[pParent->hdrOffset+8])==pgno ); }else{ - idx = pPage->idxParent; + idx = pCur->aiIdx[pCur->iPage-1]; } /* @@ -5133,7 +5043,7 @@ static int balance_nonroot(MemPage *pPage){ ** directly to balance_cleanup at any moment. */ nOld = nNew = 0; - sqlite3PagerRef(pParent->pDbPage); + /* sqlite3PagerRef(pParent->pDbPage); */ /* ** Find sibling pages to pPage and the cells in pParent that divide @@ -5161,9 +5071,9 @@ static int balance_nonroot(MemPage *pPage){ }else{ break; } - rc = getAndInitPage(pBt, pgnoOld[i], &apOld[i], pParent); + rc = getAndInitPage(pBt, pgnoOld[i], &apOld[i]); if( rc ) goto balance_cleanup; - apOld[i]->idxParent = k; + /* apOld[i]->idxParent = k; */ apCopy[i] = 0; assert( i==nOld ); nOld++; @@ -5632,10 +5542,12 @@ static int balance_nonroot(MemPage *pPage){ ** have been added to the freelist so it might no longer be initialized. ** But the parent page will always be initialized. */ - assert( pParent->isInit==PAGE_ISINIT_FULL ); + assert( pParent->isInit ); sqlite3ScratchFree(apCell); apCell = 0; - rc = balance(pParent, 0); + releasePage(pPage); + pCur->iPage--; + rc = balance(pCur, 0); /* ** Cleanup before returning. @@ -5650,7 +5562,7 @@ balance_cleanup: releasePage(apNew[i]); } - releasePage(pParent); + /* releasePage(pParent); */ TRACE(("BALANCE: finished with %d: old=%d new=%d cells=%d\n", pPage->pgno, nOld, nNew, nCell)); @@ -5662,7 +5574,8 @@ balance_cleanup: ** page contains no cells. This is an opportunity to make the tree ** shallower by one level. */ -static int balance_shallower(MemPage *pPage){ +static int balance_shallower(BtCursor *pCur){ + MemPage *pPage; /* Root page of B-Tree */ MemPage *pChild; /* The only child page of pPage */ Pgno pgnoChild; /* Page number for pChild */ int rc = SQLITE_OK; /* Return code from subprocedures */ @@ -5671,7 +5584,9 @@ static int balance_shallower(MemPage *pPage){ u8 **apCell; /* All cells from pages being balanced */ u16 *szCell; /* Local size of all cells */ - assert( pPage->pParent==0 ); + assert( pCur->iPage==0 ); + pPage = pCur->apPage[0]; + assert( pPage->nCell==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pBt = pPage->pBt; @@ -5701,7 +5616,7 @@ static int balance_shallower(MemPage *pPage){ rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0); if( rc ) goto end_shallow_balance; if( pPage->pgno==1 ){ - rc = sqlite3BtreeInitPage(pChild, pPage); + rc = sqlite3BtreeInitPage(pChild); if( rc ) goto end_shallow_balance; assert( pChild->nOverflow==0 ); if( pChild->nFree>=100 ){ @@ -5727,8 +5642,7 @@ static int balance_shallower(MemPage *pPage){ }else{ memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); pPage->isInit = 0; - pPage->pParent = 0; - rc = sqlite3BtreeInitPage(pPage, 0); + rc = sqlite3BtreeInitPage(pPage); assert( rc==SQLITE_OK ); freePage(pChild); TRACE(("BALANCE: transfer child %d into root %d\n", @@ -5762,8 +5676,9 @@ end_shallow_balance: ** child. Finally, call balance_internal() on the new child ** to cause it to split. */ -static int balance_deeper(MemPage *pPage){ +static int balance_deeper(BtCursor *pCur){ int rc; /* Return value from subprocedures */ + MemPage *pPage; /* Pointer to the root page */ MemPage *pChild; /* Pointer to a new child page */ Pgno pgnoChild; /* Page number of the new child page */ BtShared *pBt; /* The BTree */ @@ -5773,8 +5688,10 @@ static int balance_deeper(MemPage *pPage){ int hdr; /* Offset to page header in parent */ int cbrk; /* Offset to content of first cell in parent */ - assert( pPage->pParent==0 ); - assert( pPage->nOverflow>0 ); + assert( pCur->iPage==0 ); + assert( pCur->apPage[0]->nOverflow>0 ); + + pPage = pCur->apPage[0]; pBt = pPage->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); rc = allocateBtreePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0); @@ -5787,58 +5704,68 @@ static int balance_deeper(MemPage *pPage){ cdata = pChild->aData; memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr); memcpy(&cdata[cbrk], &data[cbrk], usableSize-cbrk); - if( pChild->isInit==PAGE_ISINIT_FULL ) return SQLITE_CORRUPT; - rc = sqlite3BtreeInitPage(pChild, pPage); - if( rc ) goto balancedeeper_out; - memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0])); - pChild->nOverflow = pPage->nOverflow; - if( pChild->nOverflow ){ - pChild->nFree = 0; - } - assert( pChild->nCell==pPage->nCell ); - zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); - put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild); - TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); - if( ISAUTOVACUUM ){ - int i; - rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno); - if( rc ) goto balancedeeper_out; - for(i=0; inCell; i++){ - rc = ptrmapPutOvfl(pChild, i); - if( rc!=SQLITE_OK ){ - goto balancedeeper_out; + + rc = sqlite3BtreeInitPage(pChild); + if( rc==SQLITE_OK ){ + int nCopy = pPage->nOverflow*sizeof(pPage->aOvfl[0]); + memcpy(pChild->aOvfl, pPage->aOvfl, nCopy); + pChild->nOverflow = pPage->nOverflow; + if( pChild->nOverflow ){ + pChild->nFree = 0; + } + assert( pChild->nCell==pPage->nCell ); + zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); + put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild); + TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); + if( ISAUTOVACUUM ){ + int i; + rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno); + for(i=0; rc==SQLITE_OK && inCell; i++){ + rc = ptrmapPutOvfl(pChild, i); + } + if( rc==SQLITE_OK ){ + rc = reparentChildPages(pChild, 1); } } - rc = reparentChildPages(pChild, 1); - } - if( rc==SQLITE_OK ){ - rc = balance_nonroot(pChild); } -balancedeeper_out: - releasePage(pChild); + if( rc==SQLITE_OK ){ + pCur->iPage++; + pCur->apPage[1] = pChild; + rc = balance_nonroot(pCur); + }else{ + releasePage(pChild); + } + return rc; } /* -** Decide if the page pPage needs to be balanced. If balancing is -** required, call the appropriate balancing routine. +** The page that pCur currently points to has just been modified in +** some way. This function figures out if this modification means the +** tree needs to be balanced, and if so calls the appropriate balancing +** routine. +** +** Parameter isInsert is true if a new cell was just inserted into the +** page, or false otherwise. */ -static int balance(MemPage *pPage, int insert){ +static int balance(BtCursor *pCur, int isInsert){ int rc = SQLITE_OK; + MemPage *pPage = pCur->apPage[pCur->iPage]; + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - if( pPage->pParent==0 ){ + if( pCur->iPage==0 ){ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc==SQLITE_OK && pPage->nOverflow>0 ){ - rc = balance_deeper(pPage); + rc = balance_deeper(pCur); } if( rc==SQLITE_OK && pPage->nCell==0 ){ - rc = balance_shallower(pPage); + rc = balance_shallower(pCur); } }else{ if( pPage->nOverflow>0 || - (!insert && pPage->nFree>pPage->pBt->usableSize*2/3) ){ - rc = balance_nonroot(pPage); + (!isInsert && pPage->nFree>pPage->pBt->usableSize*2/3) ){ + rc = balance_nonroot(pCur); } } return rc; @@ -5932,6 +5859,7 @@ int sqlite3BtreeInsert( int rc; int loc; int szNew; + int idx; MemPage *pPage; Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; @@ -5964,13 +5892,13 @@ int sqlite3BtreeInsert( return rc; } - pPage = pCur->pPage; + pPage = pCur->apPage[pCur->iPage]; assert( pPage->intKey || nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, nKey, nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); - assert( pPage->isInit==PAGE_ISINIT_FULL ); + assert( pPage->isInit ); allocateTempSpace(pBt); newCell = pBt->pTmpSpace; if( newCell==0 ) return SQLITE_NOMEM; @@ -5978,40 +5906,34 @@ int sqlite3BtreeInsert( if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); + idx = pCur->aiIdx[pCur->iPage]; if( loc==0 && CURSOR_VALID==pCur->eState ){ u16 szOld; - assert( pCur->idx>=0 && pCur->idxnCell ); + assert( idxnCell ); rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; } - oldCell = findCell(pPage, pCur->idx); + oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); if( rc ) goto end_insert; - dropCell(pPage, pCur->idx, szOld); + dropCell(pPage, idx, szOld); }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); - pCur->idx++; + idx = ++pCur->aiIdx[pCur->iPage]; pCur->info.nSize = 0; pCur->validNKey = 0; }else{ assert( pPage->leaf ); } - rc = insertCell(pPage, pCur->idx, newCell, szNew, 0, 0); + rc = insertCell(pPage, idx, newCell, szNew, 0, 0); if( rc!=SQLITE_OK ) goto end_insert; - rc = balance(pPage, 1); + rc = balance(pCur, 1); if( rc==SQLITE_OK ){ - /* balance() may have messed up the chain of MemPage.pParent pointers. - ** To prevent moveToRoot() from trying to use them to locate the root - ** page of this table, release the reference to the current page before - ** calling it. - */ - releasePage(pCur->pPage); - pCur->pPage = 0; moveToRoot(pCur); } end_insert: @@ -6023,7 +5945,8 @@ end_insert: ** is left pointing at a random location. */ int sqlite3BtreeDelete(BtCursor *pCur){ - MemPage *pPage = pCur->pPage; + MemPage *pPage = pCur->apPage[pCur->iPage]; + int idx; unsigned char *pCell; int rc; Pgno pgnoChild = 0; @@ -6031,7 +5954,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ BtShared *pBt = p->pBt; assert( cursorHoldsMutex(pCur) ); - assert( pPage->isInit==PAGE_ISINIT_FULL ); + assert( pPage->isInit ); if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; @@ -6041,7 +5964,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( pCur->eState==CURSOR_FAULT ){ return pCur->skip; } - if( pCur->idx >= pPage->nCell ){ + if( pCur->aiIdx[pCur->iPage]>=pPage->nCell ){ return SQLITE_ERROR; /* The cursor is not pointing to anything */ } if( !pCur->wrFlag ){ @@ -6068,7 +5991,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ - pCell = findCell(pPage, pCur->idx); + idx = pCur->aiIdx[pCur->iPage]; + pCell = findCell(pPage, idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } @@ -6086,6 +6010,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** to be a leaf so we can use it. */ BtCursor leafCur; + MemPage *pLeafPage; + int iLeafIdx; + unsigned char *pNext; int notUsed; unsigned char *tempCell = 0; @@ -6093,15 +6020,17 @@ int sqlite3BtreeDelete(BtCursor *pCur){ sqlite3BtreeGetTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc==SQLITE_OK ){ - rc = sqlite3PagerWrite(leafCur.pPage->pDbPage); + pLeafPage = leafCur.apPage[leafCur.iPage]; + iLeafIdx = leafCur.aiIdx[leafCur.iPage]; + rc = sqlite3PagerWrite(pLeafPage->pDbPage); } if( rc==SQLITE_OK ){ u16 szNext; TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", - pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); - dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); - pNext = findCell(leafCur.pPage, leafCur.idx); - szNext = cellSizePtr(leafCur.pPage, pNext); + pCur->pgnoRoot, pPage->pgno, pLeafPage->pgno)); + dropCell(pPage, idx, cellSizePtr(pPage, pCell)); + pNext = findCell(pLeafPage, iLeafIdx); + szNext = cellSizePtr(pLeafPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); allocateTempSpace(pBt); tempCell = pBt->pTmpSpace; @@ -6109,32 +6038,25 @@ int sqlite3BtreeDelete(BtCursor *pCur){ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ - rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0); + rc = insertCell(pPage, idx, pNext-4, szNext+4, tempCell, 0); } if( rc==SQLITE_OK ){ - put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); - rc = balance(pPage, 0); + put4byte(findOverflowCell(pPage, idx), pgnoChild); + rc = balance(pCur, 0); } if( rc==SQLITE_OK ){ - dropCell(leafCur.pPage, leafCur.idx, szNext); - rc = balance(leafCur.pPage, 0); + dropCell(pLeafPage, iLeafIdx, szNext); + rc = balance(&leafCur, 0); } } sqlite3BtreeReleaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", pCur->pgnoRoot, pPage->pgno)); - dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); - rc = balance(pPage, 0); + dropCell(pPage, idx, cellSizePtr(pPage, pCell)); + rc = balance(pCur, 0); } if( rc==SQLITE_OK ){ - /* balance() may have messed up the chain of MemPage.pParent pointers. - ** To prevent moveToRoot() from trying to use them to locate the root - ** page of this table, release the reference to the current page before - ** calling it. - */ - releasePage(pCur->pPage); - pCur->pPage = 0; moveToRoot(pCur); } return rc; @@ -6311,7 +6233,7 @@ static int clearDatabasePage( return SQLITE_CORRUPT_BKPT; } - rc = getAndInitPage(pBt, pgno, &pPage, pParent); + rc = getAndInitPage(pBt, pgno, &pPage); if( rc ) goto cleardatabasepage_out; for(i=0; inCell; i++){ pCell = findCell(pPage, i); @@ -6614,7 +6536,7 @@ int sqlite3BtreeFlags(BtCursor *pCur){ */ MemPage *pPage; restoreCursorPosition(pCur); - pPage = pCur->pPage; + pPage = pCur->apPage[pCur->iPage]; assert( cursorHoldsMutex(pCur) ); assert( pPage->pBt==pCur->pBt ); return pPage ? pPage->aData[pPage->hdrOffset] : 0; @@ -6830,7 +6752,7 @@ static int checkTreePage( "unable to get the page. error code=%d", rc); return 0; } - if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){ + if( (rc = sqlite3BtreeInitPage(pPage))!=0 ){ checkAppendMsg(pCheck, zContext, "sqlite3BtreeInitPage() returns error code %d", rc); releasePage(pPage); @@ -7461,7 +7383,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr, 0) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){ + if( pCsr->eState==CURSOR_INVALID || !pCsr->apPage[pCsr->iPage]->intKey ){ return SQLITE_ERROR; } diff --git a/src/btreeInt.h b/src/btreeInt.h index 2a7bf9c6b6..a10eb488b3 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btreeInt.h,v 1.31 2008/09/18 17:34:44 danielk1977 Exp $ +** $Id: btreeInt.h,v 1.32 2008/09/29 11:49:48 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -281,7 +281,6 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - u16 idxParent; /* Index in parent of this node */ u16 nFree; /* Number of free bytes on the page */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ @@ -293,21 +292,8 @@ struct MemPage { u8 *aData; /* Pointer to disk image of the page data */ DbPage *pDbPage; /* Pager page handle */ Pgno pgno; /* Page number for this page */ - MemPage *pParent; /* The parent of this page. NULL for root */ }; -/* -** Possible values for the MemPage.isInit variable. When a page is first -** loaded or if the data stored in the MemPage struct is invalidated, -** MemPage.isInit is set to PAGE_ISINIT_NONE. If the MemPage structure -** is fully initialized, then MemPage.isInit is set to PAGE_ISINIT_FULL. -** MemPage.isInit is set to PAGE_ISINIT_DATA when the MemPage struct is -** populated, but the MemPage.pParent variable is not necessarily correct. -*/ -#define PAGE_ISINIT_NONE 0 -#define PAGE_ISINIT_DATA 1 -#define PAGE_ISINIT_FULL 2 - /* ** The in-memory image of a disk page has the auxiliary information appended ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold @@ -426,6 +412,17 @@ struct CellInfo { u16 nSize; /* Size of the cell content on the main b-tree page */ }; +/* +** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than +** this will be declared corrupt. This value is calculated based on a +** maximum database size of 2^31 pages a minimum fanout of 2 for a +** root-node and 3 for all other internal nodes. +** +** If a tree that appears to be taller than this is encountered, it is +** assumed that the database is corrupt. +*/ +#define BTCURSOR_MAX_DEPTH 20 + /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. @@ -446,8 +443,6 @@ struct BtCursor { BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ Pgno pgnoRoot; /* The root page of this tree */ - MemPage *pPage; /* Page that contains the entry */ - int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 atLast; /* Cursor pointing to the last entry */ @@ -460,6 +455,10 @@ struct BtCursor { u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ Pgno *aOverflow; /* Cache of overflow page locations */ #endif + + i16 iPage; /* Index of current page in apPage */ + MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ + u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ }; /* @@ -629,11 +628,10 @@ struct IntegrityCk { ** Internal routines that should be accessed by the btree layer only. */ int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); -int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); +int sqlite3BtreeInitPage(MemPage *pPage); void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur); void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); -int sqlite3BtreeIsRootPage(MemPage *pPage); void sqlite3BtreeMoveToParent(BtCursor *pCur); diff --git a/src/pager.c b/src/pager.c index 5011418447..d5dd891f6c 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.495 2008/09/26 21:08:08 drh Exp $ +** @(#) $Id: pager.c,v 1.496 2008/09/29 11:49:48 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -1728,7 +1728,6 @@ int sqlite3PagerOpen( sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ - void (*xDesc)(DbPage*), /* Page destructor function */ int nExtra, /* Extra bytes append to each in-memory page */ int flags, /* flags controlling this file */ int vfsFlags /* flags passed through to sqlite3_vfs.xOpen() */ @@ -1870,7 +1869,7 @@ int sqlite3PagerOpen( return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); } nExtra = FORCE_ALIGNMENT(nExtra); - sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, xDesc, + sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename); @@ -3875,6 +3874,13 @@ int sqlite3PagerRefcount(Pager *pPager){ return sqlite3PcacheRefCount(pPager->pPCache); } +/* +** Return the number of references to the specified page. +*/ +int sqlite3PagerPageRefcount(DbPage *pPage){ + return sqlite3PcachePageRefcount(pPage); +} + #ifdef SQLITE_TEST /* ** This routine is used for testing and analysis only. @@ -4176,7 +4182,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ ** Return a pointer to the data for the specified page. */ void *sqlite3PagerGetData(DbPage *pPg){ - assert( pPg->nRef>0 ); + assert( pPg->nRef>0 || pPg->pPager->memDb ); return pPg->pData; } diff --git a/src/pager.h b/src/pager.h index 41332d0201..accf049e9d 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,7 +13,7 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.84 2008/09/26 21:08:08 drh Exp $ +** @(#) $Id: pager.h,v 1.85 2008/09/29 11:49:48 danielk1977 Exp $ */ #ifndef _PAGER_H_ @@ -71,7 +71,7 @@ typedef struct PgHdr DbPage; ** See source code comments for a detailed description of the following ** routines: */ -int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, void(*)(DbPage*), int,int,int); +int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int); void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*)); int sqlite3PagerSetPagesize(Pager*, u16*); @@ -82,6 +82,7 @@ int sqlite3PagerClose(Pager *pPager); int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); +int sqlite3PagerPageRefcount(DbPage*); int sqlite3PagerRef(DbPage*); int sqlite3PagerUnref(DbPage*); int sqlite3PagerWrite(DbPage*); diff --git a/src/pcache.c b/src/pcache.c index d0dbb41c2e..f55049eb58 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file implements that page cache. ** -** @(#) $Id: pcache.c,v 1.32 2008/09/24 09:12:47 danielk1977 Exp $ +** @(#) $Id: pcache.c,v 1.33 2008/09/29 11:49:48 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -43,7 +43,6 @@ struct PCache { int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ int bPurgeable; /* True if pages are on backing store */ - void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ void *pStress; /* Argument to xStress */ /********************************************************************** @@ -643,7 +642,6 @@ void sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ - void (*xDestroy)(PgHdr*), /* Called to destroy a page */ int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ void *pStress, /* Argument to xStress */ PCache *p /* Preallocated space for the PCache */ @@ -653,7 +651,6 @@ void sqlite3PcacheOpen( p->szPage = szPage; p->szExtra = szExtra; p->bPurgeable = bPurgeable; - p->xDestroy = xDestroy; p->xStress = xStress; p->pStress = pStress; p->nMax = 100; @@ -752,9 +749,6 @@ void sqlite3PcacheRelease(PgHdr *p){ p->nRef--; if( p->nRef==0 ){ PCache *pCache = p->pCache; - if( p->pCache->xDestroy ){ - p->pCache->xDestroy(p); - } pCache->nRef--; if( (p->flags&PGHDR_DIRTY)==0 ){ pCache->nPinned--; @@ -1163,6 +1157,10 @@ int sqlite3PcacheRefCount(PCache *pCache){ return pCache->nRef; } +int sqlite3PcachePageRefcount(PgHdr *p){ + return p->nRef; +} + /* ** Return the total number of pages in the cache. */ diff --git a/src/pcache.h b/src/pcache.h index 73e6e26d40..1fadc32047 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -12,7 +12,7 @@ ** This header file defines the interface that the sqlite page cache ** subsystem. ** -** @(#) $Id: pcache.h,v 1.11 2008/09/18 17:34:44 danielk1977 Exp $ +** @(#) $Id: pcache.h,v 1.12 2008/09/29 11:49:48 danielk1977 Exp $ */ #ifndef _PCACHE_H_ @@ -79,7 +79,6 @@ void sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ - void (*xDestroy)(PgHdr *), /* Called to destroy a page */ int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */ void *pStress, /* Argument to xStress */ PCache *pToInit /* Preallocated space for the PCache */ @@ -143,6 +142,8 @@ int sqlite3PcacheRefCount(PCache*); /* Increment the reference count of an existing page */ void sqlite3PcacheRef(PgHdr*); +int sqlite3PcachePageRefcount(PgHdr*); + /* Return the total number of pages stored in the cache */ int sqlite3PcachePagecount(PCache*); diff --git a/src/test2.c b/src/test2.c index 5188257d43..083cc13a47 100644 --- a/src/test2.c +++ b/src/test2.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test2.c,v 1.61 2008/08/26 18:05:48 danielk1977 Exp $ +** $Id: test2.c,v 1.62 2008/09/29 11:49:48 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -78,7 +78,7 @@ static int pager_open( return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; - rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, 0, + rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); diff --git a/src/test_btree.c b/src/test_btree.c index cc1e1c9249..e29399321e 100644 --- a/src/test_btree.c +++ b/src/test_btree.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test_btree.c,v 1.7 2008/09/02 00:52:52 drh Exp $ +** $Id: test_btree.c,v 1.8 2008/09/29 11:49:48 danielk1977 Exp $ */ #include "btreeInt.h" #include @@ -52,11 +52,11 @@ void sqlite3BtreeCursorList(Btree *p){ BtCursor *pCur; BtShared *pBt = p->pBt; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - MemPage *pPage = pCur->pPage; + MemPage *pPage = pCur->apPage[pCur->iPage]; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, - pPage ? pPage->pgno : 0, pCur->idx, + pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage], (pCur->eState==CURSOR_VALID) ? "" : " eof" ); } @@ -83,8 +83,9 @@ void sqlite3BtreeCursorList(Btree *p){ ** This routine is used for testing and debugging only. */ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ +#if 0 int cnt, idx; - MemPage *pPage = pCur->pPage; + MemPage *pPage = pCur->apPage[pCur->iPage]; BtCursor tmpCur; int rc; @@ -136,5 +137,6 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ aResult[10] = 0; } sqlite3BtreeReleaseTempCursor(&tmpCur); +#endif return SQLITE_OK; } diff --git a/test/corrupt2.test b/test/corrupt2.test index b786b0bab6..652f7844ad 100644 --- a/test/corrupt2.test +++ b/test/corrupt2.test @@ -13,7 +13,7 @@ # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # -# $Id: corrupt2.test,v 1.17 2008/09/10 11:28:38 danielk1977 Exp $ +# $Id: corrupt2.test,v 1.18 2008/09/29 11:49:48 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -225,8 +225,6 @@ do_test corrupt2-5.1 { } set result } {{*** in database main *** -Page 10: sqlite3BtreeInitPage() returns error code 11 -On tree page 3 cell 1: Child page depth differs On tree page 2 cell 0: 2nd reference to page 10 On tree page 2 cell 1: Child page depth differs Page 4 is never used}}