diff --git a/manifest b/manifest index e823d8d455..208960f7b2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\sconfigure\sscript\sfor\sversion\s3.6.16\s(CVS\s6804) -D 2009-06-23T14:39:53 +C Call\sbalance_shallower()\sfrom\sbalance_nonroot()\sinstead\sof\sfrom\sbalance().\sThis\ssimplifies\scoverage\stesting\sa\sbit.\s(CVS\s6805) +D 2009-06-23T15:43:40 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 8b8fb7823264331210cddf103831816c286ba446 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -106,7 +106,7 @@ F src/auth.c 98db07c2088455797678eb1031f42d4d94d18a71 F src/backup.c ff50af53184a5fd7bdee4d620b5dabef74717c79 F src/bitvec.c 0ef0651714728055d43de7a4cdd95e703fac0119 F src/btmutex.c 9b899c0d8df3bd68f527b0afe03088321b696d3c -F src/btree.c 732191303402ec6ab0dd7062d07a4bb6a6c51c0c +F src/btree.c 13e33e85103c19b114ce1cfdedd2d3e2647de290 F src/btree.h f70b694e8c163227369a66863b01fbff9009f323 F src/btreeInt.h 7267e965e34314aa2bddbdde268b31e1034eda9c F src/build.c e98868af6a04c8d7191c39fd05c69da34a8d9c68 @@ -737,7 +737,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746 -P 207c4a02ba4dd950948367c91b4a73209d62da41 -R b922ac03d2a566045ccf7938c02d6e2d -U drh -Z 86414292e77851f843aee830f2b6b2fd +P b614e554f7ebaef9cb1718b617e020e532568bbb +R 21b91543d4279dc39963961cdf36484b +U danielk1977 +Z 3fbc90fe51d8a097f9b06b0d67881dff diff --git a/manifest.uuid b/manifest.uuid index 5041d95e71..8911e3e3d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b614e554f7ebaef9cb1718b617e020e532568bbb \ No newline at end of file +da9893e23caf89090c8b6563cb5f88d7dbf7c260 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 2cecde08c7..d4e64a3363 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.639 2009/06/23 11:22:29 danielk1977 Exp $ +** $Id: btree.c,v 1.640 2009/06/23 15:43:40 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -5338,6 +5338,96 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){ } #endif +/* +** This function is used to copy the contents of the b-tree node stored +** on page pFrom to page pTo. If page pFrom was not a leaf page, then +** the pointer-map entries for each child page are updated so that the +** parent page stored in the pointer map is page pTo. If pFrom contained +** any cells with overflow page pointers, then the corresponding pointer +** map entries are also updated so that the parent page is page pTo. +** +** If pFrom is currently carrying any overflow cells (entries in the +** MemPage.aOvfl[] array), they are not copied to pTo. +** +** Before returning, page pTo is reinitialized using sqlite3BtreeInitPage(). +** +** The performance of this function is not critical. It is only used by +** 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 = ) sqlite3BtreeInitPage(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); + } + return rc; +} + +/* +** This routine is called on the root page of a btree when the root +** page contains no cells. This is an opportunity to make the tree +** shallower by one level. +*/ +static int balance_shallower(MemPage *pRoot, MemPage *pChild){ + /* The root page is empty but has one child. Transfer the + ** information from that one child into the root page if it + ** will fit. This reduces the depth of the tree by one. + ** + ** If the root page is page 1, it has less space available than + ** its child (due to the 100 byte header that occurs at the beginning + ** of the database fle), so it might not be able to hold all of the + ** information currently contained in the child. If this is the + ** case, then do not do the transfer. Leave page 1 empty except + ** for the right-pointer to the child page. The child page becomes + ** the virtual root of the tree. + */ + int rc = SQLITE_OK; /* Return code */ + int const hdr = pRoot->hdrOffset; /* Offset of root page header */ + + assert( sqlite3_mutex_held(pRoot->pBt->mutex) ); + assert( pRoot->nCell==0 ); + assert( pChild->pgno==get4byte(&pRoot->aData[pRoot->hdrOffset+8]) ); + assert( hdr==0 || pRoot->pgno==1 ); + + if( pChild->nFree>=hdr ){ + if( hdr ){ + rc = defragmentPage(pChild); + } + if( rc==SQLITE_OK ){ + rc = copyNodeContent(pChild, pRoot); + } + if( rc==SQLITE_OK ){ + rc = freePage(pChild); + } + } + + return rc; +} /* ** This routine redistributes cells on the iParentIdx'th child of pParent @@ -5382,7 +5472,8 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){ static int balance_nonroot( MemPage *pParent, /* Parent page of siblings being balanced */ int iParentIdx, /* Index of "the page" in pParent */ - u8 *aOvflSpace /* page-size bytes of space for parent ovfl */ + u8 *aOvflSpace, /* page-size bytes of space for parent ovfl */ + int isRoot /* True if pParent is a root-page */ ){ BtShared *pBt; /* The whole database */ int nCell = 0; /* Number of cells in apCell[] */ @@ -5939,6 +6030,16 @@ static int balance_nonroot( assert( pParent->isInit ); TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", nOld, nNew, nCell)); + + if( rc==SQLITE_OK && pParent->nCell==0 && isRoot ){ + /* The root page of the b-tree now contains no cells. If the root-page + ** is not also a leaf page, it will have a single child page. Call + ** balance_shallower to attempt to copy the contents of the single + ** child-page into the root page (this may not be possible if the + ** root page is page 1). */ + assert( nNew==1 ); + rc = balance_shallower(pParent, apNew[0]); + } /* ** Cleanup before returning. @@ -5955,109 +6056,6 @@ balance_cleanup: return rc; } -/* -** This function is used to copy the contents of the b-tree node stored -** on page pFrom to page pTo. If page pFrom was not a leaf page, then -** the pointer-map entries for each child page are updated so that the -** parent page stored in the pointer map is page pTo. If pFrom contained -** any cells with overflow page pointers, then the corresponding pointer -** map entries are also updated so that the parent page is page pTo. -** -** If pFrom is currently carrying any overflow cells (entries in the -** MemPage.aOvfl[] array), they are not copied to pTo. -** -** Before returning, page pTo is reinitialized using sqlite3BtreeInitPage(). -** -** The performance of this function is not critical. It is only used by -** 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 = ) sqlite3BtreeInitPage(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); - } - return rc; -} - -/* -** This routine is called on the root page of a btree when the root -** page contains no cells. This is an opportunity to make the tree -** shallower by one level. -*/ -static int balance_shallower(MemPage *pRoot){ - /* The root page is empty but has one child. Transfer the - ** information from that one child into the root page if it - ** will fit. This reduces the depth of the tree by one. - ** - ** If the root page is page 1, it has less space available than - ** its child (due to the 100 byte header that occurs at the beginning - ** of the database fle), so it might not be able to hold all of the - ** information currently contained in the child. If this is the - ** case, then do not do the transfer. Leave page 1 empty except - ** for the right-pointer to the child page. The child page becomes - ** the virtual root of the tree. - */ - int rc = SQLITE_OK; /* Return code */ - int const hdr = pRoot->hdrOffset; /* Offset of root page header */ - MemPage *pChild; /* Only child of pRoot */ - Pgno const pgnoChild = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); - - assert( pRoot->nCell==0 ); - assert( sqlite3_mutex_held(pRoot->pBt->mutex) ); - assert( !pRoot->leaf ); - assert( pgnoChild>0 ); - assert( pgnoChild<=pagerPagecount(pRoot->pBt) ); - assert( hdr==0 || pRoot->pgno==1 ); - - rc = sqlite3BtreeGetPage(pRoot->pBt, pgnoChild, &pChild, 0); - if( rc==SQLITE_OK ){ - if( pChild->nFree>=hdr ){ - if( hdr ){ - rc = defragmentPage(pChild); - } - if( rc==SQLITE_OK ){ - rc = copyNodeContent(pChild, pRoot); - } - if( rc==SQLITE_OK ){ - rc = freePage(pChild); - } - }else{ - /* The child has more information that will fit on the root. - ** The tree is already balanced. Do nothing. */ - TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); - } - releasePage(pChild); - } - - return rc; -} - /* ** This function is called when the root page of a b-tree structure is @@ -6126,7 +6124,6 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ ** routine. Balancing routines are: ** ** balance_quick() -** balance_shallower() ** balance_deeper() ** balance_nonroot() ** @@ -6165,19 +6162,6 @@ static int balance(BtCursor *pCur){ } VVA_ONLY( pCur->pagesShuffled = 1 ); }else{ - /* The root page of the b-tree is now empty. If the root-page is not - ** also a leaf page, it will have a single child page. Call - ** balance_shallower to attempt to copy the contents of the single - ** child-page into the root page (this may not be possible if the - ** root page is page 1). - ** - ** Whether or not this is possible , the tree is now balanced. - ** Therefore is no next iteration of the do-loop. - */ - if( pPage->nCell==0 && !pPage->leaf ){ - rc = balance_shallower(pPage); - VVA_ONLY( pCur->pagesShuffled = 1 ); - } break; } }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ @@ -6231,7 +6215,7 @@ static int balance(BtCursor *pCur){ ** pSpace buffer passed to the latter call to balance_nonroot(). */ u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); - rc = balance_nonroot(pParent, iIdx, pSpace); + rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1); if( pFree ){ /* If pFree is not NULL, it points to the pSpace buffer used ** by a previous call to balance_nonroot(). Its contents are