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

Merge recent trunk changes into the threads branch.

FossilOrigin-Name: 8729aa3e3ed1da2e15408ef8705cbe185cd2a5ac
This commit is contained in:
drh
2014-04-18 12:38:54 +00:00
24 changed files with 353 additions and 179 deletions

View File

@@ -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->curFlags &= ~BTCF_ValidOvfl)
/*
** 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
@@ -491,16 +487,14 @@ static void invalidateIncrblobCursors(
BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) );
for(p=pBt->pCursor; p; p=p->pNext){
if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){
if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
p->eState = CURSOR_INVALID;
}
}
}
#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 */
@@ -2563,7 +2557,8 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
&& pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
@@ -3638,7 +3633,8 @@ static int btreeCursor(
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
pCur->wrFlag = (u8)wrFlag;
assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
pCur->curFlags = wrFlag;
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
pCur->pNext->pPrev = pCur;
@@ -3708,7 +3704,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
releasePage(pCur->apPage[i]);
}
unlockBtreeIfUnused(pBt);
invalidateOverflowCache(pCur);
sqlite3DbFree(pBtree->db, pCur->aOverflow);
/* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree);
}
@@ -3747,7 +3743,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
pCur->validNKey = 1;
pCur->curFlags |= BTCF_ValidNKey;
}else{
assertCellInfo(pCur);
}
@@ -3757,8 +3753,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#define getCellInfo(pCur) \
if( pCur->info.nSize==0 ){ \
int iPage = pCur->iPage; \
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
pCur->validNKey = 1; \
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
pCur->curFlags |= BTCF_ValidNKey; \
}else{ \
assertCellInfo(pCur); \
}
@@ -3929,10 +3925,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.
@@ -3940,11 +3938,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
@@ -3968,15 +3966,22 @@ static int accessPayload(
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
int bEnd; /* True if reading to end of data */
#endif
assert( pPage );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
#ifdef SQLITE_DIRECT_OVERFLOW_READ
bEnd = (offset+amt==nKey+pCur->info.nData);
#endif
if( NEVER(offset+amt > nKey+pCur->info.nData)
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
@@ -3991,7 +3996,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;
@@ -4005,21 +4010,30 @@ 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
** 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 the BtCursor.aOverflow[] has not been allocated, allocate it now.
** Except, do not allocate aOverflow[] for eOp==2.
**
** The aOverflow[] 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->isIncrblobHandle && !pCur->aOverflow ){
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
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->curFlags |= BTCF_ValidOvfl;
}
}
@@ -4027,22 +4041,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->curFlags & BTCF_ValidOvfl)!=0 && 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->curFlags & BTCF_ValidOvfl)!=0 ){
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
@@ -4050,13 +4061,17 @@ static int accessPayload(
** data is not required. So first try to lookup the overflow
** page-list cache, if any, then fall back to the getOverflowPage()
** function.
**
** Note that the aOverflow[] array must be allocated because eOp!=2
** here. If eOp==2, then offset==0 and this branch is never taken.
*/
#ifndef SQLITE_OMIT_INCRBLOB
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
assert( eOp!=2 );
assert( pCur->curFlags & BTCF_ValidOvfl );
if( pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1];
} else
#endif
}else{
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
}
offset -= ovflSize;
}else{
/* Need to read this page properly. It contains some of the
@@ -4078,13 +4093,15 @@ static int accessPayload(
** 3) the database is file-backed, and
** 4) there is no open write-transaction, and
** 5) the database is not a WAL database,
** 6) all data from the page is being read.
**
** then data can be read directly from the database file into the
** 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) */
&& (bEnd || a==ovflSize) /* (6) */
&& pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
&& pBt->pPage1->aData[19]==0x01 /* (5) */
@@ -4101,12 +4118,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;
}
@@ -4257,14 +4274,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, newPgno, &pNewPage,
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0;
pCur->iPage++;
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
return SQLITE_CORRUPT_BKPT;
}
@@ -4322,7 +4339,7 @@ static void moveToParent(BtCursor *pCur){
releasePage(pCur->apPage[pCur->iPage]);
pCur->iPage--;
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
}
/*
@@ -4369,7 +4386,7 @@ static int moveToRoot(BtCursor *pCur){
return SQLITE_OK;
}else{
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -4396,8 +4413,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->aiIdx[0] = 0;
pCur->info.nSize = 0;
pCur->atLast = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
@@ -4460,7 +4476,7 @@ static int moveToRightmost(BtCursor *pCur){
if( rc==SQLITE_OK ){
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~BTCF_ValidNKey;
}
return rc;
}
@@ -4499,7 +4515,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && pCur->atLast ){
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
#ifdef SQLITE_DEBUG
/* This block serves to assert() that the cursor really does point
** to the last entry in the b-tree. */
@@ -4522,7 +4538,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
rc = moveToRightmost(pCur);
pCur->atLast = rc==SQLITE_OK ?1:0;
if( rc==SQLITE_OK ){
pCur->curFlags |= BTCF_AtLast;
}else{
pCur->curFlags &= ~BTCF_AtLast;
}
}
}
return rc;
@@ -4573,14 +4594,14 @@ int sqlite3BtreeMovetoUnpacked(
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && pCur->validNKey
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
&& pCur->apPage[0]->intKey
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
return SQLITE_OK;
}
if( pCur->atLast && pCur->info.nKey<intKey ){
if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
*pRes = -1;
return SQLITE_OK;
}
@@ -4647,7 +4668,7 @@ int sqlite3BtreeMovetoUnpacked(
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
pCur->validNKey = 1;
pCur->curFlags |= BTCF_ValidNKey;
pCur->info.nKey = nCellKey;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( !pPage->leaf ){
@@ -4704,7 +4725,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;
@@ -4754,7 +4775,7 @@ moveto_next_layer:
}
moveto_finish:
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
return rc;
}
@@ -4799,6 +4820,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){
invalidateOverflowCache(pCur);
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
@@ -4832,7 +4854,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
testcase( idx>pPage->nCell );
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
@@ -4893,7 +4915,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->atLast = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ){
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
rc = btreeRestoreCursorPosition(pCur);
@@ -4938,7 +4960,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
moveToParent(pCur);
}
pCur->info.nSize = 0;
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage];
@@ -6963,7 +6985,7 @@ int sqlite3BtreeInsert(
}
assert( cursorHoldsMutex(pCur) );
assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
@@ -6996,7 +7018,7 @@ int sqlite3BtreeInsert(
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
** call */
if( pCur->validNKey && nKey>0 && pCur->info.nKey==nKey-1 ){
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
loc = -1;
}
}
@@ -7049,7 +7071,7 @@ int sqlite3BtreeInsert(
/* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
** variables.
**
** Previous versions of SQLite called moveToRoot() to move the cursor
@@ -7069,7 +7091,7 @@ int sqlite3BtreeInsert(
*/
pCur->info.nSize = 0;
if( rc==SQLITE_OK && pPage->nOverflow ){
pCur->validNKey = 0;
pCur->curFlags &= ~(BTCF_ValidNKey);
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
@@ -7101,7 +7123,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->wrFlag );
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
@@ -8414,7 +8436,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc;
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert( pCsr->isIncrblobHandle );
assert( pCsr->curFlags & BTCF_Incrblob );
rc = restoreCursorPosition(pCsr);
if( rc!=SQLITE_OK ){
@@ -8443,7 +8465,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
** (d) there are no conflicting read-locks, and
** (e) the cursor points at a valid row of an intKey table.
*/
if( !pCsr->wrFlag ){
if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
return SQLITE_READONLY;
}
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
@@ -8456,20 +8478,10 @@ 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);
pCur->isIncrblobHandle = 1;
void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
pCur->curFlags |= BTCF_Incrblob;
}
#endif