]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further work on balance_nonroot().
authordan <dan@noemail.net>
Mon, 13 Oct 2014 18:03:27 +0000 (18:03 +0000)
committerdan <dan@noemail.net>
Mon, 13 Oct 2014 18:03:27 +0000 (18:03 +0000)
FossilOrigin-Name: 6594f9b420e2fa642737722ff8521f756ecef227

manifest
manifest.uuid
src/btree.c

index 7e782aa82c81ba1bb771863452de787b20a0a262..9f25f390d917be1e686b5708d6145b4714f0aeae 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Attempt\sto\sfurther\sreduce\smemcpy()\sin\sbalance_nonroot().
-D 2014-10-11T20:00:24.552
+C Further\swork\son\sbalance_nonroot().
+D 2014-10-13T18:03:27.743
 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 d5f4f74e309f79ace4b4025c433874ead635bed2
+F src/btree.c 63211ca1d4ae867eede39a37901aec4746d904a7
 F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
 F src/btreeInt.h 1bd7957161a1346a914f1f09231610e777a8e58d
 F src/build.c bde83dd5cf812e310a7e5ad2846790a14745bef4
@@ -1200,7 +1200,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 29304499ea4b72dbb6701e10cc19b5d41f7e5ac9
-R 3235ac37769ff059d7c714947e8a11dd
+P fec849dcca3aead2bc2d4ecffeda750684d32fb0
+R 79e5b5564c934fc68257d82dc897cefd
 U dan
-Z 17fdfd7faf788bbb79d2ec9941c17025
+Z ae5b74eee28666050af6baaa639de56c
index 006b3c0008152a21bf0096cf81a0e0dd4018f84c..fcba485229167e9d00102b5a1c6fce992133a2fc 100644 (file)
@@ -1 +1 @@
-fec849dcca3aead2bc2d4ecffeda750684d32fb0
\ No newline at end of file
+6594f9b420e2fa642737722ff8521f756ecef227
\ No newline at end of file
index 13ec9127480d1f671d90f9d2b750b6889387beea..7c9a7228de7e2244f9a656c51effa21d4c24ada9 100644 (file)
@@ -6009,7 +6009,7 @@ static void rebuildPage(
     assert( szCell[i]==cellSizePtr(pPg, pCell) );
   }
 
-  pPg->nFree = (pData - pCellptr);
+  /* The pPg->nFree field is now set incorrectly. The caller will fix it. */
   pPg->nCell = nCell;
   pPg->nOverflow = 0;
 
@@ -6019,6 +6019,106 @@ 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;
+}
+
+static int pageInsertArray(
+  MemPage *pPg,
+  u8 *pBegin,
+  u8 **ppData, 
+  u8 *pCellptr, 
+  int nCell,
+  u8 **apCell,                    /* Array of cells */
+  u16 *szCell                     /* Array of cell sizes */
+){
+  int i;
+  u8 *aData = pPg->aData;
+  u8 *pData = *ppData;
+  for(i=0; i<nCell; i++){
+    int sz = szCell[i];
+    u8 *pSlot;
+    if( (pSlot = pageFindSlot(pPg, sz))==0 ){
+      pData -= sz;
+      if( pData<pBegin ) return 1;
+      pSlot = pData;
+    }
+    memcpy(pSlot, apCell[i], sz);
+    put2byte(pCellptr, (pSlot - aData));
+    pCellptr += 2;
+  }
+  *ppData = pData;
+  return 0;
+}
+
+static int pageFreeArray(
+  MemPage *pPg,                   /* Page to edit */
+  int nCell,                      /* Cells to delete */
+  u8 **apCell,                    /* Array of cells */
+  u16 *szCell                     /* Array of cell sizes */
+){
+  u8 * const aData = pPg->aData;
+  u8 * const pEnd = &aData[pPg->pBt->usableSize];
+  int nRet = 0;
+  int i;
+  u8 *pFree = 0;
+  int szFree = 0;
+
+  for(i=0; i<nCell; i++){
+    u8 *pCell = apCell[i];
+    if( pCell>aData && pCell<pEnd ){
+      int sz = szCell[i];
+      if( pFree!=(pCell + sz) ){
+        if( pFree ) freeSpace(pPg, pFree - aData, szFree);
+        pFree = pCell;
+        szFree = sz;
+      }else{
+        pFree = pCell;
+        szFree += sz;
+      }
+      nRet++;
+    }
+  }
+  if( pFree ) freeSpace(pPg, pFree - aData, szFree);
+  return nRet;
+}
+
+
+/*
+** The pPg->nFree field is invalid when this function returns. It is the
+** responsibility of the caller to set it correctly.
+*/
 static void editPage(
   MemPage *pPg,                   /* Edit this page */
   int iOld,                       /* Index of first cell currently on page */
@@ -6027,113 +6127,93 @@ static void editPage(
   u8 **apCell,                    /* Array of cells */
   u16 *szCell                     /* Array of cell sizes */
 ){
-
-  if( 1 ){
-    u8 * const aData = pPg->aData;
-    const int hdr = pPg->hdrOffset;
-    u8 *pBegin = &pPg->aCellIdx[nNew * 2];
-    int nFree = pPg->nFree;       /* Free bytes on pPg */
-    int nCell = pPg->nCell;       /* Cells stored on pPg */
-    u8 *pData;
-    u8 *pCellptr;
-    int i;
-    int iOldEnd = iOld + pPg->nCell + pPg->nOverflow;
+  u8 * const aData = pPg->aData;
+  const int hdr = pPg->hdrOffset;
+  u8 *pBegin = &pPg->aCellIdx[nNew * 2];
+  int nCell = pPg->nCell;       /* Cells stored on pPg */
+  u8 *pData;
+  u8 *pCellptr;
+  int i;
+  int iOldEnd = iOld + pPg->nCell + pPg->nOverflow;
+  int iNewEnd = iNew + nNew;
 
 #ifdef SQLITE_DEBUG
-    u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
-    memcpy(pTmp, aData, pPg->pBt->usableSize);
+  u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
+  memcpy(pTmp, aData, pPg->pBt->usableSize);
 #endif
 
-    /* Remove cells from the start and end of the page */
-    if( iOld<iNew ){
-      int nShift = 0;
-      for(i=iOld; i<iNew; i++){
-        if( apCell[i]>aData && apCell[i]<&aData[pPg->pBt->usableSize] ){
-          freeSpace(pPg, apCell[i] - aData, szCell[i]);
-          nFree += szCell[i] + 2;
-          nShift++;
-        }
-      }
-      nCell -= nShift;
-      memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
-    }
-    for(i=iNew+nNew; i<iOldEnd; i++){
-      if( apCell[i]>aData && apCell[i]<&aData[pPg->pBt->usableSize] ){
-        freeSpace(pPg, apCell[i] - aData, szCell[i]);
-        nFree += szCell[i] + 2;
-        nCell--;
-      }
-    }
-    pData = &aData[get2byte(&aData[hdr+5])];
-    if( pData<pBegin ) goto editpage_fail;
-
-    /* Add cells to the start of the page */
-    if( iNew<iOld ){
-      pCellptr = pPg->aCellIdx;
-      memmove(&pCellptr[(iOld-iNew)*2], pCellptr, nCell*2);
-      for(i=iNew; i<iOld; i++){
-        pData -= szCell[i];
-        if( pData<pBegin ) goto editpage_fail;
-        memcpy(pData, apCell[i], szCell[i]);
-        put2byte(pCellptr, (pData - aData));
-        pCellptr += 2;
-        nFree -= (szCell[i] + 2);
-        nCell++;
-      }
-    }
+  /* Remove cells from the start and end of the page */
+  if( iOld<iNew ){
+    int nShift = pageFreeArray(
+        pPg, iNew-iOld, &apCell[iOld], &szCell[iOld]
+    );
+    memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
+    nCell -= nShift;
+  }
+  if( iNewEnd < iOldEnd ){
+    nCell -= pageFreeArray(
+        pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd]
+    );
+  }
 
-    /* Add any overflow cells */
-    for(i=0; i<pPg->nOverflow; i++){
-      int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
-      if( iCell>=0 && iCell<nNew ){
-        u8 *pCellptr = &pPg->aCellIdx[iCell * 2];
-        int sz = szCell[iCell+iNew];
-        memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
-        pData -= sz;
-        if( pData<pBegin ) goto editpage_fail;
-        memcpy(pData, apCell[iCell+iNew], sz);
-        put2byte(pCellptr, (pData - aData));
-        nFree -= (sz + 2);
-        nCell++;
-      }
-    }
+  pData = &aData[get2byte(&aData[hdr+5])];
+  if( pData<pBegin ) goto editpage_fail;
+
+  /* Add cells to the start of the page */
+  if( iNew<iOld ){
+    int nAdd = iOld-iNew;
+    pCellptr = pPg->aCellIdx;
+    memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
+    if( pageInsertArray(
+          pPg, pBegin, &pData, pCellptr,
+          nAdd, &apCell[iNew], &szCell[iNew]
+    ) ) goto editpage_fail;
+    nCell += nAdd;
+  }
 
-    /* Append cells to the end of the page */
-    pCellptr = &pPg->aCellIdx[nCell*2];
-    for(i=iNew+nCell; i<(iNew+nNew); i++){
-      pData -= szCell[i];
-      if( pData<pBegin ) goto editpage_fail;
-      memcpy(pData, apCell[i], szCell[i]);
-      put2byte(pCellptr, (pData - aData));
-      pCellptr += 2;
-      nFree -= (szCell[i] + 2);
+  /* Add any overflow cells */
+  for(i=0; i<pPg->nOverflow; i++){
+    int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
+    if( iCell>=0 && iCell<nNew ){
+      u8 *pCellptr = &pPg->aCellIdx[iCell * 2];
+      memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+      nCell++;
+      if( pageInsertArray(
+            pPg, pBegin, &pData, pCellptr,
+            1, &apCell[iCell + iNew], &szCell[iCell + iNew]
+      ) ) goto editpage_fail;
     }
+  }
 
-    pPg->nFree = nFree;
-    pPg->nCell = nNew;
-    pPg->nOverflow = 0;
+  /* Append cells to the end of the page */
+  pCellptr = &pPg->aCellIdx[nCell*2];
+  if( pageInsertArray(
+        pPg, pBegin, &pData, pCellptr,
+        nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell]
+  ) ) goto editpage_fail;
 
-    put2byte(&aData[hdr+3], pPg->nCell);
-    put2byte(&aData[hdr+5], pData - aData);
+  pPg->nCell = nNew;
+  pPg->nOverflow = 0;
+
+  put2byte(&aData[hdr+3], pPg->nCell);
+  put2byte(&aData[hdr+5], pData - aData);
 
 #ifdef SQLITE_DEBUG
-    for(i=0; i<nNew; i++){
-      u8 *pCell = apCell[i+iNew];
-      int iOff = get2byte(&pPg->aCellIdx[i*2]);
-      if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
-        pCell = &pTmp[pCell - aData];
-      }
-      assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) );
+  for(i=0; i<nNew; i++){
+    u8 *pCell = apCell[i+iNew];
+    int iOff = get2byte(&pPg->aCellIdx[i*2]);
+    if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
+      pCell = &pTmp[pCell - aData];
     }
+    assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) );
+  }
 #endif
 
 #if 0
-  printf("EDIT\n");
+printf("EDIT\n");
 #endif
 
-    return;
-  }
-
+  return;
  editpage_fail:
 #if 0
   printf("REBUILD\n");
@@ -6662,7 +6742,7 @@ static int balance_nonroot(
     assert( i<nMaxCells );
     subtotal += szCell[i] + 2;
     if( subtotal > usableSpace ){
-      szNew[k] = subtotal - szCell[i];
+      szNew[k] = subtotal - szCell[i] - 2;
       cntNew[k] = i;
       if( leafData ){ i--; }
       subtotal = 0;
@@ -7002,6 +7082,7 @@ static int balance_nonroot(
 
       editPage(apNew[iPg], iOld, iNew, nNewCell, apCell, szCell);
       abDone[iPg] = 1;
+      apNew[iPg]->nFree = usableSpace-szNew[iPg];
       assert( apNew[iPg]->nOverflow==0 );
       assert( apNew[iPg]->nCell==nNewCell );
     }