]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Begin trying to get integrity checking working on the new btree.c. (CVS 1329)
authordrh <drh@noemail.net>
Sun, 9 May 2004 01:35:05 +0000 (01:35 +0000)
committerdrh <drh@noemail.net>
Sun, 9 May 2004 01:35:05 +0000 (01:35 +0000)
FossilOrigin-Name: 499569daa6a3aed6609bcb1e11a3d231e13f4f9c

manifest
manifest.uuid
src/btree.c
test/btree.test

index 2a3b2909a444239aa27265947b7af684b1b07f33..639f6937b21259b5e40535489f0f67b9ad731c2a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C All\stests\sin\sbtree.test\snow\spass\s(but\sonly\sbecause\sI\scommented\sout\sthe\nbtree_integrity_check\stest.)\s(CVS\s1328)
-D 2004-05-09T00:40:52
+C Begin\strying\sto\sget\sintegrity\schecking\sworking\son\sthe\snew\sbtree.c.\s(CVS\s1329)
+D 2004-05-09T01:35:06
 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 fa9a58234406d84eeb900517d0c0adc4b2da051a
 F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653
-F src/btree.c 927ac9e162c4e97151ba27e0723babda761c58c0
+F src/btree.c 4c9b4a68f5e0c57382fca08d73426ca5af55c80f
 F src/btree.h 825034a68947baf99507f04f318f417013dcd3a3
 F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561
 F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210
@@ -75,7 +75,7 @@ F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185
 F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
 F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
-F test/btree.test faa386a7342b865a87f042db6bd5e5a9486259d6
+F test/btree.test c4399a76bcc6d2c84b156e3a8fef29879d2e54c4
 F test/btree2.test 2ff77e0218e5f55ff5a85874f3e15c7859e3ac26
 F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665
 F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac
@@ -190,7 +190,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P e9f84ff3fe45a014ab60fabbfd91d19e6d353477
-R 0b200f4f3f4df21ad25f92660d903a27
+P ee706e9c74c3fb32fc3369db226fad9ed4db7596
+R cfbf2d289e390333f8744d3cd9325bcf
 U drh
-Z 2b1cbf8bcd73f8c7eab6d96289461ca5
+Z d0e25b8c23267f444288dc2922ce4fd0
index b2098afa3de84e3127323f60a10efe12b02023c6..675091aec8827b441b921cd2c9df3cf94a1177c9 100644 (file)
@@ -1 +1 @@
-ee706e9c74c3fb32fc3369db226fad9ed4db7596
\ No newline at end of file
+499569daa6a3aed6609bcb1e11a3d231e13f4f9c
\ No newline at end of file
index f19aa200524f12ba4519d5abbe760ba51c4d34a1..c79a6b3d9dc703693460385b1ed215980aff3489 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.117 2004/05/09 00:40:52 drh Exp $
+** $Id: btree.c,v 1.118 2004/05/09 01:35:06 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -218,7 +218,6 @@ struct MemPage {
   u8 leaf;                       /* True if leaf flag is set */
   u8 zeroData;                   /* True if zero data flag is set */
   u8 hdrOffset;                  /* 100 for page 1.  0 otherwise */
-  u8 needRelink;                 /* True if need to run relinkCellList() */
   int idxParent;                 /* Index in pParent->aCell[] of this node */
   int nFree;                     /* Number of free bytes on the page */
   int nCell;                     /* Number of entries on this page */
@@ -378,78 +377,6 @@ static int cellSize(MemPage *pPage, unsigned char *pCell){
   return n + nPayload;
 }
 
-/*
-** Do sanity checking on a page.  Throw an exception if anything is
-** not right.
-**
-** This routine is used for internal error checking only.  It is omitted
-** from most builds.
-*/
-#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
-static void _pageIntegrity(MemPage *pPage){
-  int pageSize;
-  u8 *data;
-  int i, idx, c, pc, hdr, nFree;
-  u8 used[MX_PAGE_SIZE];
-
-  pageSize = pPage->pBt->pageSize;
-  assert( pPage->aData==&((unsigned char*)pPage)[-pageSize] );
-  hdr = pPage->hdrOffset;
-  assert( hdr==(pPage->pgno==1 ? 100 : 0) );
-  assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
-  c = pPage->aData[hdr];
-  if( pPage->isInit ){
-    assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
-    assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
-    assert( pPage->intKey == ((c & PTF_INTKEY)!=0) );
-  }
-  data = pPage->aData;
-  memset(used, 0, pageSize);
-  for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
-  nFree = 0;
-  pc = get2byte(&data[hdr+1]);
-  while( pc ){
-    int size;
-    assert( pc>0 && pc<pageSize-4 );
-    size = get2byte(&data[pc+2]);
-    assert( pc+size<=pageSize );
-    nFree += size;
-    for(i=pc; i<pc+size; i++){
-      assert( used[i]==0 );
-      used[i] = 1;
-    }
-    pc = get2byte(&data[pc]);
-  }
-  assert( pPage->isInit==0 || pPage->nFree==nFree+data[hdr+5] );
-  idx = 0;
-  pc = get2byte(&data[hdr+3]);
-  while( pc ){
-    int size;
-    assert( pPage->isInit==0 || idx<pPage->nCell );
-    assert( pc>0 && pc<pageSize-4 );
-    assert( pPage->isInit==0 || pPage->aCell[idx]==&data[pc] );
-    size = cellSize(pPage, &data[pc]);
-    assert( pc+size<=pageSize );
-    for(i=pc; i<pc+size; i++){
-      assert( used[i]==0 );
-      used[i] = 1;
-    }
-    pc = get2byte(&data[pc]);
-    idx++;
-  }
-  assert( idx==pPage->nCell );
-  nFree = 0;
-  for(i=0; i<pageSize; i++){
-    assert( used[i]<=1 );
-    if( used[i]==0 ) nFree++;
-  }
-  assert( nFree==data[hdr+5] );
-}
-#define pageIntegrity(X) _pageIntegrity(X)
-#else
-# define pageIntegrity(X)
-#endif
-
 /*
 ** Defragment the page given.  All Cells are moved to the
 ** beginning of the page and all free space is collected 
@@ -465,8 +392,6 @@ static void defragmentPage(MemPage *pPage){
   assert( sqlite3pager_iswriteable(pPage->aData) );
   assert( pPage->pBt!=0 );
   assert( pPage->pBt->pageSize <= MX_PAGE_SIZE );
-  assert( !pPage->needRelink );
-  assert( !pPage->isOverfull );
   oldPage = pPage->aData;
   hdr = pPage->hdrOffset;
   addr = 3+hdr;
@@ -483,10 +408,9 @@ static void defragmentPage(MemPage *pPage){
     size = cellSize(pPage, &oldPage[pc]);
     memcpy(&newPage[n], &oldPage[pc], size);
     put2byte(&newPage[addr],n);
-    assert( pPage->aCell[i]==&oldPage[pc] );
     pPage->aCell[i++] = &oldPage[n];
-    addr = n;
     n += size;
+    addr = pc;
     pc = get2byte(&oldPage[pc]);
   }
   assert( i==pPage->nCell );
@@ -675,12 +599,13 @@ static int initPage(
   assert( pParent==0 || pParent->pBt==pPage->pBt );
   assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
   assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] );
-  assert( pPage->pParent==0 || pPage->pParent==pParent );
-  if( pPage->pParent==0 && pParent!=0 ){
-    pPage->pParent = pParent;
+  assert( pPage->isInit==0 || pPage->pParent==pParent );
+  if( pPage->isInit ) return SQLITE_OK;
+  assert( pPage->pParent==0 );
+  pPage->pParent = pParent;
+  if( pParent ){
     sqlite3pager_ref(pParent->aData);
   }
-  if( pPage->isInit ) return SQLITE_OK;
   pPage->nCell = pPage->nCellAlloc = 0;
   assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
   hdr = pPage->hdrOffset;
@@ -690,7 +615,6 @@ static int initPage(
   pPage->zeroData = (c & PTF_ZERODATA)!=0;
   pPage->leaf = (c & PTF_LEAF)!=0;
   pPage->isOverfull = 0;
-  pPage->needRelink = 0;
   pPage->idxShift = 0;
   pageSize = pPage->pBt->pageSize;
 
@@ -733,7 +657,6 @@ static int initPage(
   }
 
   pPage->isInit = 1;
-  pageIntegrity(pPage);
   return SQLITE_OK;
 }
 
@@ -747,8 +670,6 @@ static void zeroPage(MemPage *pPage, int flags){
   int hdr = pPage->hdrOffset;
   int first;
 
-  assert( sqlite3pager_pagenumber(data)==pPage->pgno );
-  assert( &data[pBt->pageSize] == (unsigned char*)pPage );
   assert( sqlite3pager_iswriteable(data) );
   memset(&data[hdr], 0, pBt->pageSize - hdr);
   data[hdr] = flags;
@@ -764,11 +685,6 @@ static void zeroPage(MemPage *pPage, int flags){
   pPage->leaf = (flags & PTF_LEAF)!=0;
   pPage->zeroData = (flags & PTF_ZERODATA)!=0;
   pPage->hdrOffset = hdr;
-  pPage->isOverfull = 0;
-  pPage->needRelink = 0;
-  pPage->idxShift = 0;
-  pPage->isInit = 1;
-  pageIntegrity(pPage);
 }
 
 /*
@@ -829,7 +745,6 @@ static void releasePage(MemPage *pPage){
 */
 static void pageDestructor(void *pData){
   MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE];
-  assert( pPage->isInit==0 || pPage->needRelink==0 );
   if( pPage->pParent ){
     MemPage *pParent = pPage->pParent;
     pPage->pParent = 0;
@@ -1081,8 +996,7 @@ static void invalidateCursors(Btree *pBt){
   BtCursor *pCur;
   for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
     MemPage *pPage = pCur->pPage;
-    if( pPage /* && !pPage->isInit */ ){
-      pageIntegrity(pPage);
+    if( pPage && !pPage->isInit ){
       releasePage(pPage);
       pCur->pPage = 0;
       pCur->isValid = 0;
@@ -1091,24 +1005,6 @@ static void invalidateCursors(Btree *pBt){
   }
 }
 
-#ifdef SQLITE_TEST
-/*
-** Print debugging information about all cursors to standard output.
-*/
-void sqlite3BtreeCursorList(Btree *pBt){
-  BtCursor *pCur;
-  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-    MemPage *pPage = pCur->pPage;
-    char *zMode = pCur->wrFlag ? "rw" : "ro";
-    printf("CURSOR %08x rooted at %4d(%s) currently at %d.%d%s\n",
-       (int)pCur, pCur->pgnoRoot, zMode,
-       pPage ? pPage->pgno : 0, pCur->idx,
-       pCur->isValid ? "" : " eof"
-    );
-  }
-}
-#endif
-
 /*
 ** Rollback the transaction in progress.  All cursors will be
 ** invalided by this operation.  Any attempt to use a cursor
@@ -1371,7 +1267,6 @@ int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){
     *pSize = 0;
   }else{
     pPage = pCur->pPage;
-    pageIntegrity(pPage);
     assert( pPage!=0 );
     assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
     cell = pPage->aCell[pCur->idx];
@@ -1414,7 +1309,6 @@ static int getPayload(
   assert( pCur->isValid );
   pBt = pCur->pBt;
   pPage = pCur->pPage;
-  pageIntegrity(pPage);
   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
   aPayload = pPage->aCell[pCur->idx];
   aPayload += 2;  /* Skip the next cell index */
@@ -1537,7 +1431,6 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){
   assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
   pBt = pCur->pBt;
   pPage = pCur->pPage;
-  pageIntegrity(pPage);
   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
   assert( pPage->intKey==0 );
   aPayload = pPage->aCell[pCur->idx];
@@ -1574,7 +1467,6 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
   pPage = pCur->pPage;
   assert( pPage!=0 );
   assert( pPage->isInit );
-  pageIntegrity(pPage);
   if( pPage->zeroData ){
     *pSize = 0;
   }else{
@@ -1624,7 +1516,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
   assert( pCur->isValid );
   rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
   if( rc ) return rc;
-  pageIntegrity(pNewPage);
   pNewPage->idxParent = pCur->idx;
   pOldPage = pCur->pPage;
   pOldPage->idxShift = 0;
@@ -1648,9 +1539,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
 */
 static int isRootPage(MemPage *pPage){
   MemPage *pParent = pPage->pParent;
-  if( pParent==0 ) return 1;
-  if( pParent->pgno>1 ) return 0;
-  if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
+  assert( pParent==0 || pParent->isInit );
+  if( pParent==0 || (pParent->pgno==1 && pParent->nCell==0) ) return 1;
   return 0;
 }
 
@@ -1672,10 +1562,8 @@ static void moveToParent(BtCursor *pCur){
   pPage = pCur->pPage;
   assert( pPage!=0 );
   assert( !isRootPage(pPage) );
-  pageIntegrity(pPage);
   pParent = pPage->pParent;
   assert( pParent!=0 );
-  pageIntegrity(pParent);
   idxParent = pPage->idxParent;
   sqlite3pager_ref(pParent->aData);
   oldPgno = pPage->pgno;
@@ -1725,7 +1613,6 @@ static int moveToRoot(BtCursor *pCur){
     return rc;
   }
   releasePage(pCur->pPage);
-  pageIntegrity(pRoot);
   pCur->pPage = pRoot;
   pCur->idx = 0;
   if( pRoot->nCell==0 && !pRoot->leaf ){
@@ -1874,7 +1761,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
     int c = -1;  /* pRes return if table is empty must be -1 */
     lwr = 0;
     upr = pPage->nCell-1;
-    pageIntegrity(pPage);
     while( lwr<=upr ){
       void *pCellKey;
       u64 nCellKey;
@@ -2309,16 +2195,14 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
   if( pgno==0 ) return;
   assert( pBt->pPager!=0 );
   aData = sqlite3pager_lookup(pBt->pPager, pgno);
-  if( aData ){
-    pThis = (MemPage*)&aData[pBt->pageSize];
-    if( pThis->isInit ){
-      if( pThis->pParent!=pNewParent ){
-        if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
-        pThis->pParent = pNewParent;
-        if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
-      }
-      pThis->idxParent = idx;
-    }
+  pThis = (MemPage*)&aData[pBt->pageSize];
+  if( pThis && pThis->isInit ){
+    if( pThis->pParent!=pNewParent ){
+      if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
+      pThis->pParent = pNewParent;
+      if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
+    }
+    pThis->idxParent = idx;
     sqlite3pager_unref(aData);
   }
 }
@@ -2354,45 +2238,25 @@ static void reparentChildPages(MemPage *pPage){
 **
 ** "sz" must be the number of bytes in the cell.
 **
-** Try to maintain the integrity of the linked list of cells.  But if
-** the cell being inserted does not fit on the page, this will not be
-** possible.  If the linked list is not maintained, then just update
-** pPage->aCell[] and set the pPage->needRelink flag so that we will
-** know to rebuild the linked list later.
+** Do not bother maintaining the integrity of the linked list of Cells.
+** Only the pPage->aCell[] array is important.  The relinkCellList() 
+** routine will be called soon after this routine in order to rebuild 
+** the linked list.
 */
 static void dropCell(MemPage *pPage, int idx, int sz){
   int j, pc;
-  u8 *data;
   assert( idx>=0 && idx<pPage->nCell );
   assert( sz==cellSize(pPage, pPage->aCell[idx]) );
   assert( sqlite3pager_iswriteable(pPage->aData) );
   assert( pPage->aCell[idx]>=pPage->aData );
   assert( pPage->aCell[idx]<&pPage->aData[pPage->pBt->pageSize-sz] );
-  data = pPage->aData;
-  pc = Addr(pPage->aCell[idx]) - Addr(data);
+  pc = Addr(pPage->aCell[idx]) - Addr(pPage->aData);
   assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->pageSize );
   freeSpace(pPage, pc, sz);
   for(j=idx; j<pPage->nCell-1; j++){
     pPage->aCell[j] = pPage->aCell[j+1];
   }
   pPage->nCell--;
-  if( !pPage->isOverfull && !pPage->needRelink ){
-    u8 *pPrev;
-    if( idx==0 ){
-      pPrev = &data[pPage->hdrOffset+3];
-    }else{
-      pPrev = pPage->aCell[idx-1];
-    }
-    if( idx<pPage->nCell ){
-      pc = Addr(pPage->aCell[idx]) - Addr(data);
-    }else{
-      pc = 0;
-    }
-    put2byte(pPrev, pc);
-    pageIntegrity(pPage);
-  }else{
-    pPage->needRelink = 1;
-  }
   pPage->idxShift = 1;
 }
 
@@ -2404,18 +2268,17 @@ static void dropCell(MemPage *pPage, int idx, int sz){
 ** will not fit, then just make pPage->aCell[i] point to the content
 ** and set pPage->isOverfull.  
 **
-** Try to maintain the integrity of the linked list of cells.  But if
-** the cell being inserted does not fit on the page, this will not be
-** possible.  If the linked list is not maintained, then just update
-** pPage->aCell[] and set the pPage->needRelink flag so that we will
-** know to rebuild the linked list later.
+** Do not bother maintaining the integrity of the linked list of Cells.
+** Only the pPage->aCell[] array is important.  The relinkCellList() 
+** routine will be called soon after this routine in order to rebuild 
+** the linked list.
 */
 static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
   int idx, j;
   assert( i>=0 && i<=pPage->nCell );
   assert( sz==cellSize(pPage, pCell) );
   assert( sqlite3pager_iswriteable(pPage->aData) );
-  idx = pPage->needRelink ? 0 : allocateSpace(pPage, sz);
+  idx = allocateSpace(pPage, sz);
   resizeCellArray(pPage, pPage->nCell+1);
   for(j=pPage->nCell; j>i; j--){
     pPage->aCell[j] = pPage->aCell[j-1];
@@ -2425,24 +2288,8 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
     pPage->isOverfull = 1;
     pPage->aCell[i] = pCell;
   }else{
-    u8 *data = pPage->aData;
-    memcpy(&data[idx], pCell, sz);
-    pPage->aCell[i] = &data[idx];
-  }
-  if( !pPage->isOverfull && !pPage->needRelink ){
-    u8 *pPrev;
-    int pc;
-    if( i==0 ){
-      pPrev = &pPage->aData[pPage->hdrOffset+3];
-    }else{
-      pPrev = pPage->aCell[i-1];
-    }
-    pc = get2byte(pPrev);
-    put2byte(pPrev, idx);
-    put2byte(pPage->aCell[i], pc);
-    pageIntegrity(pPage);
-  }else{
-    pPage->needRelink = 1;
+    memcpy(&pPage->aData[idx], pCell, sz);
+    pPage->aCell[i] = &pPage->aData[idx];
   }
   pPage->idxShift = 1;
 }
@@ -2456,7 +2303,6 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
 static void relinkCellList(MemPage *pPage){
   int i, idxFrom;
   assert( sqlite3pager_iswriteable(pPage->aData) );
-  if( !pPage->needRelink ) return;
   idxFrom = pPage->hdrOffset+3;
   for(i=0; i<pPage->nCell; i++){
     int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData);
@@ -2465,7 +2311,6 @@ static void relinkCellList(MemPage *pPage){
     idxFrom = idx;
   }
   put2byte(&pPage->aData[idxFrom], 0);
-  pPage->needRelink = 0;
 }
 
 /*
@@ -2484,7 +2329,7 @@ static void relinkCellList(MemPage *pPage){
 **
 ** Over this operation completes, the meta data for pFrom is zeroed.
 */
-static void movePage(MemPage *pTo, MemPage *pFrom){
+static void copyPage(MemPage *pTo, MemPage *pFrom){
   uptr from, to;
   int i;
   int pageSize;
@@ -2511,15 +2356,6 @@ static void movePage(MemPage *pTo, MemPage *pFrom){
   }
 }
 
-/*
-** For debugging...
-*/
-#if 1
-# define TRACE(X)   if( pager3_refinfo_enable ) printf X
-#else
-# define TRACE(X)
-#endif
-
 /*
 ** The following parameters determine how many adjacent pages get involved
 ** in a balancing operation.  NN is the number of neighbors on either side
@@ -2585,7 +2421,6 @@ static int balance(MemPage *pPage){
   int usableSpace;             /* Bytes in pPage beyond the header */
   int pageFlags;               /* Value of pPage->aData[0] */
   int subtotal;                /* Subtotal of bytes in cells on one page */
-  MemPage *extraUnref = 0;     /* Unref this page if not zero */
   MemPage *apOld[NB];          /* pPage and up to two siblings */
   Pgno pgnoOld[NB];            /* Page numbers for each page in apOld[] */
   MemPage *apCopy[NB];         /* Private copies of apOld[] pages */
@@ -2616,7 +2451,6 @@ static int balance(MemPage *pPage){
   ** it means this page is the root page and special rules apply.
   */
   pParent = pPage->pParent;
-  TRACE(("BALANCE: begin page %d\n", pPage->pgno));
   if( pParent==0 ){
     Pgno pgnoChild;
     MemPage *pChild;
@@ -2625,7 +2459,6 @@ static int balance(MemPage *pPage){
       if( pPage->leaf ){
         /* The table is completely empty */
         relinkCellList(pPage);
-        TRACE(("BALANCE: empty table\n"));
       }else{
         /* The root page is empty but has one child.  Transfer the
         ** information from that one child into the root page if it 
@@ -2656,11 +2489,9 @@ static int balance(MemPage *pPage){
                         cellSize(pChild, pChild->aCell[i]));
             }
             freePage(pChild);
-            TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno));
           }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));
           }
         }else{
           memcpy(pPage, pChild, pBt->pageSize);
@@ -2669,7 +2500,6 @@ static int balance(MemPage *pPage){
           rc = initPage(pPage, 0);
           assert( rc==SQLITE_OK );
           freePage(pChild);
-          TRACE(("BALANCE: transfer child %d into root\n", pChild->pgno));
         }
         reparentChildPages(pPage);
         releasePage(pChild);
@@ -2680,7 +2510,6 @@ static int balance(MemPage *pPage){
       /* It is OK for the root page to be less than half full.
       */
       relinkCellList(pPage);
-      TRACE(("BALANCE:  Root page is underfull but that is ok\n"));
       return SQLITE_OK;
     }
     /*
@@ -2694,18 +2523,17 @@ static int balance(MemPage *pPage){
     rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno);
     if( rc ) return rc;
     assert( sqlite3pager_iswriteable(pChild->aData) );
-    movePage(pChild, pPage);
+    copyPage(pChild, pPage);
     assert( pChild->aData[0]==pPage->aData[pPage->hdrOffset] );
     pChild->pParent = pPage;
-    sqlite3pager_ref(pPage->aData);
     pChild->idxParent = 0;
+    sqlite3pager_ref(pPage->aData);
     pChild->isOverfull = 1;
     zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
     put4byte(&pPage->aData[pPage->hdrOffset+6], pChild->pgno);
     pParent = pPage;
     pPage = pChild;
-    extraUnref = pChild;
-    TRACE(("BALANCE: Copy root into %d and blance\n", pPage->pgno));
+    initPage(pParent, 0);
   }
   rc = sqlite3pager_write(pParent->aData);
   if( rc ) return rc;
@@ -2782,9 +2610,7 @@ static int balance(MemPage *pPage){
   for(i=0; i<nOld; i++){
     MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
     p->aData = &((u8*)p)[-pBt->pageSize];
-    p->aCell = 0;
-    p->hdrOffset = 0;
-    movePage(p, apOld[i]);
+    copyPage(p, apOld[i]);
   }
 
   /*
@@ -2809,12 +2635,11 @@ static int balance(MemPage *pPage){
       nCell++;
     }
     if( i<nOld-1 ){
-      szCell[nCell] = cellSize(pParent, apDiv[i]);
-      memcpy(aTemp[i], apDiv[i], szCell[nCell]);
+      szCell[nCell] = cellSize(pParent, apDiv[i]) - leafCorrection;
+      memcpy(aTemp[i], apDiv[i], szCell[nCell] + leafCorrection);
       apCell[nCell] = &aTemp[i][leafCorrection];
       dropCell(pParent, nxDiv, szCell[nCell]);
-      szCell[nCell] -= leafCorrection;
-      assert( get4byte(&aTemp[i][2])==pgnoOld[i] );
+      assert( get4byte(&apCell[nCell][2])==pgnoOld[i] );
       if( !pOld->leaf ){
         assert( leafCorrection==0 );
         /* The right pointer of the child page pOld becomes the left
@@ -2866,19 +2691,18 @@ static int balance(MemPage *pPage){
   assert( pPage->pgno>1 );
   pageFlags = pPage->aData[0];
   for(i=0; i<k; i++){
-    MemPage *pNew;
     if( i<nOld ){
-      pNew = apNew[i] = apOld[i];
+      apNew[i] = apOld[i];
       pgnoNew[i] = pgnoOld[i];
       apOld[i] = 0;
-      sqlite3pager_write(pNew->aData);
+      sqlite3pager_write(apNew[i]->aData);
     }else{
-      rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1]);
+      rc = allocatePage(pBt, &apNew[i], &pgnoNew[i], pgnoNew[i-1]);
       if( rc ) goto balance_cleanup;
-      apNew[i] = pNew;
     }
     nNew++;
-    zeroPage(pNew, pageFlags);
+    zeroPage(apNew[i], pageFlags);
+    apNew[i]->isInit = 1;
   }
 
   /* Free any old pages that were not reused as new pages.
@@ -2886,7 +2710,7 @@ static int balance(MemPage *pPage){
   while( i<nOld ){
     rc = freePage(apOld[i]);
     if( rc ) goto balance_cleanup;
-    releasePage(apOld[i]);
+    sqlite3pager_unref(apOld[i]->aData);
     apOld[i] = 0;
     i++;
   }
@@ -2980,11 +2804,7 @@ static int balance(MemPage *pPage){
   /*
   ** balance the parent page.
   */
-  assert( pPage->isInit );
-  assert( pParent->isInit );
-  pageIntegrity(pPage);
   rc = balance(pParent);
-  
 
   /*
   ** Cleanup before returning.
@@ -2993,6 +2813,7 @@ balance_cleanup:
   for(i=0; i<nOld; i++){
     releasePage(apOld[i]);
     if( apCopy[i] ){
+      releasePage(apCopy[i]->pParent);
       sqliteFree(apCopy[i]->aCell);
     }
   }
@@ -3000,8 +2821,6 @@ balance_cleanup:
     releasePage(apNew[i]);
   }
   releasePage(pParent);
-  releasePage(extraUnref);
-  TRACE(("BALANCE: Finished with %d\n", pPage->pgno));
   return rc;
 }
 
@@ -3153,7 +2972,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     unsigned char *pNext;
     int szNext;
     int notUsed;
-    unsigned char tempbuf[4];
     getTempCursor(pCur, &leafCur);
     rc = sqlite3BtreeNext(&leafCur, &notUsed);
     if( rc!=SQLITE_OK ){
@@ -3165,12 +2983,10 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     dropCell(pPage, pCur->idx, cellSize(pPage, pCell));
     pNext = leafCur.pPage->aCell[leafCur.idx];
     szNext = cellSize(leafCur.pPage, pNext);
-    memcpy(tempbuf, &pNext[-2], 4);
-    put4byte(&pNext[-2], pgnoChild);
     insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
+    put4byte(&pNext[-2], pgnoChild);
     rc = balance(pPage);
     if( rc ) return rc;
-    memcpy(&pNext[-2], tempbuf, 4);
     dropCell(leafCur.pPage, leafCur.idx, szNext);
     rc = balance(leafCur.pPage);
     releaseTempCursor(&leafCur);
@@ -3374,9 +3190,8 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
   pPage->intKey = (c & PTF_INTKEY)!=0;
   pPage->zeroData = (c & PTF_ZERODATA)!=0;
   pPage->leaf = (c & PTF_LEAF)!=0;
-  printf("PAGE %d:  flags=0x%02x  frag=%d   parent=%d\n", pgno,
-    data[hdr], data[hdr+5], 
-    (pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
+  printf("PAGE %d:  flags=0x%02x  frag=%d\n", pgno,
+    data[hdr], data[hdr+5]);
   i = 0;
   assert( hdr == (pgno==1 ? 100 : 0) );
   idx = get2byte(&data[hdr+3]);
@@ -3472,11 +3287,9 @@ int sqlite3BtreeFlags(BtCursor *pCur){
 **
 ** This routine is used for testing and debugging only.
 */
-int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult){
+int sqlite3BtreeCursorDump(BtCursor *pCur, int *aResult){
   int cnt, idx;
   MemPage *pPage = pCur->pPage;
-
-  pageIntegrity(pPage);
   assert( pPage->isInit );
   aResult[0] = sqlite3pager_pagenumber(pPage->aData);
   assert( aResult[0]==pPage->pgno );
index 16505dbd43f35f2eaec777dabad61f86ab2969d9..184602073d5cfac77e923088cdc0d02e3d065815 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is btree database backend
 #
-# $Id: btree.test,v 1.21 2004/05/09 00:40:52 drh Exp $
+# $Id: btree.test,v 1.22 2004/05/09 01:35:06 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -616,7 +616,6 @@ do_test btree-7.15 {
 
 # Check to see that data on overflow pages work correctly.
 #
-#btree_page_dump $::b1 1
 do_test btree-8.1 {
   set data "*** This is a very long key "
   while {[string length $data]<1234} {append data $data}
@@ -641,6 +640,9 @@ do_test btree-8.4 {
 do_test btree-8.4.1 {
   lindex [btree_get_meta $::b1] 0
 } [expr {int(([string length $::data]-238+1019)/1020)}]
+do_test btree-8.4.2 {
+  btree_integrity_check $::b1 1 2
+} {}
 do_test btree-8.5 {
   set data "*** This is an even longer key "
   while {[string length $data]<2000} {append data $data}
@@ -731,16 +733,25 @@ do_test btree-8.21 {
 do_test btree-8.22 {
   lindex [btree_pager_stats $::b1] 1
 } {2}
-do_test btree-8.23 {
+do_test btree-8.23.1 {
   btree_close_cursor $::c1
   btree_drop_table $::b1 2
+  btree_integrity_check $::b1 1
+} {}
+do_test btree-8.23.2 {
+  btree_create_table $::b1 0
+} {2}
+do_test btree_8.23.3 {
   set ::c1 [btree_cursor $::b1 2 1]
   lindex [btree_get_meta $::b1] 0
-} {5}
+} {4}
 do_test btree-8.24 {
   lindex [btree_pager_stats $::b1] 1
 } {2}
 #btree_pager_ref_dump $::b1
+do_test btree-8.25 {
+  btree_integrity_check $::b1 1 2
+} {}
 
 # Check page splitting logic
 #
@@ -807,10 +818,15 @@ do_test btree-9.6 {
   btree_close_cursor $::c1
   lindex [btree_pager_stats $::b1] 1
 } {1}
+puts "222: [btree_integrity_check $::b1 1 2]"
+
 do_test btree-9.7 {
   btree_rollback $::b1
   lindex [btree_pager_stats $::b1] 1
 } {0}
+do_test btree-9.8 {
+  btree_integrity_check $::b1 1 2
+} {}
 
 # Create a tree of depth two.  That is, there is a single divider entry
 # on the root pages and two leaf pages.  Then delete the divider entry
@@ -963,9 +979,11 @@ do_test btree-12.12 {
   btree_next $::c1
   btree_key $::c1
 } {402}
-#do_test btree-13.1 {
-#  btree_integrity_check $::b1 1 2
-#} {}
+btree_commit $::b1
+btree_tree_dump $::b1 1
+do_test btree-13.1 {
+  btree_integrity_check $::b1 1 2
+} {}
 
 # To Do:
 #