1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Changes to btree and pager in preparation for moving to run-time page

size determination. (CVS 1374)

FossilOrigin-Name: f63fb6dd4e8e33d4c1983396b1a0305836ee4df7
This commit is contained in:
drh
2004-05-14 01:58:11 +00:00
parent e7c8d58a1f
commit b6f4148607
6 changed files with 154 additions and 138 deletions

View File

@@ -109,7 +109,7 @@ SRC = \
# Source code to the test files. # Source code to the test files.
# #
TESTSRC = \ TESTSRC_SUBSET = \
$(TOP)/src/os.c \ $(TOP)/src/os.c \
$(TOP)/src/pager.c \ $(TOP)/src/pager.c \
$(TOP)/src/test1.c \ $(TOP)/src/test1.c \
@@ -118,7 +118,7 @@ TESTSRC = \
$(TOP)/src/test5.c \ $(TOP)/src/test5.c \
$(TOP)/src/md5.c $(TOP)/src/md5.c
TESTSRC_ORIG = \ TESTSRC = \
$(TOP)/src/btree.c \ $(TOP)/src/btree.c \
$(TOP)/src/func.c \ $(TOP)/src/func.c \
$(TOP)/src/os.c \ $(TOP)/src/os.c \

View File

@@ -1,5 +1,5 @@
C Changes\sto\smake\sregression\stests\sin\srowid.test\spass.\s(CVS\s1373) C Changes\sto\sbtree\sand\spager\sin\spreparation\sfor\smoving\sto\srun-time\spage\nsize\sdetermination.\s(CVS\s1374)
D 2004-05-13T13:38:52 D 2004-05-14T01:58:12
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -15,7 +15,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
F main.mk 08bc0f1706964e029ef0319af0271ad79427cc71 F main.mk fbc906044c1b891be4bd9e48a74a9fd5bcd5fc81
F publish.sh 1cd5c982388560fa91eedf6a338e210f713b35c8 F publish.sh 1cd5c982388560fa91eedf6a338e210f713b35c8
F spec.template a38492f1c1dd349fc24cb0565e08afc53045304b F spec.template a38492f1c1dd349fc24cb0565e08afc53045304b
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
@@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c bda57fe687cfa28905e5daebb0b706187649bd6b F src/btree.c 2b85dc8f6b169bbe6bc0dab1730757f77d72811b
F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050 F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
F src/build.c f25e4ac9f102efd70188bc09a459c2b461fe2135 F src/build.c f25e4ac9f102efd70188bc09a459c2b461fe2135
@@ -40,8 +40,8 @@ F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383 F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
F src/pager.c fa60e566b370de0ed400859ba681134948b027bc F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
F src/pager.h 0c95b18f2785b58bfbb2b6f6a221f23caf378687 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8 F src/pragma.c 2ab2a12b62ec5370b9221f44b4743a633a90bfa8
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53 F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
@@ -191,7 +191,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P da9b3dce334bde99360db45b4a3d41be519ec2d1 P 790226c94493a6d58a7e52fd3ed35ef495fab11e
R b8ea62c9a072cbdad240805f1fb27046 R 1732d9617f45de2d10dd8c0de779aa14
U danielk1977 U drh
Z 37e1d6f2ec906eb83a05d292d4e622d2 Z 4d4be7c36b4d139bc06baaeae3481d2d

View File

@@ -1 +1 @@
790226c94493a6d58a7e52fd3ed35ef495fab11e f63fb6dd4e8e33d4c1983396b1a0305836ee4df7

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** 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. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@@ -267,7 +267,8 @@ struct Btree {
u8 inTrans; /* True if a transaction is in progress */ u8 inTrans; /* True if a transaction is in progress */
u8 inStmt; /* True if there is a checkpoint on the transaction */ u8 inStmt; /* True if there is a checkpoint on the transaction */
u8 readOnly; /* True if the underlying file is readonly */ 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 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
int minLocal; /* Minimum local payload in non-LEAFDATA tables */ int minLocal; /* Minimum local payload in non-LEAFDATA tables */
int maxLeaf; /* Maximum local payload in a LEAFDATA table */ int maxLeaf; /* Maximum local payload in a LEAFDATA table */
@@ -332,17 +333,6 @@ static void put4byte(unsigned char *p, u32 v){
p[3] = 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. ** Read a variable-length integer. Store the result in *pResult.
** Return the number of bytes in the integer. ** Return the number of bytes in the integer.
@@ -420,7 +410,7 @@ static void parseCell(
pBt = pPage->pBt; pBt = pPage->pBt;
if( pPage->leafData ){ if( pPage->leafData ){
minLocal = pBt->minLeaf; minLocal = pBt->minLeaf;
maxLocal = pBt->pageSize - 23; maxLocal = pBt->usableSize - 23;
}else{ }else{
minLocal = pBt->minLocal; minLocal = pBt->minLocal;
maxLocal = pBt->maxLocal; maxLocal = pBt->maxLocal;
@@ -430,7 +420,7 @@ static void parseCell(
pInfo->iOverflow = 0; pInfo->iOverflow = 0;
pInfo->nSize = nPayload + n; pInfo->nSize = nPayload + n;
}else{ }else{
int surplus = minLocal + (nPayload - minLocal)%(pBt->pageSize - 4); int surplus = minLocal + (nPayload - minLocal)%(pBt->usableSize - 4);
if( surplus <= maxLocal ){ if( surplus <= maxLocal ){
pInfo->nLocal = surplus; pInfo->nLocal = surplus;
}else{ }else{
@@ -464,13 +454,13 @@ static int cellSize(MemPage *pPage, unsigned char *pCell){
*/ */
#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0 #if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
static void _pageIntegrity(MemPage *pPage){ static void _pageIntegrity(MemPage *pPage){
int pageSize; int usableSize;
u8 *data; u8 *data;
int i, idx, c, pc, hdr, nFree; int i, idx, c, pc, hdr, nFree;
u8 used[MX_PAGE_SIZE]; u8 used[MX_PAGE_SIZE];
pageSize = pPage->pBt->pageSize; usableSize = pPage->pBt->usableSize;
assert( pPage->aData==&((unsigned char*)pPage)[-pageSize] ); assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
hdr = pPage->hdrOffset; hdr = pPage->hdrOffset;
assert( hdr==(pPage->pgno==1 ? 100 : 0) ); assert( hdr==(pPage->pgno==1 ? 100 : 0) );
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) ); assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
@@ -484,15 +474,15 @@ static void _pageIntegrity(MemPage *pPage){
!(pPage->zeroData || (!pPage->leaf && pPage->leafData)) ); !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
} }
data = pPage->aData; data = pPage->aData;
memset(used, 0, pageSize); memset(used, 0, usableSize);
for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1; for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
nFree = 0; nFree = 0;
pc = get2byte(&data[hdr+1]); pc = get2byte(&data[hdr+1]);
while( pc ){ while( pc ){
int size; int size;
assert( pc>0 && pc<pageSize-4 ); assert( pc>0 && pc<usableSize-4 );
size = get2byte(&data[pc+2]); size = get2byte(&data[pc+2]);
assert( pc+size<=pageSize ); assert( pc+size<=usableSize );
nFree += size; nFree += size;
for(i=pc; i<pc+size; i++){ for(i=pc; i<pc+size; i++){
assert( used[i]==0 ); assert( used[i]==0 );
@@ -506,10 +496,10 @@ static void _pageIntegrity(MemPage *pPage){
while( pc ){ while( pc ){
int size; int size;
assert( pPage->isInit==0 || idx<pPage->nCell ); assert( pPage->isInit==0 || idx<pPage->nCell );
assert( pc>0 && pc<pageSize-4 ); assert( pc>0 && pc<usableSize-4 );
assert( pPage->isInit==0 || pPage->aCell[idx]==&data[pc] ); assert( pPage->isInit==0 || pPage->aCell[idx]==&data[pc] );
size = cellSize(pPage, &data[pc]); size = cellSize(pPage, &data[pc]);
assert( pc+size<=pageSize ); assert( pc+size<=usableSize );
for(i=pc; i<pc+size; i++){ for(i=pc; i<pc+size; i++){
assert( used[i]==0 ); assert( used[i]==0 );
used[i] = 1; used[i] = 1;
@@ -519,7 +509,7 @@ static void _pageIntegrity(MemPage *pPage){
} }
assert( idx==pPage->nCell ); assert( idx==pPage->nCell );
nFree = 0; nFree = 0;
for(i=0; i<pageSize; i++){ for(i=0; i<usableSize; i++){
assert( used[i]<=1 ); assert( used[i]<=1 );
if( used[i]==0 ) nFree++; if( used[i]==0 ) nFree++;
} }
@@ -544,7 +534,7 @@ static void defragmentPage(MemPage *pPage){
assert( sqlite3pager_iswriteable(pPage->aData) ); assert( sqlite3pager_iswriteable(pPage->aData) );
assert( pPage->pBt!=0 ); assert( pPage->pBt!=0 );
assert( pPage->pBt->pageSize <= MX_PAGE_SIZE ); assert( pPage->pBt->usableSize <= MX_PAGE_SIZE );
assert( !pPage->needRelink ); assert( !pPage->needRelink );
assert( !pPage->isOverfull ); assert( !pPage->isOverfull );
oldPage = pPage->aData; oldPage = pPage->aData;
@@ -559,7 +549,7 @@ static void defragmentPage(MemPage *pPage){
pc = get2byte(&oldPage[addr]); pc = get2byte(&oldPage[addr]);
i = 0; i = 0;
while( pc>0 ){ while( pc>0 ){
assert( n<pPage->pBt->pageSize ); assert( n<pPage->pBt->usableSize );
size = cellSize(pPage, &oldPage[pc]); size = cellSize(pPage, &oldPage[pc]);
memcpy(&newPage[n], &oldPage[pc], size); memcpy(&newPage[n], &oldPage[pc], size);
put2byte(&newPage[addr],n); put2byte(&newPage[addr],n);
@@ -570,13 +560,13 @@ static void defragmentPage(MemPage *pPage){
pc = get2byte(&oldPage[pc]); pc = get2byte(&oldPage[pc]);
} }
assert( i==pPage->nCell ); assert( i==pPage->nCell );
leftover = pPage->pBt->pageSize - n; leftover = pPage->pBt->usableSize - n;
assert( leftover>=0 ); assert( leftover>=0 );
assert( pPage->nFree==leftover ); assert( pPage->nFree==leftover );
if( leftover<4 ){ if( leftover<4 ){
oldPage[hdr+5] = leftover; oldPage[hdr+5] = leftover;
leftover = 0; leftover = 0;
n = pPage->pBt->pageSize; n = pPage->pBt->usableSize;
} }
memcpy(&oldPage[hdr], &newPage[hdr], n-hdr); memcpy(&oldPage[hdr], &newPage[hdr], n-hdr);
if( leftover==0 ){ if( leftover==0 ){
@@ -628,11 +618,11 @@ static int allocateSpace(MemPage *pPage, int nByte){
addr = hdr+1; addr = hdr+1;
pc = get2byte(&data[addr]); pc = get2byte(&data[addr]);
assert( addr<pc ); assert( addr<pc );
assert( pc<=pPage->pBt->pageSize-4 ); assert( pc<=pPage->pBt->usableSize-4 );
while( (size = get2byte(&data[pc+2]))<nByte ){ while( (size = get2byte(&data[pc+2]))<nByte ){
addr = pc; addr = pc;
pc = get2byte(&data[addr]); pc = get2byte(&data[addr]);
assert( pc<=pPage->pBt->pageSize-4 ); assert( pc<=pPage->pBt->usableSize-4 );
assert( pc>=addr+size+4 || pc==0 ); assert( pc>=addr+size+4 || pc==0 );
if( pc==0 ){ if( pc==0 ){
assert( (cnt++)==0 ); assert( (cnt++)==0 );
@@ -643,7 +633,7 @@ static int allocateSpace(MemPage *pPage, int nByte){
} }
} }
assert( pc>0 && size>=nByte ); assert( pc>0 && size>=nByte );
assert( pc+size<=pPage->pBt->pageSize ); assert( pc+size<=pPage->pBt->usableSize );
if( size>nByte+4 ){ if( size>nByte+4 ){
int newStart = pc+nByte; int newStart = pc+nByte;
put2byte(&data[addr], newStart); put2byte(&data[addr], newStart);
@@ -677,17 +667,17 @@ static void freeSpace(MemPage *pPage, int start, int size){
assert( pPage->pBt!=0 ); assert( pPage->pBt!=0 );
assert( sqlite3pager_iswriteable(data) ); assert( sqlite3pager_iswriteable(data) );
assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) ); assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );
assert( end<=pPage->pBt->pageSize ); assert( end<=pPage->pBt->usableSize );
if( size<4 ) size = 4; if( size<4 ) size = 4;
/* Add the space back into the linked list of freeblocks */ /* Add the space back into the linked list of freeblocks */
addr = pPage->hdrOffset + 1; addr = pPage->hdrOffset + 1;
while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){ while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){
assert( pbegin<=pPage->pBt->pageSize-4 ); assert( pbegin<=pPage->pBt->usableSize-4 );
assert( pbegin>addr ); assert( pbegin>addr );
addr = pbegin; addr = pbegin;
} }
assert( pbegin<=pPage->pBt->pageSize-4 ); assert( pbegin<=pPage->pBt->usableSize-4 );
assert( pbegin>addr || pbegin==0 ); assert( pbegin>addr || pbegin==0 );
put2byte(&data[addr], start); put2byte(&data[addr], start);
put2byte(&data[start], pbegin); put2byte(&data[start], pbegin);
@@ -699,7 +689,7 @@ static void freeSpace(MemPage *pPage, int start, int size){
while( (pbegin = get2byte(&data[addr]))>0 ){ while( (pbegin = get2byte(&data[addr]))>0 ){
int pnext, psize; int pnext, psize;
assert( pbegin>addr ); assert( pbegin>addr );
assert( pbegin<pPage->pBt->pageSize-4 ); assert( pbegin<pPage->pBt->usableSize-4 );
pnext = get2byte(&data[pbegin]); pnext = get2byte(&data[pbegin]);
psize = get2byte(&data[pbegin+2]); psize = get2byte(&data[pbegin+2]);
if( pbegin + psize + 3 >= pnext && pnext>0 ){ if( pbegin + psize + 3 >= pnext && pnext>0 ){
@@ -750,7 +740,7 @@ static int initPage(
){ ){
int c, pc, i, hdr; int c, pc, i, hdr;
unsigned char *data; unsigned char *data;
int pageSize; int usableSize;
int sumCell = 0; /* Total size of all cells */ int sumCell = 0; /* Total size of all cells */
assert( pPage->pBt!=0 ); assert( pPage->pBt!=0 );
@@ -776,13 +766,13 @@ static int initPage(
pPage->isOverfull = 0; pPage->isOverfull = 0;
pPage->needRelink = 0; pPage->needRelink = 0;
pPage->idxShift = 0; pPage->idxShift = 0;
pageSize = pPage->pBt->pageSize; usableSize = pPage->pBt->usableSize;
/* Initialize the cell count and cell pointers */ /* Initialize the cell count and cell pointers */
pc = get2byte(&data[hdr+3]); pc = get2byte(&data[hdr+3]);
while( pc>0 ){ while( pc>0 ){
if( pc>=pageSize ) return SQLITE_CORRUPT; if( pc>=usableSize ) return SQLITE_CORRUPT;
if( pPage->nCell>pageSize ) return SQLITE_CORRUPT; if( pPage->nCell>usableSize ) return SQLITE_CORRUPT;
pPage->nCell++; pPage->nCell++;
pc = get2byte(&data[pc]); pc = get2byte(&data[pc]);
} }
@@ -801,18 +791,18 @@ static int initPage(
pc = get2byte(&data[hdr+1]); pc = get2byte(&data[hdr+1]);
while( pc>0 ){ while( pc>0 ){
int next, size; int next, size;
if( pc>=pageSize ) return SQLITE_CORRUPT; if( pc>=usableSize ) return SQLITE_CORRUPT;
next = get2byte(&data[pc]); next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]); size = get2byte(&data[pc+2]);
if( next>0 && next<=pc+size+3 ) return SQLITE_CORRUPT; if( next>0 && next<=pc+size+3 ) return SQLITE_CORRUPT;
pPage->nFree += size; pPage->nFree += size;
pc = next; 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 /* Sanity check: Cells and freespace and header must sum to the size
** a page. */ ** 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; return SQLITE_CORRUPT;
} }
@@ -834,16 +824,16 @@ static void zeroPage(MemPage *pPage, int flags){
assert( sqlite3pager_pagenumber(data)==pPage->pgno ); assert( sqlite3pager_pagenumber(data)==pPage->pgno );
assert( &data[pBt->pageSize] == (unsigned char*)pPage ); assert( &data[pBt->pageSize] == (unsigned char*)pPage );
assert( sqlite3pager_iswriteable(data) ); assert( sqlite3pager_iswriteable(data) );
memset(&data[hdr], 0, pBt->pageSize - hdr); memset(&data[hdr], 0, pBt->usableSize - hdr);
data[hdr] = flags; data[hdr] = flags;
first = hdr + 6 + 4*((flags&PTF_LEAF)==0); first = hdr + 6 + 4*((flags&PTF_LEAF)==0);
put2byte(&data[hdr+1], first); put2byte(&data[hdr+1], first);
put2byte(&data[first+2], pBt->pageSize - first); put2byte(&data[first+2], pBt->usableSize - first);
sqliteFree(pPage->aCell); sqliteFree(pPage->aCell);
pPage->aCell = 0; pPage->aCell = 0;
pPage->nCell = 0; pPage->nCell = 0;
pPage->nCellAlloc = 0; pPage->nCellAlloc = 0;
pPage->nFree = pBt->pageSize - first; pPage->nFree = pBt->usableSize - first;
pPage->intKey = (flags & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->intKey = (flags & (PTF_INTKEY|PTF_LEAFDATA))!=0;
pPage->zeroData = (flags & PTF_ZERODATA)!=0; pPage->zeroData = (flags & PTF_ZERODATA)!=0;
pPage->leafData = (flags & PTF_LEAFDATA)!=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 ** reaches zero. We need to unref the pParent pointer when that
** happens. ** happens.
*/ */
static void pageDestructor(void *pData){ static void pageDestructor(void *pData, int pageSize){
MemPage *pPage = (MemPage*)&((char*)pData)[SQLITE_PAGE_SIZE]; MemPage *pPage = (MemPage*)&((char*)pData)[pageSize];
assert( pPage->isInit==0 || pPage->needRelink==0 ); assert( pPage->isInit==0 || pPage->needRelink==0 );
if( pPage->pParent ){ if( pPage->pParent ){
MemPage *pParent = pPage->pParent; MemPage *pParent = pPage->pParent;
@@ -978,29 +968,11 @@ int sqlite3BtreeOpen(
pBt->pPage1 = 0; pBt->pPage1 = 0;
pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager); pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
pBt->pageSize = SQLITE_PAGE_SIZE; /* FIX ME - read from header */ pBt->pageSize = SQLITE_PAGE_SIZE; /* FIX ME - read from header */
pBt->usableSize = pBt->pageSize;
pBt->maxEmbedFrac = 64; /* FIX ME - read from header */ pBt->maxEmbedFrac = 64; /* FIX ME - read from header */
pBt->minEmbedFrac = 32; /* FIX ME - read from header */ pBt->minEmbedFrac = 32; /* FIX ME - read from header */
pBt->minLeafFrac = 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; *ppBtree = pBt;
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1071,15 +1043,47 @@ static int lockBtree(Btree *pBt){
/* Do some checking to help insure the file we opened really is /* Do some checking to help insure the file we opened really is
** a valid database file. ** a valid database file.
*/ */
rc = SQLITE_NOTADB;
if( sqlite3pager_pagecount(pBt->pPager)>0 ){ if( sqlite3pager_pagecount(pBt->pPager)>0 ){
if( memcmp(pPage1->aData, zMagicHeader, 16)!=0 ){ u8 *page1 = pPage1->aData;
rc = SQLITE_NOTADB; if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed; 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; pBt->pPage1 = pPage1;
return rc; return SQLITE_OK;
page1_init_failed: page1_init_failed:
releasePage(pPage1); releasePage(pPage1);
@@ -1122,10 +1126,14 @@ static int newDatabase(Btree *pBt){
if( rc ) return rc; if( rc ) return rc;
memcpy(data, zMagicHeader, sizeof(zMagicHeader)); memcpy(data, zMagicHeader, sizeof(zMagicHeader));
assert( sizeof(zMagicHeader)==16 ); assert( sizeof(zMagicHeader)==16 );
put2byte(&data[16], SQLITE_PAGE_SIZE); put2byte(&data[16], pBt->pageSize);
data[18] = 1; data[18] = 1;
data[19] = 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 ); zeroPage(pP1, PTF_INTKEY|PTF_LEAF );
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1605,7 +1613,7 @@ static int getPayload(
if( amt>0 ){ if( amt>0 ){
nextPage = get4byte(&aPayload[info.nLocal]); nextPage = get4byte(&aPayload[info.nLocal]);
} }
ovflSize = pBt->pageSize - 4; ovflSize = pBt->usableSize - 4;
while( amt>0 && nextPage ){ while( amt>0 && nextPage ){
rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload); rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload);
if( rc!=0 ){ if( rc!=0 ){
@@ -2330,7 +2338,7 @@ static int freePage(MemPage *pPage){
rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk); rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
if( rc ) return rc; if( rc ) return rc;
k = get4byte(&pTrunk->aData[4]); 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 /* The trunk is full. Turn the page being freed into a new
** trunk page with no leaves. */ ** trunk page with no leaves. */
rc = sqlite3pager_write(pPage->aData); rc = sqlite3pager_write(pPage->aData);
@@ -2458,7 +2466,7 @@ static int fillInCell(
pPrior = pOvfl->aData; pPrior = pOvfl->aData;
put4byte(pPrior, 0); put4byte(pPrior, 0);
pPayload = &pOvfl->aData[4]; pPayload = &pOvfl->aData[4];
spaceLeft = pBt->pageSize - 4; spaceLeft = pBt->usableSize - 4;
} }
n = nPayload; n = nPayload;
if( n>spaceLeft ) n = spaceLeft; if( n>spaceLeft ) n = spaceLeft;
@@ -2491,7 +2499,7 @@ static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
assert( pBt->pPager!=0 ); assert( pBt->pPager!=0 );
aData = sqlite3pager_lookup(pBt->pPager, pgno); aData = sqlite3pager_lookup(pBt->pPager, pgno);
if( aData ){ if( aData ){
pThis = (MemPage*)&aData[pBt->pageSize]; pThis = (MemPage*)&aData[pBt->usableSize];
if( pThis->isInit ){ if( pThis->isInit ){
if( pThis->pParent!=pNewParent ){ if( pThis->pParent!=pNewParent ){
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData); 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( sz==cellSize(pPage, pPage->aCell[idx]) );
assert( sqlite3pager_iswriteable(pPage->aData) ); assert( sqlite3pager_iswriteable(pPage->aData) );
assert( pPage->aCell[idx]>=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; data = pPage->aData;
pc = Addr(pPage->aCell[idx]) - Addr(data); 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); freeSpace(pPage, pc, sz);
for(j=idx; j<pPage->nCell-1; j++){ for(j=idx; j<pPage->nCell-1; j++){
pPage->aCell[j] = pPage->aCell[j+1]; pPage->aCell[j] = pPage->aCell[j+1];
@@ -2654,7 +2662,7 @@ static void relinkCellList(MemPage *pPage){
idxFrom = pPage->hdrOffset+3; idxFrom = pPage->hdrOffset+3;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData); int idx = Addr(pPage->aCell[i]) - Addr(pPage->aData);
assert( idx>pPage->hdrOffset && idx<pPage->pBt->pageSize ); assert( idx>pPage->hdrOffset && idx<pPage->pBt->usableSize );
put2byte(&pPage->aData[idxFrom], idx); put2byte(&pPage->aData[idxFrom], idx);
idxFrom = idx; idxFrom = idx;
} }
@@ -2681,15 +2689,15 @@ static void relinkCellList(MemPage *pPage){
static void movePage(MemPage *pTo, MemPage *pFrom){ static void movePage(MemPage *pTo, MemPage *pFrom){
uptr from, to; uptr from, to;
int i; int i;
int pageSize; int usableSize;
int ofst; int ofst;
assert( pTo->hdrOffset==0 ); assert( pTo->hdrOffset==0 );
assert( pFrom->isInit ); assert( pFrom->isInit );
ofst = pFrom->hdrOffset; ofst = pFrom->hdrOffset;
pageSize = pFrom->pBt->pageSize; usableSize = pFrom->pBt->usableSize;
sqliteFree(pTo->aCell); 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)); memcpy(pTo, pFrom, offsetof(MemPage, aData));
pFrom->isInit = 0; pFrom->isInit = 0;
pFrom->aCell = 0; pFrom->aCell = 0;
@@ -2700,7 +2708,7 @@ static void movePage(MemPage *pTo, MemPage *pFrom){
from = Addr(&pFrom->aData[ofst]); from = Addr(&pFrom->aData[ofst]);
for(i=0; i<pTo->nCell; i++){ for(i=0; i<pTo->nCell; i++){
uptr x = Addr(pTo->aCell[i]); uptr x = Addr(pTo->aCell[i]);
if( x>from && x<from+pageSize-ofst ){ if( x>from && x<from+usableSize-ofst ){
*((uptr*)&pTo->aCell[i]) = x + to - from; *((uptr*)&pTo->aCell[i]) = x + to - from;
} }
} }
@@ -2772,6 +2780,7 @@ static int balance(MemPage *pPage){
int usableSpace; /* Bytes in pPage beyond the header */ int usableSpace; /* Bytes in pPage beyond the header */
int pageFlags; /* Value of pPage->aData[0] */ int pageFlags; /* Value of pPage->aData[0] */
int subtotal; /* Subtotal of bytes in cells on one page */ 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 *extraUnref = 0; /* Unref this page if not zero */
MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apOld[NB]; /* pPage and up to two siblings */
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */ 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[] */ Pgno pgnoNew[NB+1]; /* Page numbers for each page in apNew[] */
int idxDiv[NB]; /* Indices of divider cells in pParent */ int idxDiv[NB]; /* Indices of divider cells in pParent */
u8 *apDiv[NB]; /* 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 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 */ 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 */ u8 *apCell[(MX_CELL+2)*NB]; /* All cells from pages being balanced */
int szCell[(MX_CELL+2)*NB]; /* Local size of all cells */ int szCell[(MX_CELL+2)*NB]; /* Local size of all cells */
u8 aCopy[NB][MX_PAGE_SIZE+sizeof(MemPage)]; /* Space for apCopy[] */ 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 ** Return without doing any work if pPage is neither overfull nor
@@ -2795,7 +2803,7 @@ static int balance(MemPage *pPage){
assert( pPage->isInit ); assert( pPage->isInit );
assert( sqlite3pager_iswriteable(pPage->aData) ); assert( sqlite3pager_iswriteable(pPage->aData) );
pBt = pPage->pBt; pBt = pPage->pBt;
if( !pPage->isOverfull && pPage->nFree<pBt->pageSize*2/3 && pPage->nCell>=2){ if( !pPage->isOverfull && pPage->nFree<pBt->usableSize*2/3 && pPage->nCell>=2){
relinkCellList(pPage); relinkCellList(pPage);
return SQLITE_OK; 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)); TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno));
} }
}else{ }else{
memcpy(pPage->aData, pChild->aData, pBt->pageSize); memcpy(pPage->aData, pChild->aData, pBt->usableSize);
pPage->isInit = 0; pPage->isInit = 0;
pPage->pParent = 0; pPage->pParent = 0;
rc = initPage(pPage, 0); rc = initPage(pPage, 0);
@@ -2974,7 +2982,7 @@ static int balance(MemPage *pPage){
*/ */
for(i=0; i<nOld; i++){ for(i=0; i<nOld; i++){
MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)]; MemPage *p = apCopy[i] = (MemPage*)&aCopy[i+1][-sizeof(MemPage)];
p->aData = &((u8*)p)[-pBt->pageSize]; p->aData = &((u8*)p)[-pBt->usableSize];
p->aCell = 0; p->aCell = 0;
p->hdrOffset = 0; p->hdrOffset = 0;
movePage(p, apOld[i]); 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 ** Load pointers to all cells on sibling pages and the divider cells
** into the local apCell[] array. Make copies of 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 ** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied ** 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 ** child pointers. If siblings are not leaves, then all cell in
** apCell[] include child pointers. Either way, all cells in apCell[] ** apCell[] include child pointers. Either way, all cells in apCell[]
** are alike. ** are alike.
@@ -3003,16 +3012,20 @@ static int balance(MemPage *pPage){
nCell++; nCell++;
} }
if( i<nOld-1 ){ if( i<nOld-1 ){
int sz = cellSize(pParent, apDiv[i]);
if( leafData ){ if( leafData ){
int sz = cellSize(pParent, apDiv[i]);
dropCell(pParent, nxDiv, sz); dropCell(pParent, nxDiv, sz);
}else{ }else{
szCell[nCell] = cellSize(pParent, apDiv[i]); u8 *pTemp;
memcpy(aTemp[i], apDiv[i], szCell[nCell]); szCell[nCell] = sz;
apCell[nCell] = &aTemp[i][leafCorrection]; pTemp = &aSpace[iSpace];
dropCell(pParent, nxDiv, szCell[nCell]); iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
memcpy(pTemp, apDiv[i], sz);
apCell[nCell] = pTemp+leafCorrection;
dropCell(pParent, nxDiv, sz);
szCell[nCell] -= leafCorrection; szCell[nCell] -= leafCorrection;
assert( get4byte(&aTemp[i][2])==pgnoOld[i] ); assert( get4byte(pTemp+2)==pgnoOld[i] );
if( !pOld->leaf ){ if( !pOld->leaf ){
assert( leafCorrection==0 ); assert( leafCorrection==0 );
/* The right pointer of the child page pOld becomes the left /* 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 ** This little patch of code is critical for keeping the tree
** balanced. ** balanced.
*/ */
usableSpace = pBt->pageSize - 10 + leafCorrection; usableSpace = pBt->usableSize - 10 + leafCorrection;
for(subtotal=k=i=0; i<nCell; i++){ for(subtotal=k=i=0; i<nCell; i++){
subtotal += szCell[i]; subtotal += szCell[i];
if( subtotal > usableSpace ){ if( subtotal > usableSpace ){
@@ -3165,12 +3178,16 @@ static int balance(MemPage *pPage){
CellInfo info; CellInfo info;
j--; j--;
parseCell(pNew, apCell[j], &info); parseCell(pNew, apCell[j], &info);
pCell = aInsBuf[i]; pCell = &aSpace[iSpace];
fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz); fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
pTemp = 0; pTemp = 0;
}else{ }else{
pCell -= 4; pCell -= 4;
pTemp = aInsBuf[i]; pTemp = &aSpace[iSpace];
iSpace += sz;
assert( iSpace<=sizeof(aSpace) );
} }
insertCell(pParent, nxDiv, pCell, sz, pTemp); insertCell(pParent, nxDiv, pCell, sz, pTemp);
put4byte(&pParent->aCell[nxDiv][2], pNew->pgno); put4byte(&pParent->aCell[nxDiv][2], pNew->pgno);
@@ -3630,7 +3647,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
i = 0; i = 0;
assert( hdr == (pgno==1 ? 100 : 0) ); assert( hdr == (pgno==1 ? 100 : 0) );
idx = get2byte(&data[hdr+3]); idx = get2byte(&data[hdr+3]);
while( idx>0 && idx<=pBt->pageSize ){ while( idx>0 && idx<=pBt->usableSize ){
CellInfo info; CellInfo info;
Pgno child; Pgno child;
unsigned char *pCell = &data[idx]; unsigned char *pCell = &data[idx];
@@ -3672,7 +3689,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
nFree = 0; nFree = 0;
i = 0; i = 0;
idx = get2byte(&data[hdr+1]); idx = get2byte(&data[hdr+1]);
while( idx>0 && idx<pPage->pBt->pageSize ){ while( idx>0 && idx<pPage->pBt->usableSize ){
int sz = get2byte(&data[idx+2]); int sz = get2byte(&data[idx+2]);
sprintf(range,"%d..%d", idx, idx+sz-1); sprintf(range,"%d..%d", idx, idx+sz-1);
nFree += sz; nFree += sz;
@@ -3686,7 +3703,7 @@ int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
} }
if( recursive && !pPage->leaf ){ if( recursive && !pPage->leaf ){
idx = get2byte(&data[hdr+3]); idx = get2byte(&data[hdr+3]);
while( idx>0 && idx<pBt->pageSize ){ while( idx>0 && idx<pBt->usableSize ){
unsigned char *pCell = &data[idx]; unsigned char *pCell = &data[idx];
sqlite3BtreePageDump(pBt, get4byte(&pCell[2]), 1); sqlite3BtreePageDump(pBt, get4byte(&pCell[2]), 1);
idx = get2byte(pCell); idx = get2byte(pCell);
@@ -3735,7 +3752,7 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult){
aResult[4] = pPage->nFree; aResult[4] = pPage->nFree;
cnt = 0; cnt = 0;
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]); idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
while( idx>0 && idx<pPage->pBt->pageSize ){ while( idx>0 && idx<pPage->pBt->usableSize ){
cnt++; cnt++;
idx = get2byte(&pPage->aData[idx]); idx = get2byte(&pPage->aData[idx]);
} }
@@ -3880,7 +3897,7 @@ static int checkTreePage(
u8 *data; u8 *data;
BtCursor cur; BtCursor cur;
Btree *pBt; Btree *pBt;
int maxLocal, pageSize; int maxLocal, usableSize;
char zMsg[100]; char zMsg[100];
char zContext[100]; char zContext[100];
char hit[MX_PAGE_SIZE]; char hit[MX_PAGE_SIZE];
@@ -3888,7 +3905,7 @@ static int checkTreePage(
/* Check that the page exists /* Check that the page exists
*/ */
cur.pBt = pBt = pCheck->pBt; cur.pBt = pBt = pCheck->pBt;
pageSize = pBt->pageSize; usableSize = pBt->usableSize;
if( iPage==0 ) return 0; if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){ if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){
@@ -3921,7 +3938,7 @@ static int checkTreePage(
sz = info.nData; sz = info.nData;
if( !pPage->intKey ) sz += info.nKey; if( !pPage->intKey ) sz += info.nKey;
if( sz>info.nLocal ){ 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); checkList(pCheck, 0, get4byte(&pCell[info.iOverflow]),nPage,zContext);
} }
@@ -3944,23 +3961,23 @@ static int checkTreePage(
/* Check for complete coverage of the page /* Check for complete coverage of the page
*/ */
memset(hit, 0, pageSize); memset(hit, 0, usableSize);
memset(hit, 1, pPage->hdrOffset+10-4*(pPage->leaf)); memset(hit, 1, pPage->hdrOffset+10-4*(pPage->leaf));
data = pPage->aData; data = pPage->aData;
hdr = pPage->hdrOffset; hdr = pPage->hdrOffset;
for(cnt=0, i=get2byte(&data[hdr+3]); i>0 && i<pageSize && cnt<10000; cnt++){ for(cnt=0, i=get2byte(&data[hdr+3]); i>0 && i<usableSize && cnt<10000; cnt++){
int size = cellSize(pPage, &data[i]); int size = cellSize(pPage, &data[i]);
int j; int j;
for(j=i+size-1; j>=i; j--) hit[j]++; for(j=i+size-1; j>=i; j--) hit[j]++;
i = get2byte(&data[i]); i = get2byte(&data[i]);
} }
for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<pageSize && cnt<10000; cnt++){ for(cnt=0, i=get2byte(&data[hdr+1]); i>0 && i<usableSize && cnt<10000; cnt++){
int size = get2byte(&data[i+2]); int size = get2byte(&data[i+2]);
int j; int j;
for(j=i+size-1; j>=i; j--) hit[j]++; for(j=i+size-1; j>=i; j--) hit[j]++;
i = get2byte(&data[i]); i = get2byte(&data[i]);
} }
for(i=cnt=0; i<pageSize; i++){ for(i=cnt=0; i<usableSize; i++){
if( hit[i]==0 ){ if( hit[i]==0 ){
cnt++; cnt++;
}else if( hit[i]>1 ){ }else if( hit[i]>1 ){
@@ -4070,7 +4087,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
if( pBtTo->pCursor ) return SQLITE_BUSY; 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); rc = sqlite3pager_overwrite(pBtTo->pPager, 1, pBtFrom->pPage1);
nToPage = sqlite3pager_pagecount(pBtTo->pPager); nToPage = sqlite3pager_pagecount(pBtTo->pPager);
nPage = sqlite3pager_pagecount(pBtFrom->pPager); nPage = sqlite3pager_pagecount(pBtFrom->pPager);

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** 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 "os.h" /* Must be first to enable large file support */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -181,14 +181,14 @@ struct Pager {
u32 cksumInit; /* Quasi-random value added to every checksum */ u32 cksumInit; /* Quasi-random value added to every checksum */
int stmtNRec; /* Number of records in stmt subjournal */ int stmtNRec; /* Number of records in stmt subjournal */
int nExtra; /* Add this many bytes to each in-memory page */ 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 nPage; /* Total number of in-memory pages */
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
int mxPage; /* Maximum number of pages to hold in cache */ int mxPage; /* Maximum number of pages to hold in cache */
int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */ int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */ void *pCodecArg; /* First argument to xCodec() */
int pageSize; /* Page size in bytes */
u8 journalOpen; /* True if journal file descriptors is valid */ u8 journalOpen; /* True if journal file descriptors is valid */
u8 journalStarted; /* True if header of journal is synced */ u8 journalStarted; /* True if header of journal is synced */
u8 useJournal; /* Use a rollback journal on this file */ 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 ** 1 which is held in use in order to keep the lock on the database
** active. ** active.
*/ */
void *pData;
assert( pPg->nRef==0 || pPg->pgno==1 ); 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 ){ if( pPager->xDestructor ){
pPager->xDestructor(PGHDR_TO_DATA(pPg)); pPager->xDestructor(pData, pPager->pageSize);
} }
pPg->dirty = 0; pPg->dirty = 0;
pPg->needSync = 0; pPg->needSync = 0;
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); CODEC(pPager, pData, pPg->pgno, 3);
} }
return rc; return rc;
} }
@@ -1034,7 +1036,7 @@ int sqlite3pager_open(
** The destructor is not called as a result sqlite3pager_close(). ** The destructor is not called as a result sqlite3pager_close().
** Destructors are only called by sqlite3pager_unref(). ** 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; pPager->xDestructor = xDesc;
} }
@@ -1708,7 +1710,7 @@ int sqlite3pager_unref(void *pData){
pPager->pFirstSynced = pPg; pPager->pFirstSynced = pPg;
} }
if( pPager->xDestructor ){ if( pPager->xDestructor ){
pPager->xDestructor(pData); pPager->xDestructor(pData, pPager->pageSize);
} }
/* When all pages reach the freelist, drop the read lock from /* When all pages reach the freelist, drop the read lock from

View File

@@ -13,11 +13,11 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** 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. ** 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 ** 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 sqlite3pager_open(Pager **ppPager, const char *zFilename,
int nPage, int nExtra, int useJournal); 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); void sqlite3pager_set_cachesize(Pager*, int);
int sqlite3pager_close(Pager *pPager); int sqlite3pager_close(Pager *pPager);
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage); 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*); void sqlite3pager_refdump(Pager*);
int pager3_refinfo_enable; int pager3_refinfo_enable;
#endif #endif