1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Call balance_shallower() from balance_nonroot() instead of from balance(). This simplifies coverage testing a bit. (CVS 6805)

FossilOrigin-Name: da9893e23caf89090c8b6563cb5f88d7dbf7c260
This commit is contained in:
danielk1977
2009-06-23 15:43:39 +00:00
parent 5c91b64e0d
commit cd581a7eff
3 changed files with 112 additions and 128 deletions

View File

@@ -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