diff --git a/main.mk b/main.mk index 0c580567cb..3581eee7f2 100644 --- a/main.mk +++ b/main.mk @@ -109,7 +109,7 @@ SRC = \ # Source code to the test files. # -TESTSRC = \ +TESTSRC_SUBSET = \ $(TOP)/src/os.c \ $(TOP)/src/pager.c \ $(TOP)/src/test1.c \ @@ -118,7 +118,7 @@ TESTSRC = \ $(TOP)/src/test5.c \ $(TOP)/src/md5.c -TESTSRC_ORIG = \ +TESTSRC = \ $(TOP)/src/btree.c \ $(TOP)/src/func.c \ $(TOP)/src/os.c \ diff --git a/manifest b/manifest index 308c887463..82bd338898 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sto\smake\sregression\stests\sin\srowid.test\spass.\s(CVS\s1373) -D 2004-05-13T13:38:52 +C Changes\sto\sbtree\sand\spager\sin\spreparation\sfor\smoving\sto\srun-time\spage\nsize\sdetermination.\s(CVS\s1374) +D 2004-05-14T01:58:12 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -15,7 +15,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk 08bc0f1706964e029ef0319af0271ad79427cc71 +F main.mk fbc906044c1b891be4bd9e48a74a9fd5bcd5fc81 F publish.sh 1cd5c982388560fa91eedf6a338e210f713b35c8 F spec.template a38492f1c1dd349fc24cb0565e08afc53045304b F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea @@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 -F src/btree.c bda57fe687cfa28905e5daebb0b706187649bd6b +F src/btree.c 2b85dc8f6b169bbe6bc0dab1730757f77d72811b F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5 F src/build.c f25e4ac9f102efd70188bc09a459c2b461fe2135 @@ -40,8 +40,8 @@ F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383 -F src/pager.c fa60e566b370de0ed400859ba681134948b027bc -F src/pager.h 0c95b18f2785b58bfbb2b6f6a221f23caf378687 +F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5 +F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253 F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53 @@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P da9b3dce334bde99360db45b4a3d41be519ec2d1 -R b8ea62c9a072cbdad240805f1fb27046 -U danielk1977 -Z 37e1d6f2ec906eb83a05d292d4e622d2 +P 790226c94493a6d58a7e52fd3ed35ef495fab11e +R 1732d9617f45de2d10dd8c0de779aa14 +U drh +Z 4d4be7c36b4d139bc06baaeae3481d2d diff --git a/manifest.uuid b/manifest.uuid index f62da5adbd..cfe1845b60 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -790226c94493a6d58a7e52fd3ed35ef495fab11e \ No newline at end of file +f63fb6dd4e8e33d4c1983396b1a0305836ee4df7 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 5e44ed1649..32df09dfb4 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.133 2004/05/13 13:38:52 danielk1977 Exp $ +** $Id: btree.c,v 1.134 2004/05/14 01:58:13 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -267,7 +267,8 @@ struct Btree { u8 inTrans; /* True if a transaction is in progress */ u8 inStmt; /* True if there is a checkpoint on the transaction */ u8 readOnly; /* True if the underlying file is readonly */ - int pageSize; /* Number of usable bytes on each page */ + int pageSize; /* Total number of bytes on a page */ + int usableSize; /* Number of usable bytes on each page */ int maxLocal; /* Maximum local payload in non-LEAFDATA tables */ int minLocal; /* Minimum local payload in non-LEAFDATA tables */ int maxLeaf; /* Maximum local payload in a LEAFDATA table */ @@ -332,17 +333,6 @@ static void put4byte(unsigned char *p, u32 v){ p[3] = v; } -#if 0 /* NOT_USED */ -static u64 get8byte(unsigned char *p){ - u64 v = get4byte(p); - return (v<<32) | get4byte(&p[4]); -} -static void put8byte(unsigned char *p, u64 v){ - put4byte(&p[4], v>>32); - put4byte(p, v); -} -#endif - /* ** Read a variable-length integer. Store the result in *pResult. ** Return the number of bytes in the integer. @@ -420,7 +410,7 @@ static void parseCell( pBt = pPage->pBt; if( pPage->leafData ){ minLocal = pBt->minLeaf; - maxLocal = pBt->pageSize - 23; + maxLocal = pBt->usableSize - 23; }else{ minLocal = pBt->minLocal; maxLocal = pBt->maxLocal; @@ -430,7 +420,7 @@ static void parseCell( pInfo->iOverflow = 0; pInfo->nSize = nPayload + n; }else{ - int surplus = minLocal + (nPayload - minLocal)%(pBt->pageSize - 4); + int surplus = minLocal + (nPayload - minLocal)%(pBt->usableSize - 4); if( surplus <= maxLocal ){ pInfo->nLocal = surplus; }else{ @@ -464,13 +454,13 @@ static int cellSize(MemPage *pPage, unsigned char *pCell){ */ #if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0 static void _pageIntegrity(MemPage *pPage){ - int pageSize; + int usableSize; 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] ); + usableSize = pPage->pBt->usableSize; + assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] ); hdr = pPage->hdrOffset; assert( hdr==(pPage->pgno==1 ? 100 : 0) ); assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); @@ -484,15 +474,15 @@ static void _pageIntegrity(MemPage *pPage){ !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) ); } data = pPage->aData; - memset(used, 0, pageSize); + memset(used, 0, usableSize); for(i=0; ileaf*4; i++) used[i] = 1; nFree = 0; pc = get2byte(&data[hdr+1]); while( pc ){ int size; - assert( pc>0 && pc0 && pcisInit==0 || idxnCell ); - assert( pc>0 && pc0 && pcisInit==0 || pPage->aCell[idx]==&data[pc] ); size = cellSize(pPage, &data[pc]); - assert( pc+size<=pageSize ); + assert( pc+size<=usableSize ); for(i=pc; inCell ); nFree = 0; - for(i=0; iaData) ); assert( pPage->pBt!=0 ); - assert( pPage->pBt->pageSize <= MX_PAGE_SIZE ); + assert( pPage->pBt->usableSize <= MX_PAGE_SIZE ); assert( !pPage->needRelink ); assert( !pPage->isOverfull ); oldPage = pPage->aData; @@ -559,7 +549,7 @@ static void defragmentPage(MemPage *pPage){ pc = get2byte(&oldPage[addr]); i = 0; while( pc>0 ){ - assert( npBt->pageSize ); + assert( npBt->usableSize ); size = cellSize(pPage, &oldPage[pc]); memcpy(&newPage[n], &oldPage[pc], size); put2byte(&newPage[addr],n); @@ -570,13 +560,13 @@ static void defragmentPage(MemPage *pPage){ pc = get2byte(&oldPage[pc]); } assert( i==pPage->nCell ); - leftover = pPage->pBt->pageSize - n; + leftover = pPage->pBt->usableSize - n; assert( leftover>=0 ); assert( pPage->nFree==leftover ); if( leftover<4 ){ oldPage[hdr+5] = leftover; leftover = 0; - n = pPage->pBt->pageSize; + n = pPage->pBt->usableSize; } memcpy(&oldPage[hdr], &newPage[hdr], n-hdr); if( leftover==0 ){ @@ -628,11 +618,11 @@ static int allocateSpace(MemPage *pPage, int nByte){ addr = hdr+1; pc = get2byte(&data[addr]); assert( addrpBt->pageSize-4 ); + assert( pc<=pPage->pBt->usableSize-4 ); while( (size = get2byte(&data[pc+2]))pBt->pageSize-4 ); + assert( pc<=pPage->pBt->usableSize-4 ); assert( pc>=addr+size+4 || pc==0 ); if( pc==0 ){ assert( (cnt++)==0 ); @@ -643,7 +633,7 @@ static int allocateSpace(MemPage *pPage, int nByte){ } } assert( pc>0 && size>=nByte ); - assert( pc+size<=pPage->pBt->pageSize ); + assert( pc+size<=pPage->pBt->usableSize ); if( size>nByte+4 ){ int newStart = pc+nByte; put2byte(&data[addr], newStart); @@ -677,17 +667,17 @@ static void freeSpace(MemPage *pPage, int start, int size){ assert( pPage->pBt!=0 ); assert( sqlite3pager_iswriteable(data) ); assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) ); - assert( end<=pPage->pBt->pageSize ); + assert( end<=pPage->pBt->usableSize ); if( size<4 ) size = 4; /* Add the space back into the linked list of freeblocks */ addr = pPage->hdrOffset + 1; while( (pbegin = get2byte(&data[addr]))0 ){ - assert( pbegin<=pPage->pBt->pageSize-4 ); + assert( pbegin<=pPage->pBt->usableSize-4 ); assert( pbegin>addr ); addr = pbegin; } - assert( pbegin<=pPage->pBt->pageSize-4 ); + assert( pbegin<=pPage->pBt->usableSize-4 ); assert( pbegin>addr || pbegin==0 ); put2byte(&data[addr], start); put2byte(&data[start], pbegin); @@ -699,7 +689,7 @@ static void freeSpace(MemPage *pPage, int start, int size){ while( (pbegin = get2byte(&data[addr]))>0 ){ int pnext, psize; assert( pbegin>addr ); - assert( pbeginpBt->pageSize-4 ); + assert( pbeginpBt->usableSize-4 ); pnext = get2byte(&data[pbegin]); psize = get2byte(&data[pbegin+2]); if( pbegin + psize + 3 >= pnext && pnext>0 ){ @@ -750,7 +740,7 @@ static int initPage( ){ int c, pc, i, hdr; unsigned char *data; - int pageSize; + int usableSize; int sumCell = 0; /* Total size of all cells */ assert( pPage->pBt!=0 ); @@ -776,13 +766,13 @@ static int initPage( pPage->isOverfull = 0; pPage->needRelink = 0; pPage->idxShift = 0; - pageSize = pPage->pBt->pageSize; + usableSize = pPage->pBt->usableSize; /* Initialize the cell count and cell pointers */ pc = get2byte(&data[hdr+3]); while( pc>0 ){ - if( pc>=pageSize ) return SQLITE_CORRUPT; - if( pPage->nCell>pageSize ) return SQLITE_CORRUPT; + if( pc>=usableSize ) return SQLITE_CORRUPT; + if( pPage->nCell>usableSize ) return SQLITE_CORRUPT; pPage->nCell++; pc = get2byte(&data[pc]); } @@ -801,18 +791,18 @@ static int initPage( pc = get2byte(&data[hdr+1]); while( pc>0 ){ int next, size; - if( pc>=pageSize ) return SQLITE_CORRUPT; + if( pc>=usableSize ) return SQLITE_CORRUPT; next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( next>0 && next<=pc+size+3 ) return SQLITE_CORRUPT; pPage->nFree += size; pc = next; } - if( pPage->nFree>=pageSize ) return SQLITE_CORRUPT; + if( pPage->nFree>=usableSize ) return SQLITE_CORRUPT; /* Sanity check: Cells and freespace and header must sum to the size ** a page. */ - if( sumCell+pPage->nFree+hdr+10-pPage->leaf*4 != pageSize ){ + if( sumCell+pPage->nFree+hdr+10-pPage->leaf*4 != usableSize ){ return SQLITE_CORRUPT; } @@ -834,16 +824,16 @@ static void zeroPage(MemPage *pPage, int flags){ assert( sqlite3pager_pagenumber(data)==pPage->pgno ); assert( &data[pBt->pageSize] == (unsigned char*)pPage ); assert( sqlite3pager_iswriteable(data) ); - memset(&data[hdr], 0, pBt->pageSize - hdr); + memset(&data[hdr], 0, pBt->usableSize - hdr); data[hdr] = flags; first = hdr + 6 + 4*((flags&PTF_LEAF)==0); put2byte(&data[hdr+1], first); - put2byte(&data[first+2], pBt->pageSize - first); + put2byte(&data[first+2], pBt->usableSize - first); sqliteFree(pPage->aCell); pPage->aCell = 0; pPage->nCell = 0; pPage->nCellAlloc = 0; - pPage->nFree = pBt->pageSize - first; + pPage->nFree = pBt->usableSize - first; pPage->intKey = (flags & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->zeroData = (flags & PTF_ZERODATA)!=0; pPage->leafData = (flags & PTF_LEAFDATA)!=0; @@ -913,8 +903,8 @@ static void releasePage(MemPage *pPage){ ** reaches zero. We need to unref the pParent pointer when that ** happens. */ -static void pageDestructor(void *pData){ - MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE]; +static void pageDestructor(void *pData, int pageSize){ + MemPage *pPage = (MemPage*)&((char*)pData)[pageSize]; assert( pPage->isInit==0 || pPage->needRelink==0 ); if( pPage->pParent ){ MemPage *pParent = pPage->pParent; @@ -978,29 +968,11 @@ int sqlite3BtreeOpen( pBt->pPage1 = 0; pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager); pBt->pageSize = SQLITE_PAGE_SIZE; /* FIX ME - read from header */ + pBt->usableSize = pBt->pageSize; pBt->maxEmbedFrac = 64; /* FIX ME - read from header */ pBt->minEmbedFrac = 32; /* FIX ME - read from header */ pBt->minLeafFrac = 32; /* FIX ME - read from header */ - /* maxLocal is the maximum amount of payload to store locally for - ** a cell. Make sure it is small enough so that at least minFanout - ** cells can will fit on one page. We assume a 10-byte page header. - ** Besides the payload, the cell must store: - ** 2-byte pointer to next cell - ** 4-byte child pointer - ** 9-byte nKey value - ** 4-byte nData value - ** 4-byte overflow page pointer - ** So a cell consists of a header which is as much as 19 bytes long, - ** 0 to N bytes of payload, and an optional 4 byte overflow page pointer. - */ - assert(pBt->maxEmbedFrac>0 && 255/pBt->maxEmbedFrac>=3 ); - pBt->maxLocal = (pBt->pageSize-10)*pBt->maxEmbedFrac/255 - 23; - pBt->minLocal = (pBt->pageSize-10)*pBt->minEmbedFrac/255 - 23; - pBt->maxLeaf = pBt->pageSize - 33; - pBt->minLeaf = (pBt->pageSize-10)*pBt->minLeafFrac/255 - 23; - - assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE ); *ppBtree = pBt; return SQLITE_OK; } @@ -1071,15 +1043,47 @@ static int lockBtree(Btree *pBt){ /* Do some checking to help insure the file we opened really is ** a valid database file. */ + rc = SQLITE_NOTADB; if( sqlite3pager_pagecount(pBt->pPager)>0 ){ - if( memcmp(pPage1->aData, zMagicHeader, 16)!=0 ){ - rc = SQLITE_NOTADB; + u8 *page1 = pPage1->aData; + if( memcmp(page1, zMagicHeader, 16)!=0 ){ goto page1_init_failed; } - /*** TBD: Other header checks such as page size ****/ + if( page1[18]>1 || page1[19]>1 ){ + goto page1_init_failed; + } + pBt->pageSize = get2byte(&page1[16]); + pBt->usableSize = pBt->pageSize - page1[20]; + if( pBt->usableSize<500 ){ + goto page1_init_failed; + } + pBt->maxEmbedFrac = page1[21]; + pBt->minEmbedFrac = page1[22]; + pBt->minLeafFrac = page1[23]; } + + /* maxLocal is the maximum amount of payload to store locally for + ** a cell. Make sure it is small enough so that at least minFanout + ** cells can will fit on one page. We assume a 10-byte page header. + ** Besides the payload, the cell must store: + ** 2-byte pointer to next cell + ** 4-byte child pointer + ** 9-byte nKey value + ** 4-byte nData value + ** 4-byte overflow page pointer + ** So a cell consists of a header which is as much as 19 bytes long, + ** 0 to N bytes of payload, and an optional 4 byte overflow page pointer. + */ + pBt->maxLocal = (pBt->usableSize-10)*pBt->maxEmbedFrac/255 - 23; + pBt->minLocal = (pBt->usableSize-10)*pBt->minEmbedFrac/255 - 23; + pBt->maxLeaf = pBt->usableSize - 33; + pBt->minLeaf = (pBt->usableSize-10)*pBt->minLeafFrac/255 - 23; + if( pBt->minLocal>pBt->maxLocal || pBt->maxLocal<0 ){ + goto page1_init_failed; + } + assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE ); pBt->pPage1 = pPage1; - return rc; + return SQLITE_OK; page1_init_failed: releasePage(pPage1); @@ -1122,10 +1126,14 @@ static int newDatabase(Btree *pBt){ if( rc ) return rc; memcpy(data, zMagicHeader, sizeof(zMagicHeader)); assert( sizeof(zMagicHeader)==16 ); - put2byte(&data[16], SQLITE_PAGE_SIZE); + put2byte(&data[16], pBt->pageSize); data[18] = 1; data[19] = 1; - put2byte(&data[22], (SQLITE_PAGE_SIZE-10)/4-12); + data[20] = pBt->pageSize - pBt->usableSize; + data[21] = pBt->maxEmbedFrac; + data[22] = pBt->minEmbedFrac; + data[23] = pBt->minLeafFrac; + memset(&data[24], 0, 100-24); zeroPage(pP1, PTF_INTKEY|PTF_LEAF ); return SQLITE_OK; } @@ -1605,7 +1613,7 @@ static int getPayload( if( amt>0 ){ nextPage = get4byte(&aPayload[info.nLocal]); } - ovflSize = pBt->pageSize - 4; + ovflSize = pBt->usableSize - 4; while( amt>0 && nextPage ){ rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload); if( rc!=0 ){ @@ -2330,7 +2338,7 @@ static int freePage(MemPage *pPage){ rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk); if( rc ) return rc; k = get4byte(&pTrunk->aData[4]); - if( k==pBt->pageSize/4 - 8 ){ + if( k==pBt->usableSize/4 - 8 ){ /* The trunk is full. Turn the page being freed into a new ** trunk page with no leaves. */ rc = sqlite3pager_write(pPage->aData); @@ -2458,7 +2466,7 @@ static int fillInCell( pPrior = pOvfl->aData; put4byte(pPrior, 0); pPayload = &pOvfl->aData[4]; - spaceLeft = pBt->pageSize - 4; + spaceLeft = pBt->usableSize - 4; } n = nPayload; if( n>spaceLeft ) n = spaceLeft; @@ -2491,7 +2499,7 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){ assert( pBt->pPager!=0 ); aData = sqlite3pager_lookup(pBt->pPager, pgno); if( aData ){ - pThis = (MemPage*)&aData[pBt->pageSize]; + pThis = (MemPage*)&aData[pBt->usableSize]; if( pThis->isInit ){ if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData); @@ -2548,10 +2556,10 @@ static void dropCell(MemPage *pPage, int idx, int sz){ 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] ); + assert( pPage->aCell[idx]<=&pPage->aData[pPage->pBt->usableSize-sz] ); data = pPage->aData; pc = Addr(pPage->aCell[idx]) - Addr(data); - assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->pageSize ); + assert( pc>pPage->hdrOffset && pc+sz<=pPage->pBt->usableSize ); freeSpace(pPage, pc, sz); for(j=idx; jnCell-1; j++){ pPage->aCell[j] = pPage->aCell[j+1]; @@ -2654,7 +2662,7 @@ static void relinkCellList(MemPage *pPage){ idxFrom = pPage->hdrOffset+3; for(i=0; inCell; i++){ int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData); - assert( idx>pPage->hdrOffset && idxpBt->pageSize ); + assert( idx>pPage->hdrOffset && idxpBt->usableSize ); put2byte(&pPage->aData[idxFrom], idx); idxFrom = idx; } @@ -2681,15 +2689,15 @@ static void relinkCellList(MemPage *pPage){ static void movePage(MemPage *pTo, MemPage *pFrom){ uptr from, to; int i; - int pageSize; + int usableSize; int ofst; assert( pTo->hdrOffset==0 ); assert( pFrom->isInit ); ofst = pFrom->hdrOffset; - pageSize = pFrom->pBt->pageSize; + usableSize = pFrom->pBt->usableSize; sqliteFree(pTo->aCell); - memcpy(pTo->aData, &pFrom->aData[ofst], pageSize - ofst); + memcpy(pTo->aData, &pFrom->aData[ofst], usableSize - ofst); memcpy(pTo, pFrom, offsetof(MemPage, aData)); pFrom->isInit = 0; pFrom->aCell = 0; @@ -2700,7 +2708,7 @@ static void movePage(MemPage *pTo, MemPage *pFrom){ from = Addr(&pFrom->aData[ofst]); for(i=0; inCell; i++){ uptr x = Addr(pTo->aCell[i]); - if( x>from && xfrom && xaCell[i]) = x + to - from; } } @@ -2772,6 +2780,7 @@ 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 */ + int iSpace = 0; /* First unused byte of aSpace[] */ 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[] */ @@ -2780,13 +2789,12 @@ static int balance(MemPage *pPage){ Pgno pgnoNew[NB+1]; /* Page numbers for each page in apNew[] */ int idxDiv[NB]; /* Indices of divider cells in pParent */ u8 *apDiv[NB]; /* Divider cells in pParent */ - u8 aTemp[NB][MX_CELL_SIZE]; /* Temporary holding area for apDiv[] */ - u8 aInsBuf[NB][MX_CELL_SIZE];/* Space to hold dividers cells during insert */ int cntNew[NB+1]; /* Index in aCell[] of cell after i-th page */ int szNew[NB+1]; /* 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][MX_PAGE_SIZE+sizeof(MemPage)]; /* Space for apCopy[] */ + u8 aSpace[MX_PAGE_SIZE*4]; /* Space to copies of divider cells */ /* ** Return without doing any work if pPage is neither overfull nor @@ -2795,7 +2803,7 @@ static int balance(MemPage *pPage){ assert( pPage->isInit ); assert( sqlite3pager_iswriteable(pPage->aData) ); pBt = pPage->pBt; - if( !pPage->isOverfull && pPage->nFreepageSize*2/3 && pPage->nCell>=2){ + if( !pPage->isOverfull && pPage->nFreeusableSize*2/3 && pPage->nCell>=2){ relinkCellList(pPage); return SQLITE_OK; } @@ -2851,7 +2859,7 @@ static int balance(MemPage *pPage){ TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); } }else{ - memcpy(pPage->aData, pChild->aData, pBt->pageSize); + memcpy(pPage->aData, pChild->aData, pBt->usableSize); pPage->isInit = 0; pPage->pParent = 0; rc = initPage(pPage, 0); @@ -2974,7 +2982,7 @@ static int balance(MemPage *pPage){ */ for(i=0; iaData = &((u8*)p)[-pBt->pageSize]; + p->aData = &((u8*)p)[-pBt->usableSize]; p->aCell = 0; p->hdrOffset = 0; movePage(p, apOld[i]); @@ -2983,11 +2991,12 @@ static int balance(MemPage *pPage){ /* ** Load pointers to all cells on sibling pages and the divider cells ** into the local apCell[] array. Make copies of the divider cells - ** into aTemp[] and remove the the divider Cells from pParent. + ** into space obtained form aSpace[] and remove the the divider Cells + ** from pParent. ** ** If the siblings are on leaf pages, then the child pointers of the ** divider cells are stripped from the cells before they are copied - ** into aTemp[]. In this wall, all cells in apCell[] are without + ** into aSpace[]. In this wall, all cells in apCell[] are without ** child pointers. If siblings are not leaves, then all cell in ** apCell[] include child pointers. Either way, all cells in apCell[] ** are alike. @@ -3003,16 +3012,20 @@ static int balance(MemPage *pPage){ nCell++; } if( ileaf ){ assert( leafCorrection==0 ); /* The right pointer of the child page pOld becomes the left @@ -3036,7 +3049,7 @@ static int balance(MemPage *pPage){ ** This little patch of code is critical for keeping the tree ** balanced. */ - usableSpace = pBt->pageSize - 10 + leafCorrection; + usableSpace = pBt->usableSize - 10 + leafCorrection; for(subtotal=k=i=0; i usableSpace ){ @@ -3165,12 +3178,16 @@ static int balance(MemPage *pPage){ CellInfo info; j--; parseCell(pNew, apCell[j], &info); - pCell = aInsBuf[i]; + pCell = &aSpace[iSpace]; fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz); + iSpace += sz; + assert( iSpace<=sizeof(aSpace) ); pTemp = 0; }else{ pCell -= 4; - pTemp = aInsBuf[i]; + pTemp = &aSpace[iSpace]; + iSpace += sz; + assert( iSpace<=sizeof(aSpace) ); } insertCell(pParent, nxDiv, pCell, sz, pTemp); put4byte(&pParent->aCell[nxDiv][2], pNew->pgno); @@ -3630,7 +3647,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ i = 0; assert( hdr == (pgno==1 ? 100 : 0) ); idx = get2byte(&data[hdr+3]); - while( idx>0 && idx<=pBt->pageSize ){ + while( idx>0 && idx<=pBt->usableSize ){ CellInfo info; Pgno child; unsigned char *pCell = &data[idx]; @@ -3672,7 +3689,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ nFree = 0; i = 0; idx = get2byte(&data[hdr+1]); - while( idx>0 && idxpBt->pageSize ){ + while( idx>0 && idxpBt->usableSize ){ int sz = get2byte(&data[idx+2]); sprintf(range,"%d..%d", idx, idx+sz-1); nFree += sz; @@ -3686,7 +3703,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ } if( recursive && !pPage->leaf ){ idx = get2byte(&data[hdr+3]); - while( idx>0 && idxpageSize ){ + while( idx>0 && idxusableSize ){ unsigned char *pCell = &data[idx]; sqlite3BtreePageDump(pBt, get4byte(&pCell[2]), 1); idx = get2byte(pCell); @@ -3735,7 +3752,7 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult){ aResult[4] = pPage->nFree; cnt = 0; idx = get2byte(&pPage->aData[pPage->hdrOffset+1]); - while( idx>0 && idxpBt->pageSize ){ + while( idx>0 && idxpBt->usableSize ){ cnt++; idx = get2byte(&pPage->aData[idx]); } @@ -3880,7 +3897,7 @@ static int checkTreePage( u8 *data; BtCursor cur; Btree *pBt; - int maxLocal, pageSize; + int maxLocal, usableSize; char zMsg[100]; char zContext[100]; char hit[MX_PAGE_SIZE]; @@ -3888,7 +3905,7 @@ static int checkTreePage( /* Check that the page exists */ cur.pBt = pBt = pCheck->pBt; - pageSize = pBt->pageSize; + usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){ @@ -3921,7 +3938,7 @@ static int checkTreePage( sz = info.nData; if( !pPage->intKey ) sz += info.nKey; if( sz>info.nLocal ){ - int nPage = (sz - info.nLocal + pageSize - 5)/(pageSize - 4); + int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4); checkList(pCheck, 0, get4byte(&pCell[info.iOverflow]),nPage,zContext); } @@ -3944,23 +3961,23 @@ static int checkTreePage( /* Check for complete coverage of the page */ - memset(hit, 0, pageSize); + memset(hit, 0, usableSize); memset(hit, 1, pPage->hdrOffset+10-4*(pPage->leaf)); data = pPage->aData; hdr = pPage->hdrOffset; - for(cnt=0, i=get2byte(&data[hdr+3]); i>0 && i0 && i=i; j--) hit[j]++; i = get2byte(&data[i]); } - for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i0 && i=i; j--) hit[j]++; i = get2byte(&data[i]); } - for(i=cnt=0; i1 ){ @@ -4070,7 +4087,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; if( pBtTo->pCursor ) return SQLITE_BUSY; - memcpy(pBtTo->pPage1, pBtFrom->pPage1, pBtFrom->pageSize); + memcpy(pBtTo->pPage1, pBtFrom->pPage1, pBtFrom->usableSize); rc = sqlite3pager_overwrite(pBtTo->pPager, 1, pBtFrom->pPage1); nToPage = sqlite3pager_pagecount(pBtTo->pPager); nPage = sqlite3pager_pagecount(pBtFrom->pPager); diff --git a/src/pager.c b/src/pager.c index 29db8640d2..b5315e8f58 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.107 2004/05/12 13:30:08 drh Exp $ +** @(#) $Id: pager.c,v 1.108 2004/05/14 01:58:13 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -181,14 +181,14 @@ struct Pager { u32 cksumInit; /* Quasi-random value added to every checksum */ int stmtNRec; /* Number of records in stmt subjournal */ int nExtra; /* Add this many bytes to each in-memory page */ - void (*xDestructor)(void*); /* Call this routine when freeing pages */ + void (*xDestructor)(void*,int); /* Call this routine when freeing pages */ + int pageSize; /* Number of bytes in a page */ int nPage; /* Total number of in-memory pages */ int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ int mxPage; /* Maximum number of pages to hold in cache */ int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */ void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *pCodecArg; /* First argument to xCodec() */ - int pageSize; /* Page size in bytes */ u8 journalOpen; /* True if journal file descriptors is valid */ u8 journalStarted; /* True if header of journal is synced */ u8 useJournal; /* Use a rollback journal on this file */ @@ -587,14 +587,16 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){ ** 1 which is held in use in order to keep the lock on the database ** active. */ + void *pData; assert( pPg->nRef==0 || pPg->pgno==1 ); - memcpy(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE); + pData = PGHDR_TO_DATA(pPg); + memcpy(pData, pgRec.aData, pPager->pageSize); if( pPager->xDestructor ){ - pPager->xDestructor(PGHDR_TO_DATA(pPg)); + pPager->xDestructor(pData, pPager->pageSize); } pPg->dirty = 0; pPg->needSync = 0; - CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); + CODEC(pPager, pData, pPg->pgno, 3); } return rc; } @@ -1034,7 +1036,7 @@ int sqlite3pager_open( ** The destructor is not called as a result sqlite3pager_close(). ** Destructors are only called by sqlite3pager_unref(). */ -void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*)){ +void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){ pPager->xDestructor = xDesc; } @@ -1708,7 +1710,7 @@ int sqlite3pager_unref(void *pData){ pPager->pFirstSynced = pPg; } if( pPager->xDestructor ){ - pPager->xDestructor(pData); + pPager->xDestructor(pData, pPager->pageSize); } /* When all pages reach the freelist, drop the read lock from diff --git a/src/pager.h b/src/pager.h index f08491a682..1aa70c715d 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,11 +13,11 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.28 2004/05/08 08:23:30 danielk1977 Exp $ +** @(#) $Id: pager.h,v 1.29 2004/05/14 01:58:13 drh Exp $ */ /* -** The size of one page +** The size of a page. ** ** You can change this value to another (reasonable) value you want. ** It need not be a power of two, though the interface to the disk @@ -71,7 +71,7 @@ typedef struct Pager Pager; */ int sqlite3pager_open(Pager **ppPager, const char *zFilename, int nPage, int nExtra, int useJournal); -void sqlite3pager_set_destructor(Pager*, void(*)(void*)); +void sqlite3pager_set_destructor(Pager*, void(*)(void*,int)); void sqlite3pager_set_cachesize(Pager*, int); int sqlite3pager_close(Pager *pPager); int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage); @@ -103,6 +103,3 @@ void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*); void sqlite3pager_refdump(Pager*); int pager3_refinfo_enable; #endif - - -