]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a bug in the BTree balancing routine. (CVS 1387)
authordrh <drh@noemail.net>
Sun, 16 May 2004 16:24:36 +0000 (16:24 +0000)
committerdrh <drh@noemail.net>
Sun, 16 May 2004 16:24:36 +0000 (16:24 +0000)
FossilOrigin-Name: 6c73544bfacb891aae8d6124a2903ccff616494b

manifest
manifest.uuid
src/btree.c

index ef7110089be1275d6219667546735dda3ebb3dc3..9ad9a3996e0cdaefea6f7f2930e51a3964abaf35 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index f8e86d924a83e77abda7783671e1ae9a681b8784..2d51f8b3536472f3c5f95641414fa0e8f03731c1 100644 (file)
@@ -1 +1 @@
-5cba8a510c0aeae740db695e960c60e5f6c303f5
\ No newline at end of file
+6c73544bfacb891aae8d6124a2903ccff616494b
\ No newline at end of file
index b01fe2f083182090fd6959c1f5ed422e8a8a0f14..b4a5dcb84f3481212e5172827e67f7f594c73ff1 100644 (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 );