Fix a bug in the BTree balancing routine. (CVS 1387)

FossilOrigin-Name: 6c73544bfacb891aae8d6124a2903ccff616494b
This commit is contained in:
drh 2004-05-16 16:24:36 +00:00
parent f9dd2c2e04
commit 96f5b7672d
3 changed files with 53 additions and 17 deletions

View File

@ -1,5 +1,5 @@
C Fix\stwo\sbugs\sthat\swere\scausing\slots\sof\stests\sto\sfail.\s(CVS\s1386)
D 2004-05-16T11:57:28
C Fix\sa\sbug\sin\sthe\sBTree\sbalancing\sroutine.\s(CVS\s1387)
D 2004-05-16T16:24:37
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c 05aefd3eec56690d9731bf090203b57d8ae4bf19
F src/btree.c bf8d9592b66fb9ba89a5be13fd99a7d8b8a67d7f
F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
F src/build.c fd37eda7100d2507c647df43f9f3ce56a2f59ab4
@ -192,7 +192,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P a4af838f8d1b81ec6c8db97655c6876aca0738d9
R a401956638c6d55c9de15d1b9c3564d6
U danielk1977
Z d5bacfd02a451c5d78cf0909159519e5
P 5cba8a510c0aeae740db695e960c60e5f6c303f5
R 25cd950de731900e925b6b5361c9fbb9
U drh
Z fd6768d10af70b66f5ace479a66938d7

View File

@ -1 +1 @@
5cba8a510c0aeae740db695e960c60e5f6c303f5
6c73544bfacb891aae8d6124a2903ccff616494b

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.140 2004/05/15 00:29:24 drh Exp $
** $Id: btree.c,v 1.141 2004/05/16 16:24:37 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -2812,7 +2812,8 @@ static int balance(MemPage *pPage){
assert( pPage->isInit );
assert( sqlite3pager_iswriteable(pPage->aData) );
pBt = pPage->pBt;
if( !pPage->isOverfull && pPage->nFree<pBt->usableSize*2/3 && pPage->nCell>=2){
if( !pPage->isOverfull && pPage->nFree<pBt->usableSize*2/3
&& pPage->nCell>=2){
relinkCellList(pPage);
return SQLITE_OK;
}
@ -3004,10 +3005,13 @@ static int balance(MemPage *pPage){
**
** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied
** into aSpace[]. In this wall, all cells in apCell[] are without
** into aSpace[]. In this way, all cells in apCell[] are without
** child pointers. If siblings are not leaves, then all cell in
** apCell[] include child pointers. Either way, all cells in apCell[]
** are alike.
**
** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf.
** leafData: 1 if pPage holds key+data and pParent holds only keys.
*/
nCell = 0;
leafCorrection = pPage->leaf*4;
@ -3022,6 +3026,11 @@ static int balance(MemPage *pPage){
if( i<nOld-1 ){
int sz = cellSize(pParent, apDiv[i]);
if( leafData ){
/* With the LEAFDATA flag, pParent cells hold only INTKEYs that
** are duplicates of keys on the child pages. We need to remove
** the divider cells from pParent, but the dividers cells are not
** added to apCell[] because they are duplicates of child cells.
*/
dropCell(pParent, nxDiv, sz);
}else{
u8 *pTemp;
@ -3054,8 +3063,14 @@ static int balance(MemPage *pPage){
** in apCell[] of the cell that divides page i from page i+1.
** cntNew[k] should equal nCell.
**
** This little patch of code is critical for keeping the tree
** balanced.
** Values computed by this block:
**
** k: The total number of sibling pages
** szNew[i]: Spaced used on the i-th sibling page.
** cntNew[i]: Index in apCell[] and szCell[] for the first cell to
** the right of the i-th sibling page.
** usableSpace: Number of bytes of space available on each sibling.
**
*/
usableSpace = pBt->usableSize - 10 + leafCorrection;
for(subtotal=k=i=0; i<nCell; i++){
@ -3071,13 +3086,34 @@ static int balance(MemPage *pPage){
szNew[k] = subtotal;
cntNew[k] = nCell;
k++;
/*
** The packing computed by the previous block is biased toward the siblings
** on the left side. The left siblings are always nearly full, while the
** right-most sibling might be nearly empty. This block of code attempts
** to adjust the packing of siblings to get a better balance.
**
** This adjustment is more than an optimization. The packing above might
** be so out of balance as to be illegal. For example, the right-most
** sibling might be completely empty. This adjustment is not optional.
*/
for(i=k-1; i>0; i--){
while( szNew[i]<usableSpace/2 ){
int szRight = szNew[i]; /* Size of sibling on the right */
int szLeft = szNew[i-1]; /* Size of sibling on the left */
int r; /* Index of right-most cell in left sibling */
int d; /* Index of first cell to the left of right sibling */
r = cntNew[i-1] - 1;
d = r + 1 - leafData;
while( szRight==0 || szRight+szCell[d]<=szLeft-szCell[r] ){
szRight += szCell[d];
szLeft -= szCell[r];
cntNew[i-1]--;
assert( cntNew[i-1]>0 );
szNew[i] += szCell[cntNew[i-1]];
szNew[i-1] -= szCell[cntNew[i-1]-1];
r = cntNew[i-1] - 1;
d = r + 1 - leafData;
}
szNew[i] = szRight;
szNew[i-1] = szLeft;
}
assert( cntNew[0]>0 );