/ Check-in [41d03d88]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the MemPage.xParseCell method and provide various implementations (variations on the former btreeParseCellPtr()) depending on the page type.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 41d03d883c4f7ca279eb9dd679f3ab81c8d957d9
User & Date: drh 2015-06-19 17:19:34
Context
2015-06-19
20:31
Performance improvements in btreeParseCell() by inlining the varint decoder. check-in: 172a864d user: drh tags: trunk
18:24
Performance improvements in btreeParseCell() by inlining the varint decoder. check-in: faab0ed9 user: drh tags: btree-opt
17:19
Add the MemPage.xParseCell method and provide various implementations (variations on the former btreeParseCellPtr()) depending on the page type. check-in: 41d03d88 user: drh tags: trunk
15:07
Make cellSizePtr() a method on the MemPage object, with alternative implementations depending on the page type. This results is a small performance improvement and size reduction. check-in: 02f7e9d7 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

   976    976         iCell--;
   977    977       }
   978    978     }
   979    979     return findCell(pPage, iCell);
   980    980   }
   981    981   
   982    982   /*
   983         -** Parse a cell content block and fill in the CellInfo structure.  There
   984         -** are two versions of this function.  btreeParseCell() takes a 
   985         -** cell index as the second argument and btreeParseCellPtr() 
   986         -** takes a pointer to the body of the cell as its second argument.
          983  +** This is common tail processing for btreeParseCellPtr() and
          984  +** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
          985  +** on a single B-tree page.  Make necessary adjustments to the CellInfo
          986  +** structure.
   987    987   */
          988  +static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
          989  +  MemPage *pPage,         /* Page containing the cell */
          990  +  u8 *pCell,              /* Pointer to the cell text. */
          991  +  CellInfo *pInfo         /* Fill in this structure */
          992  +){
          993  +  /* If the payload will not fit completely on the local page, we have
          994  +  ** to decide how much to store locally and how much to spill onto
          995  +  ** overflow pages.  The strategy is to minimize the amount of unused
          996  +  ** space on overflow pages while keeping the amount of local storage
          997  +  ** in between minLocal and maxLocal.
          998  +  **
          999  +  ** Warning:  changing the way overflow payload is distributed in any
         1000  +  ** way will result in an incompatible file format.
         1001  +  */
         1002  +  int minLocal;  /* Minimum amount of payload held locally */
         1003  +  int maxLocal;  /* Maximum amount of payload held locally */
         1004  +  int surplus;   /* Overflow payload available for local storage */
         1005  +
         1006  +  minLocal = pPage->minLocal;
         1007  +  maxLocal = pPage->maxLocal;
         1008  +  surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4);
         1009  +  testcase( surplus==maxLocal );
         1010  +  testcase( surplus==maxLocal+1 );
         1011  +  if( surplus <= maxLocal ){
         1012  +    pInfo->nLocal = (u16)surplus;
         1013  +  }else{
         1014  +    pInfo->nLocal = (u16)minLocal;
         1015  +  }
         1016  +  pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
         1017  +  pInfo->nSize = pInfo->iOverflow + 4;
         1018  +}
         1019  +
         1020  +/*
         1021  +** The following routines are implementations of the MemPage.xParseCell()
         1022  +** method.
         1023  +**
         1024  +** Parse a cell content block and fill in the CellInfo structure.
         1025  +**
         1026  +** btreeParseCellPtr()        =>   table btree leaf nodes
         1027  +** btreeParseCellNoPayload()  =>   table btree internal nodes
         1028  +** btreeParseCellPtrIndex()   =>   index btree nodes
         1029  +**
         1030  +** There is also a wrapper function btreeParseCell() that works for
         1031  +** all MemPage types and that references the cell by index rather than
         1032  +** by pointer.
         1033  +*/
         1034  +static void btreeParseCellPtrNoPayload(
         1035  +  MemPage *pPage,         /* Page containing the cell */
         1036  +  u8 *pCell,              /* Pointer to the cell text. */
         1037  +  CellInfo *pInfo         /* Fill in this structure */
         1038  +){
         1039  +  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
         1040  +  assert( pPage->leaf==0 );
         1041  +  assert( pPage->noPayload );
         1042  +  assert( pPage->childPtrSize==4 );
         1043  +  pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
         1044  +  pInfo->nPayload = 0;
         1045  +  pInfo->nLocal = 0;
         1046  +  pInfo->iOverflow = 0;
         1047  +  pInfo->pPayload = 0;
         1048  +  return;
         1049  +}
   988   1050   static void btreeParseCellPtr(
   989   1051     MemPage *pPage,         /* Page containing the cell */
   990   1052     u8 *pCell,              /* Pointer to the cell text. */
   991   1053     CellInfo *pInfo         /* Fill in this structure */
   992   1054   ){
   993   1055     u8 *pIter;              /* For scanning through pCell */
   994   1056     u32 nPayload;           /* Number of bytes of cell payload */
   995   1057   
   996   1058     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
   997   1059     assert( pPage->leaf==0 || pPage->leaf==1 );
   998         -  if( pPage->intKeyLeaf ){
   999         -    assert( pPage->childPtrSize==0 );
  1000         -    pIter = pCell + getVarint32(pCell, nPayload);
  1001         -    pIter += getVarint(pIter, (u64*)&pInfo->nKey);
  1002         -  }else if( pPage->noPayload ){
  1003         -    assert( pPage->childPtrSize==4 );
  1004         -    pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
  1005         -    pInfo->nPayload = 0;
  1006         -    pInfo->nLocal = 0;
         1060  +  assert( pPage->intKeyLeaf || pPage->noPayload );
         1061  +  assert( pPage->noPayload==0 );
         1062  +  assert( pPage->intKeyLeaf );
         1063  +  assert( pPage->childPtrSize==0 );
         1064  +  pIter = pCell + getVarint32(pCell, nPayload);
         1065  +  pIter += getVarint(pIter, (u64*)&pInfo->nKey);
         1066  +  pInfo->nPayload = nPayload;
         1067  +  pInfo->pPayload = pIter;
         1068  +  testcase( nPayload==pPage->maxLocal );
         1069  +  testcase( nPayload==pPage->maxLocal+1 );
         1070  +  if( nPayload<=pPage->maxLocal ){
         1071  +    /* This is the (easy) common case where the entire payload fits
         1072  +    ** on the local page.  No overflow is required.
         1073  +    */
         1074  +    pInfo->nSize = nPayload + (u16)(pIter - pCell);
         1075  +    if( pInfo->nSize<4 ) pInfo->nSize = 4;
         1076  +    pInfo->nLocal = (u16)nPayload;
  1007   1077       pInfo->iOverflow = 0;
  1008         -    pInfo->pPayload = 0;
  1009         -    return;
  1010   1078     }else{
  1011         -    pIter = pCell + pPage->childPtrSize;
  1012         -    pIter += getVarint32(pIter, nPayload);
  1013         -    pInfo->nKey = nPayload;
         1079  +    btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
  1014   1080     }
         1081  +}
         1082  +static void btreeParseCellPtrIndex(
         1083  +  MemPage *pPage,         /* Page containing the cell */
         1084  +  u8 *pCell,              /* Pointer to the cell text. */
         1085  +  CellInfo *pInfo         /* Fill in this structure */
         1086  +){
         1087  +  u8 *pIter;              /* For scanning through pCell */
         1088  +  u32 nPayload;           /* Number of bytes of cell payload */
         1089  +
         1090  +  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
         1091  +  assert( pPage->leaf==0 || pPage->leaf==1 );
         1092  +  assert( pPage->intKeyLeaf==0 );
         1093  +  assert( pPage->noPayload==0 );
         1094  +  pIter = pCell + pPage->childPtrSize;
         1095  +  nPayload = *pIter;
         1096  +  if( nPayload>=0x80 ){
         1097  +    u8 *pEnd = &pIter[9];
         1098  +    nPayload &= 0x7f;
         1099  +    do{
         1100  +      nPayload = (nPayload<<7) | (*++pIter & 0x7f);
         1101  +    }while( *(pIter)>=0x80 && pIter<pEnd );
         1102  +  }
         1103  +  pIter++;
         1104  +  pInfo->nKey = nPayload;
  1015   1105     pInfo->nPayload = nPayload;
  1016   1106     pInfo->pPayload = pIter;
  1017   1107     testcase( nPayload==pPage->maxLocal );
  1018   1108     testcase( nPayload==pPage->maxLocal+1 );
  1019   1109     if( nPayload<=pPage->maxLocal ){
  1020   1110       /* This is the (easy) common case where the entire payload fits
  1021   1111       ** on the local page.  No overflow is required.
  1022   1112       */
  1023   1113       pInfo->nSize = nPayload + (u16)(pIter - pCell);
  1024   1114       if( pInfo->nSize<4 ) pInfo->nSize = 4;
  1025   1115       pInfo->nLocal = (u16)nPayload;
  1026   1116       pInfo->iOverflow = 0;
  1027   1117     }else{
  1028         -    /* If the payload will not fit completely on the local page, we have
  1029         -    ** to decide how much to store locally and how much to spill onto
  1030         -    ** overflow pages.  The strategy is to minimize the amount of unused
  1031         -    ** space on overflow pages while keeping the amount of local storage
  1032         -    ** in between minLocal and maxLocal.
  1033         -    **
  1034         -    ** Warning:  changing the way overflow payload is distributed in any
  1035         -    ** way will result in an incompatible file format.
  1036         -    */
  1037         -    int minLocal;  /* Minimum amount of payload held locally */
  1038         -    int maxLocal;  /* Maximum amount of payload held locally */
  1039         -    int surplus;   /* Overflow payload available for local storage */
  1040         -
  1041         -    minLocal = pPage->minLocal;
  1042         -    maxLocal = pPage->maxLocal;
  1043         -    surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);
  1044         -    testcase( surplus==maxLocal );
  1045         -    testcase( surplus==maxLocal+1 );
  1046         -    if( surplus <= maxLocal ){
  1047         -      pInfo->nLocal = (u16)surplus;
  1048         -    }else{
  1049         -      pInfo->nLocal = (u16)minLocal;
  1050         -    }
  1051         -    pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
  1052         -    pInfo->nSize = pInfo->iOverflow + 4;
         1118  +    btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
  1053   1119     }
  1054   1120   }
  1055   1121   static void btreeParseCell(
  1056   1122     MemPage *pPage,         /* Page containing the cell */
  1057   1123     int iCell,              /* The cell index.  First cell is 0 */
  1058   1124     CellInfo *pInfo         /* Fill in this structure */
  1059   1125   ){
  1060         -  btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo);
         1126  +  pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo);
  1061   1127   }
  1062   1128   
  1063   1129   /*
         1130  +** The following routines are implementations of the MemPage.xCellSize
         1131  +** method.
         1132  +**
  1064   1133   ** Compute the total number of bytes that a Cell needs in the cell
  1065   1134   ** data area of the btree-page.  The return number includes the cell
  1066   1135   ** data header and the local payload, but not any overflow page or
  1067   1136   ** the space used by the cell pointer.
  1068   1137   **
  1069         -** The first implementation, cellSizePtr(), handles pages that contain
  1070         -** payload, which is to say all index pages and left table pages.  The
  1071         -** second cellSizePtrNoPayload() implemention is a high-speed version
  1072         -** for pages that contain no payload - internal table pages.
         1138  +** cellSizePtrNoPayload()    =>   table internal nodes
         1139  +** cellSizePtr()             =>   all index nodes & table leaf nodes
  1073   1140   */
  1074   1141   static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
  1075   1142     u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
  1076   1143     u8 *pEnd;                                /* End mark for a varint */
  1077   1144     u32 nSize;                               /* Size value to return */
  1078   1145   
  1079   1146   #ifdef SQLITE_DEBUG
  1080   1147     /* The value returned by this function should always be the same as
  1081   1148     ** the (CellInfo.nSize) value found by doing a full parse of the
  1082   1149     ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
  1083   1150     ** this function verifies that this invariant is not violated. */
  1084   1151     CellInfo debuginfo;
  1085         -  btreeParseCellPtr(pPage, pCell, &debuginfo);
         1152  +  pPage->xParseCell(pPage, pCell, &debuginfo);
  1086   1153   #endif
  1087   1154   
  1088   1155     assert( pPage->noPayload==0 );
  1089   1156     nSize = *pIter;
  1090   1157     if( nSize>=0x80 ){
  1091   1158       pEnd = &pIter[9];
  1092   1159       nSize &= 0x7f;
................................................................................
  1126   1193   
  1127   1194   #ifdef SQLITE_DEBUG
  1128   1195     /* The value returned by this function should always be the same as
  1129   1196     ** the (CellInfo.nSize) value found by doing a full parse of the
  1130   1197     ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
  1131   1198     ** this function verifies that this invariant is not violated. */
  1132   1199     CellInfo debuginfo;
  1133         -  btreeParseCellPtr(pPage, pCell, &debuginfo);
         1200  +  pPage->xParseCell(pPage, pCell, &debuginfo);
  1134   1201   #endif
  1135   1202   
  1136   1203     assert( pPage->childPtrSize==4 );
  1137   1204     pEnd = pIter + 9;
  1138   1205     while( (*pIter++)&0x80 && pIter<pEnd );
  1139   1206     assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB );
  1140   1207     return (u16)(pIter - pCell);
................................................................................
  1155   1222   ** to an overflow page, insert an entry into the pointer-map
  1156   1223   ** for the overflow page.
  1157   1224   */
  1158   1225   static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
  1159   1226     CellInfo info;
  1160   1227     if( *pRC ) return;
  1161   1228     assert( pCell!=0 );
  1162         -  btreeParseCellPtr(pPage, pCell, &info);
         1229  +  pPage->xParseCell(pPage, pCell, &info);
  1163   1230     if( info.iOverflow ){
  1164   1231       Pgno ovfl = get4byte(&pCell[info.iOverflow]);
  1165   1232       ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
  1166   1233     }
  1167   1234   }
  1168   1235   #endif
  1169   1236   
................................................................................
  1536   1603       /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
  1537   1604       ** table b-tree page. */
  1538   1605       assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
  1539   1606       pPage->intKey = 1;
  1540   1607       if( pPage->leaf ){
  1541   1608         pPage->intKeyLeaf = 1;
  1542   1609         pPage->noPayload = 0;
         1610  +      pPage->xParseCell = btreeParseCellPtr;
  1543   1611       }else{
  1544   1612         pPage->intKeyLeaf = 0;
  1545   1613         pPage->noPayload = 1;
  1546   1614         pPage->xCellSize = cellSizePtrNoPayload;
         1615  +      pPage->xParseCell = btreeParseCellPtrNoPayload;
  1547   1616       }
  1548   1617       pPage->maxLocal = pBt->maxLeaf;
  1549   1618       pPage->minLocal = pBt->minLeaf;
  1550   1619     }else if( flagByte==PTF_ZERODATA ){
  1551   1620       /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
  1552   1621       ** index b-tree page. */
  1553   1622       assert( (PTF_ZERODATA)==2 );
  1554   1623       /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
  1555   1624       ** index b-tree page. */
  1556   1625       assert( (PTF_ZERODATA|PTF_LEAF)==10 );
  1557   1626       pPage->intKey = 0;
  1558   1627       pPage->intKeyLeaf = 0;
  1559   1628       pPage->noPayload = 0;
         1629  +    pPage->xParseCell = btreeParseCellPtrIndex;
  1560   1630       pPage->maxLocal = pBt->maxLocal;
  1561   1631       pPage->minLocal = pBt->minLocal;
  1562   1632     }else{
  1563   1633       /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
  1564   1634       ** an error. */
  1565   1635       return SQLITE_CORRUPT_BKPT;
  1566   1636     }
................................................................................
  3143   3213       if( rc ) return rc;
  3144   3214       nCell = pPage->nCell;
  3145   3215   
  3146   3216       for(i=0; i<nCell; i++){
  3147   3217         u8 *pCell = findCell(pPage, i);
  3148   3218         if( eType==PTRMAP_OVERFLOW1 ){
  3149   3219           CellInfo info;
  3150         -        btreeParseCellPtr(pPage, pCell, &info);
         3220  +        pPage->xParseCell(pPage, pCell, &info);
  3151   3221           if( info.iOverflow
  3152   3222            && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
  3153   3223            && iFrom==get4byte(&pCell[info.iOverflow])
  3154   3224           ){
  3155   3225             put4byte(&pCell[info.iOverflow], iTo);
  3156   3226             break;
  3157   3227           }
................................................................................
  4988   5058             **
  4989   5059             ** If the record is corrupt, the xRecordCompare routine may read
  4990   5060             ** up to two varints past the end of the buffer. An extra 18 
  4991   5061             ** bytes of padding is allocated at the end of the buffer in
  4992   5062             ** case this happens.  */
  4993   5063             void *pCellKey;
  4994   5064             u8 * const pCellBody = pCell - pPage->childPtrSize;
  4995         -          btreeParseCellPtr(pPage, pCellBody, &pCur->info);
         5065  +          pPage->xParseCell(pPage, pCellBody, &pCur->info);
  4996   5066             nCell = (int)pCur->info.nKey;
  4997   5067             testcase( nCell<0 );   /* True if key size is 2^32 or more */
  4998   5068             testcase( nCell==0 );  /* Invalid key size:  0x80 0x80 0x00 */
  4999   5069             testcase( nCell==1 );  /* Invalid key size:  0x80 0x80 0x01 */
  5000   5070             testcase( nCell==2 );  /* Minimum legal index key size */
  5001   5071             if( nCell<2 ){
  5002   5072               rc = SQLITE_CORRUPT_BKPT;
................................................................................
  5777   5847     CellInfo info;
  5778   5848     Pgno ovflPgno;
  5779   5849     int rc;
  5780   5850     int nOvfl;
  5781   5851     u32 ovflPageSize;
  5782   5852   
  5783   5853     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  5784         -  btreeParseCellPtr(pPage, pCell, &info);
         5854  +  pPage->xParseCell(pPage, pCell, &info);
  5785   5855     *pnSize = info.nSize;
  5786   5856     if( info.iOverflow==0 ){
  5787   5857       return SQLITE_OK;  /* No overflow pages. Return without doing anything */
  5788   5858     }
  5789   5859     if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
  5790   5860       return SQLITE_CORRUPT_BKPT;  /* Cell extends past end of page */
  5791   5861     }
................................................................................
  5931   6001     **
  5932   6002     ** Use a call to btreeParseCellPtr() to verify that the values above
  5933   6003     ** were computed correctly.
  5934   6004     */
  5935   6005   #if SQLITE_DEBUG
  5936   6006     {
  5937   6007       CellInfo info;
  5938         -    btreeParseCellPtr(pPage, pCell, &info);
         6008  +    pPage->xParseCell(pPage, pCell, &info);
  5939   6009       assert( nHeader=(int)(info.pPayload - pCell) );
  5940   6010       assert( info.nKey==nKey );
  5941   6011       assert( *pnSize == info.nSize );
  5942   6012       assert( spaceLeft == info.nLocal );
  5943   6013       assert( pPrior == &pCell[info.iOverflow] );
  5944   6014     }
  5945   6015   #endif
................................................................................
  6580   6650       assert( pPage->isInit );
  6581   6651   
  6582   6652       for(j=0; j<pPage->nCell; j++){
  6583   6653         CellInfo info;
  6584   6654         u8 *z;
  6585   6655        
  6586   6656         z = findCell(pPage, j);
  6587         -      btreeParseCellPtr(pPage, z, &info);
         6657  +      pPage->xParseCell(pPage, z, &info);
  6588   6658         if( info.iOverflow ){
  6589   6659           Pgno ovfl = get4byte(&z[info.iOverflow]);
  6590   6660           ptrmapGet(pBt, ovfl, &e, &n);
  6591   6661           assert( n==pPage->pgno && e==PTRMAP_OVERFLOW1 );
  6592   6662         }
  6593   6663         if( !pPage->leaf ){
  6594   6664           Pgno child = get4byte(z);
................................................................................
  7211   7281         /* If the tree is a leaf-data tree, and the siblings are leaves, 
  7212   7282         ** then there is no divider cell in apCell[]. Instead, the divider 
  7213   7283         ** cell consists of the integer key for the right-most cell of 
  7214   7284         ** the sibling-page assembled above only.
  7215   7285         */
  7216   7286         CellInfo info;
  7217   7287         j--;
  7218         -      btreeParseCellPtr(pNew, apCell[j], &info);
         7288  +      pNew->xParseCell(pNew, apCell[j], &info);
  7219   7289         pCell = pTemp;
  7220   7290         sz = 4 + putVarint(&pCell[4], info.nKey);
  7221   7291         pTemp = 0;
  7222   7292       }else{
  7223   7293         pCell -= 4;
  7224   7294         /* Obscure case for non-leaf-data trees: If the cell at pCell was
  7225   7295         ** previously stored on a leaf node, and its reported size was 4
................................................................................
  8711   8781   
  8712   8782       /* Check payload overflow pages
  8713   8783       */
  8714   8784       pCheck->zPfx = "On tree page %d cell %d: ";
  8715   8785       pCheck->v1 = iPage;
  8716   8786       pCheck->v2 = i;
  8717   8787       pCell = findCell(pPage,i);
  8718         -    btreeParseCellPtr(pPage, pCell, &info);
         8788  +    pPage->xParseCell(pPage, pCell, &info);
  8719   8789       sz = info.nPayload;
  8720   8790       /* For intKey pages, check that the keys are in order.
  8721   8791       */
  8722   8792       if( pPage->intKey ){
  8723   8793         if( i==0 ){
  8724   8794           nMinKey = nMaxKey = info.nKey;
  8725   8795         }else if( info.nKey <= nMaxKey ){

Changes to src/btreeInt.h.

   227    227   ** small cells will be rare, but they are possible.
   228    228   */
   229    229   #define MX_CELL(pBt) ((pBt->pageSize-8)/6)
   230    230   
   231    231   /* Forward declarations */
   232    232   typedef struct MemPage MemPage;
   233    233   typedef struct BtLock BtLock;
          234  +typedef struct CellInfo CellInfo;
   234    235   
   235    236   /*
   236    237   ** This is a magic string that appears at the beginning of every
   237    238   ** SQLite database in order to identify the file as a real database.
   238    239   **
   239    240   ** You can change this value at compile-time by specifying a
   240    241   ** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
................................................................................
   291    292                          ** non-overflow cell */
   292    293     u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
   293    294     BtShared *pBt;       /* Pointer to BtShared that this page is part of */
   294    295     u8 *aData;           /* Pointer to disk image of the page data */
   295    296     u8 *aDataEnd;        /* One byte past the end of usable data */
   296    297     u8 *aCellIdx;        /* The cell index area */
   297    298     DbPage *pDbPage;     /* Pager page handle */
   298         -  u16 (*xCellSize)(MemPage*,u8*);  /* cellSizePtr method */
          299  +  u16 (*xCellSize)(MemPage*,u8*);             /* cellSizePtr method */
          300  +  void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
   299    301     Pgno pgno;           /* Page number for this page */
   300    302   };
   301    303   
   302    304   /*
   303    305   ** The in-memory image of a disk page has the auxiliary information appended
   304    306   ** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
   305    307   ** that extra information.
................................................................................
   457    459   #define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
   458    460   
   459    461   /*
   460    462   ** An instance of the following structure is used to hold information
   461    463   ** about a cell.  The parseCellPtr() function fills in this structure
   462    464   ** based on information extract from the raw disk page.
   463    465   */
   464         -typedef struct CellInfo CellInfo;
   465    466   struct CellInfo {
   466    467     i64 nKey;      /* The key for INTKEY tables, or nPayload otherwise */
   467    468     u8 *pPayload;  /* Pointer to the start of payload */
   468    469     u32 nPayload;  /* Bytes of payload */
   469    470     u16 nLocal;    /* Amount of payload held locally, not on overflow */
   470    471     u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
   471    472     u16 nSize;     /* Size of the cell content on the main b-tree page */