Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Cache the location of overflow pages in cursors used for incremental blob IO. (CVS 3899) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
349f1ea7895f06c40affc985a13aa668 |
User & Date: | danielk1977 2007-05-02 16:48:37.000 |
Context
2007-05-02
| ||
16:51 | More fixes and improvements to the zeroblob() mechanism. (CVS 3900) (check-in: 83ab25014e user: drh tags: trunk) | |
16:48 | Cache the location of overflow pages in cursors used for incremental blob IO. (CVS 3899) (check-in: 349f1ea789 user: danielk1977 tags: trunk) | |
15:36 | Fix an invalid UTF8 encoding in the tests for the trim function. (CVS 3898) (check-in: 4dbbfff4a7 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.366 2007/05/02 16:48:37 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ void *pKey; /* Saved key that was cursor's last known position */ i64 nKey; /* Size of pKey, or last integer key */ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ }; /* ** Potential values for BtCursor.eState. ** ** CURSOR_VALID: ** Cursor points to a valid entry. getPayload() etc. may be called. | > > > > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ void *pKey; /* Saved key that was cursor's last known position */ i64 nKey; /* Size of pKey, or last integer key */ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ #ifndef SQLITE_OMIT_INCRBLOB u8 cacheOverflow; /* True to use aOverflow */ Pgno *aOverflow; /* Cache of overflow page locations */ #endif }; /* ** Potential values for BtCursor.eState. ** ** CURSOR_VALID: ** Cursor points to a valid entry. getPayload() etc. may be called. |
︙ | ︙ | |||
686 687 688 689 690 691 692 693 694 695 696 697 698 699 | assert( !pCur->pPage->intKey || !pCur->pKey ); if( rc==SQLITE_OK ){ releasePage(pCur->pPage); pCur->pPage = 0; pCur->eState = CURSOR_REQUIRESEEK; } return rc; } /* ** Save the positions of all cursors except pExcept open on the table ** with root-page iRoot. Usually, this is called just before cursor | > > > > > > | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | assert( !pCur->pPage->intKey || !pCur->pKey ); if( rc==SQLITE_OK ){ releasePage(pCur->pPage); pCur->pPage = 0; pCur->eState = CURSOR_REQUIRESEEK; } #ifndef SQLITE_OMIT_INCRBLOB /* Delete the cache of overflow page numbers. */ sqliteFree(pCur->aOverflow); pCur->aOverflow = 0; #endif return rc; } /* ** Save the positions of all cursors except pExcept open on the table ** with root-page iRoot. Usually, this is called just before cursor |
︙ | ︙ | |||
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 | ** ** If the incremental vacuum is finished after this function has run, ** SQLITE_DONE is returned. If it is not finished, but no error occured, ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ BtShared *pBt = p->pBt; assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ return SQLITE_DONE; } | > > > > > > | > | > > > > > > > > > | 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 | ** ** If the incremental vacuum is finished after this function has run, ** SQLITE_DONE is returned. If it is not finished, but no error occured, ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ BtShared *pBt = p->pBt; BtCursor *pCur; assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ return SQLITE_DONE; } #ifndef SQLITE_OMIT_INCRBLOB for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ /* Delete the cache of overflow page numbers. */ sqliteFree(pCur->aOverflow); pCur->aOverflow = 0; } #endif return incrVacuumStep(pBt, 0); } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is commited for an auto-vacuum database. ** ** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages ** the database file should be truncated to during the commit process. ** i.e. the database has been reorganized so that only the first *pnTrunc ** pages are in use. */ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ int rc = SQLITE_OK; Pager *pPager = pBt->pPager; #ifndef NDEBUG int nRef = sqlite3PagerRefcount(pPager); #endif #ifndef SQLITE_OMIT_INCRBLOB BtCursor *pCur; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ /* Delete the cache of overflow page numbers. */ sqliteFree(pCur->aOverflow); pCur->aOverflow = 0; } #endif assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ Pgno nFin = 0; if( pBt->nTrunc==0 ){ Pgno nFree; |
︙ | ︙ | |||
2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 | pBt->pCursor = pCur->pNext; } if( pCur->pNext ){ pCur->pNext->pPrev = pCur->pPrev; } releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); sqliteFree(pCur); return SQLITE_OK; } /* ** Make a temporary cursor by filling in the fields of pTempCur. ** The temporary cursor is not on the cursor list for the Btree. | > > > | 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 | pBt->pCursor = pCur->pNext; } if( pCur->pNext ){ pCur->pNext->pPrev = pCur->pPrev; } releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); #ifndef SQLITE_OMIT_INCRBLOB sqliteFree(pCur->aOverflow); #endif sqliteFree(pCur); return SQLITE_OK; } /* ** Make a temporary cursor by filling in the fields of pTempCur. ** The temporary cursor is not on the cursor list for the Btree. |
︙ | ︙ | |||
3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 | unsigned char *aPayload; Pgno nextPage; int rc; MemPage *pPage; BtShared *pBt; int ovflSize; u32 nKey; assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->eState==CURSOR_VALID ); pBt = pCur->pBtree->pBt; pPage = pCur->pPage; assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); getCellInfo(pCur); | > | 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 | unsigned char *aPayload; Pgno nextPage; int rc; MemPage *pPage; BtShared *pBt; int ovflSize; u32 nKey; int iIdx = 0; assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->eState==CURSOR_VALID ); pBt = pCur->pBtree->pBt; pPage = pCur->pPage; assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); getCellInfo(pCur); |
︙ | ︙ | |||
3166 3167 3168 3169 3170 3171 3172 | amt -= a; }else{ offset -= pCur->info.nLocal; } ovflSize = pBt->usableSize - 4; if( amt>0 ){ nextPage = get4byte(&aPayload[pCur->info.nLocal]); | > > > > > > > > > > > > > > | > > > > > > > > > > > | 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 | amt -= a; }else{ offset -= pCur->info.nLocal; } ovflSize = pBt->usableSize - 4; if( amt>0 ){ nextPage = get4byte(&aPayload[pCur->info.nLocal]); #ifndef SQLITE_OMIT_INCRBLOB 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; } } if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){ iIdx = (offset/ovflSize); nextPage = pCur->aOverflow[iIdx]; offset = (offset%ovflSize); } #endif for(iIdx++; amt>0 && nextPage; iIdx++){ 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. */ 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; } #endif }else{ /* Need to read this page properly, to obtain data to copy into ** the caller's buffer. */ 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; } 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; } #endif } } } if( amt>0 ){ return SQLITE_CORRUPT_BKPT; } |
︙ | ︙ | |||
6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 | BtShared *pBt = pCsr->pBtree->pBt; int rc; u32 iRem = amt; /* Remaining bytes to write */ u8 *zRem = (u8 *)z; /* Pointer to data not yet written */ u32 iOffset = offset; /* Offset from traversal point to start of write */ Pgno iOvfl; /* Page number for next overflow page */ int ovflSize; /* Bytes of data per overflow page. */ CellInfo *pInfo; /* Check some preconditions: ** (a) a write-transaction is open, | > | 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 | BtShared *pBt = pCsr->pBtree->pBt; int rc; u32 iRem = amt; /* Remaining bytes to write */ u8 *zRem = (u8 *)z; /* Pointer to data not yet written */ u32 iOffset = offset; /* Offset from traversal point to start of write */ Pgno iIdx = 0; /* Index of overflow page in pCsr->aOverflow */ Pgno iOvfl; /* Page number for next overflow page */ int ovflSize; /* Bytes of data per overflow page. */ CellInfo *pInfo; /* Check some preconditions: ** (a) a write-transaction is open, |
︙ | ︙ | |||
6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 | ** enough for the proposed write operation. */ getCellInfo(pCsr); pInfo = &pCsr->info; if( pInfo->nData<(offset+amt) ){ return SQLITE_ERROR; } if( pInfo->nLocal>iOffset ){ /* In this case data must be written to the b-tree page. */ int iWrite = pInfo->nLocal - offset; if( iWrite>iRem ){ iWrite = iRem; } rc = sqlite3PagerWrite(pCsr->pPage->pDbPage); if( rc!=SQLITE_OK ){ return rc; } memcpy(&pInfo->pCell[iOffset+pInfo->nHeader], zRem, iWrite); zRem += iWrite; iRem -= iWrite; } iOffset = ((iOffset<pInfo->nLocal)?0:(iOffset-pInfo->nLocal)); | > > > > > > > > > > < < | > | < < | < < < < | > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | > | | | | | | | | | > > > > > > > > > > > | 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 | ** enough for the proposed write operation. */ getCellInfo(pCsr); pInfo = &pCsr->info; if( pInfo->nData<(offset+amt) ){ return SQLITE_ERROR; } ovflSize = pBt->usableSize - 4; assert(pCsr->cacheOverflow); if( !pCsr->aOverflow ){ int nOverflow = (pInfo->nPayload - pInfo->nLocal + ovflSize - 1)/ovflSize; pCsr->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOverflow); if( nOverflow && !pCsr->aOverflow ){ return SQLITE_NOMEM; } } if( pInfo->nLocal>iOffset ){ /* In this case data must be written to the b-tree page. */ int iWrite = pInfo->nLocal - offset; if( iWrite>iRem ){ iWrite = iRem; } rc = sqlite3PagerWrite(pCsr->pPage->pDbPage); if( rc!=SQLITE_OK ){ return rc; } memcpy(&pInfo->pCell[iOffset+pInfo->nHeader], zRem, iWrite); zRem += iWrite; iRem -= iWrite; } iOffset = ((iOffset<pInfo->nLocal)?0:(iOffset-pInfo->nLocal)); assert(pInfo->iOverflow>0 || iRem==0); if( iRem>0 ){ if( pCsr->aOverflow[iOffset/ovflSize] ){ iIdx = iOffset/ovflSize; iOvfl = pCsr->aOverflow[iIdx]; iOffset = iOffset%ovflSize; }else{ iOvfl = get4byte(&pInfo->pCell[pInfo->iOverflow]); } for(iIdx++; iRem>0; iIdx++){ if( iOffset>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. */ rc = getOverflowPage(pBt, iOvfl, 0, &iOvfl); if( rc!=SQLITE_OK ){ return rc; } iOffset -= ovflSize; pCsr->aOverflow[iIdx] = iOvfl; }else{ int iWrite = ovflSize - iOffset; DbPage *pOvfl; /* The overflow page. */ u8 *aData; /* Page data */ rc = sqlite3PagerGet(pBt->pPager, iOvfl, &pOvfl); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pOvfl); if( rc!=SQLITE_OK ){ sqlite3PagerUnref(pOvfl); return rc; } aData = sqlite3PagerGetData(pOvfl); iOvfl = get4byte(aData); pCsr->aOverflow[iIdx] = iOvfl; if( iWrite>iRem ){ iWrite = iRem; } memcpy(&aData[iOffset+4], zRem, iWrite); sqlite3PagerUnref(pOvfl); zRem += iWrite; iRem -= iWrite; iOffset = ((iOffset<ovflSize)?0:(iOffset-ovflSize)); } } } return SQLITE_OK; } /* ** Set a flag on this cursor to cache the locations of pages from the ** overflow list for the current row. */ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ assert(!pCur->cacheOverflow); assert(!pCur->aOverflow); pCur->cacheOverflow = 1; } #endif /* ** The following debugging interface has to be in this file (rather ** than in, for example, test1.c) so that it can get access to ** the definition of BtShared. */ |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.78 2007/05/02 16:48:37 danielk1977 Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ |
︙ | ︙ | |||
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*); #ifdef SQLITE_TEST int sqlite3BtreeCursorInfo(BtCursor*, int*, int); void sqlite3BtreeCursorList(Btree*); #endif #ifdef SQLITE_DEBUG int sqlite3BtreePageDump(Btree*, int, int recursive); #else #define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK #endif #endif /* _BTREE_H_ */ | > | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*); void sqlite3BtreeCacheOverflow(BtCursor *); #ifdef SQLITE_TEST int sqlite3BtreeCursorInfo(BtCursor*, int*, int); void sqlite3BtreeCursorList(Btree*); #endif #ifdef SQLITE_DEBUG int sqlite3BtreePageDump(Btree*, int, int recursive); #else #define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK #endif #endif /* _BTREE_H_ */ |
Changes to src/vdbeblob.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** $Id: vdbeblob.c,v 1.2 2007/05/02 16:48:37 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ | |||
169 170 171 172 173 174 175 176 177 178 179 180 181 182 | pBlob = (Incrblob *)sqliteMalloc(sizeof(Incrblob)); if( sqlite3MallocFailed() ){ sqliteFree(pBlob); goto blob_open_out; } pBlob->flags = flags; pBlob->pCsr = v->apCsr[0]->pCursor; pBlob->pStmt = (sqlite3_stmt *)v; pBlob->iOffset = v->apCsr[0]->aOffset[iCol]; pBlob->nByte = sqlite3VdbeSerialTypeLen(type); *ppBlob = (sqlite3_blob *)pBlob; rc = SQLITE_OK; }else{ if( rc==SQLITE_DONE ){ | > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | pBlob = (Incrblob *)sqliteMalloc(sizeof(Incrblob)); if( sqlite3MallocFailed() ){ sqliteFree(pBlob); goto blob_open_out; } pBlob->flags = flags; pBlob->pCsr = v->apCsr[0]->pCursor; sqlite3BtreeCacheOverflow(pBlob->pCsr); pBlob->pStmt = (sqlite3_stmt *)v; pBlob->iOffset = v->apCsr[0]->aOffset[iCol]; pBlob->nByte = sqlite3VdbeSerialTypeLen(type); *ppBlob = (sqlite3_blob *)pBlob; rc = SQLITE_OK; }else{ if( rc==SQLITE_DONE ){ |
︙ | ︙ |