mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Enable the b-tree cursor objects overflow page-number cache, which is normally enabled only for incr-blob cursors, for all cursors.
FossilOrigin-Name: da59198505990a4fe832be7932117c7e014955b7
This commit is contained in:
98
src/btree.c
98
src/btree.c
@@ -446,16 +446,11 @@ static int cursorHoldsMutex(BtCursor *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for cursor pCur, if any.
|
||||
** Invalidate the overflow cache of the cursor passed as the first argument.
|
||||
** on the shared btree structure pBt.
|
||||
*/
|
||||
static void invalidateOverflowCache(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
sqlite3_free(pCur->aOverflow);
|
||||
pCur->aOverflow = 0;
|
||||
}
|
||||
#define invalidateOverflowCache(pCur) (pCur->bOvflValid = 0)
|
||||
|
||||
/*
|
||||
** Invalidate the overflow page-list cache for all cursors opened
|
||||
@@ -469,6 +464,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** This function is called before modifying the contents of a table
|
||||
** to invalidate any incrblob cursors that are open on the
|
||||
@@ -498,9 +494,7 @@ static void invalidateIncrblobCursors(
|
||||
}
|
||||
|
||||
#else
|
||||
/* Stub functions when INCRBLOB is omitted */
|
||||
#define invalidateOverflowCache(x)
|
||||
#define invalidateAllOverflowCache(x)
|
||||
/* Stub function when INCRBLOB is omitted */
|
||||
#define invalidateIncrblobCursors(x,y,z)
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
@@ -3694,7 +3688,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
releasePage(pCur->apPage[i]);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
invalidateOverflowCache(pCur);
|
||||
sqlite3DbFree(pBtree->db, pCur->aOverflow);
|
||||
/* sqlite3_free(pCur); */
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
@@ -3915,10 +3909,12 @@ static int copyPayload(
|
||||
|
||||
/*
|
||||
** This function is used to read or overwrite payload information
|
||||
** for the entry that the pCur cursor is pointing to. If the eOp
|
||||
** parameter is 0, this is a read operation (data copied into
|
||||
** buffer pBuf). If it is non-zero, a write (data copied from
|
||||
** buffer pBuf).
|
||||
** for the entry that the pCur cursor is pointing to. The eOp
|
||||
** argument is interpreted as follows:
|
||||
**
|
||||
** 0: The operation is a read. Populate the overflow cache.
|
||||
** 1: The operation is a write. Populate the overflow cache.
|
||||
** 2: The operation is a read. Do not populate the overflow cache.
|
||||
**
|
||||
** A total of "amt" bytes are read or written beginning at "offset".
|
||||
** Data is read to or from the buffer pBuf.
|
||||
@@ -3926,11 +3922,11 @@ static int copyPayload(
|
||||
** The content being read or written might appear on the main page
|
||||
** or be scattered out on multiple overflow pages.
|
||||
**
|
||||
** If the BtCursor.isIncrblobHandle 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.
|
||||
** If the current cursor entry uses one or more overflow pages and the
|
||||
** eOp argument is not 2, this function may allocate 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
|
||||
@@ -3977,7 +3973,7 @@ static int accessPayload(
|
||||
if( a+offset>pCur->info.nLocal ){
|
||||
a = pCur->info.nLocal - offset;
|
||||
}
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
|
||||
offset = 0;
|
||||
pBuf += a;
|
||||
amt -= a;
|
||||
@@ -3991,7 +3987,6 @@ static int accessPayload(
|
||||
|
||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If the isIncrblobHandle 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
|
||||
@@ -3999,13 +3994,22 @@ static int accessPayload(
|
||||
** etc. A value of 0 in the aOverflow[] array means "not yet known"
|
||||
** (the cache is lazily populated).
|
||||
*/
|
||||
if( pCur->isIncrblobHandle && !pCur->aOverflow ){
|
||||
if( eOp!=2 && !pCur->bOvflValid ){
|
||||
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
||||
pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
|
||||
/* nOvfl is always positive. If it were zero, fetchPayload would have
|
||||
** been used instead of this routine. */
|
||||
if( ALWAYS(nOvfl) && !pCur->aOverflow ){
|
||||
rc = SQLITE_NOMEM;
|
||||
if( nOvfl>pCur->nOvflAlloc ){
|
||||
Pgno *aNew = (Pgno*)sqlite3DbRealloc(
|
||||
pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
|
||||
);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pCur->nOvflAlloc = nOvfl*2;
|
||||
pCur->aOverflow = aNew;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
|
||||
pCur->bOvflValid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4013,22 +4017,19 @@ static int accessPayload(
|
||||
** entry for the first required overflow page is valid, skip
|
||||
** directly to it.
|
||||
*/
|
||||
if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
|
||||
if( pCur->bOvflValid && pCur->aOverflow[offset/ovflSize] ){
|
||||
iIdx = (offset/ovflSize);
|
||||
nextPage = pCur->aOverflow[iIdx];
|
||||
offset = (offset%ovflSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
/* If required, populate the overflow page-list cache. */
|
||||
if( pCur->aOverflow ){
|
||||
if( pCur->bOvflValid ){
|
||||
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
|
||||
@@ -4037,11 +4038,9 @@ static int accessPayload(
|
||||
** page-list cache, if any, then fall back to the getOverflowPage()
|
||||
** function.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
|
||||
if( pCur->bOvflValid && pCur->aOverflow[iIdx+1] ){
|
||||
nextPage = pCur->aOverflow[iIdx+1];
|
||||
} else
|
||||
#endif
|
||||
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
|
||||
offset -= ovflSize;
|
||||
}else{
|
||||
@@ -4069,7 +4068,7 @@ static int accessPayload(
|
||||
** output buffer, bypassing the page-cache altogether. This speeds
|
||||
** up loading large records that span many overflow pages.
|
||||
*/
|
||||
if( eOp==0 /* (1) */
|
||||
if( (eOp&0x01)==0 /* (1) */
|
||||
&& offset==0 /* (2) */
|
||||
&& pBt->inTransaction==TRANS_READ /* (4) */
|
||||
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
|
||||
@@ -4087,12 +4086,12 @@ static int accessPayload(
|
||||
{
|
||||
DbPage *pDbPage;
|
||||
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
|
||||
(eOp==0 ? PAGER_GET_READONLY : 0)
|
||||
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
aPayload = sqlite3PagerGetData(pDbPage);
|
||||
nextPage = get4byte(aPayload);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
offset = 0;
|
||||
}
|
||||
@@ -4337,6 +4336,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
|
||||
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
|
||||
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
|
||||
invalidateOverflowCache(pCur);
|
||||
if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
@@ -4686,7 +4686,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
@@ -4775,6 +4775,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
invalidateOverflowCache(pCur);
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -4870,6 +4871,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
invalidateOverflowCache(pCur);
|
||||
pCur->atLast = 0;
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
|
||||
@@ -8424,19 +8426,9 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set a flag on this cursor to cache the locations of pages from the
|
||||
** 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()).
|
||||
** Mark this cursor as an incremental blob cursor.
|
||||
*/
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
invalidateOverflowCache(pCur);
|
||||
void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
|
||||
pCur->isIncrblobHandle = 1;
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user