Fix some code duplication issues on this branch. Add minor optimizations to the new code.
FossilOrigin-Name: 58d7793bd5d608ba9fc3a2cd44b9d9512e0332ba
This commit is contained in:
parent
d0b8f93b5f
commit
8e9ba0c335
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\strunk\schanges\sinto\sthis\sbranch.
|
||||
D 2014-10-13T18:09:13.737
|
||||
C Fix\ssome\scode\sduplication\sissues\son\sthis\sbranch.\sAdd\sminor\soptimizations\sto\sthe\snew\scode.
|
||||
D 2014-10-14T17:27:04.829
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -172,7 +172,7 @@ F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2
|
||||
F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
|
||||
F src/btree.c 3d9d1db1d05724346876cf456a850628a9e75331
|
||||
F src/btree.c 3c72c5aa96b1a06ea15da24b82c526e6f14010ab
|
||||
F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
|
||||
F src/btreeInt.h 1bd7957161a1346a914f1f09231610e777a8e58d
|
||||
F src/build.c 9dc2bd94347b878c89627000c92b0c8d97ec2919
|
||||
@ -1204,7 +1204,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 6594f9b420e2fa642737722ff8521f756ecef227 04892f8ba6c55cec4fe37bfe59b6349fd2a40698
|
||||
R 76183a9b7ddeb938a48604dbc4dd8cd6
|
||||
P d5b7c5a88dd58de85b3060a1f28b6d96e6e21207
|
||||
R ff1ec1f8aba483920a0100e96e95dccf
|
||||
U dan
|
||||
Z 504cabb1e1fb0c47450f76fec3d8495b
|
||||
Z 9c750816a0b42cc370356f0c03af45ae
|
||||
|
@ -1 +1 @@
|
||||
d5b7c5a88dd58de85b3060a1f28b6d96e6e21207
|
||||
58d7793bd5d608ba9fc3a2cd44b9d9512e0332ba
|
295
src/btree.c
295
src/btree.c
@ -1224,6 +1224,57 @@ static int defragmentPage(MemPage *pPage){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search the free-list on page pPg for space to store a cell nByte bytes in
|
||||
** size. If one can be found, return a pointer to the space and remove it
|
||||
** from the free-list.
|
||||
**
|
||||
** If no suitable space can be found on the free-list, return NULL.
|
||||
**
|
||||
** This function may detect corruption within pPg. If it does and argument
|
||||
** pRc is non-NULL, then *pRc is set to SQLITE_CORRUPT and NULL is returned.
|
||||
** Or, if corruption is detected by pRc is NULL, NULL is returned and the
|
||||
** corruption goes unreported.
|
||||
*/
|
||||
static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
const int hdr = pPg->hdrOffset;
|
||||
u8 * const aData = pPg->aData;
|
||||
int iAddr;
|
||||
int pc;
|
||||
int usableSize = pPg->pBt->usableSize;
|
||||
|
||||
for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
|
||||
int size; /* Size of the free slot */
|
||||
if( pc>usableSize-4 || pc<iAddr+4 ){
|
||||
if( pRc ) *pRc = SQLITE_CORRUPT_BKPT;
|
||||
return 0;
|
||||
}
|
||||
size = get2byte(&aData[pc+2]);
|
||||
if( size>=nByte ){
|
||||
int x = size - nByte;
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( x<4 ){
|
||||
if( aData[hdr+7]>=60 ) return 0;
|
||||
/* Remove the slot from the free-list. Update the number of
|
||||
** fragmented bytes within the page. */
|
||||
memcpy(&aData[iAddr], &aData[pc], 2);
|
||||
aData[hdr+7] += (u8)x;
|
||||
}else if( size+pc > usableSize ){
|
||||
if( pRc ) *pRc = SQLITE_CORRUPT_BKPT;
|
||||
return 0;
|
||||
}else{
|
||||
/* The slot remains on the free-list. Reduce its size to account
|
||||
** for the portion used by the new allocation. */
|
||||
put2byte(&aData[pc+2], x);
|
||||
}
|
||||
return &aData[pc + x];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate nByte bytes of space from within the B-Tree page passed
|
||||
** as the first argument. Write into *pIdx the index into pPage->aData[]
|
||||
@ -1274,33 +1325,12 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
testcase( gap+1==top );
|
||||
testcase( gap==top );
|
||||
if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){
|
||||
int pc, addr;
|
||||
for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){
|
||||
int size; /* Size of the free slot */
|
||||
if( pc>usableSize-4 || pc<addr+4 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
size = get2byte(&data[pc+2]);
|
||||
if( size>=nByte ){
|
||||
int x = size - nByte;
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( x<4 ){
|
||||
if( data[hdr+7]>=60 ) goto defragment_page;
|
||||
/* Remove the slot from the free-list. Update the number of
|
||||
** fragmented bytes within the page. */
|
||||
memcpy(&data[addr], &data[pc], 2);
|
||||
data[hdr+7] += (u8)x;
|
||||
}else if( size+pc > usableSize ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
/* The slot remains on the free-list. Reduce its size to account
|
||||
** for the portion used by the new allocation. */
|
||||
put2byte(&data[pc+2], x);
|
||||
}
|
||||
*pIdx = pc + x;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
int rc = SQLITE_OK;
|
||||
u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
|
||||
if( rc ) return rc;
|
||||
if( pSpace ){
|
||||
*pIdx = pSpace - data;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1309,7 +1339,6 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
*/
|
||||
testcase( gap+2+nByte==top );
|
||||
if( gap+2+nByte>top ){
|
||||
defragment_page:
|
||||
testcase( pPage->nCell==0 );
|
||||
rc = defragmentPage(pPage);
|
||||
if( rc ) return rc;
|
||||
@ -5933,48 +5962,18 @@ static void insertCell(
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a list of cells to a page. The page should be initially empty.
|
||||
** The cells are guaranteed to fit on the page.
|
||||
** Array apCell[] contains pointers to nCell b-tree page cells. The
|
||||
** szCell[] array contains the size in bytes of each cell. This function
|
||||
** replaces the current contents of page pPg with the contents of the cell
|
||||
** array.
|
||||
**
|
||||
** Some of the cells in apCell[] may currently be stored in pPg. This
|
||||
** function works around problems caused by this by making a copy of any
|
||||
** such cells before overwriting the page data.
|
||||
**
|
||||
** The MemPage.nFree field is invalidated by this function. It is the
|
||||
** responsibility of the caller to set it correctly.
|
||||
*/
|
||||
static void assemblePage(
|
||||
MemPage *pPage, /* The page to be assembled */
|
||||
int nCell, /* The number of cells to add to this page */
|
||||
u8 **apCell, /* Pointers to cell bodies */
|
||||
u16 *aSize /* Sizes of the cells */
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
u8 *pCellptr; /* Address of next cell pointer */
|
||||
int cellbody; /* Address of next cell body */
|
||||
u8 * const data = pPage->aData; /* Pointer to data for pPage */
|
||||
const int hdr = pPage->hdrOffset; /* Offset of header on pPage */
|
||||
const int nUsable = pPage->pBt->usableSize; /* Usable size of page */
|
||||
|
||||
assert( pPage->nOverflow==0 );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt)
|
||||
&& (int)MX_CELL(pPage->pBt)<=10921);
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
|
||||
/* Check that the page has just been zeroed by zeroPage() */
|
||||
assert( pPage->nCell==0 );
|
||||
assert( get2byteNotZero(&data[hdr+5])==nUsable );
|
||||
|
||||
pCellptr = pPage->aCellIdx;
|
||||
cellbody = nUsable;
|
||||
for(i=0; i<nCell; i++){
|
||||
u16 sz = aSize[i];
|
||||
cellbody -= sz;
|
||||
put2byte(pCellptr, cellbody);
|
||||
pCellptr += 2;
|
||||
memcpy(&data[cellbody], apCell[i], sz);
|
||||
}
|
||||
put2byte(&data[hdr+3], nCell);
|
||||
put2byte(&data[hdr+5], cellbody);
|
||||
pPage->nFree -= (nCell*2 + nUsable - cellbody);
|
||||
pPage->nCell = (u16)nCell;
|
||||
}
|
||||
|
||||
|
||||
static void rebuildPage(
|
||||
MemPage *pPg, /* Edit this page */
|
||||
int nCell, /* Final number of cells on page */
|
||||
@ -5992,8 +5991,8 @@ static void rebuildPage(
|
||||
|
||||
i = get2byte(&aData[hdr+5]);
|
||||
memcpy(&pTmp[i], &aData[i], usableSize - i);
|
||||
pData = &aData[usableSize];
|
||||
|
||||
pData = pEnd;
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pCell = apCell[i];
|
||||
if( pCell>aData && pCell<pEnd ){
|
||||
@ -6016,57 +6015,49 @@ static void rebuildPage(
|
||||
aData[hdr+7] = 0x00;
|
||||
}
|
||||
|
||||
static u8 *pageFindSlot(MemPage *pPg, int nByte){
|
||||
const int hdr = pPg->hdrOffset;
|
||||
u8 * const aData = pPg->aData;
|
||||
int iAddr;
|
||||
int pc;
|
||||
int usableSize = pPg->pBt->usableSize;
|
||||
|
||||
for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
|
||||
int size; /* Size of the free slot */
|
||||
if( pc>usableSize-4 || pc<iAddr+4 ) return 0;
|
||||
size = get2byte(&aData[pc+2]);
|
||||
if( size>=nByte ){
|
||||
int x = size - nByte;
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( x<4 ){
|
||||
if( aData[hdr+7]>=60 ) return 0;
|
||||
/* Remove the slot from the free-list. Update the number of
|
||||
** fragmented bytes within the page. */
|
||||
memcpy(&aData[iAddr], &aData[pc], 2);
|
||||
aData[hdr+7] += (u8)x;
|
||||
}else if( size+pc > usableSize ){
|
||||
return 0;
|
||||
}else{
|
||||
/* The slot remains on the free-list. Reduce its size to account
|
||||
** for the portion used by the new allocation. */
|
||||
put2byte(&aData[pc+2], x);
|
||||
}
|
||||
return &aData[pc + x];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
||||
** contains the size in bytes of each such cell. This function attempts to
|
||||
** add the cells stored in the array to page pPg. If it cannot (because
|
||||
** the page needs to be defragmented before the cells will fit), non-zero
|
||||
** is returned. Otherwise, if the cells are added successfully, zero is
|
||||
** returned.
|
||||
**
|
||||
** Argument pCellptr points to the first entry in the cell-pointer array
|
||||
** (part of page pPg) to populate. After cell apCell[0] is written to the
|
||||
** page body, a 16-bit offset is written to pCellptr. And so on, for each
|
||||
** cell in the array. It is the responsibility of the caller to ensure
|
||||
** that it is safe to overwrite this part of the cell-pointer array.
|
||||
**
|
||||
** When this function is called, *ppData points to the start of the
|
||||
** content area on page pPg. If the size of the content area is extended,
|
||||
** *ppData is updated to point to the new start of the content area
|
||||
** before returning.
|
||||
**
|
||||
** Finally, argument pBegin points to the byte immediately following the
|
||||
** end of the space required by this page for the cell-pointer area (for
|
||||
** all cells - not just those inserted by the current call). If the content
|
||||
** area must be extended to before this point in order to accomodate all
|
||||
** cells in apCell[], then the cells do not fit and non-zero is returned.
|
||||
*/
|
||||
static int pageInsertArray(
|
||||
MemPage *pPg,
|
||||
u8 *pBegin,
|
||||
u8 **ppData,
|
||||
u8 *pCellptr,
|
||||
int nCell,
|
||||
MemPage *pPg, /* Page to add cells to */
|
||||
u8 *pBegin, /* End of cell-pointer array */
|
||||
u8 **ppData, /* IN/OUT: Page content -area pointer */
|
||||
u8 *pCellptr, /* Pointer to cell-pointer area */
|
||||
int nCell, /* Number of cells to add to pPg */
|
||||
u8 **apCell, /* Array of cells */
|
||||
u16 *szCell /* Array of cell sizes */
|
||||
){
|
||||
int i;
|
||||
u8 *aData = pPg->aData;
|
||||
u8 *pData = *ppData;
|
||||
const int bFreelist = aData[1] || aData[2];
|
||||
assert( pPg->hdrOffset==0 ); /* Never called on page 1 */
|
||||
for(i=0; i<nCell; i++){
|
||||
int sz = szCell[i];
|
||||
u8 *pSlot;
|
||||
if( (pSlot = pageFindSlot(pPg, sz))==0 ){
|
||||
if( bFreelist==0 || (pSlot = pageFindSlot(pPg, sz, 0))==0 ){
|
||||
pData -= sz;
|
||||
if( pData<pBegin ) return 1;
|
||||
pSlot = pData;
|
||||
@ -6079,6 +6070,15 @@ static int pageInsertArray(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
||||
** contains the size in bytes of each such cell. This function adds the
|
||||
** space associated with each cell in the array that is currently stored
|
||||
** within the body of pPg to the pPg free-list. The cell-pointers and other
|
||||
** fields of the page are not updated.
|
||||
**
|
||||
** This function returns the total number of cells added to the free-list.
|
||||
*/
|
||||
static int pageFreeArray(
|
||||
MemPage *pPg, /* Page to edit */
|
||||
int nCell, /* Cells to delete */
|
||||
@ -6111,7 +6111,6 @@ static int pageFreeArray(
|
||||
return nRet;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The pPg->nFree field is invalid when this function returns. It is the
|
||||
** responsibility of the caller to set it correctly.
|
||||
@ -6206,15 +6205,8 @@ static void editPage(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printf("EDIT\n");
|
||||
#endif
|
||||
|
||||
return;
|
||||
editpage_fail:
|
||||
#if 0
|
||||
printf("REBUILD\n");
|
||||
#endif
|
||||
/* Unable to edit this page. Rebuild it from scratch instead. */
|
||||
rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]);
|
||||
}
|
||||
@ -6288,7 +6280,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
|
||||
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
|
||||
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
|
||||
assemblePage(pNew, 1, &pCell, &szCell);
|
||||
rebuildPage(pNew, 1, &pCell, &szCell);
|
||||
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
|
||||
|
||||
/* If this is an auto-vacuum database, update the pointer map
|
||||
** with entries for the new page, and any pointer from the
|
||||
@ -6518,8 +6511,6 @@ static int balance_nonroot(
|
||||
u8 *aSpace1; /* Space for copies of dividers cells */
|
||||
Pgno pgno; /* Temp var to store a page number in */
|
||||
|
||||
int aShiftLeft[NB+2];
|
||||
int aShiftRight[NB+2];
|
||||
u8 abDone[NB+2];
|
||||
Pgno aPgno[NB+2];
|
||||
u16 aPgFlags[NB+2];
|
||||
@ -6887,49 +6878,6 @@ static int balance_nonroot(
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
put4byte(pRight, apNew[nNew-1]->pgno);
|
||||
|
||||
j = 0;
|
||||
for(i=0; i<nNew; i++){
|
||||
/* At this point, "j" is the apCell[] index of the first cell currently
|
||||
** stored on page apNew[i]. Or, if apNew[i] was not one of the original
|
||||
** sibling pages, "j" should be set to nCell. Variable iFirst is set
|
||||
** to the apCell[] index of the first cell that will appear on the
|
||||
** page following this balancing operation. */
|
||||
int iFirst = (i==0 ? 0 : cntNew[i-1] + !leafData); /* new first cell */
|
||||
|
||||
#if 0
|
||||
MemPage *pNew = apNew[i];
|
||||
int iCell;
|
||||
int nCta = 0;
|
||||
int nFree;
|
||||
|
||||
printf("REBUILD %d: %d@%d -> %d@%d", apNew[i]->pgno,
|
||||
pNew->nCell+pNew->nOverflow, j,
|
||||
cntNew[i] - iFirst, iFirst
|
||||
);
|
||||
for(iCell=iFirst; iCell<cntNew[i]; iCell++){
|
||||
if( apCell[iCell]<pNew->aData
|
||||
|| apCell[iCell]>=&pNew->aData[pBt->usableSize]
|
||||
){
|
||||
nCta += szCell[iCell];
|
||||
}
|
||||
}
|
||||
nFree = get2byte(&pNew->aData[pNew->hdrOffset+5]);
|
||||
nFree -= (pNew->cellOffset + (cntNew[i] - iFirst) * 2);
|
||||
printf(" cta=%d free=%d\n", nCta, nFree);
|
||||
if( i==(nNew-1) ){
|
||||
printf("-----\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert( i<nOld || j==nCell );
|
||||
aShiftLeft[i] = j - iFirst;
|
||||
j += apNew[i]->nCell + apNew[i]->nOverflow;
|
||||
aShiftRight[i] = cntNew[i] - j;
|
||||
assert( i!=nOld-1 || j==nCell );
|
||||
if( j<nCell ) j += !leafData;
|
||||
}
|
||||
|
||||
/* If the sibling pages are not leaves, ensure that the right-child pointer
|
||||
** of the right-most new sibling page is set to the value that was
|
||||
** originally in the same field of the right-most old sibling page. */
|
||||
@ -7047,22 +6995,21 @@ static int balance_nonroot(
|
||||
** is important, as this code needs to avoid disrupting any page from which
|
||||
** cells may still to be read. In practice, this means:
|
||||
**
|
||||
** 1) If the aShiftLeft[] entry is less than 0, it is not safe to
|
||||
** update the page until the page to the left of the current page
|
||||
** (apNew[i-1]) has already been updated.
|
||||
** 1) If cells are to be removed from the start of the page and shifted
|
||||
** to the left-hand sibling, it is not safe to update the page until
|
||||
** the left-hand sibling (apNew[i-1]) has already been updated.
|
||||
**
|
||||
** 2) If the aShiftRight[] entry is less than 0, it is not safe to
|
||||
** update the page until the page to the right of the current page
|
||||
** (apNew[i+1]) has already been updated.
|
||||
** 2) If cells are to be removed from the end of the page and shifted
|
||||
** to the right-hand sibling, it is not safe to update the page until
|
||||
** the right-hand sibling (apNew[i+1]) has already been updated.
|
||||
**
|
||||
** If neither of the above apply, the page is safe to update.
|
||||
*/
|
||||
assert( aShiftRight[nNew-1]>=0 && aShiftLeft[0]==0 );
|
||||
for(i=0; i<nNew*2; i++){
|
||||
int iPg = (i>=nNew ? i-nNew : nNew-1-i);
|
||||
if( abDone[iPg]==0
|
||||
&& (aShiftLeft[iPg]>=0 || abDone[iPg-1])
|
||||
&& (aShiftRight[iPg]>=0 || abDone[iPg+1])
|
||||
&& (iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1])
|
||||
&& (cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1])
|
||||
){
|
||||
int iNew;
|
||||
int iOld;
|
||||
|
Loading…
Reference in New Issue
Block a user