diff --git a/manifest b/manifest index 6bf9b7ae46..5297a725c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sfirst\stest\sfile\sfor\sBTree\sadded.\sSimple\sinsert\sand\sdelete\stests\spass.\nThere\sis\sstill\sa\slot\sof\swork\sto\sbe\sdone,\sthough.\s(CVS\s228) -D 2001-06-24T20:39:41 +C More\stests\sand\sbug\sfixes\sin\sbtree.c\s(CVS\s229) +D 2001-06-25T02:11:07 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in 65862a30703b070209b5f5e565d75cc870962b3c F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 @@ -12,8 +12,8 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464 F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 -F src/btree.c e46ab610d0bef3d1a9f698bede21d554c42763e5 -F src/btree.h 40ae2c9b6d2ba8feb03461a589ccab9afc04ec29 +F src/btree.c 977621ad8c0607c13e4f404284ae1fb28adf542f +F src/btree.h 2ce445f0b733e0d077377cbb49c12316e7ce524d F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651 F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8 @@ -45,7 +45,7 @@ F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6 F src/tclsqlite.c af29a45cb4c2244a6fd032568a22d26516472b2c F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4 F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a -F src/test3.c 405ea28287faeefc108ca362eca527731421e6bb +F src/test3.c a66bb93c540d53d1026b0d183faca928d6c82ba0 F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6 F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc @@ -53,7 +53,7 @@ F src/vdbe.c f93be4414ba892df9c5589815d2a57c1fb12c820 F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437 F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048 -F test/btree.test 8db61fdd957e906d7d237bf0f578f3e8cc9fb33e +F test/btree.test 9207999792e0a784821fdfa1287311e3f22ff4b0 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf @@ -108,7 +108,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P f4df6664037c68e1ce539c84c852124d95cd5a56 -R 3068b07f88f8e6db3749d5669bb8ecc6 +P 85f015c9750a5eab274e82f0e2c6e8f09dc7ca70 +R 3996a4b0538db0f013a966fe30254459 U drh -Z ee5edd13b8c55ec829c3087fe59854aa +Z 373fed59edcfc36190ad26edeac1578b diff --git a/manifest.uuid b/manifest.uuid index 55e4356685..eb975e72a0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85f015c9750a5eab274e82f0e2c6e8f09dc7ca70 \ No newline at end of file +6b9b298b2846146b95d7df7f423867976bafa390 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index b4666da409..d1761c5fba 100644 --- a/src/btree.c +++ b/src/btree.c @@ -21,7 +21,7 @@ ** http://www.hwaci.com/drh/ ** ************************************************************************* -** $Id: btree.c,v 1.14 2001/06/24 20:39:41 drh Exp $ +** $Id: btree.c,v 1.15 2001/06/25 02:11:07 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -141,7 +141,8 @@ struct PageOne { char zMagic[MAGIC_SIZE]; /* String that identifies the file as a database */ int iMagic; /* Integer to verify correct byte order */ Pgno freeList; /* First free page in a list of all free pages */ - int aMeta[SQLITE_N_BTREE_META]; /* User defined integers */ + int nFree; /* Number of pages on the free list */ + int aMeta[SQLITE_N_BTREE_META-1]; /* User defined integers */ }; /* @@ -205,7 +206,7 @@ struct CellHdr { ** This number is chosen so that at least 4 cells will fit on every page. */ #define MX_LOCAL_PAYLOAD \ - ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/4-(sizeof(CellHdr)+sizeof(Pgno))) + (((SQLITE_PAGE_SIZE-sizeof(PageHdr))/4-(sizeof(CellHdr)+sizeof(Pgno)))&~3) /* ** Data on a database page is stored as a linked list of Cell structures. @@ -364,7 +365,7 @@ static void defragmentPage(MemPage *pPage){ pPage->u.hdr.firstCell = pc; memcpy(newPage, pPage->u.aDisk, pc); for(i=0; inCell; i++){ - Cell *pCell = (Cell*)&pPage->apCell[i]; + Cell *pCell = pPage->apCell[i]; /* This routine should never be called on an overfull page. The ** following asserts verify that constraint. */ @@ -372,13 +373,16 @@ static void defragmentPage(MemPage *pPage){ assert( Addr(pCell) < Addr(pPage) + SQLITE_PAGE_SIZE ); n = cellSize(pCell); - pCell->h.iNext = inCell-1 ? pc + n : 0; + pCell->h.iNext = pc + n; memcpy(&newPage[pc], pCell, n); pPage->apCell[i] = (Cell*)&pPage->u.aDisk[pc]; pc += n; } assert( pPage->nFree==SQLITE_PAGE_SIZE-pc ); memcpy(pPage->u.aDisk, newPage, pc); + if( pPage->nCell>0 ){ + pPage->apCell[pPage->nCell-1]->h.iNext = 0; + } pFBlk = (FreeBlk*)&pPage->u.aDisk[pc]; pFBlk->iSize = SQLITE_PAGE_SIZE - pc; pFBlk->iNext = 0; @@ -729,12 +733,11 @@ static void unlockBtree(Btree *pBt){ } /* -** Commit the transaction currently in progress. All cursors -** must be closed before this routine is called. +** Commit the transaction currently in progress. */ int sqliteBtreeCommit(Btree *pBt){ int rc; - if( pBt->pCursor!=0 || pBt->inTrans==0 ) return SQLITE_ERROR; + if( pBt->inTrans==0 ) return SQLITE_ERROR; rc = sqlitepager_commit(pBt->pPager); pBt->inTrans = 0; unlockBtree(pBt); @@ -890,7 +893,7 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ if( a==amt ){ return SQLITE_OK; } - offset += a; + offset = 0; zBuf += a; amt -= a; } @@ -910,10 +913,12 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ a = OVERFLOW_SIZE - offset; } memcpy(zBuf, &pOvfl->aPayload[offset], a); + offset = 0; amt -= a; zBuf += a; + }else{ + offset -= OVERFLOW_SIZE; } - offset -= OVERFLOW_SIZE; sqlitepager_unref(pOvfl); } return amt==0 ? SQLITE_OK : SQLITE_CORRUPT; @@ -1267,9 +1272,10 @@ static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno){ return rc; } pPage1->freeList = pOvfl->iNext; + pPage1->nFree--; *ppPage = (MemPage*)pOvfl; }else{ - *pPgno = sqlitepager_pagecount(pBt->pPager); + *pPgno = sqlitepager_pagecount(pBt->pPager) + 1; rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); if( rc ) return rc; rc = sqlitepager_write(*ppPage); @@ -1294,6 +1300,7 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){ assert( pOvfl!=0 ); pgno = sqlitepager_pagenumber(pOvfl); } + assert( pgno>2 ); rc = sqlitepager_write(pPage1); if( rc ){ return rc; @@ -1311,6 +1318,7 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){ } pOvfl->iNext = pPage1->freeList; pPage1->freeList = pgno; + pPage1->nFree++; memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); ((MemPage*)pPage)->isInit = 0; assert( ((MemPage*)pPage)->pParent==0 ); @@ -1340,7 +1348,6 @@ static int clearCell(Btree *pBt, Cell *pCell){ rc = freePage(pBt, pOvfl, ovfl); if( rc ) return rc; ovfl = nextOvfl; - sqlitepager_unref(pOvfl); } return SQLITE_OK; } @@ -1477,11 +1484,11 @@ static void insertCell(MemPage *pPage, int i, Cell *pCell, int sz){ int idx, j; assert( i>=0 && i<=pPage->nCell ); assert( sz==cellSize(pCell) ); + idx = allocateSpace(pPage, sz); for(j=pPage->nCell; j>i; j--){ pPage->apCell[j] = pPage->apCell[j-1]; } pPage->nCell++; - idx = allocateSpace(pPage, sz); if( idx<=0 ){ pPage->isOverfull = 1; pPage->apCell[i] = pCell; @@ -2002,7 +2009,7 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){ ** Erase the given database page and all its children. Return ** the page to the freelist. */ -static int clearDatabasePage(Btree *pBt, Pgno pgno){ +static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){ MemPage *pPage; int rc; Cell *pCell; @@ -2015,15 +2022,22 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno){ pCell = (Cell*)&pPage->u.aDisk[idx]; idx = pCell->h.iNext; if( pCell->h.leftChild ){ - rc = clearDatabasePage(pBt, pCell->h.leftChild); + rc = clearDatabasePage(pBt, pCell->h.leftChild, 1); if( rc ) return rc; } rc = clearCell(pBt, pCell); if( rc ) return rc; } - rc = clearDatabasePage(pBt, pPage->u.hdr.rightChild); - if( rc ) return rc; - return freePage(pBt, pPage, pgno); + if( pPage->u.hdr.rightChild ){ + rc = clearDatabasePage(pBt, pPage->u.hdr.rightChild, 1); + if( rc ) return rc; + } + if( freePageFlag ){ + rc = freePage(pBt, pPage, pgno); + }else{ + zeroPage(pPage); + } + return rc; } /* @@ -2034,7 +2048,7 @@ int sqliteBtreeClearTable(Btree *pBt, int iTable){ if( !pBt->inTrans ){ return SQLITE_ERROR; /* Must start a transaction first */ } - rc = clearDatabasePage(pBt, (Pgno)iTable); + rc = clearDatabasePage(pBt, (Pgno)iTable, 0); if( rc ){ sqliteBtreeRollback(pBt); } @@ -2053,13 +2067,15 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){ return SQLITE_ERROR; /* Must start a transaction first */ } rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage); - if( rc==SQLITE_OK ){ - rc = sqliteBtreeClearTable(pBt, iTable); + if( rc ) return rc; + rc = sqliteBtreeClearTable(pBt, iTable); + if( rc ) return rc; + if( iTable>2 ){ + rc = freePage(pBt, pPage, iTable); + }else{ + zeroPage(pPage); + sqlitepager_unref(pPage); } - if( rc==SQLITE_OK && iTable!=2 ){ - rc = freePage(pBt, pPage, (Pgno)iTable); - } - sqlitepager_unref(pPage); return rc; } @@ -2072,7 +2088,8 @@ int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){ rc = sqlitepager_get(pBt->pPager, 1, (void**)&pP1); if( rc ) return rc; - memcpy(aMeta, pP1->aMeta, sizeof(pP1->aMeta)); + aMeta[0] = pP1->nFree; + memcpy(&aMeta[1], pP1->aMeta, sizeof(pP1->aMeta)); sqlitepager_unref(pP1); return SQLITE_OK; } @@ -2088,8 +2105,8 @@ int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){ } pP1 = pBt->page1; rc = sqlitepager_write(pP1); - if( rc ) return rc; - memcpy(pP1->aMeta, aMeta, sizeof(pP1->aMeta)); + if( rc ) return rc; + memcpy(pP1->aMeta, &aMeta[1], sizeof(pP1->aMeta)); return SQLITE_OK; } @@ -2116,6 +2133,7 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){ Cell *pCell = (Cell*)&pPage->u.aDisk[idx]; int sz = cellSize(pCell); sprintf(range,"%d..%d", idx, idx+sz-1); + sz = pCell->h.nKey + pCell->h.nData; if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1; memcpy(payload, pCell->aPayload, sz); for(j=0; jh.leftChild, pCell->h.nKey, pCell->h.nData, - pCell->aPayload + payload ); + if( pPage->apCell[i]!=pCell ){ + printf("**** apCell[%d] does not match on prior entry ****\n", i); + } i++; idx = pCell->h.iNext; } @@ -2144,6 +2165,7 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){ printf("freeblock %2d: i=%-10s size=%-4d total=%d\n", i, range, p->iSize, nFree); idx = p->iNext; + i++; } if( idx!=0 ){ printf("ERROR: next freeblock index out of range: %d\n", idx); @@ -2155,12 +2177,40 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){ #ifdef SQLITE_TEST /* -** Put the page number and index of a cursor into aResult[0] and aResult[1] -** This routine is used for debugging and testing only. +** Fill aResult[] with information about the entry and page that the +** cursor is pointing to. +** +** aResult[0] = The page number +** aResult[1] = The entry number +** aResult[2] = Total number of entries on this page +** aResult[3] = Size of this entry +** aResult[4] = Number of free bytes on this page +** aResult[5] = Number of free blocks on the page +** aResult[6] = Page number of the left child of this entry +** aResult[7] = Page number of the right child for the whole page */ int sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){ - aResult[0] = sqlitepager_pagenumber(pCur->pPage); + int cnt, idx; + MemPage *pPage = pCur->pPage; + aResult[0] = sqlitepager_pagenumber(pPage); aResult[1] = pCur->idx; + aResult[2] = pPage->nCell; + if( pCur->idx>=0 && pCur->idxnCell ){ + aResult[3] = cellSize(pPage->apCell[pCur->idx]); + aResult[6] = pPage->apCell[pCur->idx]->h.leftChild; + }else{ + aResult[3] = 0; + aResult[6] = 0; + } + aResult[4] = pPage->nFree; + cnt = 0; + idx = pPage->u.hdr.firstFree; + while( idx>0 && idxu.aDisk[idx])->iNext; + } + aResult[5] = cnt; + aResult[7] = pPage->u.hdr.rightChild; return SQLITE_OK; } #endif diff --git a/src/btree.h b/src/btree.h index b751c2f843..17f7400938 100644 --- a/src/btree.h +++ b/src/btree.h @@ -24,7 +24,7 @@ ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** -** @(#) $Id: btree.h,v 1.5 2001/06/22 19:15:00 drh Exp $ +** @(#) $Id: btree.h,v 1.6 2001/06/25 02:11:07 drh Exp $ */ typedef struct Btree Btree; @@ -52,7 +52,7 @@ int sqliteBtreeDataSize(BtCursor*, int *pSize); int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf); int sqliteBtreeCloseCursor(BtCursor*); -#define SQLITE_N_BTREE_META 3 +#define SQLITE_N_BTREE_META 4 int sqliteBtreeGetMeta(Btree*, int*); int sqliteBtreeUpdateMeta(Btree*, int*); diff --git a/src/test3.c b/src/test3.c index 87b36e37e5..02c965a740 100644 --- a/src/test3.c +++ b/src/test3.c @@ -25,7 +25,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.2 2001/06/22 19:15:01 drh Exp $ +** $Id: test3.c,v 1.3 2001/06/25 02:11:07 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -610,8 +610,17 @@ static int btree_data( /* ** Usage: btree_cursor_dump ID ** -** Return two integers which are the page number and cell index for -** the given cursor. +** Return eight integers containing information about the entry the +** cursor is pointing to: +** +** aResult[0] = The page number +** aResult[1] = The entry number +** aResult[2] = Total number of entries on this page +** aResult[3] = Size of this entry +** aResult[4] = Number of free bytes on this page +** aResult[5] = Number of free blocks on the page +** aResult[6] = Page number of the left child of this entry +** aResult[7] = Page number of the right child for the whole page */ static int btree_cursor_dump( void *NotUsed, @@ -621,8 +630,9 @@ static int btree_cursor_dump( ){ BtCursor *pCur; int rc; - int aResult[2]; - char zBuf[50]; + int i, j; + int aResult[8]; + char zBuf[400]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], @@ -635,8 +645,12 @@ static int btree_cursor_dump( Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } - sprintf(zBuf,"%d %d",aResult[0], aResult[1]); - Tcl_AppendResult(interp, zBuf, 0); + j = 0; + for(i=0; i