From 457f501464475ccb24f5c377d305d8daa867b863 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 9 May 2004 01:35:05 +0000 Subject: [PATCH] Begin trying to get integrity checking working on the new btree.c. (CVS 1329) FossilOrigin-Name: 499569daa6a3aed6609bcb1e11a3d231e13f4f9c --- manifest | 14 +-- manifest.uuid | 2 +- src/btree.c | 283 ++++++++---------------------------------------- test/btree.test | 32 ++++-- 4 files changed, 81 insertions(+), 250 deletions(-) diff --git a/manifest b/manifest index 2a3b2909a4..639f6937b2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C All\stests\sin\sbtree.test\snow\spass\s(but\sonly\sbecause\sI\scommented\sout\sthe\nbtree_integrity_check\stest.)\s(CVS\s1328) -D 2004-05-09T00:40:52 +C Begin\strying\sto\sget\sintegrity\schecking\sworking\son\sthe\snew\sbtree.c.\s(CVS\s1329) +D 2004-05-09T01:35:06 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a F src/auth.c a2a46e3ed7799134cf3d2dd5ae6650115f26b653 -F src/btree.c 927ac9e162c4e97151ba27e0723babda761c58c0 +F src/btree.c 4c9b4a68f5e0c57382fca08d73426ca5af55c80f F src/btree.h 825034a68947baf99507f04f318f417013dcd3a3 F src/btree_rb.c 47e5b5ec90846af392b5668b34648198ba459561 F src/build.c 21b6645c966970dac51bcccfa8650403a3f56210 @@ -75,7 +75,7 @@ F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185 F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a -F test/btree.test faa386a7342b865a87f042db6bd5e5a9486259d6 +F test/btree.test c4399a76bcc6d2c84b156e3a8fef29879d2e54c4 F test/btree2.test 2ff77e0218e5f55ff5a85874f3e15c7859e3ac26 F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665 F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac @@ -190,7 +190,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P e9f84ff3fe45a014ab60fabbfd91d19e6d353477 -R 0b200f4f3f4df21ad25f92660d903a27 +P ee706e9c74c3fb32fc3369db226fad9ed4db7596 +R cfbf2d289e390333f8744d3cd9325bcf U drh -Z 2b1cbf8bcd73f8c7eab6d96289461ca5 +Z d0e25b8c23267f444288dc2922ce4fd0 diff --git a/manifest.uuid b/manifest.uuid index b2098afa3d..675091aec8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ee706e9c74c3fb32fc3369db226fad9ed4db7596 \ No newline at end of file +499569daa6a3aed6609bcb1e11a3d231e13f4f9c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index f19aa20052..c79a6b3d9d 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.117 2004/05/09 00:40:52 drh Exp $ +** $Id: btree.c,v 1.118 2004/05/09 01:35:06 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -218,7 +218,6 @@ struct MemPage { u8 leaf; /* True if leaf flag is set */ u8 zeroData; /* True if zero data flag is set */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ - u8 needRelink; /* True if need to run relinkCellList() */ int idxParent; /* Index in pParent->aCell[] of this node */ int nFree; /* Number of free bytes on the page */ int nCell; /* Number of entries on this page */ @@ -378,78 +377,6 @@ static int cellSize(MemPage *pPage, unsigned char *pCell){ return n + nPayload; } -/* -** Do sanity checking on a page. Throw an exception if anything is -** not right. -** -** This routine is used for internal error checking only. It is omitted -** from most builds. -*/ -#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0 -static void _pageIntegrity(MemPage *pPage){ - int pageSize; - u8 *data; - int i, idx, c, pc, hdr, nFree; - u8 used[MX_PAGE_SIZE]; - - pageSize = pPage->pBt->pageSize; - assert( pPage->aData==&((unsigned char*)pPage)[-pageSize] ); - hdr = pPage->hdrOffset; - assert( hdr==(pPage->pgno==1 ? 100 : 0) ); - assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); - c = pPage->aData[hdr]; - if( pPage->isInit ){ - assert( pPage->leaf == ((c & PTF_LEAF)!=0) ); - assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) ); - assert( pPage->intKey == ((c & PTF_INTKEY)!=0) ); - } - data = pPage->aData; - memset(used, 0, pageSize); - for(i=0; ileaf*4; i++) used[i] = 1; - nFree = 0; - pc = get2byte(&data[hdr+1]); - while( pc ){ - int size; - assert( pc>0 && pcisInit==0 || pPage->nFree==nFree+data[hdr+5] ); - idx = 0; - pc = get2byte(&data[hdr+3]); - while( pc ){ - int size; - assert( pPage->isInit==0 || idxnCell ); - assert( pc>0 && pcisInit==0 || pPage->aCell[idx]==&data[pc] ); - size = cellSize(pPage, &data[pc]); - assert( pc+size<=pageSize ); - for(i=pc; inCell ); - nFree = 0; - for(i=0; iaData) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->pageSize <= MX_PAGE_SIZE ); - assert( !pPage->needRelink ); - assert( !pPage->isOverfull ); oldPage = pPage->aData; hdr = pPage->hdrOffset; addr = 3+hdr; @@ -483,10 +408,9 @@ static void defragmentPage(MemPage *pPage){ size = cellSize(pPage, &oldPage[pc]); memcpy(&newPage[n], &oldPage[pc], size); put2byte(&newPage[addr],n); - assert( pPage->aCell[i]==&oldPage[pc] ); pPage->aCell[i++] = &oldPage[n]; - addr = n; n += size; + addr = pc; pc = get2byte(&oldPage[pc]); } assert( i==pPage->nCell ); @@ -675,12 +599,13 @@ static int initPage( assert( pParent==0 || pParent->pBt==pPage->pBt ); assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); assert( pPage->aData == &((unsigned char*)pPage)[-pPage->pBt->pageSize] ); - assert( pPage->pParent==0 || pPage->pParent==pParent ); - if( pPage->pParent==0 && pParent!=0 ){ - pPage->pParent = pParent; + assert( pPage->isInit==0 || pPage->pParent==pParent ); + if( pPage->isInit ) return SQLITE_OK; + assert( pPage->pParent==0 ); + pPage->pParent = pParent; + if( pParent ){ sqlite3pager_ref(pParent->aData); } - if( pPage->isInit ) return SQLITE_OK; pPage->nCell = pPage->nCellAlloc = 0; assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); hdr = pPage->hdrOffset; @@ -690,7 +615,6 @@ static int initPage( pPage->zeroData = (c & PTF_ZERODATA)!=0; pPage->leaf = (c & PTF_LEAF)!=0; pPage->isOverfull = 0; - pPage->needRelink = 0; pPage->idxShift = 0; pageSize = pPage->pBt->pageSize; @@ -733,7 +657,6 @@ static int initPage( } pPage->isInit = 1; - pageIntegrity(pPage); return SQLITE_OK; } @@ -747,8 +670,6 @@ static void zeroPage(MemPage *pPage, int flags){ int hdr = pPage->hdrOffset; int first; - assert( sqlite3pager_pagenumber(data)==pPage->pgno ); - assert( &data[pBt->pageSize] == (unsigned char*)pPage ); assert( sqlite3pager_iswriteable(data) ); memset(&data[hdr], 0, pBt->pageSize - hdr); data[hdr] = flags; @@ -764,11 +685,6 @@ static void zeroPage(MemPage *pPage, int flags){ pPage->leaf = (flags & PTF_LEAF)!=0; pPage->zeroData = (flags & PTF_ZERODATA)!=0; pPage->hdrOffset = hdr; - pPage->isOverfull = 0; - pPage->needRelink = 0; - pPage->idxShift = 0; - pPage->isInit = 1; - pageIntegrity(pPage); } /* @@ -829,7 +745,6 @@ static void releasePage(MemPage *pPage){ */ static void pageDestructor(void *pData){ MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE]; - assert( pPage->isInit==0 || pPage->needRelink==0 ); if( pPage->pParent ){ MemPage *pParent = pPage->pParent; pPage->pParent = 0; @@ -1081,8 +996,7 @@ static void invalidateCursors(Btree *pBt){ BtCursor *pCur; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; - if( pPage /* && !pPage->isInit */ ){ - pageIntegrity(pPage); + if( pPage && !pPage->isInit ){ releasePage(pPage); pCur->pPage = 0; pCur->isValid = 0; @@ -1091,24 +1005,6 @@ static void invalidateCursors(Btree *pBt){ } } -#ifdef SQLITE_TEST -/* -** Print debugging information about all cursors to standard output. -*/ -void sqlite3BtreeCursorList(Btree *pBt){ - BtCursor *pCur; - for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - MemPage *pPage = pCur->pPage; - char *zMode = pCur->wrFlag ? "rw" : "ro"; - printf("CURSOR %08x rooted at %4d(%s) currently at %d.%d%s\n", - (int)pCur, pCur->pgnoRoot, zMode, - pPage ? pPage->pgno : 0, pCur->idx, - pCur->isValid ? "" : " eof" - ); - } -} -#endif - /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor @@ -1371,7 +1267,6 @@ int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){ *pSize = 0; }else{ pPage = pCur->pPage; - pageIntegrity(pPage); assert( pPage!=0 ); assert( pCur->idx>=0 && pCur->idxnCell ); cell = pPage->aCell[pCur->idx]; @@ -1414,7 +1309,6 @@ static int getPayload( assert( pCur->isValid ); pBt = pCur->pBt; pPage = pCur->pPage; - pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); aPayload = pPage->aCell[pCur->idx]; aPayload += 2; /* Skip the next cell index */ @@ -1537,7 +1431,6 @@ void *sqlite3BtreeKeyFetch(BtCursor *pCur){ assert( pCur->idx>=0 && pCur->idxpPage->nCell ); pBt = pCur->pBt; pPage = pCur->pPage; - pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); assert( pPage->intKey==0 ); aPayload = pPage->aCell[pCur->idx]; @@ -1574,7 +1467,6 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ pPage = pCur->pPage; assert( pPage!=0 ); assert( pPage->isInit ); - pageIntegrity(pPage); if( pPage->zeroData ){ *pSize = 0; }else{ @@ -1624,7 +1516,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ assert( pCur->isValid ); rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); if( rc ) return rc; - pageIntegrity(pNewPage); pNewPage->idxParent = pCur->idx; pOldPage = pCur->pPage; pOldPage->idxShift = 0; @@ -1648,9 +1539,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ */ static int isRootPage(MemPage *pPage){ MemPage *pParent = pPage->pParent; - if( pParent==0 ) return 1; - if( pParent->pgno>1 ) return 0; - if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1; + assert( pParent==0 || pParent->isInit ); + if( pParent==0 || (pParent->pgno==1 && pParent->nCell==0) ) return 1; return 0; } @@ -1672,10 +1562,8 @@ static void moveToParent(BtCursor *pCur){ pPage = pCur->pPage; assert( pPage!=0 ); assert( !isRootPage(pPage) ); - pageIntegrity(pPage); pParent = pPage->pParent; assert( pParent!=0 ); - pageIntegrity(pParent); idxParent = pPage->idxParent; sqlite3pager_ref(pParent->aData); oldPgno = pPage->pgno; @@ -1725,7 +1613,6 @@ static int moveToRoot(BtCursor *pCur){ return rc; } releasePage(pCur->pPage); - pageIntegrity(pRoot); pCur->pPage = pRoot; pCur->idx = 0; if( pRoot->nCell==0 && !pRoot->leaf ){ @@ -1874,7 +1761,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){ int c = -1; /* pRes return if table is empty must be -1 */ lwr = 0; upr = pPage->nCell-1; - pageIntegrity(pPage); while( lwr<=upr ){ void *pCellKey; u64 nCellKey; @@ -2309,16 +2195,14 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){ if( pgno==0 ) return; assert( pBt->pPager!=0 ); aData = sqlite3pager_lookup(pBt->pPager, pgno); - if( aData ){ - pThis = (MemPage*)&aData[pBt->pageSize]; - if( pThis->isInit ){ - if( pThis->pParent!=pNewParent ){ - if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData); - pThis->pParent = pNewParent; - if( pNewParent ) sqlite3pager_ref(pNewParent->aData); - } - pThis->idxParent = idx; + pThis = (MemPage*)&aData[pBt->pageSize]; + if( pThis && pThis->isInit ){ + if( pThis->pParent!=pNewParent ){ + if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData); + pThis->pParent = pNewParent; + if( pNewParent ) sqlite3pager_ref(pNewParent->aData); } + pThis->idxParent = idx; sqlite3pager_unref(aData); } } @@ -2354,45 +2238,25 @@ static void reparentChildPages(MemPage *pPage){ ** ** "sz" must be the number of bytes in the cell. ** -** Try to maintain the integrity of the linked list of cells. But if -** the cell being inserted does not fit on the page, this will not be -** possible. If the linked list is not maintained, then just update -** pPage->aCell[] and set the pPage->needRelink flag so that we will -** know to rebuild the linked list later. +** Do not bother maintaining the integrity of the linked list of Cells. +** Only the pPage->aCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. */ static void dropCell(MemPage *pPage, int idx, int sz){ int j, pc; - u8 *data; assert( idx>=0 && idxnCell ); assert( sz==cellSize(pPage, pPage->aCell[idx]) ); assert( sqlite3pager_iswriteable(pPage->aData) ); assert( pPage->aCell[idx]>=pPage->aData ); assert( pPage->aCell[idx]<&pPage->aData[pPage->pBt->pageSize-sz] ); - data = pPage->aData; - pc = Addr(pPage->aCell[idx]) - Addr(data); + pc = Addr(pPage->aCell[idx]) - Addr(pPage->aData); assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->pageSize ); freeSpace(pPage, pc, sz); for(j=idx; jnCell-1; j++){ pPage->aCell[j] = pPage->aCell[j+1]; } pPage->nCell--; - if( !pPage->isOverfull && !pPage->needRelink ){ - u8 *pPrev; - if( idx==0 ){ - pPrev = &data[pPage->hdrOffset+3]; - }else{ - pPrev = pPage->aCell[idx-1]; - } - if( idxnCell ){ - pc = Addr(pPage->aCell[idx]) - Addr(data); - }else{ - pc = 0; - } - put2byte(pPrev, pc); - pageIntegrity(pPage); - }else{ - pPage->needRelink = 1; - } pPage->idxShift = 1; } @@ -2404,18 +2268,17 @@ static void dropCell(MemPage *pPage, int idx, int sz){ ** will not fit, then just make pPage->aCell[i] point to the content ** and set pPage->isOverfull. ** -** Try to maintain the integrity of the linked list of cells. But if -** the cell being inserted does not fit on the page, this will not be -** possible. If the linked list is not maintained, then just update -** pPage->aCell[] and set the pPage->needRelink flag so that we will -** know to rebuild the linked list later. +** Do not bother maintaining the integrity of the linked list of Cells. +** Only the pPage->aCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. */ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){ int idx, j; assert( i>=0 && i<=pPage->nCell ); assert( sz==cellSize(pPage, pCell) ); assert( sqlite3pager_iswriteable(pPage->aData) ); - idx = pPage->needRelink ? 0 : allocateSpace(pPage, sz); + idx = allocateSpace(pPage, sz); resizeCellArray(pPage, pPage->nCell+1); for(j=pPage->nCell; j>i; j--){ pPage->aCell[j] = pPage->aCell[j-1]; @@ -2425,24 +2288,8 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){ pPage->isOverfull = 1; pPage->aCell[i] = pCell; }else{ - u8 *data = pPage->aData; - memcpy(&data[idx], pCell, sz); - pPage->aCell[i] = &data[idx]; - } - if( !pPage->isOverfull && !pPage->needRelink ){ - u8 *pPrev; - int pc; - if( i==0 ){ - pPrev = &pPage->aData[pPage->hdrOffset+3]; - }else{ - pPrev = pPage->aCell[i-1]; - } - pc = get2byte(pPrev); - put2byte(pPrev, idx); - put2byte(pPage->aCell[i], pc); - pageIntegrity(pPage); - }else{ - pPage->needRelink = 1; + memcpy(&pPage->aData[idx], pCell, sz); + pPage->aCell[i] = &pPage->aData[idx]; } pPage->idxShift = 1; } @@ -2456,7 +2303,6 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){ static void relinkCellList(MemPage *pPage){ int i, idxFrom; assert( sqlite3pager_iswriteable(pPage->aData) ); - if( !pPage->needRelink ) return; idxFrom = pPage->hdrOffset+3; for(i=0; inCell; i++){ int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData); @@ -2465,7 +2311,6 @@ static void relinkCellList(MemPage *pPage){ idxFrom = idx; } put2byte(&pPage->aData[idxFrom], 0); - pPage->needRelink = 0; } /* @@ -2484,7 +2329,7 @@ static void relinkCellList(MemPage *pPage){ ** ** Over this operation completes, the meta data for pFrom is zeroed. */ -static void movePage(MemPage *pTo, MemPage *pFrom){ +static void copyPage(MemPage *pTo, MemPage *pFrom){ uptr from, to; int i; int pageSize; @@ -2511,15 +2356,6 @@ static void movePage(MemPage *pTo, MemPage *pFrom){ } } -/* -** For debugging... -*/ -#if 1 -# define TRACE(X) if( pager3_refinfo_enable ) printf X -#else -# define TRACE(X) -#endif - /* ** The following parameters determine how many adjacent pages get involved ** in a balancing operation. NN is the number of neighbors on either side @@ -2585,7 +2421,6 @@ static int balance(MemPage *pPage){ int usableSpace; /* Bytes in pPage beyond the header */ int pageFlags; /* Value of pPage->aData[0] */ int subtotal; /* Subtotal of bytes in cells on one page */ - MemPage *extraUnref = 0; /* Unref this page if not zero */ 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 */ @@ -2616,7 +2451,6 @@ static int balance(MemPage *pPage){ ** it means this page is the root page and special rules apply. */ pParent = pPage->pParent; - TRACE(("BALANCE: begin page %d\n", pPage->pgno)); if( pParent==0 ){ Pgno pgnoChild; MemPage *pChild; @@ -2625,7 +2459,6 @@ static int balance(MemPage *pPage){ if( pPage->leaf ){ /* The table is completely empty */ relinkCellList(pPage); - TRACE(("BALANCE: empty table\n")); }else{ /* The root page is empty but has one child. Transfer the ** information from that one child into the root page if it @@ -2656,11 +2489,9 @@ static int balance(MemPage *pPage){ cellSize(pChild, pChild->aCell[i])); } freePage(pChild); - TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno)); }else{ /* The child has more information that will fit on the root. ** The tree is already balanced. Do nothing. */ - TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); } }else{ memcpy(pPage, pChild, pBt->pageSize); @@ -2669,7 +2500,6 @@ static int balance(MemPage *pPage){ rc = initPage(pPage, 0); assert( rc==SQLITE_OK ); freePage(pChild); - TRACE(("BALANCE: transfer child %d into root\n", pChild->pgno)); } reparentChildPages(pPage); releasePage(pChild); @@ -2680,7 +2510,6 @@ static int balance(MemPage *pPage){ /* It is OK for the root page to be less than half full. */ relinkCellList(pPage); - TRACE(("BALANCE: Root page is underfull but that is ok\n")); return SQLITE_OK; } /* @@ -2694,18 +2523,17 @@ static int balance(MemPage *pPage){ rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno); if( rc ) return rc; assert( sqlite3pager_iswriteable(pChild->aData) ); - movePage(pChild, pPage); + copyPage(pChild, pPage); assert( pChild->aData[0]==pPage->aData[pPage->hdrOffset] ); pChild->pParent = pPage; - sqlite3pager_ref(pPage->aData); pChild->idxParent = 0; + sqlite3pager_ref(pPage->aData); pChild->isOverfull = 1; zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); put4byte(&pPage->aData[pPage->hdrOffset+6], pChild->pgno); pParent = pPage; pPage = pChild; - extraUnref = pChild; - TRACE(("BALANCE: Copy root into %d and blance\n", pPage->pgno)); + initPage(pParent, 0); } rc = sqlite3pager_write(pParent->aData); if( rc ) return rc; @@ -2782,9 +2610,7 @@ static int balance(MemPage *pPage){ for(i=0; iaData = &((u8*)p)[-pBt->pageSize]; - p->aCell = 0; - p->hdrOffset = 0; - movePage(p, apOld[i]); + copyPage(p, apOld[i]); } /* @@ -2809,12 +2635,11 @@ static int balance(MemPage *pPage){ nCell++; } if( ileaf ){ assert( leafCorrection==0 ); /* The right pointer of the child page pOld becomes the left @@ -2866,19 +2691,18 @@ static int balance(MemPage *pPage){ assert( pPage->pgno>1 ); pageFlags = pPage->aData[0]; for(i=0; iaData); + sqlite3pager_write(apNew[i]->aData); }else{ - rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1]); + rc = allocatePage(pBt, &apNew[i], &pgnoNew[i], pgnoNew[i-1]); if( rc ) goto balance_cleanup; - apNew[i] = pNew; } nNew++; - zeroPage(pNew, pageFlags); + zeroPage(apNew[i], pageFlags); + apNew[i]->isInit = 1; } /* Free any old pages that were not reused as new pages. @@ -2886,7 +2710,7 @@ static int balance(MemPage *pPage){ while( iaData); apOld[i] = 0; i++; } @@ -2980,11 +2804,7 @@ static int balance(MemPage *pPage){ /* ** balance the parent page. */ - assert( pPage->isInit ); - assert( pParent->isInit ); - pageIntegrity(pPage); rc = balance(pParent); - /* ** Cleanup before returning. @@ -2993,6 +2813,7 @@ balance_cleanup: for(i=0; ipParent); sqliteFree(apCopy[i]->aCell); } } @@ -3000,8 +2821,6 @@ balance_cleanup: releasePage(apNew[i]); } releasePage(pParent); - releasePage(extraUnref); - TRACE(("BALANCE: Finished with %d\n", pPage->pgno)); return rc; } @@ -3153,7 +2972,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){ unsigned char *pNext; int szNext; int notUsed; - unsigned char tempbuf[4]; getTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc!=SQLITE_OK ){ @@ -3165,12 +2983,10 @@ int sqlite3BtreeDelete(BtCursor *pCur){ dropCell(pPage, pCur->idx, cellSize(pPage, pCell)); pNext = leafCur.pPage->aCell[leafCur.idx]; szNext = cellSize(leafCur.pPage, pNext); - memcpy(tempbuf, &pNext[-2], 4); - put4byte(&pNext[-2], pgnoChild); insertCell(pPage, pCur->idx, &pNext[-4], szNext+4); + put4byte(&pNext[-2], pgnoChild); rc = balance(pPage); if( rc ) return rc; - memcpy(&pNext[-2], tempbuf, 4); dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(leafCur.pPage); releaseTempCursor(&leafCur); @@ -3374,9 +3190,8 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ pPage->intKey = (c & PTF_INTKEY)!=0; pPage->zeroData = (c & PTF_ZERODATA)!=0; pPage->leaf = (c & PTF_LEAF)!=0; - printf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno, - data[hdr], data[hdr+5], - (pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0); + printf("PAGE %d: flags=0x%02x frag=%d\n", pgno, + data[hdr], data[hdr+5]); i = 0; assert( hdr == (pgno==1 ? 100 : 0) ); idx = get2byte(&data[hdr+3]); @@ -3472,11 +3287,9 @@ int sqlite3BtreeFlags(BtCursor *pCur){ ** ** This routine is used for testing and debugging only. */ -int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult){ +int sqlite3BtreeCursorDump(BtCursor *pCur, int *aResult){ int cnt, idx; MemPage *pPage = pCur->pPage; - - pageIntegrity(pPage); assert( pPage->isInit ); aResult[0] = sqlite3pager_pagenumber(pPage->aData); assert( aResult[0]==pPage->pgno ); diff --git a/test/btree.test b/test/btree.test index 16505dbd43..184602073d 100644 --- a/test/btree.test +++ b/test/btree.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree.test,v 1.21 2004/05/09 00:40:52 drh Exp $ +# $Id: btree.test,v 1.22 2004/05/09 01:35:06 drh Exp $ set testdir [file dirname $argv0] @@ -616,7 +616,6 @@ do_test btree-7.15 { # Check to see that data on overflow pages work correctly. # -#btree_page_dump $::b1 1 do_test btree-8.1 { set data "*** This is a very long key " while {[string length $data]<1234} {append data $data} @@ -641,6 +640,9 @@ do_test btree-8.4 { do_test btree-8.4.1 { lindex [btree_get_meta $::b1] 0 } [expr {int(([string length $::data]-238+1019)/1020)}] +do_test btree-8.4.2 { + btree_integrity_check $::b1 1 2 +} {} do_test btree-8.5 { set data "*** This is an even longer key " while {[string length $data]<2000} {append data $data} @@ -731,16 +733,25 @@ do_test btree-8.21 { do_test btree-8.22 { lindex [btree_pager_stats $::b1] 1 } {2} -do_test btree-8.23 { +do_test btree-8.23.1 { btree_close_cursor $::c1 btree_drop_table $::b1 2 + btree_integrity_check $::b1 1 +} {} +do_test btree-8.23.2 { + btree_create_table $::b1 0 +} {2} +do_test btree_8.23.3 { set ::c1 [btree_cursor $::b1 2 1] lindex [btree_get_meta $::b1] 0 -} {5} +} {4} do_test btree-8.24 { lindex [btree_pager_stats $::b1] 1 } {2} #btree_pager_ref_dump $::b1 +do_test btree-8.25 { + btree_integrity_check $::b1 1 2 +} {} # Check page splitting logic # @@ -807,10 +818,15 @@ do_test btree-9.6 { btree_close_cursor $::c1 lindex [btree_pager_stats $::b1] 1 } {1} +puts "222: [btree_integrity_check $::b1 1 2]" + do_test btree-9.7 { btree_rollback $::b1 lindex [btree_pager_stats $::b1] 1 } {0} +do_test btree-9.8 { + btree_integrity_check $::b1 1 2 +} {} # Create a tree of depth two. That is, there is a single divider entry # on the root pages and two leaf pages. Then delete the divider entry @@ -963,9 +979,11 @@ do_test btree-12.12 { btree_next $::c1 btree_key $::c1 } {402} -#do_test btree-13.1 { -# btree_integrity_check $::b1 1 2 -#} {} +btree_commit $::b1 +btree_tree_dump $::b1 1 +do_test btree-13.1 { + btree_integrity_check $::b1 1 2 +} {} # To Do: #