]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid parsing the structure of b-tree pages (in sqlite3BtreeInitPage) more than is...
authordanielk1977 <danielk1977@noemail.net>
Thu, 18 Sep 2008 17:34:44 +0000 (17:34 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Thu, 18 Sep 2008 17:34:44 +0000 (17:34 +0000)
FossilOrigin-Name: 6b998f3066754e219c266501327e5578c9406b63

manifest
manifest.uuid
src/btree.c
src/btreeInt.h
src/pager.c
src/pager.h
src/pcache.c
src/pcache.h

index ea5cfda61c418eb7619df0f629abecd98a4e3248..489cd9314561c3d61a2dd222c27da32ac982342c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\sthe\sversion\snumber\sto\s3.6.3.\s(CVS\s5719)
-D 2008-09-18T13:49:13
+C Avoid\sparsing\sthe\sstructure\sof\sb-tree\spages\s(in\ssqlite3BtreeInitPage)\smore\sthan\sis\snecessary.\s(CVS\s5720)
+D 2008-09-18T17:34:44
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -99,9 +99,9 @@ F src/attach.c db3f4a60538733c1e4dcb9d0217a6e0d6ccd615b
 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d
 F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53
-F src/btree.c 5db7b54e9d39dddb06e066e993901fc8630c6e49
+F src/btree.c e8484887722a3a84f2aab5663a0dc93e0c7806c7
 F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107
-F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576
+F src/btreeInt.h e36f77e6621d671beb19ae581af1eba116cdfdc4
 F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe
 F src/callback.c 7a40fd44da3eb89e7f6eff30aa6f940c45d73a97
 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
@@ -137,11 +137,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
 F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
 F src/os_unix.c 8f4def6a92681735908fa1b87b5cc0291ebafde6
 F src/os_win.c 3209dc0ed734291764393ea8d534ba0d8696a540
-F src/pager.c 34318b85cead25e179a6ff83092c79d6dcecb2fd
-F src/pager.h c45380ca9d0933ea5bc4ecb3a43958b6d2ec5a9c
+F src/pager.c bcfa1c4034414a247c1583fd97c9c561afae53f9
+F src/pager.h 1ef5a3f8e0b4c8b30f19c8e01d4fca2db9bb5797
 F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
-F src/pcache.c c799d753a5d4b913961a4fe66c8a7c706b04d28d
-F src/pcache.h deddea69babf3e0931b11eea3bf5c9e33a654389
+F src/pcache.c e025e5380d75ffc25ef069fee8d128b595513ece
+F src/pcache.h 0b6871e820159629915e8688b5c67a81a203773f
 F src/pragma.c e633b6b7dabc110e2abfed4e35ba34a4039cb65c
 F src/prepare.c c7e00ed1b0bdcf699b1aad651247d4dc3d281b0b
 F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
@@ -637,7 +637,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 0889b22a2949160c3f2d06beaa05a867b4c228b3
-R ac300755102001ce1aa8c09d26102ac6
-U drh
-Z c0568459c1b6c869285e59f30eb43c51
+P 419764b35c96a1b08aefc0d6093c19fdf2aef517
+R abfec31e169b70fffcf581f021d6269e
+U danielk1977
+Z fbad4f393b6c492a76554e62ab4e7b3d
index da2f7cad3bb50387d99800e602dfa48cd0aa4a97..e1b3a273d6f7c1730fa7f6dc95ebf3641145dee2 100644 (file)
@@ -1 +1 @@
-419764b35c96a1b08aefc0d6093c19fdf2aef517
\ No newline at end of file
+6b998f3066754e219c266501327e5578c9406b63
\ No newline at end of file
index 12d29e25ef0736a03dd4c3b419ebbd2901b6af23..efb509d96946c00908ed9c5f0df399cd3798b64c 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.512 2008/09/18 01:08:16 drh Exp $
+** $Id: btree.c,v 1.513 2008/09/18 17:34:44 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** See the header comment on "btreeInt.h" for additional information.
@@ -941,57 +941,60 @@ int sqlite3BtreeInitPage(
   if( pPage==pParent ){
     return SQLITE_CORRUPT_BKPT;
   }
-  if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
+  if( (pPage->pParent!=pParent)
+   && (pPage->pParent!=0 || pPage->isInit==PAGE_ISINIT_FULL) ){
     /* The parent page should never change unless the file is corrupt */
     return SQLITE_CORRUPT_BKPT;
   }
-  if( pPage->isInit ) return SQLITE_OK;
-  if( pPage->pParent==0 && pParent!=0 ){
+  if( pPage->isInit==PAGE_ISINIT_FULL ) return SQLITE_OK;
+  if( pParent!=0 ){
     pPage->pParent = pParent;
     sqlite3PagerRef(pParent->pDbPage);
   }
-  hdr = pPage->hdrOffset;
-  data = pPage->aData;
-  if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
-  assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
-  pPage->maskPage = pBt->pageSize - 1;
-  pPage->nOverflow = 0;
-  pPage->idxShift = 0;
-  usableSize = pBt->usableSize;
-  pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
-  top = get2byte(&data[hdr+5]);
-  pPage->nCell = get2byte(&data[hdr+3]);
-  if( pPage->nCell>MX_CELL(pBt) ){
-    /* To many cells for a single page.  The page must be corrupt */
-    return SQLITE_CORRUPT_BKPT;
-  }
-  if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
-    /* All pages must have at least one cell, except for root pages */
-    return SQLITE_CORRUPT_BKPT;
-  }
-
-  /* Compute the total free space on the page */
-  pc = get2byte(&data[hdr+1]);
-  nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell);
-  while( pc>0 ){
-    int next, size;
-    if( pc>usableSize-4 ){
-      /* Free block is off the page */
-      return SQLITE_CORRUPT_BKPT; 
+  if( pPage->isInit==PAGE_ISINIT_NONE ){
+    hdr = pPage->hdrOffset;
+    data = pPage->aData;
+    if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
+    assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
+    pPage->maskPage = pBt->pageSize - 1;
+    pPage->nOverflow = 0;
+    pPage->idxShift = 0;
+    usableSize = pBt->usableSize;
+    pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
+    top = get2byte(&data[hdr+5]);
+    pPage->nCell = get2byte(&data[hdr+3]);
+    if( pPage->nCell>MX_CELL(pBt) ){
+      /* To many cells for a single page.  The page must be corrupt */
+      return SQLITE_CORRUPT_BKPT;
     }
-    next = get2byte(&data[pc]);
-    size = get2byte(&data[pc+2]);
-    if( next>0 && next<=pc+size+3 ){
-      /* Free blocks must be in accending order */
+    if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
+      /* All pages must have at least one cell, except for root pages */
+      return SQLITE_CORRUPT_BKPT;
+    }
+  
+    /* Compute the total free space on the page */
+    pc = get2byte(&data[hdr+1]);
+    nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell);
+    while( pc>0 ){
+      int next, size;
+      if( pc>usableSize-4 ){
+        /* Free block is off the page */
+        return SQLITE_CORRUPT_BKPT; 
+      }
+      next = get2byte(&data[pc]);
+      size = get2byte(&data[pc+2]);
+      if( next>0 && next<=pc+size+3 ){
+        /* Free blocks must be in accending order */
+        return SQLITE_CORRUPT_BKPT; 
+      }
+      nFree += size;
+      pc = next;
+    }
+    pPage->nFree = nFree;
+    if( nFree>=usableSize ){
+      /* Free space cannot exceed total page size */
       return SQLITE_CORRUPT_BKPT; 
     }
-    nFree += size;
-    pc = next;
-  }
-  pPage->nFree = nFree;
-  if( nFree>=usableSize ){
-    /* Free space cannot exceed total page size */
-    return SQLITE_CORRUPT_BKPT; 
   }
 
 #if 0
@@ -1014,7 +1017,7 @@ int sqlite3BtreeInitPage(
   }
 #endif
 
-  pPage->isInit = 1;
+  pPage->isInit = PAGE_ISINIT_FULL;
   return SQLITE_OK;
 }
 
@@ -1048,7 +1051,7 @@ static void zeroPage(MemPage *pPage, int flags){
   pPage->maskPage = pBt->pageSize - 1;
   pPage->idxShift = 0;
   pPage->nCell = 0;
-  pPage->isInit = 1;
+  pPage->isInit = PAGE_ISINIT_FULL;
 }
 
 
@@ -1120,7 +1123,7 @@ static int getAndInitPage(
   MemPage *pPage;
 
   assert( sqlite3_mutex_held(pBt->mutex) );
-  assert( !pParent || pParent->isInit );
+  assert( !pParent || pParent->isInit==PAGE_ISINIT_FULL );
   if( pgno==0 ){
     return SQLITE_CORRUPT_BKPT; 
   }
@@ -1144,7 +1147,7 @@ static int getAndInitPage(
     if( rc ) return rc;
     pPage = *ppPage;
   }
-  if( pPage->isInit==0 ){
+  if( pPage->isInit!=PAGE_ISINIT_FULL ){
      rc = sqlite3BtreeInitPage(pPage, pParent);
   }else if( pParent && (pPage==pParent || pPage->pParent!=pParent) ){
     /* This condition indicates a loop in the b-tree structure (the scenario
@@ -1184,14 +1187,18 @@ static void pageDestructor(DbPage *pData){
   MemPage *pPage;
   pPage = (MemPage *)sqlite3PagerGetExtra(pData);
   if( pPage ){
-    assert( pPage->isInit==0 || sqlite3_mutex_held(pPage->pBt->mutex) );
+    assert( pPage->isInit!=PAGE_ISINIT_FULL 
+         || sqlite3_mutex_held(pPage->pBt->mutex) 
+    );
     if( pPage->pParent ){
       MemPage *pParent = pPage->pParent;
       assert( pParent->pBt==pPage->pBt );
       pPage->pParent = 0;
       releasePage(pParent);
     }
-    pPage->isInit = 0;
+    if( pPage->isInit==PAGE_ISINIT_FULL ){
+      pPage->isInit = PAGE_ISINIT_DATA;
+    }
   }
 }
 
@@ -1203,14 +1210,15 @@ static void pageDestructor(DbPage *pData){
 ** This routine needs to reset the extra data section at the end of the
 ** page to agree with the restored data.
 */
-static void pageReinit(DbPage *pData, int pageSize){
+static void pageReinit(DbPage *pData){
   MemPage *pPage;
-  assert( (pageSize & 7)==0 );
   pPage = (MemPage *)sqlite3PagerGetExtra(pData);
-  if( pPage->isInit ){
+  if( pPage->isInit==PAGE_ISINIT_FULL ){
     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
     pPage->isInit = 0;
     sqlite3BtreeInitPage(pPage, pPage->pParent);
+  }else if( pPage->isInit==PAGE_ISINIT_DATA ){
+    pPage->isInit = 0;
   }
 }
 
@@ -3557,7 +3565,7 @@ static int moveToRoot(BtCursor *pCur){
   }
   pRoot = pCur->pPage;
   if( pRoot && pRoot->pgno==pCur->pgnoRoot ){
-    assert( pRoot->isInit );
+    assert( pRoot->isInit==PAGE_ISINIT_FULL );
   }else{
     if( 
       SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0))
@@ -3743,7 +3751,7 @@ int sqlite3BtreeMovetoUnpacked(
     return rc;
   }
   assert( pCur->pPage );
-  assert( pCur->pPage->isInit );
+  assert( pCur->pPage->isInit==PAGE_ISINIT_FULL );
   if( pCur->eState==CURSOR_INVALID ){
     *pRes = -1;
     assert( pCur->pPage->nCell==0 );
@@ -3829,7 +3837,7 @@ int sqlite3BtreeMovetoUnpacked(
       pCur->idx = (lwr+upr)/2;
     }
     assert( lwr==upr+1 );
-    assert( pPage->isInit );
+    assert( pPage->isInit==PAGE_ISINIT_FULL );
     if( pPage->leaf ){
       chldPg = 0;
     }else if( lwr>=pPage->nCell ){
@@ -3935,7 +3943,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
   }
   pCur->skip = 0;
 
-  assert( pPage->isInit );
+  assert( pPage->isInit==PAGE_ISINIT_FULL );
   assert( pCur->idx<pPage->nCell );
 
   pCur->idx++;
@@ -4004,7 +4012,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
   pCur->skip = 0;
 
   pPage = pCur->pPage;
-  assert( pPage->isInit );
+  assert( pPage->isInit==PAGE_ISINIT_FULL );
   assert( pCur->idx>=0 );
   if( !pPage->leaf ){
     pgno = get4byte( findCell(pPage, pCur->idx) );
@@ -4295,6 +4303,13 @@ static int allocateBtreePage(
 end_allocate_page:
   releasePage(pTrunk);
   releasePage(pPrevTrunk);
+  if( rc==SQLITE_OK ){
+    if( (*ppPage)->isInit==PAGE_ISINIT_FULL ){
+      releasePage(*ppPage);
+      return SQLITE_CORRUPT_BKPT;
+    }
+    (*ppPage)->isInit = 0;
+  }
   return rc;
 }
 
@@ -4594,7 +4609,7 @@ static int reparentPage(
   pDbPage = sqlite3PagerLookup(pBt->pPager, pgno);
   if( pDbPage ){
     pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage);
-    if( pThis->isInit ){
+    if( pThis->isInit==PAGE_ISINIT_FULL ){
       assert( pThis->aData==sqlite3PagerGetData(pDbPage) );
       if( pThis->pParent!=pNewParent ){
         if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage);
@@ -4877,7 +4892,7 @@ static int balance(MemPage*, int);
 */
 static int balance_quick(MemPage *pPage, MemPage *pParent){
   int rc;
-  MemPage *pNew;
+  MemPage *pNew = 0;
   Pgno pgnoNew;
   u8 *pCell;
   u16 szCell;
@@ -4893,63 +4908,78 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
   ** into it. Then remove the overflow cell from pPage.
   */
   rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
-  if( rc!=SQLITE_OK ){
-    return rc;
+  if( rc==SQLITE_OK ){
+    pCell = pPage->aOvfl[0].pCell;
+    szCell = cellSizePtr(pPage, pCell);
+    zeroPage(pNew, pPage->aData[0]);
+    assemblePage(pNew, 1, &pCell, &szCell);
+    pPage->nOverflow = 0;
+  
+    /* Set the parent of the newly allocated page to pParent. */
+    pNew->pParent = pParent;
+    sqlite3PagerRef(pParent->pDbPage);
+  
+    /* pPage is currently the right-child of pParent. Change this
+    ** so that the right-child is the new page allocated above and
+    ** pPage is the next-to-right child. 
+    **
+    ** Ignore the return value of the call to fillInCell(). fillInCell()
+    ** may only return other than SQLITE_OK if it is required to allocate
+    ** one or more overflow pages. Since an internal table B-Tree cell 
+    ** may never spill over onto an overflow page (it is a maximum of 
+    ** 13 bytes in size), it is not neccessary to check the return code.
+    **
+    ** Similarly, the insertCell() function cannot fail if the page
+    ** being inserted into is already writable and the cell does not 
+    ** contain an overflow pointer. So ignore this return code too.
+    */
+    assert( pPage->nCell>0 );
+    pCell = findCell(pPage, pPage->nCell-1);
+    sqlite3BtreeParseCellPtr(pPage, pCell, &info);
+    fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
+    assert( parentSize<64 );
+    assert( sqlite3PagerIswriteable(pParent->pDbPage) );
+    insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4);
+    put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno);
+    put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
+  
+    /* If this is an auto-vacuum database, update the pointer map
+    ** with entries for the new page, and any pointer from the 
+    ** cell on the page to an overflow page.
+    */
+    if( ISAUTOVACUUM ){
+      rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno);
+      if( rc==SQLITE_OK ){
+        rc = ptrmapPutOvfl(pNew, 0);
+      }
+    }
   }
-  pCell = pPage->aOvfl[0].pCell;
-  szCell = cellSizePtr(pPage, pCell);
-  zeroPage(pNew, pPage->aData[0]);
-  assemblePage(pNew, 1, &pCell, &szCell);
-  pPage->nOverflow = 0;
-
-  /* Set the parent of the newly allocated page to pParent. */
-  pNew->pParent = pParent;
-  sqlite3PagerRef(pParent->pDbPage);
 
-  /* pPage is currently the right-child of pParent. Change this
-  ** so that the right-child is the new page allocated above and
-  ** pPage is the next-to-right child. 
-  **
-  ** Ignore the return value of the call to fillInCell(). fillInCell()
-  ** may only return other than SQLITE_OK if it is required to allocate
-  ** one or more overflow pages. Since an internal table B-Tree cell 
-  ** may never spill over onto an overflow page (it is a maximum of 
-  ** 13 bytes in size), it is not neccessary to check the return code.
+  /* At this point the pPage->nFree variable is not set correctly with
+  ** respect to the content of the page (because it was set to 0 by 
+  ** insertCell). So call sqlite3BtreeInitPage() to make sure it is
+  ** correct.
   **
-  ** Similarly, the insertCell() function cannot fail if the page
-  ** being inserted into is already writable and the cell does not 
-  ** contain an overflow pointer. So ignore this return code too.
+  ** This has to be done even if an error will be returned. Normally, if
+  ** an error occurs during tree balancing, the contents of MemPage are
+  ** not important, as they will be recalculated when the page is rolled
+  ** back. But here, in balance_quick(), it is possible that pPage has 
+  ** not yet been marked dirty or written into the journal file. Therefore
+  ** it will not be rolled back and so it is important to make sure that
+  ** the page data and contents of MemPage are consistent.
   */
-  assert( pPage->nCell>0 );
-  pCell = findCell(pPage, pPage->nCell-1);
-  sqlite3BtreeParseCellPtr(pPage, pCell, &info);
-  fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
-  assert( parentSize<64 );
-  assert( sqlite3PagerIswriteable(pParent->pDbPage) );
-  insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4);
-  put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno);
-  put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
-
-  /* If this is an auto-vacuum database, update the pointer map
-  ** with entries for the new page, and any pointer from the 
-  ** cell on the page to an overflow page.
-  */
-  if( ISAUTOVACUUM ){
-    rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno);
-    if( rc==SQLITE_OK ){
-      rc = ptrmapPutOvfl(pNew, 0);
-    }
-    if( rc!=SQLITE_OK ){
-      releasePage(pNew);
-      return rc;
-    }
-  }
+  pPage->isInit = 0;
+  sqlite3BtreeInitPage(pPage, pPage->pParent);
+  sqlite3PagerUnref(pPage->pParent->pDbPage);
 
   /* Release the reference to the new page and balance the parent page,
   ** in case the divider cell inserted caused it to become overfull.
   */
   releasePage(pNew);
-  return balance(pParent, 0);
+  if( rc==SQLITE_OK ){
+    rc = balance(pParent, 0);
+  }
+  return rc;
 }
 #endif /* SQLITE_OMIT_QUICKBALANCE */
 
@@ -5022,7 +5052,7 @@ static int balance_nonroot(MemPage *pPage){
   /* 
   ** Find the parent page.
   */
-  assert( pPage->isInit );
+  assert( pPage->isInit==PAGE_ISINIT_FULL );
   assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 );
   pBt = pPage->pBt;
   pParent = pPage->pParent;
@@ -5554,7 +5584,7 @@ static int balance_nonroot(MemPage *pPage){
   ** have been added to the freelist so it might no longer be initialized.
   ** But the parent page will always be initialized.
   */
-  assert( pParent->isInit );
+  assert( pParent->isInit==PAGE_ISINIT_FULL );
   sqlite3ScratchFree(apCell);
   apCell = 0;
   rc = balance(pParent, 0);
@@ -5571,9 +5601,11 @@ balance_cleanup:
   for(i=0; i<nNew; i++){
     releasePage(apNew[i]);
   }
+
   releasePage(pParent);
   TRACE(("BALANCE: finished with %d: old=%d new=%d cells=%d\n",
           pPage->pgno, nOld, nNew, nCell));
+
   return rc;
 }
 
@@ -5707,7 +5739,7 @@ static int balance_deeper(MemPage *pPage){
   cdata = pChild->aData;
   memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
   memcpy(&cdata[cbrk], &data[cbrk], usableSize-cbrk);
-  if( pChild->isInit ) return SQLITE_CORRUPT;
+  if( pChild->isInit==PAGE_ISINIT_FULL ) return SQLITE_CORRUPT;
   rc = sqlite3BtreeInitPage(pChild, pPage);
   if( rc ) goto balancedeeper_out;
   memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
@@ -5890,7 +5922,7 @@ int sqlite3BtreeInsert(
   TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
           pCur->pgnoRoot, nKey, nData, pPage->pgno,
           loc==0 ? "overwrite" : "new entry"));
-  assert( pPage->isInit );
+  assert( pPage->isInit==PAGE_ISINIT_FULL );
   allocateTempSpace(pBt);
   newCell = pBt->pTmpSpace;
   if( newCell==0 ) return SQLITE_NOMEM;
@@ -5944,7 +5976,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
   BtShared *pBt = p->pBt;
 
   assert( cursorHoldsMutex(pCur) );
-  assert( pPage->isInit );
+  assert( pPage->isInit==PAGE_ISINIT_FULL );
   if( pBt->inTransaction!=TRANS_WRITE ){
     /* Must start a transaction before doing a delete */
     rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
@@ -7124,7 +7156,11 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){
         }
       }
 
-      if( pToPage ) sqlite3PagerUnref(pToPage);
+      if( pToPage ){
+        MemPage *p = (MemPage *)sqlite3PagerGetExtra(pToPage);
+        p->isInit = 0;
+        sqlite3PagerUnref(pToPage);
+      }
     }
   }
 
index 663a41e0810feba17e8f5e4f9f8a625870d6d558..2a7bf9c6b627377d8556df4c2c483bb48bd70efe 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btreeInt.h,v 1.30 2008/08/01 20:10:08 drh Exp $
+** $Id: btreeInt.h,v 1.31 2008/09/18 17:34:44 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -296,6 +296,18 @@ struct MemPage {
   MemPage *pParent;    /* The parent of this page.  NULL for root */
 };
 
+/*
+** Possible values for the MemPage.isInit variable. When a page is first
+** loaded or if the data stored in the MemPage struct is invalidated, 
+** MemPage.isInit is set to PAGE_ISINIT_NONE. If the MemPage structure
+** is fully initialized, then MemPage.isInit is set to PAGE_ISINIT_FULL.
+** MemPage.isInit is set to PAGE_ISINIT_DATA when the MemPage struct is
+** populated, but the MemPage.pParent variable is not necessarily correct.
+*/
+#define PAGE_ISINIT_NONE 0
+#define PAGE_ISINIT_DATA 1
+#define PAGE_ISINIT_FULL 2
+
 /*
 ** The in-memory image of a disk page has the auxiliary information appended
 ** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
index 51fafebd7db4d2e63b5998274ae240bd1841e55c..72187172291f154fa4b394d9d842beb1b06d97ef 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.491 2008/09/17 20:06:26 drh Exp $
+** @(#) $Id: pager.c,v 1.492 2008/09/18 17:34:44 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -208,8 +208,7 @@ struct Pager {
   int nHit, nMiss;            /* Cache hits and missing */
   int nRead, nWrite;          /* Database pages read/written */
 #endif
-  void (*xDestructor)(DbPage*,int); /* Call this routine when freeing pages */
-  void (*xReiniter)(DbPage*,int);   /* Call this routine when reloading pages */
+  void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
 #ifdef SQLITE_HAS_CODEC
   void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
   void *pCodecArg;            /* First argument to xCodec() */
@@ -1159,7 +1158,7 @@ static int pager_playback_one_page(
     pData = pPg->pData;
     memcpy(pData, aData, pPager->pageSize);
     if( pPager->xReiniter ){
-      pPager->xReiniter(pPg, pPager->pageSize);
+      pPager->xReiniter(pPg);
     }
     if( isMainJrnl ) makeClean(pPg);
 #ifdef SQLITE_CHECK_PAGES
@@ -1941,7 +1940,7 @@ void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){
 ** an opportunity to restore the EXTRA section to agree with the restored
 ** page data.
 */
-void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){
+void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*)){
   pPager->xReiniter = xReinit;
 }
 
@@ -3830,8 +3829,8 @@ int sqlite3PagerRollback(Pager *pPager){
   int rc = SQLITE_OK;
   PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
   if( MEMDB ){
-    sqlite3PcacheRollback(pPager->pPCache, 1);
-    sqlite3PcacheRollback(pPager->pPCache, 0);
+    sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter);
+    sqlite3PcacheRollback(pPager->pPCache, 0, pPager->xReiniter);
     sqlite3PcacheCleanAll(pPager->pPCache);
     sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
     pPager->dbSize = pPager->origDbSize;
@@ -3991,7 +3990,7 @@ int sqlite3PagerStmtRollback(Pager *pPager){
   if( pPager->stmtInUse ){
     PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
     if( MEMDB ){
-      sqlite3PcacheRollback(pPager->pPCache, 1);
+      sqlite3PcacheRollback(pPager->pPCache, 1, pPager->xReiniter);
       pPager->dbSize = pPager->stmtSize;
       pager_truncate_cache(pPager);
       rc = SQLITE_OK;
index 04331a26a6b5d2ead1192d6f1fb14c251c097916..906c92eabc34b289dce6e998375d59a9383b9388 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  The page cache subsystem reads and writes a file a page
 ** at a time and provides a journal for rollback.
 **
-** @(#) $Id: pager.h,v 1.82 2008/09/01 17:23:29 drh Exp $
+** @(#) $Id: pager.h,v 1.83 2008/09/18 17:34:44 danielk1977 Exp $
 */
 
 #ifndef _PAGER_H_
@@ -72,7 +72,7 @@ typedef struct PgHdr DbPage;
 */
 int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, void(*)(DbPage*), int,int,int);
 void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
-void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
+void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*));
 int sqlite3PagerSetPagesize(Pager*, u16*);
 int sqlite3PagerMaxPageCount(Pager*, int);
 int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
index 29672095aa456c0ad8264dd877b85d8adf00270d..3731b5ccaf19d7dd95630a22841975788b964da8 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file implements that page cache.
 **
-** @(#) $Id: pcache.c,v 1.29 2008/09/17 20:06:26 drh Exp $
+** @(#) $Id: pcache.c,v 1.30 2008/09/18 17:34:44 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1019,7 +1019,11 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){
 /*
 ** Rollback a change previously preserved.
 */
-void sqlite3PcacheRollback(PCache *pCache, int idJournal){
+void sqlite3PcacheRollback(
+  PCache *pCache,                  /* Pager cache */
+  int idJournal,                   /* Which copy to rollback to */
+  void (*xReiniter)(PgHdr*)        /* Called on each rolled back page */
+){
   PgHdr *p;
   int sz;
   int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff;
@@ -1030,6 +1034,9 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){
       memcpy(p->pData, p->apSave[idJournal], sz);
       pcacheFree(p->apSave[idJournal]);
       p->apSave[idJournal] = 0;
+      if( xReiniter ){
+        xReiniter(p);
+      }
     }
     p->flags &= mask;
   }
index 3d24025ca94f2a67d24fdef2b82f4e1208f70784..73e6e26d40fc465c124ec492a67ae4c78c7dc030 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the sqlite page cache
 ** subsystem. 
 **
-** @(#) $Id: pcache.h,v 1.10 2008/09/17 20:06:26 drh Exp $
+** @(#) $Id: pcache.h,v 1.11 2008/09/18 17:34:44 danielk1977 Exp $
 */
 
 #ifndef _PCACHE_H_
@@ -113,7 +113,7 @@ void sqlite3PcacheTruncate(PCache*, Pgno x);
 /* Routines used to implement transactions on memory-only databases. */
 int sqlite3PcachePreserve(PgHdr*, int);    /* Preserve current page content */
 void sqlite3PcacheCommit(PCache*, int);    /* Drop preserved copy */
-void sqlite3PcacheRollback(PCache*, int);  /* Rollback to preserved copy */
+void sqlite3PcacheRollback(PCache*, int, void (*xReiniter)(PgHdr*));
 
 /* Get a list of all dirty pages in the cache, sorted by page number */
 PgHdr *sqlite3PcacheDirtyList(PCache*);