]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rework accessPayload() function for clarity. (CVS 3912)
authordanielk1977 <danielk1977@noemail.net>
Fri, 4 May 2007 08:32:13 +0000 (08:32 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 4 May 2007 08:32:13 +0000 (08:32 +0000)
FossilOrigin-Name: 42d07c70ec1eb6dd9619c97d753c9d2824aeae32

manifest
manifest.uuid
src/btree.c

index 0676bc5d6705c88bd1d171fcb8d8bbb9982ab47b..5162054073fc529315742ae613977c12b720a413 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C fix\sfrom\sGentoo\sfor\sallowing\sTCLLIBDIR\sto\sbe\soverridden\sin\senv\s(CVS\s3911)
-D 2007-05-03T20:06:11
+C Rework\saccessPayload()\sfunction\sfor\sclarity.\s(CVS\s3912)
+D 2007-05-04T08:32:14
 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -59,7 +59,7 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
 F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
 F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
-F src/btree.c 1f75491c8d5348998ce53decc6fde671d4cfd36d
+F src/btree.c b88c9265e323b9a55290c39f9712e44050a6162c
 F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0
 F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
 F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
@@ -473,7 +473,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 64705410bdf43b6283f7a7e59ce8c20d09cd46e4
-R b876dc164a523921b9a9aaaae2c8ff74
-U vapier
-Z 4615c64c7ad9754928d4d7f62fcb1f5a
+P e54a49e264ecd54083587f8d3b17cce4c811fddc
+R 6675084e0bd9661ee80adf52bdde8264
+U danielk1977
+Z cda47f0f1385e7692b319bbdf6df8c16
index e6ef3b9b4efe88b28c36469931a8bcc9cb44e3a9..fc5cbf80a53034d016ac4d7b4cee783ee3026b89 100644 (file)
@@ -1 +1 @@
-e54a49e264ecd54083587f8d3b17cce4c811fddc
\ No newline at end of file
+42d07c70ec1eb6dd9619c97d753c9d2824aeae32
\ No newline at end of file
index 6fd0cc50e8ad16dd347176c99c92bea098aa3387..c517c9e0c57e044dd1bd4b42d167a10479541c70 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.370 2007/05/03 13:11:32 danielk1977 Exp $
+** $Id: btree.c,v 1.371 2007/05/04 08:32:14 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -3137,6 +3137,37 @@ static int getOverflowPage(
   return rc;
 }
 
+/*
+** Copy data from a buffer to a page, or from a page to a buffer.
+**
+** pPayload is a pointer to data stored on database page pDbPage.
+** If argument eOp is false, then nByte bytes of data are copied
+** from pPayload to the buffer pointed at by pBuf. If eOp is true,
+** then sqlite3PagerWrite() is called on pDbPage and nByte bytes
+** of data are copied from the buffer pBuf to pPayload.
+**
+** SQLITE_OK is returned on success, otherwise an error code.
+*/
+static int copyPayload(
+  void *pPayload,           /* Pointer to page data */
+  void *pBuf,               /* Pointer to buffer */
+  int nByte,                /* Number of bytes to copy */
+  int eOp,                  /* 0 -> copy from page, 1 -> copy to page */
+  DbPage *pDbPage           /* Page containing pPayload */
+){
+  if( eOp ){
+    /* Copy data from buffer to page (a write operation) */
+    int rc = sqlite3PagerWrite(pDbPage);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    memcpy(pPayload, pBuf, nByte);
+  }else{
+    /* Copy data from page to buffer (a read operation) */
+    memcpy(pBuf, pPayload, nByte);
+  }
+  return SQLITE_OK;
+}
 
 /*
 ** This function is used to read or overwrite payload information
@@ -3152,6 +3183,21 @@ static int getOverflowPage(
 ** It just reads or writes bytes from the payload area.  Data might 
 ** appear on the main page or be scattered out on multiple overflow 
 ** pages.
+**
+** If the BtCursor.cacheOverflow flag is set, and the current
+** cursor entry uses one or more overflow pages, this function
+** allocates space for and lazily popluates the overflow page-list 
+** cache array (BtCursor.aOverflow). Subsequent calls use this
+** cache to make seeking to the supplied offset more efficient.
+**
+** Once an overflow page-list cache has been allocated, it may be
+** invalidated if some other cursor writes to the same table, or if
+** the cursor is moved to a different row. Additionally, in auto-vacuum
+** mode, the following events may invalidate an overflow page-list cache.
+**
+**   * An incremental vacuum,
+**   * A commit in auto_vacuum="full" mode,
+**   * Creating a table (may require moving an overflow page).
 */
 #define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
 static int accessPayload(
@@ -3163,92 +3209,101 @@ static int accessPayload(
   int eOp              /* zero to read. non-zero to write. */
 ){
   unsigned char *aPayload;
-  Pgno nextPage;
-  int rc;
-  MemPage *pPage;
-  BtShared *pBt;
-  int ovflSize;
+  int rc = SQLITE_OK;
   u32 nKey;
   int iIdx = 0;
+  MemPage *pPage = pCur->pPage;        /* Btree page of current cursor entry */
+  BtShared *pBt = pCur->pBtree->pBt;   /* Btree this cursor belongs to */
 
-  assert( pCur!=0 && pCur->pPage!=0 );
+  assert( pPage );
   assert( pCur->eState==CURSOR_VALID );
-  pBt = pCur->pBtree->pBt;
-  pPage = pCur->pPage;
   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+  assert( offset>=0 );
+
   getCellInfo(pCur);
   aPayload = pCur->info.pCell + pCur->info.nHeader;
-  if( pPage->intKey ){
-    nKey = 0;
-  }else{
-    nKey = pCur->info.nKey;
-  }
-  assert( offset>=0 );
+  nKey = (pPage->intKey ? 0 : pCur->info.nKey);
+
   if( skipKey ){
     offset += nKey;
   }
   if( offset+amt > nKey+pCur->info.nData ){
+    /* Trying to read or write past the end of the data is an error */
     return SQLITE_ERROR;
   }
+
+  /* Check if data must be read/written to/from the btree page itself. */
   if( offset<pCur->info.nLocal ){
     int a = amt;
     if( a+offset>pCur->info.nLocal ){
       a = pCur->info.nLocal - offset;
     }
-    if( eOp ){
-      /* A write operation. */
-      rc = sqlite3PagerWrite(pPage->pDbPage);
-      if( rc!=SQLITE_OK ){
-        return rc;
-      }
-      memcpy(&aPayload[offset], pBuf, a);
-    }else{
-      /* A read operation */
-      memcpy(pBuf, &aPayload[offset], a);
-    }
-    if( a==amt ){
-      return SQLITE_OK;
-    }
+    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
     offset = 0;
     pBuf += a;
     amt -= a;
   }else{
     offset -= pCur->info.nLocal;
   }
-  ovflSize = pBt->usableSize - 4;
-  if( amt>0 ){
+
+  if( rc==SQLITE_OK && amt>0 ){
+    const int ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
+    Pgno nextPage;
+
     nextPage = get4byte(&aPayload[pCur->info.nLocal]);
+
 #ifndef SQLITE_OMIT_INCRBLOB
+    /* If the cacheOverflow flag is set and the BtCursor.aOverflow[]
+    ** has not been allocated, allocate it now. The array is sized at
+    ** one entry for each overflow page in the overflow chain. The
+    ** page number of the first overflow page is stored in aOverflow[0],
+    ** etc. A value of 0 in the aOverflow[] array means "not yet known"
+    ** (the cache is lazily populated).
+    */
     if( pCur->cacheOverflow && !pCur->aOverflow ){
       int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
       pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
       if( nOvfl && !pCur->aOverflow ){
-        return SQLITE_NOMEM;
+        rc = SQLITE_NOMEM;
       }
     }
+
+    /* If the overflow page-list cache has been allocated and the
+    ** entry for the first required overflow page is valid, skip
+    ** directly to it.
+    */
     if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
       iIdx = (offset/ovflSize);
       nextPage = pCur->aOverflow[iIdx];
       offset = (offset%ovflSize);
     }
 #endif
-    for(iIdx++; amt>0 && nextPage; iIdx++){
+
+    for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
+
+#ifndef SQLITE_OMIT_INCRBLOB
+      /* If required, populate the overflow page-list cache. */
+      if( pCur->aOverflow ){
+        assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
+        pCur->aOverflow[iIdx] = nextPage;
+      }
+#endif
+
       if( offset>=ovflSize ){
         /* The only reason to read this page is to obtain the page
-        ** number for the next page in the overflow chain. So try
-        ** the getOverflowPage() shortcut.
+        ** number for the next page in the overflow chain. The page
+       ** data is not required. So first try to lookup the overflow
+       ** page-list cache, if any, then fall back to the getOverflowPage()
+        ** function.
         */
-        rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
-        if( rc!=SQLITE_OK ){
-          return rc;
-        }
-        offset -= ovflSize;
 #ifndef SQLITE_OMIT_INCRBLOB
-        if( pCur->aOverflow ){
-          assert(nextPage);
-          pCur->aOverflow[iIdx] = nextPage;
-        }
+        if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
+          nextPage = pCur->aOverflow[iIdx+1];
+        } else 
 #endif
+          rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
+        assert(rc==SQLITE_OK || nextPage==0);
+        offset -= ovflSize;
       }else{
         /* Need to read this page properly. It contains some of the
         ** range of data that is being read (eOp==0) or written (eOp!=0).
@@ -3256,43 +3311,26 @@ static int accessPayload(
         DbPage *pDbPage;
         int a = amt;
         rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
-        if( rc!=0 ){
-          return rc;
-        }
-        aPayload = sqlite3PagerGetData(pDbPage);
-        nextPage = get4byte(aPayload);
-        if( a + offset > ovflSize ){
-          a = ovflSize - offset;
-        }
-        if( eOp ){
-          /* A write operation. */
-          rc = sqlite3PagerWrite(pDbPage);
-          if( rc!=SQLITE_OK ){
-            sqlite3PagerUnref(pDbPage);
-            return rc;
+        if( rc==SQLITE_OK ){
+          aPayload = sqlite3PagerGetData(pDbPage);
+          nextPage = get4byte(aPayload);
+          if( a + offset > ovflSize ){
+            a = ovflSize - offset;
           }
-          memcpy(&aPayload[offset+4], pBuf, a);
-        }else{
-          /* A read operation */
-          memcpy(pBuf, &aPayload[offset+4], a);
-        }
-        offset = 0;
-        amt -= a;
-        pBuf += a;
-        sqlite3PagerUnref(pDbPage);
-#ifndef SQLITE_OMIT_INCRBLOB
-        if( pCur->aOverflow && nextPage ){
-          pCur->aOverflow[iIdx] = nextPage;
+          rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
+          sqlite3PagerUnref(pDbPage);
+          offset = 0;
+          amt -= a;
+          pBuf += a;
         }
-#endif
       }
     }
   }
 
-  if( amt>0 ){
+  if( rc==SQLITE_OK && amt>0 ){
     return SQLITE_CORRUPT_BKPT;
   }
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
@@ -6983,7 +7021,13 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
 
 /* 
 ** Set a flag on this cursor to cache the locations of pages from the 
-** overflow list for the current row.
+** overflow list for the current row. This is used by cursors opened
+** for incremental blob IO only.
+**
+** This function sets a flag only. The actual page location cache
+** (stored in BtCursor.aOverflow[]) is allocated and used by function
+** accessPayload() (the worker function for sqlite3BtreeData() and
+** sqlite3BtreePutData()).
 */
 void sqlite3BtreeCacheOverflow(BtCursor *pCur){
   assert(!pCur->cacheOverflow);