Add the MemPage.xParseCell method and provide various implementations
(variations on the former btreeParseCellPtr()) depending on the page type. FossilOrigin-Name: 41d03d883c4f7ca279eb9dd679f3ab81c8d957d9
This commit is contained in:
parent
25ada07ab4
commit
5fa605142f
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Make\scellSizePtr()\sa\smethod\son\sthe\sMemPage\sobject,\swith\salternative\nimplementations\sdepending\son\sthe\spage\stype.\s\sThis\sresults\sis\sa\ssmall\sperformance\nimprovement\sand\ssize\sreduction.
|
||||
D 2015-06-19T15:07:14.566
|
||||
C Add\sthe\sMemPage.xParseCell\smethod\sand\sprovide\svarious\simplementations\n(variations\son\sthe\sformer\sbtreeParseCellPtr())\sdepending\son\sthe\spage\stype.
|
||||
D 2015-06-19T17:19:34.228
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -192,9 +192,9 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
|
||||
F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d
|
||||
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
|
||||
F src/btree.c 960e66f4a9fd494c5712f4342432a2fb1cbb72c1
|
||||
F src/btree.c cf8310b4429e5f0400868b598d75d414b32da98e
|
||||
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
|
||||
F src/btreeInt.h 97901d5434a22344cd5ae47e80ed677bd21d572d
|
||||
F src/btreeInt.h 6ece2dd9c8e2eac05f0a8ded8772a44e96486c65
|
||||
F src/build.c b3f15255d5b16e42dafeaa638fd4f8a47c94ed70
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575
|
||||
@ -1286,7 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 9246eca54adaee571dab0c066afaa604fcf9c44f
|
||||
R 65525ba5a493bb8d3d370265d6f2abe8
|
||||
P 02f7e9d7d7b93d0b6bbd6cc0d0359b3b741b9931
|
||||
R 2f4b41ef502fc9cfa753afb16ada8794
|
||||
U drh
|
||||
Z b80278f806bcab0592c2162609b43f46
|
||||
Z a171034151748a0b17304cc3b38b62ab
|
||||
|
@ -1 +1 @@
|
||||
02f7e9d7d7b93d0b6bbd6cc0d0359b3b741b9931
|
||||
41d03d883c4f7ca279eb9dd679f3ab81c8d957d9
|
190
src/btree.c
190
src/btree.c
@ -980,11 +980,73 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse a cell content block and fill in the CellInfo structure. There
|
||||
** are two versions of this function. btreeParseCell() takes a
|
||||
** cell index as the second argument and btreeParseCellPtr()
|
||||
** takes a pointer to the body of the cell as its second argument.
|
||||
** This is common tail processing for btreeParseCellPtr() and
|
||||
** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
|
||||
** on a single B-tree page. Make necessary adjustments to the CellInfo
|
||||
** structure.
|
||||
*/
|
||||
static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
/* If the payload will not fit completely on the local page, we have
|
||||
** to decide how much to store locally and how much to spill onto
|
||||
** overflow pages. The strategy is to minimize the amount of unused
|
||||
** space on overflow pages while keeping the amount of local storage
|
||||
** in between minLocal and maxLocal.
|
||||
**
|
||||
** Warning: changing the way overflow payload is distributed in any
|
||||
** way will result in an incompatible file format.
|
||||
*/
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
|
||||
minLocal = pPage->minLocal;
|
||||
maxLocal = pPage->maxLocal;
|
||||
surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
||||
testcase( surplus==maxLocal );
|
||||
testcase( surplus==maxLocal+1 );
|
||||
if( surplus <= maxLocal ){
|
||||
pInfo->nLocal = (u16)surplus;
|
||||
}else{
|
||||
pInfo->nLocal = (u16)minLocal;
|
||||
}
|
||||
pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
|
||||
pInfo->nSize = pInfo->iOverflow + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xParseCell()
|
||||
** method.
|
||||
**
|
||||
** Parse a cell content block and fill in the CellInfo structure.
|
||||
**
|
||||
** btreeParseCellPtr() => table btree leaf nodes
|
||||
** btreeParseCellNoPayload() => table btree internal nodes
|
||||
** btreeParseCellPtrIndex() => index btree nodes
|
||||
**
|
||||
** There is also a wrapper function btreeParseCell() that works for
|
||||
** all MemPage types and that references the cell by index rather than
|
||||
** by pointer.
|
||||
*/
|
||||
static void btreeParseCellPtrNoPayload(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 );
|
||||
assert( pPage->noPayload );
|
||||
assert( pPage->childPtrSize==4 );
|
||||
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
|
||||
pInfo->nPayload = 0;
|
||||
pInfo->nLocal = 0;
|
||||
pInfo->iOverflow = 0;
|
||||
pInfo->pPayload = 0;
|
||||
return;
|
||||
}
|
||||
static void btreeParseCellPtr(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
@ -995,23 +1057,12 @@ static void btreeParseCellPtr(
|
||||
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 || pPage->leaf==1 );
|
||||
if( pPage->intKeyLeaf ){
|
||||
assert( pPage->childPtrSize==0 );
|
||||
pIter = pCell + getVarint32(pCell, nPayload);
|
||||
pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
||||
}else if( pPage->noPayload ){
|
||||
assert( pPage->childPtrSize==4 );
|
||||
pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
|
||||
pInfo->nPayload = 0;
|
||||
pInfo->nLocal = 0;
|
||||
pInfo->iOverflow = 0;
|
||||
pInfo->pPayload = 0;
|
||||
return;
|
||||
}else{
|
||||
pIter = pCell + pPage->childPtrSize;
|
||||
pIter += getVarint32(pIter, nPayload);
|
||||
pInfo->nKey = nPayload;
|
||||
}
|
||||
assert( pPage->intKeyLeaf || pPage->noPayload );
|
||||
assert( pPage->noPayload==0 );
|
||||
assert( pPage->intKeyLeaf );
|
||||
assert( pPage->childPtrSize==0 );
|
||||
pIter = pCell + getVarint32(pCell, nPayload);
|
||||
pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
||||
pInfo->nPayload = nPayload;
|
||||
pInfo->pPayload = pIter;
|
||||
testcase( nPayload==pPage->maxLocal );
|
||||
@ -1025,31 +1076,46 @@ static void btreeParseCellPtr(
|
||||
pInfo->nLocal = (u16)nPayload;
|
||||
pInfo->iOverflow = 0;
|
||||
}else{
|
||||
/* If the payload will not fit completely on the local page, we have
|
||||
** to decide how much to store locally and how much to spill onto
|
||||
** overflow pages. The strategy is to minimize the amount of unused
|
||||
** space on overflow pages while keeping the amount of local storage
|
||||
** in between minLocal and maxLocal.
|
||||
**
|
||||
** Warning: changing the way overflow payload is distributed in any
|
||||
** way will result in an incompatible file format.
|
||||
*/
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
|
||||
}
|
||||
}
|
||||
static void btreeParseCellPtrIndex(
|
||||
MemPage *pPage, /* Page containing the cell */
|
||||
u8 *pCell, /* Pointer to the cell text. */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
u8 *pIter; /* For scanning through pCell */
|
||||
u32 nPayload; /* Number of bytes of cell payload */
|
||||
|
||||
minLocal = pPage->minLocal;
|
||||
maxLocal = pPage->maxLocal;
|
||||
surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);
|
||||
testcase( surplus==maxLocal );
|
||||
testcase( surplus==maxLocal+1 );
|
||||
if( surplus <= maxLocal ){
|
||||
pInfo->nLocal = (u16)surplus;
|
||||
}else{
|
||||
pInfo->nLocal = (u16)minLocal;
|
||||
}
|
||||
pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
|
||||
pInfo->nSize = pInfo->iOverflow + 4;
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( pPage->leaf==0 || pPage->leaf==1 );
|
||||
assert( pPage->intKeyLeaf==0 );
|
||||
assert( pPage->noPayload==0 );
|
||||
pIter = pCell + pPage->childPtrSize;
|
||||
nPayload = *pIter;
|
||||
if( nPayload>=0x80 ){
|
||||
u8 *pEnd = &pIter[9];
|
||||
nPayload &= 0x7f;
|
||||
do{
|
||||
nPayload = (nPayload<<7) | (*++pIter & 0x7f);
|
||||
}while( *(pIter)>=0x80 && pIter<pEnd );
|
||||
}
|
||||
pIter++;
|
||||
pInfo->nKey = nPayload;
|
||||
pInfo->nPayload = nPayload;
|
||||
pInfo->pPayload = pIter;
|
||||
testcase( nPayload==pPage->maxLocal );
|
||||
testcase( nPayload==pPage->maxLocal+1 );
|
||||
if( nPayload<=pPage->maxLocal ){
|
||||
/* This is the (easy) common case where the entire payload fits
|
||||
** on the local page. No overflow is required.
|
||||
*/
|
||||
pInfo->nSize = nPayload + (u16)(pIter - pCell);
|
||||
if( pInfo->nSize<4 ) pInfo->nSize = 4;
|
||||
pInfo->nLocal = (u16)nPayload;
|
||||
pInfo->iOverflow = 0;
|
||||
}else{
|
||||
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
|
||||
}
|
||||
}
|
||||
static void btreeParseCell(
|
||||
@ -1057,19 +1123,20 @@ static void btreeParseCell(
|
||||
int iCell, /* The cell index. First cell is 0 */
|
||||
CellInfo *pInfo /* Fill in this structure */
|
||||
){
|
||||
btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo);
|
||||
pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xCellSize
|
||||
** method.
|
||||
**
|
||||
** Compute the total number of bytes that a Cell needs in the cell
|
||||
** data area of the btree-page. The return number includes the cell
|
||||
** data header and the local payload, but not any overflow page or
|
||||
** the space used by the cell pointer.
|
||||
**
|
||||
** The first implementation, cellSizePtr(), handles pages that contain
|
||||
** payload, which is to say all index pages and left table pages. The
|
||||
** second cellSizePtrNoPayload() implemention is a high-speed version
|
||||
** for pages that contain no payload - internal table pages.
|
||||
** cellSizePtrNoPayload() => table internal nodes
|
||||
** cellSizePtr() => all index nodes & table leaf nodes
|
||||
*/
|
||||
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
||||
u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
|
||||
@ -1082,7 +1149,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
||||
** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
|
||||
** this function verifies that this invariant is not violated. */
|
||||
CellInfo debuginfo;
|
||||
btreeParseCellPtr(pPage, pCell, &debuginfo);
|
||||
pPage->xParseCell(pPage, pCell, &debuginfo);
|
||||
#endif
|
||||
|
||||
assert( pPage->noPayload==0 );
|
||||
@ -1130,7 +1197,7 @@ static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){
|
||||
** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
|
||||
** this function verifies that this invariant is not violated. */
|
||||
CellInfo debuginfo;
|
||||
btreeParseCellPtr(pPage, pCell, &debuginfo);
|
||||
pPage->xParseCell(pPage, pCell, &debuginfo);
|
||||
#endif
|
||||
|
||||
assert( pPage->childPtrSize==4 );
|
||||
@ -1159,7 +1226,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
||||
CellInfo info;
|
||||
if( *pRC ) return;
|
||||
assert( pCell!=0 );
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.iOverflow ){
|
||||
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
|
||||
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
|
||||
@ -1540,10 +1607,12 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
if( pPage->leaf ){
|
||||
pPage->intKeyLeaf = 1;
|
||||
pPage->noPayload = 0;
|
||||
pPage->xParseCell = btreeParseCellPtr;
|
||||
}else{
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->noPayload = 1;
|
||||
pPage->xCellSize = cellSizePtrNoPayload;
|
||||
pPage->xParseCell = btreeParseCellPtrNoPayload;
|
||||
}
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
@ -1557,6 +1626,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->noPayload = 0;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else{
|
||||
@ -3147,7 +3217,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
u8 *pCell = findCell(pPage, i);
|
||||
if( eType==PTRMAP_OVERFLOW1 ){
|
||||
CellInfo info;
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.iOverflow
|
||||
&& pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
|
||||
&& iFrom==get4byte(&pCell[info.iOverflow])
|
||||
@ -4992,7 +5062,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** case this happens. */
|
||||
void *pCellKey;
|
||||
u8 * const pCellBody = pCell - pPage->childPtrSize;
|
||||
btreeParseCellPtr(pPage, pCellBody, &pCur->info);
|
||||
pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
||||
nCell = (int)pCur->info.nKey;
|
||||
testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
||||
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
||||
@ -5781,7 +5851,7 @@ static int clearCell(
|
||||
u32 ovflPageSize;
|
||||
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
*pnSize = info.nSize;
|
||||
if( info.iOverflow==0 ){
|
||||
return SQLITE_OK; /* No overflow pages. Return without doing anything */
|
||||
@ -5935,7 +6005,7 @@ static int fillInCell(
|
||||
#if SQLITE_DEBUG
|
||||
{
|
||||
CellInfo info;
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
assert( nHeader=(int)(info.pPayload - pCell) );
|
||||
assert( info.nKey==nKey );
|
||||
assert( *pnSize == info.nSize );
|
||||
@ -6584,7 +6654,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
||||
u8 *z;
|
||||
|
||||
z = findCell(pPage, j);
|
||||
btreeParseCellPtr(pPage, z, &info);
|
||||
pPage->xParseCell(pPage, z, &info);
|
||||
if( info.iOverflow ){
|
||||
Pgno ovfl = get4byte(&z[info.iOverflow]);
|
||||
ptrmapGet(pBt, ovfl, &e, &n);
|
||||
@ -7215,7 +7285,7 @@ static int balance_nonroot(
|
||||
*/
|
||||
CellInfo info;
|
||||
j--;
|
||||
btreeParseCellPtr(pNew, apCell[j], &info);
|
||||
pNew->xParseCell(pNew, apCell[j], &info);
|
||||
pCell = pTemp;
|
||||
sz = 4 + putVarint(&pCell[4], info.nKey);
|
||||
pTemp = 0;
|
||||
@ -8715,7 +8785,7 @@ static int checkTreePage(
|
||||
pCheck->v1 = iPage;
|
||||
pCheck->v2 = i;
|
||||
pCell = findCell(pPage,i);
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
sz = info.nPayload;
|
||||
/* For intKey pages, check that the keys are in order.
|
||||
*/
|
||||
|
@ -231,6 +231,7 @@
|
||||
/* Forward declarations */
|
||||
typedef struct MemPage MemPage;
|
||||
typedef struct BtLock BtLock;
|
||||
typedef struct CellInfo CellInfo;
|
||||
|
||||
/*
|
||||
** This is a magic string that appears at the beginning of every
|
||||
@ -295,7 +296,8 @@ struct MemPage {
|
||||
u8 *aDataEnd; /* One byte past the end of usable data */
|
||||
u8 *aCellIdx; /* The cell index area */
|
||||
DbPage *pDbPage; /* Pager page handle */
|
||||
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
|
||||
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
|
||||
void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
|
||||
Pgno pgno; /* Page number for this page */
|
||||
};
|
||||
|
||||
@ -461,7 +463,6 @@ struct BtShared {
|
||||
** about a cell. The parseCellPtr() function fills in this structure
|
||||
** based on information extract from the raw disk page.
|
||||
*/
|
||||
typedef struct CellInfo CellInfo;
|
||||
struct CellInfo {
|
||||
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
|
||||
u8 *pPayload; /* Pointer to the start of payload */
|
||||
|
Loading…
Reference in New Issue
Block a user