]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix some code duplication issues on this branch. Add minor optimizations to the new...
authordan <dan@noemail.net>
Tue, 14 Oct 2014 17:27:04 +0000 (17:27 +0000)
committerdan <dan@noemail.net>
Tue, 14 Oct 2014 17:27:04 +0000 (17:27 +0000)
FossilOrigin-Name: 58d7793bd5d608ba9fc3a2cd44b9d9512e0332ba

manifest
manifest.uuid
src/btree.c

index f6d9403e16617acd8fed4bdc9154728a62bafc36..347e58fbc222a00713ebb6e126362f710b6a7b1f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\strunk\schanges\sinto\sthis\sbranch.
-D 2014-10-13T18:09:13.737
+C Fix\ssome\scode\sduplication\sissues\son\sthis\sbranch.\sAdd\sminor\soptimizations\sto\sthe\snew\scode.
+D 2014-10-14T17:27:04.829
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -172,7 +172,7 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2
 F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
 F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
-F src/btree.c 3d9d1db1d05724346876cf456a850628a9e75331
+F src/btree.c 3c72c5aa96b1a06ea15da24b82c526e6f14010ab
 F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
 F src/btreeInt.h 1bd7957161a1346a914f1f09231610e777a8e58d
 F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919
@@ -1204,7 +1204,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 6594f9b420e2fa642737722ff8521f756ecef227 04892f8ba6c55cec4fe37bfe59b6349fd2a40698
-R 76183a9b7ddeb938a48604dbc4dd8cd6
+P d5b7c5a88dd58de85b3060a1f28b6d96e6e21207
+R ff1ec1f8aba483920a0100e96e95dccf
 U dan
-Z 504cabb1e1fb0c47450f76fec3d8495b
+Z 9c750816a0b42cc370356f0c03af45ae
index 32265a861c835a8435db0f02d6be246f2be2d3bf..065d26bf44daf039e492d6a001e009d20a104f5f 100644 (file)
@@ -1 +1 @@
-d5b7c5a88dd58de85b3060a1f28b6d96e6e21207
\ No newline at end of file
+58d7793bd5d608ba9fc3a2cd44b9d9512e0332ba
\ No newline at end of file
index 7136b45b24b604bcd75c56d77dbf8e321c89f0e2..acf466304f30ae965f822b81702f7d6fdeecc891 100644 (file)
@@ -1224,6 +1224,57 @@ static int defragmentPage(MemPage *pPage){
   return SQLITE_OK;
 }
 
+/*
+** Search the free-list on page pPg for space to store a cell nByte bytes in
+** size. If one can be found, return a pointer to the space and remove it
+** from the free-list.
+**
+** If no suitable space can be found on the free-list, return NULL.
+**
+** This function may detect corruption within pPg. If it does and argument 
+** pRc is non-NULL, then *pRc is set to SQLITE_CORRUPT and NULL is returned.
+** Or, if corruption is detected by pRc is NULL, NULL is returned and the
+** corruption goes unreported.
+*/
+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
+  const int hdr = pPg->hdrOffset;
+  u8 * const aData = pPg->aData;
+  int iAddr;
+  int pc;
+  int usableSize = pPg->pBt->usableSize;
+
+  for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
+    int size;            /* Size of the free slot */
+    if( pc>usableSize-4 || pc<iAddr+4 ){
+      if( pRc ) *pRc = SQLITE_CORRUPT_BKPT;
+      return 0;
+    }
+    size = get2byte(&aData[pc+2]);
+    if( size>=nByte ){
+      int x = size - nByte;
+      testcase( x==4 );
+      testcase( x==3 );
+      if( x<4 ){
+        if( aData[hdr+7]>=60 ) return 0;
+        /* Remove the slot from the free-list. Update the number of
+        ** fragmented bytes within the page. */
+        memcpy(&aData[iAddr], &aData[pc], 2);
+        aData[hdr+7] += (u8)x;
+      }else if( size+pc > usableSize ){
+        if( pRc ) *pRc = SQLITE_CORRUPT_BKPT;
+        return 0;
+      }else{
+        /* The slot remains on the free-list. Reduce its size to account
+         ** for the portion used by the new allocation. */
+        put2byte(&aData[pc+2], x);
+      }
+      return &aData[pc + x];
+    }
+  }
+
+  return 0;
+}
+
 /*
 ** Allocate nByte bytes of space from within the B-Tree page passed
 ** as the first argument. Write into *pIdx the index into pPage->aData[]
@@ -1274,33 +1325,12 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
   testcase( gap+1==top );
   testcase( gap==top );
   if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){
-    int pc, addr;
-    for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){
-      int size;            /* Size of the free slot */
-      if( pc>usableSize-4 || pc<addr+4 ){
-        return SQLITE_CORRUPT_BKPT;
-      }
-      size = get2byte(&data[pc+2]);
-      if( size>=nByte ){
-        int x = size - nByte;
-        testcase( x==4 );
-        testcase( x==3 );
-        if( x<4 ){
-          if( data[hdr+7]>=60 ) goto defragment_page;
-          /* Remove the slot from the free-list. Update the number of
-          ** fragmented bytes within the page. */
-          memcpy(&data[addr], &data[pc], 2);
-          data[hdr+7] += (u8)x;
-        }else if( size+pc > usableSize ){
-          return SQLITE_CORRUPT_BKPT;
-        }else{
-          /* The slot remains on the free-list. Reduce its size to account
-          ** for the portion used by the new allocation. */
-          put2byte(&data[pc+2], x);
-        }
-        *pIdx = pc + x;
-        return SQLITE_OK;
-      }
+    int rc = SQLITE_OK;
+    u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
+    if( rc ) return rc;
+    if( pSpace ){
+      *pIdx = pSpace - data;
+      return SQLITE_OK;
     }
   }
 
@@ -1309,7 +1339,6 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
   */
   testcase( gap+2+nByte==top );
   if( gap+2+nByte>top ){
-defragment_page:
     testcase( pPage->nCell==0 );
     rc = defragmentPage(pPage);
     if( rc ) return rc;
@@ -5933,48 +5962,18 @@ static void insertCell(
 }
 
 /*
-** Add a list of cells to a page.  The page should be initially empty.
-** The cells are guaranteed to fit on the page.
+** Array apCell[] contains pointers to nCell b-tree page cells. The 
+** szCell[] array contains the size in bytes of each cell. This function
+** replaces the current contents of page pPg with the contents of the cell
+** array.
+**
+** Some of the cells in apCell[] may currently be stored in pPg. This
+** function works around problems caused by this by making a copy of any 
+** such cells before overwriting the page data.
+**
+** The MemPage.nFree field is invalidated by this function. It is the 
+** responsibility of the caller to set it correctly.
 */
-static void assemblePage(
-  MemPage *pPage,   /* The page to be assembled */
-  int nCell,        /* The number of cells to add to this page */
-  u8 **apCell,      /* Pointers to cell bodies */
-  u16 *aSize        /* Sizes of the cells */
-){
-  int i;            /* Loop counter */
-  u8 *pCellptr;     /* Address of next cell pointer */
-  int cellbody;     /* Address of next cell body */
-  u8 * const data = pPage->aData;             /* Pointer to data for pPage */
-  const int hdr = pPage->hdrOffset;           /* Offset of header on pPage */
-  const int nUsable = pPage->pBt->usableSize; /* Usable size of page */
-
-  assert( pPage->nOverflow==0 );
-  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
-  assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt)
-            && (int)MX_CELL(pPage->pBt)<=10921);
-  assert( sqlite3PagerIswriteable(pPage->pDbPage) );
-
-  /* Check that the page has just been zeroed by zeroPage() */
-  assert( pPage->nCell==0 );
-  assert( get2byteNotZero(&data[hdr+5])==nUsable );
-
-  pCellptr = pPage->aCellIdx;
-  cellbody = nUsable;
-  for(i=0; i<nCell; i++){
-    u16 sz = aSize[i];
-    cellbody -= sz;
-    put2byte(pCellptr, cellbody);
-    pCellptr += 2;
-    memcpy(&data[cellbody], apCell[i], sz);
-  }
-  put2byte(&data[hdr+3], nCell);
-  put2byte(&data[hdr+5], cellbody);
-  pPage->nFree -= (nCell*2 + nUsable - cellbody);
-  pPage->nCell = (u16)nCell;
-}
-
-
 static void rebuildPage(
   MemPage *pPg,                   /* Edit this page */
   int nCell,                      /* Final number of cells on page */
@@ -5992,8 +5991,8 @@ static void rebuildPage(
 
   i = get2byte(&aData[hdr+5]);
   memcpy(&pTmp[i], &aData[i], usableSize - i);
-  pData = &aData[usableSize];
 
+  pData = pEnd;
   for(i=0; i<nCell; i++){
     u8 *pCell = apCell[i];
     if( pCell>aData && pCell<pEnd ){
@@ -6016,57 +6015,49 @@ static void rebuildPage(
   aData[hdr+7] = 0x00;
 }
 
-static u8 *pageFindSlot(MemPage *pPg, int nByte){
-  const int hdr = pPg->hdrOffset;
-  u8 * const aData = pPg->aData;
-  int iAddr;
-  int pc;
-  int usableSize = pPg->pBt->usableSize;
-
-  for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
-    int size;            /* Size of the free slot */
-    if( pc>usableSize-4 || pc<iAddr+4 ) return 0;
-    size = get2byte(&aData[pc+2]);
-    if( size>=nByte ){
-      int x = size - nByte;
-      testcase( x==4 );
-      testcase( x==3 );
-      if( x<4 ){
-        if( aData[hdr+7]>=60 ) return 0;
-        /* Remove the slot from the free-list. Update the number of
-         ** fragmented bytes within the page. */
-        memcpy(&aData[iAddr], &aData[pc], 2);
-        aData[hdr+7] += (u8)x;
-      }else if( size+pc > usableSize ){
-        return 0;
-      }else{
-        /* The slot remains on the free-list. Reduce its size to account
-         ** for the portion used by the new allocation. */
-        put2byte(&aData[pc+2], x);
-      }
-      return &aData[pc + x];
-    }
-  }
-
-  return 0;
-}
-
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
+** contains the size in bytes of each such cell. This function attempts to 
+** add the cells stored in the array to page pPg. If it cannot (because 
+** the page needs to be defragmented before the cells will fit), non-zero
+** is returned. Otherwise, if the cells are added successfully, zero is
+** returned.
+**
+** Argument pCellptr points to the first entry in the cell-pointer array
+** (part of page pPg) to populate. After cell apCell[0] is written to the
+** page body, a 16-bit offset is written to pCellptr. And so on, for each
+** cell in the array. It is the responsibility of the caller to ensure
+** that it is safe to overwrite this part of the cell-pointer array.
+**
+** When this function is called, *ppData points to the start of the 
+** content area on page pPg. If the size of the content area is extended,
+** *ppData is updated to point to the new start of the content area
+** before returning.
+**
+** Finally, argument pBegin points to the byte immediately following the
+** end of the space required by this page for the cell-pointer area (for
+** all cells - not just those inserted by the current call). If the content
+** area must be extended to before this point in order to accomodate all
+** cells in apCell[], then the cells do not fit and non-zero is returned.
+*/
 static int pageInsertArray(
-  MemPage *pPg,
-  u8 *pBegin,
-  u8 **ppData, 
-  u8 *pCellptr, 
-  int nCell,
+  MemPage *pPg,                   /* Page to add cells to */
+  u8 *pBegin,                     /* End of cell-pointer array */
+  u8 **ppData,                    /* IN/OUT: Page content -area pointer */
+  u8 *pCellptr,                   /* Pointer to cell-pointer area */
+  int nCell,                      /* Number of cells to add to pPg */
   u8 **apCell,                    /* Array of cells */
   u16 *szCell                     /* Array of cell sizes */
 ){
   int i;
   u8 *aData = pPg->aData;
   u8 *pData = *ppData;
+  const int bFreelist = aData[1] || aData[2];
+  assert( pPg->hdrOffset==0 );    /* Never called on page 1 */
   for(i=0; i<nCell; i++){
     int sz = szCell[i];
     u8 *pSlot;
-    if( (pSlot = pageFindSlot(pPg, sz))==0 ){
+    if( bFreelist==0 || (pSlot = pageFindSlot(pPg, sz, 0))==0 ){
       pData -= sz;
       if( pData<pBegin ) return 1;
       pSlot = pData;
@@ -6079,6 +6070,15 @@ static int pageInsertArray(
   return 0;
 }
 
+/*
+** Array apCell[] contains nCell pointers to b-tree cells. Array szCell 
+** contains the size in bytes of each such cell. This function adds the
+** space associated with each cell in the array that is currently stored 
+** within the body of pPg to the pPg free-list. The cell-pointers and other
+** fields of the page are not updated.
+**
+** This function returns the total number of cells added to the free-list.
+*/
 static int pageFreeArray(
   MemPage *pPg,                   /* Page to edit */
   int nCell,                      /* Cells to delete */
@@ -6111,7 +6111,6 @@ static int pageFreeArray(
   return nRet;
 }
 
-
 /*
 ** The pPg->nFree field is invalid when this function returns. It is the
 ** responsibility of the caller to set it correctly.
@@ -6206,15 +6205,8 @@ static void editPage(
   }
 #endif
 
-#if 0
-printf("EDIT\n");
-#endif
-
   return;
  editpage_fail:
-#if 0
-  printf("REBUILD\n");
-#endif
   /* Unable to edit this page. Rebuild it from scratch instead. */
   rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]);
 }
@@ -6288,7 +6280,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
     assert( sqlite3PagerIswriteable(pNew->pDbPage) );
     assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
     zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
-    assemblePage(pNew, 1, &pCell, &szCell);
+    rebuildPage(pNew, 1, &pCell, &szCell);
+    pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
 
     /* If this is an auto-vacuum database, update the pointer map
     ** with entries for the new page, and any pointer from the 
@@ -6518,8 +6511,6 @@ static int balance_nonroot(
   u8 *aSpace1;                 /* Space for copies of dividers cells */
   Pgno pgno;                   /* Temp var to store a page number in */
 
-  int aShiftLeft[NB+2];
-  int aShiftRight[NB+2];
   u8 abDone[NB+2];
   Pgno aPgno[NB+2];
   u16 aPgFlags[NB+2];
@@ -6887,49 +6878,6 @@ static int balance_nonroot(
   assert( sqlite3PagerIswriteable(pParent->pDbPage) );
   put4byte(pRight, apNew[nNew-1]->pgno);
 
-  j = 0;
-  for(i=0; i<nNew; i++){
-    /* At this point, "j" is the apCell[] index of the first cell currently
-    ** stored on page apNew[i]. Or, if apNew[i] was not one of the original 
-    ** sibling pages, "j" should be set to nCell. Variable iFirst is set
-    ** to the apCell[] index of the first cell that will appear on the
-    ** page following this balancing operation.  */
-    int iFirst = (i==0 ? 0 : cntNew[i-1] + !leafData);     /* new first cell */
-
-#if 0
-    MemPage *pNew = apNew[i];
-    int iCell;
-    int nCta = 0;
-    int nFree;
-
-    printf("REBUILD %d: %d@%d -> %d@%d", apNew[i]->pgno,
-          pNew->nCell+pNew->nOverflow, j,
-          cntNew[i] - iFirst, iFirst
-    );
-    for(iCell=iFirst; iCell<cntNew[i]; iCell++){
-      if( apCell[iCell]<pNew->aData 
-       || apCell[iCell]>=&pNew->aData[pBt->usableSize] 
-      ){
-        nCta += szCell[iCell];
-      }
-    }
-    nFree = get2byte(&pNew->aData[pNew->hdrOffset+5]);
-    nFree -= (pNew->cellOffset + (cntNew[i] - iFirst) * 2);
-    printf(" cta=%d free=%d\n", nCta, nFree);
-    if( i==(nNew-1) ){
-      printf("-----\n");
-      fflush(stdout);
-    }
-#endif
-
-    assert( i<nOld || j==nCell );
-    aShiftLeft[i] = j - iFirst;
-    j += apNew[i]->nCell + apNew[i]->nOverflow;
-    aShiftRight[i] = cntNew[i] - j;
-    assert( i!=nOld-1 || j==nCell );
-    if( j<nCell ) j += !leafData;
-  }
-
   /* If the sibling pages are not leaves, ensure that the right-child pointer
   ** of the right-most new sibling page is set to the value that was 
   ** originally in the same field of the right-most old sibling page. */
@@ -7047,22 +6995,21 @@ static int balance_nonroot(
   ** is important, as this code needs to avoid disrupting any page from which
   ** cells may still to be read. In practice, this means:
   **
-  **   1) If the aShiftLeft[] entry is less than 0, it is not safe to 
-  **      update the page until the page to the left of the current page
-  **      (apNew[i-1]) has already been updated.
+  **   1) If cells are to be removed from the start of the page and shifted
+  **      to the left-hand sibling, it is not safe to update the page until 
+  **      the left-hand sibling (apNew[i-1]) has already been updated.
   **
-  **   2) If the aShiftRight[] entry is less than 0, it is not safe to 
-  **      update the page until the page to the right of the current page
-  **      (apNew[i+1]) has already been updated.
+  **   2) If cells are to be removed from the end of the page and shifted
+  **      to the right-hand sibling, it is not safe to update the page until 
+  **      the right-hand sibling (apNew[i+1]) has already been updated.
   **
   ** If neither of the above apply, the page is safe to update.
   */
-  assert( aShiftRight[nNew-1]>=0 && aShiftLeft[0]==0 );
   for(i=0; i<nNew*2; i++){
     int iPg = (i>=nNew ? i-nNew : nNew-1-i);
     if( abDone[iPg]==0 
-     && (aShiftLeft[iPg]>=0 || abDone[iPg-1])
-     && (aShiftRight[iPg]>=0 || abDone[iPg+1])
+     && (iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1])
+     && (cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1])
     ){
       int iNew;
       int iOld;