diff --git a/manifest b/manifest index ea5cfda61c..489cd93145 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\sversion\snumber\sto\s3.6.3.\s(CVS\s5719) -D 2008-09-18T13:49:13 +C Avoid\sparsing\sthe\sstructure\sof\sb-tree\spages\s(in\ssqlite3BtreeInitPage)\smore\sthan\sis\snecessary.\s(CVS\s5720) +D 2008-09-18T17:34:44 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329 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 5db7b54e9d39dddb06e066e993901fc8630c6e49 +F src/btree.c e8484887722a3a84f2aab5663a0dc93e0c7806c7 F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107 -F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576 +F src/btreeInt.h e36f77e6621d671beb19ae581af1eba116cdfdc4 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 8f4def6a92681735908fa1b87b5cc0291ebafde6 F src/os_win.c 3209dc0ed734291764393ea8d534ba0d8696a540 -F src/pager.c 34318b85cead25e179a6ff83092c79d6dcecb2fd -F src/pager.h c45380ca9d0933ea5bc4ecb3a43958b6d2ec5a9c +F src/pager.c bcfa1c4034414a247c1583fd97c9c561afae53f9 +F src/pager.h 1ef5a3f8e0b4c8b30f19c8e01d4fca2db9bb5797 F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8 -F src/pcache.c c799d753a5d4b913961a4fe66c8a7c706b04d28d -F src/pcache.h deddea69babf3e0931b11eea3bf5c9e33a654389 +F src/pcache.c e025e5380d75ffc25ef069fee8d128b595513ece +F src/pcache.h 0b6871e820159629915e8688b5c67a81a203773f F src/pragma.c e633b6b7dabc110e2abfed4e35ba34a4039cb65c F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d @@ -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 0889b22a2949160c3f2d06beaa05a867b4c228b3 -R ac300755102001ce1aa8c09d26102ac6 -U drh -Z c0568459c1b6c869285e59f30eb43c51 +P 419764b35c96a1b08aefc0d6093c19fdf2aef517 +R abfec31e169b70fffcf581f021d6269e +U danielk1977 +Z fbad4f393b6c492a76554e62ab4e7b3d diff --git a/manifest.uuid b/manifest.uuid index da2f7cad3b..e1b3a273d6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -419764b35c96a1b08aefc0d6093c19fdf2aef517 \ No newline at end of file +6b998f3066754e219c266501327e5578c9406b63 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 12d29e25ef..efb509d969 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.512 2008/09/18 01:08:16 drh Exp $ +** $Id: btree.c,v 1.513 2008/09/18 17:34:44 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -941,57 +941,60 @@ int sqlite3BtreeInitPage( if( pPage==pParent ){ return SQLITE_CORRUPT_BKPT; } - if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ + 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 ) return SQLITE_OK; - if( pPage->pParent==0 && pParent!=0 ){ + if( pPage->isInit==PAGE_ISINIT_FULL ) return SQLITE_OK; + if( pParent!=0 ){ pPage->pParent = pParent; sqlite3PagerRef(pParent->pDbPage); } - hdr = pPage->hdrOffset; - data = pPage->aData; - if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; - assert( pBt->pageSize>=512 && pBt->pageSize<=32768 ); - pPage->maskPage = pBt->pageSize - 1; - pPage->nOverflow = 0; - pPage->idxShift = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; - top = get2byte(&data[hdr+5]); - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* 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]); - nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); - while( pc>0 ){ - int next, size; - if( pc>usableSize-4 ){ - /* Free block is off the page */ + if( pPage->isInit==PAGE_ISINIT_NONE ){ + hdr = pPage->hdrOffset; + data = pPage->aData; + if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; + assert( pBt->pageSize>=512 && pBt->pageSize<=32768 ); + pPage->maskPage = pBt->pageSize - 1; + pPage->nOverflow = 0; + pPage->idxShift = 0; + usableSize = pBt->usableSize; + pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; + top = get2byte(&data[hdr+5]); + pPage->nCell = get2byte(&data[hdr+3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* 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]); + nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); + while( pc>0 ){ + int next, size; + if( pc>usableSize-4 ){ + /* Free block is off the page */ + return SQLITE_CORRUPT_BKPT; + } + next = get2byte(&data[pc]); + size = get2byte(&data[pc+2]); + if( next>0 && next<=pc+size+3 ){ + /* Free blocks must be in accending order */ + return SQLITE_CORRUPT_BKPT; + } + nFree += size; + pc = next; + } + pPage->nFree = nFree; + if( nFree>=usableSize ){ + /* Free space cannot exceed total page size */ return SQLITE_CORRUPT_BKPT; } - next = get2byte(&data[pc]); - size = get2byte(&data[pc+2]); - if( next>0 && next<=pc+size+3 ){ - /* Free blocks must be in accending order */ - return SQLITE_CORRUPT_BKPT; - } - nFree += size; - pc = next; - } - pPage->nFree = nFree; - if( nFree>=usableSize ){ - /* Free space cannot exceed total page size */ - return SQLITE_CORRUPT_BKPT; } #if 0 @@ -1014,7 +1017,7 @@ int sqlite3BtreeInitPage( } #endif - pPage->isInit = 1; + pPage->isInit = PAGE_ISINIT_FULL; return SQLITE_OK; } @@ -1048,7 +1051,7 @@ static void zeroPage(MemPage *pPage, int flags){ pPage->maskPage = pBt->pageSize - 1; pPage->idxShift = 0; pPage->nCell = 0; - pPage->isInit = 1; + pPage->isInit = PAGE_ISINIT_FULL; } @@ -1120,7 +1123,7 @@ static int getAndInitPage( MemPage *pPage; assert( sqlite3_mutex_held(pBt->mutex) ); - assert( !pParent || pParent->isInit ); + assert( !pParent || pParent->isInit==PAGE_ISINIT_FULL ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } @@ -1144,7 +1147,7 @@ static int getAndInitPage( if( rc ) return rc; pPage = *ppPage; } - if( pPage->isInit==0 ){ + 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 @@ -1184,14 +1187,18 @@ static void pageDestructor(DbPage *pData){ MemPage *pPage; pPage = (MemPage *)sqlite3PagerGetExtra(pData); if( pPage ){ - assert( pPage->isInit==0 || sqlite3_mutex_held(pPage->pBt->mutex) ); + 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); } - pPage->isInit = 0; + if( pPage->isInit==PAGE_ISINIT_FULL ){ + pPage->isInit = PAGE_ISINIT_DATA; + } } } @@ -1203,14 +1210,15 @@ static void pageDestructor(DbPage *pData){ ** This routine needs to reset the extra data section at the end of the ** page to agree with the restored data. */ -static void pageReinit(DbPage *pData, int pageSize){ +static void pageReinit(DbPage *pData){ MemPage *pPage; - assert( (pageSize & 7)==0 ); pPage = (MemPage *)sqlite3PagerGetExtra(pData); - if( pPage->isInit ){ + if( pPage->isInit==PAGE_ISINIT_FULL ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; sqlite3BtreeInitPage(pPage, pPage->pParent); + }else if( pPage->isInit==PAGE_ISINIT_DATA ){ + pPage->isInit = 0; } } @@ -3557,7 +3565,7 @@ static int moveToRoot(BtCursor *pCur){ } pRoot = pCur->pPage; if( pRoot && pRoot->pgno==pCur->pgnoRoot ){ - assert( pRoot->isInit ); + assert( pRoot->isInit==PAGE_ISINIT_FULL ); }else{ if( SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) @@ -3743,7 +3751,7 @@ int sqlite3BtreeMovetoUnpacked( return rc; } assert( pCur->pPage ); - assert( pCur->pPage->isInit ); + assert( pCur->pPage->isInit==PAGE_ISINIT_FULL ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; assert( pCur->pPage->nCell==0 ); @@ -3829,7 +3837,7 @@ int sqlite3BtreeMovetoUnpacked( pCur->idx = (lwr+upr)/2; } assert( lwr==upr+1 ); - assert( pPage->isInit ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); if( pPage->leaf ){ chldPg = 0; }else if( lwr>=pPage->nCell ){ @@ -3935,7 +3943,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ } pCur->skip = 0; - assert( pPage->isInit ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); assert( pCur->idxnCell ); pCur->idx++; @@ -4004,7 +4012,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ pCur->skip = 0; pPage = pCur->pPage; - assert( pPage->isInit ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ pgno = get4byte( findCell(pPage, pCur->idx) ); @@ -4295,6 +4303,13 @@ 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; + } return rc; } @@ -4594,7 +4609,7 @@ static int reparentPage( pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); if( pDbPage ){ pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage); - if( pThis->isInit ){ + if( pThis->isInit==PAGE_ISINIT_FULL ){ assert( pThis->aData==sqlite3PagerGetData(pDbPage) ); if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage); @@ -4877,7 +4892,7 @@ static int balance(MemPage*, int); */ static int balance_quick(MemPage *pPage, MemPage *pParent){ int rc; - MemPage *pNew; + MemPage *pNew = 0; Pgno pgnoNew; u8 *pCell; u16 szCell; @@ -4893,63 +4908,78 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ ** into it. Then remove the overflow cell from pPage. */ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - pCell = pPage->aOvfl[0].pCell; - szCell = cellSizePtr(pPage, pCell); - zeroPage(pNew, pPage->aData[0]); - assemblePage(pNew, 1, &pCell, &szCell); - pPage->nOverflow = 0; - - /* Set the parent of the newly allocated page to pParent. */ - pNew->pParent = pParent; - sqlite3PagerRef(pParent->pDbPage); - - /* pPage is currently the right-child of pParent. Change this - ** so that the right-child is the new page allocated above and - ** pPage is the next-to-right child. - ** - ** Ignore the return value of the call to fillInCell(). fillInCell() - ** may only return other than SQLITE_OK if it is required to allocate - ** one or more overflow pages. Since an internal table B-Tree cell - ** may never spill over onto an overflow page (it is a maximum of - ** 13 bytes in size), it is not neccessary to check the return code. - ** - ** Similarly, the insertCell() function cannot fail if the page - ** being inserted into is already writable and the cell does not - ** contain an overflow pointer. So ignore this return code too. - */ - assert( pPage->nCell>0 ); - pCell = findCell(pPage, pPage->nCell-1); - sqlite3BtreeParseCellPtr(pPage, pCell, &info); - fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); - assert( parentSize<64 ); - assert( sqlite3PagerIswriteable(pParent->pDbPage) ); - insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); - put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno); - put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); - - /* If this is an auto-vacuum database, update the pointer map - ** with entries for the new page, and any pointer from the - ** cell on the page to an overflow page. - */ - if( ISAUTOVACUUM ){ - rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno); - if( rc==SQLITE_OK ){ - rc = ptrmapPutOvfl(pNew, 0); - } - if( rc!=SQLITE_OK ){ - releasePage(pNew); - return rc; + if( rc==SQLITE_OK ){ + pCell = pPage->aOvfl[0].pCell; + szCell = cellSizePtr(pPage, pCell); + zeroPage(pNew, pPage->aData[0]); + assemblePage(pNew, 1, &pCell, &szCell); + pPage->nOverflow = 0; + + /* Set the parent of the newly allocated page to pParent. */ + pNew->pParent = pParent; + sqlite3PagerRef(pParent->pDbPage); + + /* pPage is currently the right-child of pParent. Change this + ** so that the right-child is the new page allocated above and + ** pPage is the next-to-right child. + ** + ** Ignore the return value of the call to fillInCell(). fillInCell() + ** may only return other than SQLITE_OK if it is required to allocate + ** one or more overflow pages. Since an internal table B-Tree cell + ** may never spill over onto an overflow page (it is a maximum of + ** 13 bytes in size), it is not neccessary to check the return code. + ** + ** Similarly, the insertCell() function cannot fail if the page + ** being inserted into is already writable and the cell does not + ** contain an overflow pointer. So ignore this return code too. + */ + assert( pPage->nCell>0 ); + pCell = findCell(pPage, pPage->nCell-1); + sqlite3BtreeParseCellPtr(pPage, pCell, &info); + fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); + assert( parentSize<64 ); + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); + put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno); + put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); + + /* If this is an auto-vacuum database, update the pointer map + ** with entries for the new page, and any pointer from the + ** cell on the page to an overflow page. + */ + if( ISAUTOVACUUM ){ + rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno); + if( rc==SQLITE_OK ){ + rc = ptrmapPutOvfl(pNew, 0); + } } } + /* At this point the pPage->nFree variable is not set correctly with + ** respect to the content of the page (because it was set to 0 by + ** insertCell). So call sqlite3BtreeInitPage() to make sure it is + ** correct. + ** + ** This has to be done even if an error will be returned. Normally, if + ** an error occurs during tree balancing, the contents of MemPage are + ** not important, as they will be recalculated when the page is rolled + ** back. But here, in balance_quick(), it is possible that pPage has + ** not yet been marked dirty or written into the journal file. Therefore + ** it will not be rolled back and so it is important to make sure that + ** the page data and contents of MemPage are consistent. + */ + pPage->isInit = 0; + sqlite3BtreeInitPage(pPage, pPage->pParent); + sqlite3PagerUnref(pPage->pParent->pDbPage); + /* Release the reference to the new page and balance the parent page, ** in case the divider cell inserted caused it to become overfull. */ releasePage(pNew); - return balance(pParent, 0); + if( rc==SQLITE_OK ){ + rc = balance(pParent, 0); + } + return rc; } #endif /* SQLITE_OMIT_QUICKBALANCE */ @@ -5022,7 +5052,7 @@ static int balance_nonroot(MemPage *pPage){ /* ** Find the parent page. */ - assert( pPage->isInit ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 ); pBt = pPage->pBt; pParent = pPage->pParent; @@ -5554,7 +5584,7 @@ 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 ); + assert( pParent->isInit==PAGE_ISINIT_FULL ); sqlite3ScratchFree(apCell); apCell = 0; rc = balance(pParent, 0); @@ -5571,9 +5601,11 @@ balance_cleanup: for(i=0; ipgno, nOld, nNew, nCell)); + return rc; } @@ -5707,7 +5739,7 @@ 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 ) return SQLITE_CORRUPT; + 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])); @@ -5890,7 +5922,7 @@ int sqlite3BtreeInsert( 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 ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); allocateTempSpace(pBt); newCell = pBt->pTmpSpace; if( newCell==0 ) return SQLITE_NOMEM; @@ -5944,7 +5976,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ BtShared *pBt = p->pBt; assert( cursorHoldsMutex(pCur) ); - assert( pPage->isInit ); + assert( pPage->isInit==PAGE_ISINIT_FULL ); if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; @@ -7124,7 +7156,11 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){ } } - if( pToPage ) sqlite3PagerUnref(pToPage); + if( pToPage ){ + MemPage *p = (MemPage *)sqlite3PagerGetExtra(pToPage); + p->isInit = 0; + sqlite3PagerUnref(pToPage); + } } } diff --git a/src/btreeInt.h b/src/btreeInt.h index 663a41e081..2a7bf9c6b6 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.30 2008/08/01 20:10:08 drh Exp $ +** $Id: btreeInt.h,v 1.31 2008/09/18 17:34:44 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -296,6 +296,18 @@ struct MemPage { 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 diff --git a/src/pager.c b/src/pager.c index 51fafebd7d..7218717229 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.491 2008/09/17 20:06:26 drh Exp $ +** @(#) $Id: pager.c,v 1.492 2008/09/18 17:34:44 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -208,8 +208,7 @@ struct Pager { int nHit, nMiss; /* Cache hits and missing */ int nRead, nWrite; /* Database pages read/written */ #endif - void (*xDestructor)(DbPage*,int); /* Call this routine when freeing pages */ - void (*xReiniter)(DbPage*,int); /* Call this routine when reloading pages */ + void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ #ifdef SQLITE_HAS_CODEC void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *pCodecArg; /* First argument to xCodec() */ @@ -1159,7 +1158,7 @@ static int pager_playback_one_page( pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); if( pPager->xReiniter ){ - pPager->xReiniter(pPg, pPager->pageSize); + pPager->xReiniter(pPg); } if( isMainJrnl ) makeClean(pPg); #ifdef SQLITE_CHECK_PAGES @@ -1941,7 +1940,7 @@ void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){ ** an opportunity to restore the EXTRA section to agree with the restored ** page data. */ -void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){ +void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*)){ pPager->xReiniter = xReinit; } @@ -3830,8 +3829,8 @@ int sqlite3PagerRollback(Pager *pPager){ int rc = SQLITE_OK; PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ - sqlite3PcacheRollback(pPager->pPCache, 1); - sqlite3PcacheRollback(pPager->pPCache, 0); + sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter); + sqlite3PcacheRollback(pPager->pPCache, 0, pPager->xReiniter); sqlite3PcacheCleanAll(pPager->pPCache); sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL); pPager->dbSize = pPager->origDbSize; @@ -3991,7 +3990,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){ if( pPager->stmtInUse ){ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ - sqlite3PcacheRollback(pPager->pPCache, 1); + sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter); pPager->dbSize = pPager->stmtSize; pager_truncate_cache(pPager); rc = SQLITE_OK; diff --git a/src/pager.h b/src/pager.h index 04331a26a6..906c92eabc 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.82 2008/09/01 17:23:29 drh Exp $ +** @(#) $Id: pager.h,v 1.83 2008/09/18 17:34:44 danielk1977 Exp $ */ #ifndef _PAGER_H_ @@ -72,7 +72,7 @@ typedef struct PgHdr DbPage; */ int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, void(*)(DbPage*), int,int,int); void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); -void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int)); +void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*)); int sqlite3PagerSetPagesize(Pager*, u16*); int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); diff --git a/src/pcache.c b/src/pcache.c index 29672095aa..3731b5ccaf 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file implements that page cache. ** -** @(#) $Id: pcache.c,v 1.29 2008/09/17 20:06:26 drh Exp $ +** @(#) $Id: pcache.c,v 1.30 2008/09/18 17:34:44 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -1019,7 +1019,11 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){ /* ** Rollback a change previously preserved. */ -void sqlite3PcacheRollback(PCache *pCache, int idJournal){ +void sqlite3PcacheRollback( + PCache *pCache, /* Pager cache */ + int idJournal, /* Which copy to rollback to */ + void (*xReiniter)(PgHdr*) /* Called on each rolled back page */ +){ PgHdr *p; int sz; int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff; @@ -1030,6 +1034,9 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){ memcpy(p->pData, p->apSave[idJournal], sz); pcacheFree(p->apSave[idJournal]); p->apSave[idJournal] = 0; + if( xReiniter ){ + xReiniter(p); + } } p->flags &= mask; } diff --git a/src/pcache.h b/src/pcache.h index 3d24025ca9..73e6e26d40 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.10 2008/09/17 20:06:26 drh Exp $ +** @(#) $Id: pcache.h,v 1.11 2008/09/18 17:34:44 danielk1977 Exp $ */ #ifndef _PCACHE_H_ @@ -113,7 +113,7 @@ void sqlite3PcacheTruncate(PCache*, Pgno x); /* Routines used to implement transactions on memory-only databases. */ int sqlite3PcachePreserve(PgHdr*, int); /* Preserve current page content */ void sqlite3PcacheCommit(PCache*, int); /* Drop preserved copy */ -void sqlite3PcacheRollback(PCache*, int); /* Rollback to preserved copy */ +void sqlite3PcacheRollback(PCache*, int, void (*xReiniter)(PgHdr*)); /* Get a list of all dirty pages in the cache, sorted by page number */ PgHdr *sqlite3PcacheDirtyList(PCache*);