1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Rework accessPayload() function for clarity. (CVS 3912)

FossilOrigin-Name: 42d07c70ec1eb6dd9619c97d753c9d2824aeae32
This commit is contained in:
danielk1977
2007-05-04 08:32:13 +00:00
parent acf1a933ca
commit da10719890
3 changed files with 126 additions and 82 deletions

View File

@@ -1,5 +1,5 @@
C fix\sfrom\sGentoo\sfor\sallowing\sTCLLIBDIR\sto\sbe\soverridden\sin\senv\s(CVS\s3911) C Rework\saccessPayload()\sfunction\sfor\sclarity.\s(CVS\s3912)
D 2007-05-03T20:06:11 D 2007-05-04T08:32:14
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -59,7 +59,7 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 1f75491c8d5348998ce53decc6fde671d4cfd36d F src/btree.c b88c9265e323b9a55290c39f9712e44050a6162c
F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0 F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42 F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
@@ -473,7 +473,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 64705410bdf43b6283f7a7e59ce8c20d09cd46e4 P e54a49e264ecd54083587f8d3b17cce4c811fddc
R b876dc164a523921b9a9aaaae2c8ff74 R 6675084e0bd9661ee80adf52bdde8264
U vapier U danielk1977
Z 4615c64c7ad9754928d4d7f62fcb1f5a Z cda47f0f1385e7692b319bbdf6df8c16

View File

@@ -1 +1 @@
e54a49e264ecd54083587f8d3b17cce4c811fddc 42d07c70ec1eb6dd9619c97d753c9d2824aeae32

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** 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. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@@ -3137,6 +3137,37 @@ static int getOverflowPage(
return rc; 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 ** 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 ** It just reads or writes bytes from the payload area. Data might
** appear on the main page or be scattered out on multiple overflow ** appear on the main page or be scattered out on multiple overflow
** pages. ** 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) #define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
static int accessPayload( static int accessPayload(
@@ -3163,92 +3209,101 @@ static int accessPayload(
int eOp /* zero to read. non-zero to write. */ int eOp /* zero to read. non-zero to write. */
){ ){
unsigned char *aPayload; unsigned char *aPayload;
Pgno nextPage; int rc = SQLITE_OK;
int rc;
MemPage *pPage;
BtShared *pBt;
int ovflSize;
u32 nKey; u32 nKey;
int iIdx = 0; 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 ); assert( pCur->eState==CURSOR_VALID );
pBt = pCur->pBtree->pBt;
pPage = pCur->pPage;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
assert( offset>=0 );
getCellInfo(pCur); getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader; aPayload = pCur->info.pCell + pCur->info.nHeader;
if( pPage->intKey ){ nKey = (pPage->intKey ? 0 : pCur->info.nKey);
nKey = 0;
}else{
nKey = pCur->info.nKey;
}
assert( offset>=0 );
if( skipKey ){ if( skipKey ){
offset += nKey; offset += nKey;
} }
if( offset+amt > nKey+pCur->info.nData ){ if( offset+amt > nKey+pCur->info.nData ){
/* Trying to read or write past the end of the data is an error */
return SQLITE_ERROR; return SQLITE_ERROR;
} }
/* Check if data must be read/written to/from the btree page itself. */
if( offset<pCur->info.nLocal ){ if( offset<pCur->info.nLocal ){
int a = amt; int a = amt;
if( a+offset>pCur->info.nLocal ){ if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset; a = pCur->info.nLocal - offset;
} }
if( eOp ){ rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
/* 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;
}
offset = 0; offset = 0;
pBuf += a; pBuf += a;
amt -= a; amt -= a;
}else{ }else{
offset -= pCur->info.nLocal; 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]); nextPage = get4byte(&aPayload[pCur->info.nLocal]);
#ifndef SQLITE_OMIT_INCRBLOB #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 ){ if( pCur->cacheOverflow && !pCur->aOverflow ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl); pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
if( nOvfl && !pCur->aOverflow ){ 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] ){ if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
iIdx = (offset/ovflSize); iIdx = (offset/ovflSize);
nextPage = pCur->aOverflow[iIdx]; nextPage = pCur->aOverflow[iIdx];
offset = (offset%ovflSize); offset = (offset%ovflSize);
} }
#endif #endif
for(iIdx++; amt>0 && nextPage; iIdx++){
if( offset>=ovflSize ){ for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
/* 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.
*/
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
if( rc!=SQLITE_OK ){
return rc;
}
offset -= ovflSize;
#ifndef SQLITE_OMIT_INCRBLOB #ifndef SQLITE_OMIT_INCRBLOB
/* If required, populate the overflow page-list cache. */
if( pCur->aOverflow ){ if( pCur->aOverflow ){
assert(nextPage); assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
pCur->aOverflow[iIdx] = nextPage; pCur->aOverflow[iIdx] = nextPage;
} }
#endif #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. 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.
*/
#ifndef SQLITE_OMIT_INCRBLOB
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{ }else{
/* Need to read this page properly. It contains some of the /* Need to read this page properly. It contains some of the
** range of data that is being read (eOp==0) or written (eOp!=0). ** range of data that is being read (eOp==0) or written (eOp!=0).
@@ -3256,43 +3311,26 @@ static int accessPayload(
DbPage *pDbPage; DbPage *pDbPage;
int a = amt; int a = amt;
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
if( rc!=0 ){ if( rc==SQLITE_OK ){
return rc;
}
aPayload = sqlite3PagerGetData(pDbPage); aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload); nextPage = get4byte(aPayload);
if( a + offset > ovflSize ){ if( a + offset > ovflSize ){
a = ovflSize - offset; a = ovflSize - offset;
} }
if( eOp ){ rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
/* A write operation. */
rc = sqlite3PagerWrite(pDbPage);
if( rc!=SQLITE_OK ){
sqlite3PagerUnref(pDbPage); sqlite3PagerUnref(pDbPage);
return rc;
}
memcpy(&aPayload[offset+4], pBuf, a);
}else{
/* A read operation */
memcpy(pBuf, &aPayload[offset+4], a);
}
offset = 0; offset = 0;
amt -= a; amt -= a;
pBuf += a; pBuf += a;
sqlite3PagerUnref(pDbPage);
#ifndef SQLITE_OMIT_INCRBLOB
if( pCur->aOverflow && nextPage ){
pCur->aOverflow[iIdx] = nextPage;
} }
#endif
} }
} }
} }
if( amt>0 ){ if( rc==SQLITE_OK && amt>0 ){
return SQLITE_CORRUPT_BKPT; 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 ** 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){ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
assert(!pCur->cacheOverflow); assert(!pCur->cacheOverflow);