Modify btree.c so that is allocates big data structures using malloc()

instead of allocating from the stack.  Stack allocations cause problems
for embedded systems and pthreads implementations that only allocate a
limited amount of stack space. (CVS 1937)

FossilOrigin-Name: 4595292f936bdbec10734f42682824e91ff71d11
This commit is contained in:
drh 2004-09-03 18:38:44 +00:00
parent 2c7e56798b
commit 2e38c32b67
4 changed files with 148 additions and 97 deletions

View File

@ -1,5 +1,5 @@
C More\stests\sof\ssqlite3_step()\sand\sSQLITE_BUSY\sadded.\s(CVS\s1936)
D 2004-09-03T00:27:57
C Modify\sbtree.c\sso\sthat\sis\sallocates\sbig\sdata\sstructures\susing\smalloc()\ninstead\sof\sallocating\sfrom\sthe\sstack.\s\sStack\sallocations\scause\sproblems\nfor\sembedded\ssystems\sand\spthreads\simplementations\sthat\sonly\sallocate\sa\nlimited\samount\sof\sstack\sspace.\s(CVS\s1937)
D 2004-09-03T18:38:45
F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -28,7 +28,7 @@ F sqlite3.def 84215604aa7b547d75e0f7b437966e7ad18fa8b2
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/attach.c 0bd4f11da6999665da30625665a4096ba7898de6
F src/auth.c 60db23b98bb94c8b0178180faaf49dc116674217
F src/btree.c 598e7eccfa93194851f570c0ea146f6efe098ac3
F src/btree.c 91a6f5e90c6e7a15cc9af4257866a03c1614442e
F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029
F src/build.c 35275654d9c5ce6c1c0c78e391f85e6915a8a66b
F src/date.c edff4aa851eeca8abbc737dc3933a2f0671156ce
@ -139,7 +139,7 @@ F test/lock2.test 2213590d442147d09fd2334c905a755586c1c398
F test/main.test 1430a4b5bd3a6d5e0294966b742d80a551f87211
F test/malloc.test 769b240d89a7ef3320d88919fdb6765f9395a51f
F test/memdb.test b8a13fa79f006bd087bbcf135ce8eb62056a6027
F test/memleak.test a7efa33c7adc2762add028a4cc70a6bb04fe573e
F test/memleak.test f1fa233f8295dd1d955a00d5e5ee857850f27f29
F test/minmax.test c0f92d3f7b11656221735385f2c8b1878bbbdaf6
F test/misc1.test 1a20ea722dff15155e93948dc4ac3e8d80fec386
F test/misc2.test 703734f5817215ca54e364833b3bf5ff36fcc21e
@ -248,7 +248,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 45d7158878a9648708d8ed47944707169a7f7f1c
R 14f7ba7cd5cb5bab38c50df92d09018d
P 9e6645dd781cb8e422e371ca23766dc1b689481e
R f084bc97486f0a01c7a5a8e06138356c
U drh
Z 97faa8433bbaa30accc2ea468a82795b
Z 4d667560618f87c860d31b44d3368e4d

View File

@ -1 +1 @@
9e6645dd781cb8e422e371ca23766dc1b689481e
4595292f936bdbec10734f42682824e91ff71d11

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.185 2004/09/01 16:12:25 drh Exp $
** $Id: btree.c,v 1.186 2004/09/03 18:38:45 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -214,13 +214,13 @@
/* The following value is the maximum cell size assuming a maximum page
** size give above.
*/
#define MX_CELL_SIZE (SQLITE_MAX_PAGE_SIZE-8)
#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
/* The maximum number of cells on a single page of the database. This
** assumes a minimum cell size of 3 bytes. Such small cells will be
** exceedingly rare, but they are possible.
*/
#define MX_CELL ((SQLITE_MAX_PAGE_SIZE-8)/3)
#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
/* Forward declarations */
typedef struct MemPage MemPage;
@ -527,8 +527,10 @@ static void _pageIntegrity(MemPage *pPage){
int i, j, idx, c, pc, hdr, nFree;
int cellOffset;
int nCell, cellLimit;
u8 used[SQLITE_MAX_PAGE_SIZE];
u8 *used;
used = sqliteMallocRaw( pPage->pBt->pageSize );
if( used==0 ) return;
usableSize = pPage->pBt->usableSize;
assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
hdr = pPage->hdrOffset;
@ -589,6 +591,7 @@ static void _pageIntegrity(MemPage *pPage){
if( used[i]==0 ) nFree++;
}
assert( nFree==data[hdr+7] );
sqliteFree(used);
}
#define pageIntegrity(X) _pageIntegrity(X)
#else
@ -600,7 +603,7 @@ static void _pageIntegrity(MemPage *pPage){
** beginning of the page and all free space is collected
** into one big FreeBlk at the end of the page.
*/
static void defragmentPage(MemPage *pPage){
static int defragmentPage(MemPage *pPage){
int i; /* Loop counter */
int pc; /* Address of a i-th cell */
int addr; /* Offset of first byte after cell pointer array */
@ -610,13 +613,15 @@ static void defragmentPage(MemPage *pPage){
int cellOffset; /* Offset to the cell pointer array */
int brk; /* Offset to the cell content area */
int nCell; /* Number of cells on the page */
unsigned char *data; /* The page data */
unsigned char temp[SQLITE_MAX_PAGE_SIZE]; /* Temp area for cell content */
unsigned char *data; /* The page data */
unsigned char *temp; /* Temp area for cell content */
assert( sqlite3pager_iswriteable(pPage->aData) );
assert( pPage->pBt!=0 );
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
temp = sqliteMalloc( pPage->pBt->pageSize );
if( temp==0 ) return SQLITE_NOMEM;
data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
@ -643,6 +648,8 @@ static void defragmentPage(MemPage *pPage){
data[hdr+7] = 0;
addr = cellOffset+2*nCell;
memset(&data[addr], 0, brk-addr);
sqliteFree(temp);
return SQLITE_OK;
}
/*
@ -702,7 +709,7 @@ static int allocateSpace(MemPage *pPage, int nByte){
nCell = get2byte(&data[hdr+3]);
cellOffset = pPage->cellOffset;
if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){
defragmentPage(pPage);
if( defragmentPage(pPage) ) return 0;
top = get2byte(&data[hdr+5]);
}
top -= nByte;
@ -819,15 +826,17 @@ static int initPage(
int i; /* Loop counter */
int hdr; /* Offset to beginning of page header */
u8 *data; /* Equal to pPage->aData */
Btree *pBt; /* The main btree structure */
int usableSize; /* Amount of usable space on each page */
int cellOffset; /* Offset from start of page to first cell pointer */
int nFree; /* Number of unused bytes on the page */
int top; /* First byte of the cell content area */
assert( pPage->pBt!=0 );
assert( pParent==0 || pParent->pBt==pPage->pBt );
pBt = pPage->pBt;
assert( pBt!=0 );
assert( pParent==0 || pParent->pBt==pBt );
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] );
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
/* The parent page should never change unless the file is corrupt */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
@ -842,11 +851,11 @@ static int initPage(
decodeFlags(pPage, data[hdr]);
pPage->nOverflow = 0;
pPage->idxShift = 0;
usableSize = pPage->pBt->usableSize;
usableSize = pBt->usableSize;
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
top = get2byte(&data[hdr+5]);
pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL ){
if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
}
@ -1218,7 +1227,7 @@ static int lockBtree(Btree *pBt){
if( pBt->minLocal>pBt->maxLocal || pBt->maxLocal<0 ){
goto page1_init_failed;
}
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE );
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
pBt->pageSizeFixed = 1;
return SQLITE_OK;
@ -2916,6 +2925,7 @@ static int balance_nonroot(MemPage *pPage){
int pageFlags; /* Value of pPage->aData[0] */
int subtotal; /* Subtotal of bytes in cells on one page */
int iSpace = 0; /* First unused byte of aSpace[] */
int mxCellPerPage; /* Maximum number of cells in one page */
MemPage *apOld[NB]; /* pPage and up to two siblings */
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
@ -2925,10 +2935,10 @@ static int balance_nonroot(MemPage *pPage){
u8 *apDiv[NB]; /* Divider cells in pParent */
int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
int szNew[NB+2]; /* Combined size of cells place on i-th page */
u8 *apCell[(MX_CELL+2)*NB]; /* All cells from pages being balanced */
int szCell[(MX_CELL+2)*NB]; /* Local size of all cells */
u8 aCopy[NB][SQLITE_MAX_PAGE_SIZE+sizeof(MemPage)]; /* Space for apCopy[] */
u8 aSpace[SQLITE_MAX_PAGE_SIZE*5]; /* Space to copies of divider cells */
u8 **apCell; /* All cells begin balanced */
int *szCell; /* Local size of all cells in apCell[] */
u8 *aCopy[NB]; /* Space for holding data of apCopy[] */
u8 *aSpace; /* Space to hold copies of dividers cells */
/*
** Find the parent page.
@ -2940,6 +2950,25 @@ static int balance_nonroot(MemPage *pPage){
sqlite3pager_write(pParent->aData);
assert( pParent );
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
/*
** Allocate space for memory structures
*/
mxCellPerPage = MX_CELL(pBt);
apCell = sqliteMallocRaw(
(mxCellPerPage+2)*NB*(sizeof(u8*)+sizeof(int))
+ sizeof(MemPage)*NB
+ pBt->pageSize*(5+NB)
);
if( apCell==0 ){
return SQLITE_NOMEM;
}
szCell = (int*)&apCell[(mxCellPerPage+2)*NB];
aCopy[0] = (u8*)&szCell[(mxCellPerPage+2)*NB];
for(i=1; i<NB; i++){
aCopy[i] = &aCopy[i-1][pBt->pageSize+sizeof(MemPage)];
}
aSpace = &aCopy[NB-1][pBt->pageSize+sizeof(MemPage)];
/*
** Find the cell in the parent page whose left child points back
@ -3010,7 +3039,7 @@ static int balance_nonroot(MemPage *pPage){
** process of being overwritten.
*/
for(i=0; i<nOld; i++){
MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-(int)sizeof(MemPage)];
MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->pageSize];
p->aData = &((u8*)p)[-pBt->pageSize];
memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage));
p->aData = &((u8*)p)[-pBt->pageSize];
@ -3057,7 +3086,7 @@ static int balance_nonroot(MemPage *pPage){
szCell[nCell] = sz;
pTemp = &aSpace[iSpace];
iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
assert( iSpace<=pBt->pageSize*5 );
memcpy(pTemp, apDiv[i], sz);
apCell[nCell] = pTemp+leafCorrection;
dropCell(pParent, nxDiv, sz);
@ -3241,13 +3270,13 @@ static int balance_nonroot(MemPage *pPage){
pCell = &aSpace[iSpace];
fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
assert( iSpace<=pBt->pageSize*5 );
pTemp = 0;
}else{
pCell -= 4;
pTemp = &aSpace[iSpace];
iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
assert( iSpace<=pBt->pageSize*5 );
}
insertCell(pParent, nxDiv, pCell, sz, pTemp);
put4byte(findOverflowCell(pParent,nxDiv), pNew->pgno);
@ -3290,6 +3319,7 @@ static int balance_nonroot(MemPage *pPage){
** Cleanup before returning.
*/
balance_cleanup:
sqliteFree(apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@ -3310,12 +3340,19 @@ balance_cleanup:
static int balance_shallower(MemPage *pPage){
MemPage *pChild; /* The only child page of pPage */
Pgno pgnoChild; /* Page number for pChild */
int rc; /* Return code from subprocedures */
u8 *apCell[(MX_CELL+2)*NB]; /* All cells from pages being balanced */
int szCell[(MX_CELL+2)*NB]; /* Local size of all cells */
int rc = SQLITE_OK; /* Return code from subprocedures */
Btree *pBt; /* The main BTree structure */
int mxCellPerPage; /* Maximum number of cells per page */
u8 **apCell; /* All cells from pages being balanced */
int *szCell; /* Local size of all cells */
assert( pPage->pParent==0 );
assert( pPage->nCell==0 );
pBt = pPage->pBt;
mxCellPerPage = MX_CELL(pBt);
apCell = sqliteMallocRaw( mxCellPerPage*(sizeof(u8*)+sizeof(int)) );
if( apCell==0 ) return SQLITE_NOMEM;
szCell = (int*)&apCell[mxCellPerPage];
if( pPage->leaf ){
/* The table is completely empty */
TRACE(("BALANCE: empty table %d\n", pPage->pgno));
@ -3336,10 +3373,10 @@ static int balance_shallower(MemPage *pPage){
assert( pgnoChild>0 );
assert( pgnoChild<=sqlite3pager_pagecount(pPage->pBt->pPager) );
rc = getPage(pPage->pBt, pgnoChild, &pChild);
if( rc ) return rc;
if( rc ) goto end_shallow_balance;
if( pPage->pgno==1 ){
rc = initPage(pChild, pPage);
if( rc ) return rc;
if( rc ) goto end_shallow_balance;
assert( pChild->nOverflow==0 );
if( pChild->nFree>=100 ){
/* The child information will fit on the root page, so do the
@ -3371,7 +3408,9 @@ static int balance_shallower(MemPage *pPage){
reparentChildPages(pPage);
releasePage(pChild);
}
return SQLITE_OK;
end_shallow_balance:
sqliteFree(apCell);
return rc;
}
@ -3492,7 +3531,7 @@ int sqlite3BtreeInsert(
MemPage *pPage;
Btree *pBt = pCur->pBt;
unsigned char *oldCell;
unsigned char newCell[MX_CELL_SIZE];
unsigned char *newCell = 0;
if( pCur->status ){
return pCur->status; /* A rollback destroyed this cursor */
@ -3519,10 +3558,12 @@ int sqlite3BtreeInsert(
assert( pPage->isInit );
rc = sqlite3pager_write(pPage->aData);
if( rc ) return rc;
newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
if( newCell==0 ) return SQLITE_NOMEM;
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew);
if( rc ) return rc;
if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) );
assert( szNew<=sizeof(newCell) );
assert( szNew<=MX_CELL_SIZE(pBt) );
if( loc==0 && pCur->isValid ){
int szOld;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
@ -3532,7 +3573,7 @@ int sqlite3BtreeInsert(
}
szOld = cellSizePtr(pPage, oldCell);
rc = clearCell(pPage, oldCell);
if( rc ) return rc;
if( rc ) goto end_insert;
dropCell(pPage, pCur->idx, szOld);
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
@ -3546,6 +3587,8 @@ int sqlite3BtreeInsert(
/* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
/* fflush(stdout); */
moveToRoot(pCur);
end_insert:
sqliteFree(newCell);
return rc;
}
@ -3597,7 +3640,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
unsigned char *pNext;
int szNext;
int notUsed;
unsigned char tempCell[MX_CELL_SIZE];
unsigned char *tempCell;
assert( !pPage->leafData );
getTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, &notUsed);
@ -3614,10 +3657,13 @@ int sqlite3BtreeDelete(BtCursor *pCur){
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
pNext = findCell(leafCur.pPage, leafCur.idx);
szNext = cellSizePtr(leafCur.pPage, pNext);
assert( sizeof(tempCell)>=szNext+4 );
assert( MX_CELL_SIZE(pBt)>=szNext+4 );
tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
if( tempCell==0 ) return SQLITE_NOMEM;
insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell);
put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
rc = balance(pPage);
sqliteFree(tempCell);
if( rc ) return rc;
dropCell(leafCur.pPage, leafCur.idx, szNext);
rc = balance(leafCur.pPage);
@ -4013,7 +4059,18 @@ struct IntegrityCk {
/*
** Append a message to the error message string.
*/
static void checkAppendMsg(IntegrityCk *pCheck, char *zMsg1, char *zMsg2){
static void checkAppendMsg(
IntegrityCk *pCheck,
char *zMsg1,
const char *zFormat,
...
){
va_list ap;
char *zMsg2;
va_start(ap, zFormat);
zMsg2 = sqlite3VMPrintf(zFormat, ap);
va_end(ap);
if( zMsg1==0 ) zMsg1 = "";
if( pCheck->zErrMsg ){
char *zOld = pCheck->zErrMsg;
pCheck->zErrMsg = 0;
@ -4022,6 +4079,7 @@ static void checkAppendMsg(IntegrityCk *pCheck, char *zMsg1, char *zMsg2){
}else{
sqlite3SetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0);
}
sqliteFree(zMsg2);
}
/*
@ -4035,15 +4093,11 @@ static void checkAppendMsg(IntegrityCk *pCheck, char *zMsg1, char *zMsg2){
static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){
if( iPage==0 ) return 1;
if( iPage>pCheck->nPage || iPage<0 ){
char zBuf[100];
sprintf(zBuf, "invalid page number %d", iPage);
checkAppendMsg(pCheck, zContext, zBuf);
checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
return 1;
}
if( pCheck->anRef[iPage]==1 ){
char zBuf[100];
sprintf(zBuf, "2nd reference to page %d", iPage);
checkAppendMsg(pCheck, zContext, zBuf);
checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
return 1;
}
return (pCheck->anRef[iPage]++)>1;
@ -4063,26 +4117,24 @@ static void checkList(
int i;
int expected = N;
int iFirst = iPage;
char zMsg[100];
while( N-- > 0 ){
unsigned char *pOvfl;
if( iPage<1 ){
sprintf(zMsg, "%d of %d pages missing from overflow list starting at %d",
checkAppendMsg(pCheck, zContext,
"%d of %d pages missing from overflow list starting at %d",
N+1, expected, iFirst);
checkAppendMsg(pCheck, zContext, zMsg);
break;
}
if( checkRef(pCheck, iPage, zContext) ) break;
if( sqlite3pager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){
sprintf(zMsg, "failed to get page %d", iPage);
checkAppendMsg(pCheck, zContext, zMsg);
checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
break;
}
if( isFreeList ){
int n = get4byte(&pOvfl[4]);
if( n>pCheck->pBt->usableSize/4-8 ){
sprintf(zMsg, "freelist leaf count too big on page %d", iPage);
checkAppendMsg(pCheck, zContext, zMsg);
checkAppendMsg(pCheck, zContext,
"freelist leaf count too big on page %d", iPage);
N--;
}else{
for(i=0; i<n; i++){
@ -4132,9 +4184,8 @@ static int checkTreePage(
BtCursor cur;
Btree *pBt;
int maxLocal, usableSize;
char zMsg[100];
char zContext[100];
char hit[SQLITE_MAX_PAGE_SIZE];
char *hit;
/* Check that the page exists
*/
@ -4143,14 +4194,13 @@ static int checkTreePage(
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){
sprintf(zMsg, "unable to get the page. error code=%d", rc);
checkAppendMsg(pCheck, zContext, zMsg);
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
}
maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
if( (rc = initPage(pPage, pParent))!=0 ){
sprintf(zMsg, "initPage() returns error code %d", rc);
checkAppendMsg(pCheck, zContext, zMsg);
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
releasePage(pPage);
return 0;
}
@ -4197,36 +4247,40 @@ static int checkTreePage(
*/
data = pPage->aData;
hdr = pPage->hdrOffset;
memset(hit, 0, usableSize);
memset(hit, 1, get2byte(&data[hdr+5]));
nCell = get2byte(&data[hdr+3]);
cellStart = hdr + 12 - 4*pPage->leaf;
for(i=0; i<nCell; i++){
int pc = get2byte(&data[cellStart+i*2]);
int size = cellSizePtr(pPage, &data[pc]);
int j;
for(j=pc+size-1; j>=pc; j--) hit[j]++;
}
for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<usableSize && cnt<10000; cnt++){
int size = get2byte(&data[i+2]);
int j;
for(j=i+size-1; j>=i; j--) hit[j]++;
i = get2byte(&data[i]);
}
for(i=cnt=0; i<usableSize; i++){
if( hit[i]==0 ){
cnt++;
}else if( hit[i]>1 ){
sprintf(zMsg, "Multiple uses for byte %d of page %d", i, iPage);
checkAppendMsg(pCheck, zMsg, 0);
break;
hit = sqliteMalloc( usableSize );
if( hit ){
memset(hit, 1, get2byte(&data[hdr+5]));
nCell = get2byte(&data[hdr+3]);
cellStart = hdr + 12 - 4*pPage->leaf;
for(i=0; i<nCell; i++){
int pc = get2byte(&data[cellStart+i*2]);
int size = cellSizePtr(pPage, &data[pc]);
int j;
for(j=pc+size-1; j>=pc; j--) hit[j]++;
}
for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<usableSize && cnt<10000;
cnt++){
int size = get2byte(&data[i+2]);
int j;
for(j=i+size-1; j>=i; j--) hit[j]++;
i = get2byte(&data[i]);
}
for(i=cnt=0; i<usableSize; i++){
if( hit[i]==0 ){
cnt++;
}else if( hit[i]>1 ){
checkAppendMsg(pCheck, 0,
"Multiple uses for byte %d of page %d", i, iPage);
break;
}
}
if( cnt!=data[hdr+7] ){
checkAppendMsg(pCheck, 0,
"Fragmented space is %d byte reported as %d on page %d",
cnt, data[hdr+7], iPage);
}
}
if( cnt!=data[hdr+7] ){
sprintf(zMsg, "Fragmented space is %d byte reported as %d on page %d",
cnt, data[hdr+7], iPage);
checkAppendMsg(pCheck, zMsg, 0);
}
sqliteFree(hit);
releasePage(pPage);
return depth+1;
@ -4282,9 +4336,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
*/
for(i=1; i<=sCheck.nPage; i++){
if( sCheck.anRef[i]==0 ){
char zBuf[100];
sprintf(zBuf, "Page %d is never used", i);
checkAppendMsg(&sCheck, zBuf, 0);
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
}
}
@ -4292,12 +4344,10 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
*/
unlockBtreeIfUnused(pBt);
if( nRef != *sqlite3pager_stats(pBt->pPager) ){
char zBuf[100];
sprintf(zBuf,
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
nRef, *sqlite3pager_stats(pBt->pPager)
);
checkAppendMsg(&sCheck, zBuf, 0);
}
/* Clean up and report errors.

View File

@ -10,7 +10,7 @@
#***********************************************************************
# This file runs all tests.
#
# $Id: memleak.test,v 1.6 2004/08/01 03:52:18 drh Exp $
# $Id: memleak.test,v 1.7 2004/09/03 18:38:46 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -41,6 +41,7 @@ set EXCLUDE {
btree2.test
trans.test
crash.test
corrupt.test
}
if {[sqlite3 -has-codec]} {
# lappend EXCLUDE