From c314dc7996406f39db0849e300024afc482f5b25 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 Jul 2009 11:52:34 +0000 Subject: [PATCH] Changes to btree.c in support of coverage testing. (CVS 6913) FossilOrigin-Name: 4cf23e9e860bd6245344884ec84f487fdf36f86f --- manifest | 12 ++--- manifest.uuid | 2 +- src/btree.c | 130 ++++++++++++++++++++++++++------------------------ 3 files changed, 75 insertions(+), 69 deletions(-) diff --git a/manifest b/manifest index bc9a46f8b6..9d5e459a75 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reverse\sthe\sorder\sof\stwo\sconditionals\sin\sa\stest\sin\sorder\sto\sachieve\scoverage\nof\sthem\sboth.\s\sAlso:\sclarifications\sto\scomments\sin\sbtree.c.\s(CVS\s6912) -D 2009-07-20T19:30:01 +C Changes\sto\sbtree.c\sin\ssupport\sof\scoverage\stesting.\s(CVS\s6913) +D 2009-07-21T11:52:35 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in df9359da7a726ccb67a45db905c5447d5c00c6ef F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -106,7 +106,7 @@ F src/auth.c 802a9439dfa0b8c208b10055cba400e82ef18025 F src/backup.c 6f1c2d9862c8a3feb7739dfcca02c1f5352e37f3 F src/bitvec.c cfbf6af5b0ababb4f06ed3e75c616dadaf47fcbd F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7 -F src/btree.c 123dd6ab71226ee9c41d6658fd11b2f7bed73f44 +F src/btree.c d5dde31b5743d90cee35071f4828ff38bdf90199 F src/btree.h e53a10fd31d16c60a86f03c9467a6f470aa3683b F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705 F src/build.c 867028ee9f63f7bc8eb8d4a720bb98cf9b9a12b4 @@ -741,7 +741,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746 -P 7dcf2a78727ce448d9d26bd6e2e23b553456ec54 -R ee81aff6c227cadf19a47a764a1a15d2 +P a159e9d24708dfe6c5a98d220e39f3b1b2a3d281 +R 1cd0f279a79b2344821cde6c251ba1a6 U drh -Z f9f7c95bd23663f1ba6a8b648cb1cde3 +Z b3b11d19f04a316773edec9a04d19c25 diff --git a/manifest.uuid b/manifest.uuid index 0eb9b914ee..f252768ab5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a159e9d24708dfe6c5a98d220e39f3b1b2a3d281 \ No newline at end of file +4cf23e9e860bd6245344884ec84f487fdf36f86f \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 506b479d55..f0161a0eb3 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.693 2009/07/20 19:30:01 drh Exp $ +** $Id: btree.c,v 1.694 2009/07/21 11:52:35 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -1128,6 +1128,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); + assert( nBytepBt->usableSize-8 ); nFrag = data[hdr+7]; assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); @@ -1184,10 +1185,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ /* Allocate memory from the gap in between the cell pointer array - ** and the cell content area. + ** and the cell content area. The btreeInitPage() call has already + ** validated the freelist. Given that the freelist is valid, there + ** is no way that the allocation can extend off the end of the page. + ** The assert() below verifies the previous sentence. */ top -= nByte; put2byte(&data[hdr+5], top); + assert( top+nByte <= pPage->pBt->usableSize ); *pIdx = top; return SQLITE_OK; } @@ -4960,8 +4965,10 @@ freepage_out: releasePage(pTrunk); return rc; } -static int freePage(MemPage *pPage){ - return freePage2(pPage->pBt, pPage, pPage->pgno); +static void freePage(MemPage *pPage, int *pRC){ + if( (*pRC)==SQLITE_OK ){ + *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); + } } /* @@ -5184,6 +5191,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ u8 *data; /* pPage->aData */ u8 *ptr; /* Used to move bytes around within data[] */ int rc; /* The return code */ + int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; @@ -5194,8 +5202,10 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ data = pPage->aData; ptr = &data[pPage->cellOffset + 2*idx]; pc = get2byte(ptr); - if( (pchdrOffset+6+pPage->childPtrSize) - || (pc+sz>pPage->pBt->usableSize) ){ + hdr = pPage->hdrOffset; + testcase( pc==get2byte(&data[hdr+5]) ); + testcase( pc+sz==pPage->pBt->usableSize ); + if( pc < get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -5209,7 +5219,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ ptr[1] = ptr[3]; } pPage->nCell--; - put2byte(&data[pPage->hdrOffset+3], pPage->nCell); + put2byte(&data[hdr+3], pPage->nCell); pPage->nFree += 2; } @@ -5281,11 +5291,10 @@ static void insertCell( ins = cellOffset + 2*i; rc = allocateSpace(pPage, sz, &idx); if( rc ){ *pRC = rc; return; } - assert( idx>=end+2 ); - if( idx+sz > pPage->pBt->usableSize ){ - *pRC = SQLITE_CORRUPT_BKPT; - return; - } + /* The allocateSpace() routine guarantees the following two properties + ** if it returns success */ + assert( idx >= end+2 ); + assert( idx+sz <= pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); @@ -5372,7 +5381,7 @@ static void assemblePage( ** tree, in other words, when the new entry will become the largest ** entry in the tree. ** -** Instead of trying balance the 3 right-most leaf pages, just add +** Instead of trying to balance the 3 right-most leaf pages, just add ** a new page to the right-hand side and put the one new entry in ** that page. This leaves the right side of the tree somewhat ** unbalanced. But odds are that we will be inserting new entries @@ -5399,7 +5408,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); - if( pPage->nCell<=0 ) return SQLITE_CORRUPT_BKPT; + if( NEVER(pPage->nCell<=0) ) return SQLITE_CORRUPT_BKPT; /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -5528,37 +5537,40 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){ ** the balance_shallower() and balance_deeper() procedures, neither of ** which are called often under normal circumstances. */ -static int copyNodeContent(MemPage *pFrom, MemPage *pTo){ - BtShared * const pBt = pFrom->pBt; - u8 * const aFrom = pFrom->aData; - u8 * const aTo = pTo->aData; - int const iFromHdr = pFrom->hdrOffset; - int const iToHdr = ((pTo->pgno==1) ? 100 : 0); - int rc = SQLITE_OK; - int iData; - - assert( pFrom->isInit ); - assert( pFrom->nFree>=iToHdr ); - assert( get2byte(&aFrom[iFromHdr+5])<=pBt->usableSize ); - - /* Copy the b-tree node content from page pFrom to page pTo. */ - iData = get2byte(&aFrom[iFromHdr+5]); - memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); - memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); - - /* Reinitialize page pTo so that the contents of the MemPage structure - ** match the new data. The initialization of pTo "cannot" fail, as the - ** data copied from pFrom is known to be valid. */ - pTo->isInit = 0; - TESTONLY(rc = ) btreeInitPage(pTo); - assert( rc==SQLITE_OK ); - - /* If this is an auto-vacuum database, update the pointer-map entries - ** for any b-tree or overflow pages that pTo now contains the pointers to. */ - if( ISAUTOVACUUM ){ - rc = setChildPtrmaps(pTo); +static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ + if( (*pRC)==SQLITE_OK ){ + BtShared * const pBt = pFrom->pBt; + u8 * const aFrom = pFrom->aData; + u8 * const aTo = pTo->aData; + int const iFromHdr = pFrom->hdrOffset; + int const iToHdr = ((pTo->pgno==1) ? 100 : 0); + TESTONLY(int rc;) + int iData; + + + assert( pFrom->isInit ); + assert( pFrom->nFree>=iToHdr ); + assert( get2byte(&aFrom[iFromHdr+5])<=pBt->usableSize ); + + /* Copy the b-tree node content from page pFrom to page pTo. */ + iData = get2byte(&aFrom[iFromHdr+5]); + memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); + memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); + + /* Reinitialize page pTo so that the contents of the MemPage structure + ** match the new data. The initialization of pTo "cannot" fail, as the + ** data copied from pFrom is known to be valid. */ + pTo->isInit = 0; + TESTONLY(rc = ) btreeInitPage(pTo); + assert( rc==SQLITE_OK ); + + /* If this is an auto-vacuum database, update the pointer-map entries + ** for any b-tree or overflow pages that pTo now contains the pointers to. + */ + if( ISAUTOVACUUM ){ + *pRC = setChildPtrmaps(pTo); + } } - return rc; } /* @@ -5927,7 +5939,7 @@ static int balance_nonroot( /* Free any old pages that were not reused as new pages. */ while( inFree == (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) ); - if( SQLITE_OK==(rc = copyNodeContent(apNew[0], pParent)) ){ - rc = freePage(apNew[0]); - } + copyNodeContent(apNew[0], pParent, &rc); + freePage(apNew[0], &rc); }else if( ISAUTOVACUUM ){ /* Fix the pointer-map entries for all the cells that were shifted around. ** There are several different types of pointer-map entries that need to @@ -6117,7 +6128,7 @@ static int balance_nonroot( int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1); j = 0; /* Current 'old' sibling page */ k = 0; /* Current 'new' sibling page */ - for(i=0; ipDbPage); if( rc==SQLITE_OK ){ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); - if( rc==SQLITE_OK ){ - rc = copyNodeContent(pRoot, pChild); - if( ISAUTOVACUUM ){ - ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); - } + copyNodeContent(pRoot, pChild, &rc); + if( ISAUTOVACUUM ){ + ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); } } if( rc ){ @@ -6846,7 +6855,7 @@ static int clearDatabasePage( *pnChange += pPage->nCell; } if( freePageFlag ){ - rc = freePage(pPage); + freePage(pPage, &rc); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[0] | PTF_LEAF); } @@ -6941,7 +6950,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ if( iTable>1 ){ #ifdef SQLITE_OMIT_AUTOVACUUM - rc = freePage(pPage); + freePage(pPage, &rc); releasePage(pPage); #else if( pBt->autoVacuum ){ @@ -6952,7 +6961,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ /* If the table being dropped is the table with the largest root-page ** number in the database, put the root page on the free list. */ - rc = freePage(pPage); + freePage(pPage, &rc); releasePage(pPage); if( rc!=SQLITE_OK ){ return rc; @@ -6974,10 +6983,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ return rc; } rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - rc = freePage(pMove); + freePage(pMove, &rc); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; @@ -6999,7 +7005,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); }else{ - rc = freePage(pPage); + freePage(pPage, &rc); releasePage(pPage); } #endif