-C :-)\s(CVS\s1713)
-D 2001-01-29T01:27:20
+C Working\sbetter\swith\sWin95.\nContinued\swork\son\sthe\snew\sdb.c\sbackend.\s(CVS\s1714)
+D 2001-01-31T13:28:08
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 7efa81e2985b45ba73db27d55b70cc927f5abfd7
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F doc/report1.txt ad0a41513479f1be0355d1f3f074e66779ff2282
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4
-F src/db.c c789cd4491afcdeddc2327107dcf3d15d4558e1a
-F src/db.h 7109f0acd9694c58529fbf98ad6f51a74fb95bc8
+F src/db.c fff070e77423bbf98f5b138f23c605006a61066d
+F src/db.h 6c8b8b6777f7c55b37cb851e9fe4bc3f379920c0
F src/dbbe.c 162d29b09ac379f160892c5795efc14099dcc8eb
F src/dbbe.h 0435a36906a839cce062608f51bd9d3e79878fec
F src/dbbegdbm.c 5bfcb1b4ee47a98c5eae83041e9716cd3233fd0e
F src/parse.y 25ee4d8efccc4b247c32fe4ab194e3dd8fd5a4ee
F src/pg.c 2981173b2a752ef3578168e7af1a32ff22b70db6
F src/pg.h a95c4803a1aae99449aa2c0a1af0c8d863a3f340
-F src/printf.c 1efb6b3e7f28a93be57132de3f8f400d2ac1460e
-F src/random.c 3dc42fb35d834901577aa547308ff3c8941fea25
+F src/printf.c af0dc65c293427272e1949c7807b1d88f10004fd
+F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
F src/select.c 0cadab95c8011ddbffe804de94f12f3c0e317863
F src/shell.c 441e20913cde0bb71281f4027623c623530241cd
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 7c1a53f020418d89d13ed2fe9c477ff54540755d
F src/sqliteInt.h fd513fa6b7ac94919f85ebfa183aaa194284ce16
F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9
-F src/tclsqlite.c 178adf318eab2ff480c288a87541d4ab1c37d985
+F src/tclsqlite.c 2a925e1835c348f07dd17c87d95ae9a577833407
F src/tokenize.c 6843f1d7a5d2ee08ceb10bdecfcc8684131ffcf7
F src/update.c 9692fbac8e95fdbc5318d39db576aa6c57b9c8ab
F src/util.c 0298100e6427a4b644f767ede12276fa7170fbb6
F src/where.c fcc2c2c84fe81a008485a32c680db3eb0aee5d22
F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
-F test/dbbe.test bd2cd9fe84c6d69b6ae42ac5f55b1e940bdca886
+F test/dbbe.test 27deeebf2a01da97cabaab8dc7f34ca3b51a0123
F test/delete.test 402ee3ccb6e544582d24c573ef70b34d09583ae7
F test/expr.test 48273bf48a15d226c35829f702af4254c0ff6795
F test/func.test 02aed8845b98bde1043dda97455de1d37238ebb3
F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31
F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5
F test/table.test eaa25951c0f18615763cd3dc248ea4bc38739c05
-F test/tester.tcl e053e14aa986c05a87de0b5635e76566f1e022ae
+F test/tester.tcl e24caef6d07c58c16b24e7afc967464b288a4065
F test/update.test 62f6ce99ff31756aab0ca832ff6d34c5a87b6250
F test/vacuum.test 2127748ff4ddb409212efbb6d9fb9c469ea1b49c
F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397
F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
F www/c_interface.tcl 11be2d5826eb7d6efd629751d3b483c1ed78ba14
F www/changes.tcl cb276a239c98524731e2780c70deb01b2e7e4bcc
-F www/crosscompile.tcl bee79c34f6c3f162ec1c6f5294e79f73651d27ee
+F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
F www/index.tcl b19418d506f90968deef972bf1b427d98bdf13e0
F www/lang.tcl 9192e114b19987e630a41e879585b87006eb84a1
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P edb01b1275c3de7c398522b5826c898917811247
-R fad18d8d52121b49568c3b69513e9996
+P 3259a53111bd19417e78160174bd67c69098494a
+R 75bfcecb552e742e2d0e7291a0cc0ff8
U drh
-Z f548d6e222a005fc922c38f88384f46b
+Z 45825268c6b006d5b2dd82f20b34d079
** http://www.hwaci.com/drh/
**
*************************************************************************
-** $Id: db.c,v 1.5 2001/01/29 01:27:20 drh Exp $
+** $Id: db.c,v 1.6 2001/01/31 13:28:08 drh Exp $
*/
#include "sqliteInt.h"
#include "pg.h"
Pgr *pPgr; /* The pager for the database */
DbCursor *pCursor; /* All open cursors */
int inTransaction; /* True if a transaction is in progress */
- int nContents; /* Number of slots in aContents[] */
- int nAlloc; /* Space allocated for aContents[] */
- u32 *aContents; /* Contents table for the database */
+ u32 freeList; /* List of free blocks */
+ int nTable; /* Number of slots in aContent[] */
+ u32 *aTable; /* Root page numbers for all tables */
};
/*
int pgno; /* The page number */
u32 *aPage; /* The page data */
int idx; /* Index into pPage[] */
- int hashLB; /* Lower bound on hash at this level */
- int hashUB; /* Upper bound on hash at this level */
};
/*
};
/*
-** Used for rebalancing
-*/
-typedef struct DbEntry DbEntry;
-struct DbEntry {
- int nByte; /* Space needed on leaf to record this entry */
- int pgno; /* Page on which this entry is currently found */
- int idx; /* Index slot in part that points to leaf "pgno" */
- u32 *aPage; /* Pointer to the leaf for this entry */
- u32 *aEntry; /* Pointer to the actual text of this entry */
- DbEntry *pNext; /* Next entry in a list of them all */
-};
-typedef struct DbEntrySet DbEntrySet;
-struct DbEntrySet {
- u32 *pIndex; /* The index node above the leaf pages being balanced */
- int nAlloc; /* Number of slots allocated in aEntry[] */
- int nEntry; /* Number of slots in aEntry[] actually used */
- DbEntry *pFirst; /* First entry in hash order */
- DbEntry aEntry[100]; /* Descriptions of actual database entries */
-};
-
-/*
-** The first word of every page is some combination of these values
-** used to indicate its function.
-*/
-#define BLOCK_MAGIC 0x24e47190
-#define BLOCK_INDEX 0x00000001
-#define BLOCK_LEAF 0x00000002
-#define BLOCK_FREE 0x00000003
-#define BLOCK_OVERFLOW 0x00000004
-#define BLOCK_CONTENTS 0x00000005
-#define BLOCK_MAGIC_MASK 0xfffffff8
-#define BLOCK_TYPE_MASK 0x00000007
-
-/*
-** Free blocks:
+** Data layouts
**
-** 0. BLOCK_MAGIC | BLOCK_FREE
-** 1. address of next block on freelist
+** LEAF:
+** x[0] Magic number: BLOCK_LEAF
+** x[1] If root page, total number of entries in this table
+** ... One or more entries follow the leaf.
**
-** Leaf blocks:
+** Entry:
+** x[N+0] Number of u32-sized words in this entry
+** x[N+1] Hash value for this entry
+** x[N+2] Number of bytes of key in the payload
+** x[N+3] Number of bytes of data in the payload
+** x{N+4]... The payload area.
**
-** 0. BLOCK_MAGIC | BLOCK_LEAF
-** 1. number of table entries (only used if a table root block)
-** entries....
-** 0. size of this entry (measured in u32's)
-** 1. hash
-** 2. keysize (in bytes)
-** 3. datasize (in bytes)
-** 4. payload
+** INDEX:
+** x[0] Magic number: BLOCK_INDEX
+** x[1] If root page: total number of entries in this table
+** x[2] Number of slots in this index (Max value of N)
+** x[2*N+3] Page number containing entries with hash <= x[2*N+4]
+** x[2*N+4] The maximum hash value for entries on page x[2*N+3].
**
-** Payload area:
+** FREE:
+** x[0] Magic number: BLOCK_FREE
+** x[1] Page number of the next free block on the free list
**
-** * up to LOCAL_PAYLOAD bytes of data
-** * 10 page number of direct blocks
-** * 1 indirect block
-** * 1 double-indirect block
-**
-** Index block:
-**
-** 0. BLOCK_MAGIC | BLOCK_INDEX
-** 1. number of table entries (only used if a table root block)
-** 2. entries in this index block
-** entries...
-** 0. largest hash value for pgno
-** 1. pgno of subblock
-**
-** Contents block: (The first page in the file)
-** 0. BLOCK_MAGIC | BLOCK_CONTENTS
-** 1. zero
-** 2. number of bytes of payload
-** 3. freelist
-** 4... root pages numbers of tables
+** PAGE1:
+** x[0] Magic number: BLOCK_PAGE1
+** x[1] First page of the freelist
+** x[2] Number of tables in this database
+** x[N+3] Root page for table N
+
+/*
+** The first word of every page is some combination of these values
+** used to indicate its function.
*/
+#define BLOCK_PAGE1 0x24e47191
+#define BLOCK_INDEX 0x7ac53b46
+#define BLOCK_LEAF 0x60c45eef
+#define BLOCK_FREE 0x5b2dda47
/*
** The number of u32-sized objects that will fit on one page.
#define N_DIRECT 10
/*
-** The maximum amount of payload that will fit on on the same
-** page as a leaf, assuming the leaf contains only a single
-** database entry and the entry uses no overflow pages.
+** The maximum amount of payload (in bytes) that will fit on on the same
+** page as a leaf. In other words, the maximum amount of payload
+** that does not require any overflow pages.
+**
+** This size is chosen so that a least 3 entry will fit on every
+** leaf. That guarantees it will always be possible to add a new
+** entry after a page split.
*/
-#define LOCAL_PAYLOAD (SQLITE_PAGE_SIZE - (8+N_DIRECT)*sizeof(u32))
+#define LOCAL_PAYLOAD (((U32_PER_PAGE-2)/3 - (6+N_DIRECT))*sizeof(u32))
/*
** Allocate a new page. Return both the page number and a pointer
** to the page data. The calling function is responsible for unref-ing
** the page when it is no longer needed.
+**
+** The page is obtained from the freelist if there is anything there.
+** If the freelist is empty, the new page comes from the end of the
+** database file.
*/
int allocPage(Db *pDb, u32 *pPgno, u32 **ppPage){
u32 pgno;
int rc;
- if( pDb->aContent==0 ) return SQLITE_NOMEM;
+ if( pDb->aTable==0 ) return SQLITE_NOMEM;
/* Try to reuse a page from the freelist
*/
- pgno = pDb->aContent[0];
- if( pgno!=0 ){
- rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage);
+ if( pDb->freeList==0 ){
+ u32 *pPage;
+ rc = sqlitePgGet(pDb->pPgr, pDb->freeList, &pPage);
if( rc==SQLITE_OK ){
- pDb->aContent[0] = pFree[1];
- *pPgno = pgno;
- memset(*ppPage, 0, SQLITE_PAGE_SIZE);
- return SQLITE_OK;
+ if( pPage[0]==BLOCK_FREE ){
+ *pPgno = pDb->freeList;
+ *ppPage = aPage;
+ pDb->freeList = aPage[1];
+ memset(*ppPage, 0, SQLITE_PAGE_SIZE);
+ return SQLITE_OK;
+ }
+ /* This only happens if we have database corruption */
+ sqlitePgUnref(pPage);
}
}
** Return a page to the freelist and dereference the page.
*/
static void freePage(DB *pDb, u32 pgno, u32 *aPage){
- if( pDb->aContent==0 ) return;
if( pgno==0 ) return
if( aPage==0 ){
int rc;
rc = sqlitePgGet(pDb->pPgr, pgno, &aPage);
if( rc!=SQLITE_OK ) return;
}
- aPage[0] = BLOCK_MAGIC | BLOCK_FREE;
- aPage[1] = pDb->aContent[0];
+ assert( sqlitePgNum(aPage)==pgno );
+ aPage[0] = BLOCK_FREE;
+ aPage[1] = pDb->freeList;
+ pDb->freeList = pgno;
memset(&aPage[2], 0, SQLITE_PAGE_SIZE - 2*sizeof(u32));
- pDb->aContent[0] = pgno;
sqlitePgTouch(aPage);
sqlitePgUnref(aPage);
}
}
/*
-** Release any and all overflow pages associated with data starting
-** with byte "newSize". oldSize is the amount of payload before doing
-** the free operation.
+** Resize the payload area. If the payload area descreases in size,
+** this routine deallocates unused overflow pages. If the payload
+** area increases in size, this routine is a no-op.
*/
-static int payloadFree(Db *pDb, u32 *aPage, int newSize, int oldSize){
+static int payloadResize(Db *pDb, u32 *aPage, int oldSize, int newSize){
int i, j; /* Loop counters */
int first, last; /* Indices of first and last pages to be freed */
int rc; /* Return code from sqlitePgGet() */
** Allocate space for the content table in the given Db structure.
** return SQLITE_OK on success and SQLITE_NOMEM if it fails.
*/
-static int sqliteDbExpandContent(Db *pDb, int newSize){
- if( pDb->nAlloc>=newSize ) return SQLITE_OK;
- pDb->nAlloc = newSize;
- pDb->aContent = sqliteRealloc( pDb->aContent, pDb->nAlloc*sizeof(u32));
- if( pDb->aContent==0 ){
- pDb->nContent = 0;
- pDb->nAlloc = 0;
+static int sqliteDbExpandTableArray(Db *pDb){
+ pDb->aTable = sqliteRealloc( pDb->aTable, pDb->nTable*sizeof(u32));
+ if( pDb->aTable==0 ){
pDb->inTranaction = 0;
return SQLITE_NOMEM;
}
if( rc!=0 ) goto open_err;
if( nPage==0 ){
sqlitePgBeginTransaction(pDb->pPgr);
- aPage1[0] = BLOCK_MAGIC|BLOCK_CONTENT;
- aPage1[2] = sizeof(u32)*10;
+ aPage1[0] = BLOCK_PAGE1;
sqlitePgTouch(aPage1);
sqlitePgCommit(pDb->pPgr);
}
- pDb->nContent = aPage1[2]/sizeof(u32);
- pDb->nAlloc = 0;
- rc = sqliteDbExpandContent(pDb, pDb->nContent);
+ pDb->freeList = aPage[1];
+ pDb->nTable = aPage[2];
+ rc = sqliteDbExpandTableArray(pDb);
if( rc!=SQLITE_OK ) goto open_err;
- rc = payloadRead(pDb, &aPage1[3], 0, aPage1[2], pDb->aContent);
+ rc = payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
sqlitePgUnref(aPage1);
if( rc!=SQLITE_OK ) goto open_err;
*ppDb = pDb;
}
rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
if( rc!=SQLITE_OK ) return rc;
- aPage1[2] = pDb->nContent*sizeof(u32);
- payloadWrite(pDb, 0, aPage1[2], pDb->aContent);
+ aPage1[1] = pDb->freeList;
+ aPage1[2] = pDb->nTable;
+ payloadWrite(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
sqlitePgUnref(aPage1);
rc = sqlitePgCommit(pDb->pPgr);
if( rc!=SQLITE_OK ) return rc;
if( rc!=SQLITE_OK ) return rc;
rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
if( rc!=SQLITE_OK ) return rc;
- pDb->nContent = SWB(aPage1[3]) + 2;
- if( sqliteDbExpandContent(pDb, pDb->nContent)!=SQLITE_OK ){
+ pDb->freeList = aPage1[1];
+ pDb->nTable = aPage1[2];
+ if( sqliteDbExpandTableArray(pDb)!=SQLITE_OK ){
return SQLITE_NOMEM;
}
- payloadRead(pDb, &aPage1[3], 0, pDb->nContent*sizeof(u32), pDb->aContent);
+ payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
+ sqlitePgUnref(aPage1);
pDb->inTransaction = 0;
return SQLITE_OK;
}
** that is used to open a cursor into that table into *pTblno.
*/
int sqliteDbCreateTable(Db *pDb, int *pTblno){
- u32 *pPage;
+ u32 *aPage;
u32 pgno;
int rc;
int swTblno;
int i;
- rc = allocPage(pDb, &pgno, &pPage);
+ rc = allocPage(pDb, &pgno, &aPage);
if( rc!=SQLITE_OK ){
return rc;
}
tblno = -1;
- for(i=2; i<pDb->nContent; i++){
- if( pDb->aContent[i]==0 ){
- tblno = i - 2;
+ for(i=0; i<pDb->nTable; i++){
+ if( pDb->aTable[i]==0 ){
+ tblno = i;
break;
}
}
if( tblno<0 ){
- tblno = pDb->aContent[1];
- }
- if( tblno+2 >= pDb->nContent ){
- sqliteDbExpandContent(pDb, tblno+2);
- }
- if( pDb->aContent==0 ){
- rc = SQLITE_NOMEM;
- }else{
- pDb->aContent[tblno+2] = pgno;
- pPage[0] = SWB(BLOCK_MAGIC | BLOCK_LEAF);
- memset(&pPage[1], 0, SQLITE_PAGE_SIZE - sizeof(u32));
- sqlitePgTouch(pPage);
+ pDb->nTable++;
+ rc = sqliteExpandTableArray(pDb);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
}
- sqlitePgUnref(pPage);
+ pDb->aTable[tblno] = pgno;
+ aPage[0] = BLOCK_LEAF;
+ memset(&aPage[1], 0, SQLITE_PAGE_SIZE - sizeof(u32));
+ sqlitePgTouch(aPage);
+ sqlitePgUnref(aPage);
return rc;
}
rc = sqlitePgGet(pDb->pPgr, pgno, (void**)&aPage);
if( rc!=SQLITE_OK ) return rc;
switch( aPage[0] ){
- case BLOCK_MAGIC | BLOCK_INDEX: {
+ case BLOCK_INDEX: {
int n, i;
n = aPage[2];
for(i=0; i<n; i++){
- u32 subpgno = aPage[4+i*2];
+ u32 subpgno = aPage[3 + i*2];
if( subpgno>0 ) sqliteDbDropPage(pDb, subpgno);
}
freePage(pDb, pgno, aPage);
break;
}
- case BLOCK_MAGIC | BLOCK_LEAF: {
+ case BLOCK_LEAF: {
int i = 2;
while( i<U32_PER_PAGE ){
int entrySize = aPage[i];
if( entrySize==0 ) break;
- payloadFree(pDb, &aPage[i+4], 0, aPage[i+2]+aPage[i+3]);
+ payloadResize(pDb, &aPage[i+4], aPage[i+2]+aPage[i+3], 0);
i += entrySize;
}
freePage(pDb, pgno, aPage);
/* Find the root page for the table to be dropped.
*/
- if( pDb->aContent==0 ){
+ if( pDb->aTable==0 ){
return SQLITE_NOMEM;
}
- if( tblno<0 || tblno+2>=pDb->nContent || pDb->aContent[tblno+2]==0 ){
+ if( tblno<0 || tblno>=pDb->nTable || pDb->aTable[tblno]==0 ){
return SQLITE_NOTFOUND;
}
- pgno = pDb->aContent[tblno+2];
- pDb->aContent[tblno+2] = 0;
+ pgno = pDb->aTable[tblno];
+ pDb->aTable[tblno] = 0;
+ if( tblno==pDb->nTable-1 ){
+ pDb->nTable--;
+ }
/* Reset any cursors pointing to the table that is about to
** be dropped */
/* Translate the table number into a page number
*/
- if( pDb->aContent==0 ){
+ if( pDb->aTable==0 ){
*ppCur = 0;
return SQLITE_NOMEM;
}
- if( tblno<0 || tblno+2>=pDb->nContent || pDb->aContent[tblno+2]==0 ){
+ if( tblno<0 || tblno>=pDb->nContent || pDb->aTable[tblno]==0 ){
*ppCur = 0;
return SQLITE_NOTFOUND;
}
- pgno = SWB(pDb->aContent[tblno+2]);
+ pgno = pDb->aTable[tblno];
/* Allocate the cursor
*/
while( rc < 0 ){
u32 *aPage = pCur->aLevel[i].aPage;
assert( aPage!=0 );
- switch( SWB(aPage[0]) ){
- case BLOCK_LEAF | BLOCK_MAGIC: {
- if( aPage[1]!=0 ){
- pCur->aLevel[i].idx = 1;
+ switch( aPage[0] ){
+ case BLOCK_LEAF: {
+ if( aPage[2]!=0 ){
+ pCur->aLevel[i].idx = 2;
pCur->onEntry = 1;
}else{
sqliteDbResetCursor(pCur, 1);
rc = SQLITE_OK;
break;
}
- case BLOCK_INDEX | BLOCK_MAGIC: {
- int n = SWB(aPage[2]);
- if( n<2 || n>=((SQLITE_PAGE_SIZE/sizeof(u32))-3)/2 ){
+ case BLOCK_INDEX: {
+ int n = aPage[2];
+ if( n<2 || n>=((U32_PER_PAGE - 3)/2) ){
sqliteDbResetCur(pCur, 1);
rc = SQLITE_CORRUPT;
break;
}
pCur->nLevel++;
i++;
- pCur->aLevel[i].pgno = SWB(aPage[4]);
+ pCur->aLevel[i].pgno = aPage[3];
rc = sqlitePgGet(pCur->pDb->pPgr, pCur->aLevel[i].pgno,
&pCur->aLevel[i].aPage);
if( rc != SQLITE_OK ){
return rc;
}
+################
+
/*
** Move the cursor to the first entry in the table.
*/