:-) (CVS 216)

FossilOrigin-Name: c3e521190f02120a34f1e9244fe1ea3a975a6caa
This commit is contained in:
drh 2001-05-11 11:02:46 +00:00
parent 08ed44e72c
commit 365d68f7f1
4 changed files with 156 additions and 109 deletions

View File

@ -1,5 +1,5 @@
C :-)\s(CVS\s215) C :-)\s(CVS\s216)
D 2001-04-29T23:32:56 D 2001-05-11T11:02:47
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664 F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@ -9,10 +9,10 @@ F configure.in e7465c88bbfb76882f97769c2dd90dbba8eca5db
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e
F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464 F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
F notes/notes2.txt 80a0c3e3a0063b81fa8df6aab01bd014353dde01 F notes/notes2.txt 49b4d7ba35f183feb1fb098a27272b82f5c76eca
F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744 F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/btree.c eb7eec19f54e758c86a231f97fd366cc2d4cffc1 F src/btree.c 9b985eede929ce3f1a6ad510ecd04c197ce092f7
F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94 F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94
F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651 F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
@ -106,7 +106,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P 73a1ed61265040925f1a41c9c0cfeea50db70b01 P 624ccbca98be33a26c2af72d2d91c78f8a06ae9c
R 6983c25437d4d42e0292396f95237df8 R dd7612c12a95a523d5ea5cc83b2e1f75
U drh U drh
Z 352332e9d2b2a7ec788ddf63618fa616 Z 7bf915d3af7096b69289ffd2ecea3428

View File

@ -1 +1 @@
624ccbca98be33a26c2af72d2d91c78f8a06ae9c c3e521190f02120a34f1e9244fe1ea3a975a6caa

View File

@ -1,48 +1,111 @@
How to do a B*Tree insert: How to do a B*Tree insert:
add_to_page(cursor, data, ptr){ add_to_page(pageptr, data, pgno){
if( data_fits_on_page ){ add data to page; return; } pgno.parent = pageptr
if( page==root ){ if( data+pgno fits on pageptr ){
split currentpage+(data+ptr) into lowerpart, center, upperpart add data+pgno to pageptr
newpage1 = lowerpart; return
newpage2 = upperpart; }
page = ptr(newpage1) + center + ptr(newpage2); if( pageptr==root ){
return; split pageptr+(data+pgno) into newpage1, center, newpage2
pageptr = ptr(newpage1) + center + ptr(newpage2);
return
} }
if( move_some_data_left || move_some_data_right ){ if( move_some_data_left || move_some_data_right ){
add data to page add data+pgno to pageptr
return return
} }
split currentpage+(data+ptr) into lowerpart, center, upperpart split pageptr+(data+pgno) into pageptr, center, newpage
newpage = upperpart add_to_page(parent(pageptr), center, ptr(newpage));
currentpage = lowerpart newpage.parent = parent(pageptr)
pop cursor one level
add_to_page(cursor, center, ptr(newpage));
} }
Cursor: pageptr, idx
unlink_entry(cursor, olddata){ unlink_entry(cursor, olddata){
if( !is_a_leaf ){ if( cursor.pageptr is not a leaf page ){
n = next_entry() if( olddata!=nil) copy payload(cursor) into olddata
if( n fits pageof(cursor) ){ n = next_entry(cursor)
if( olddata!=nil ) copy dataof(cursor) into olddata if( payloadsize(n) <= freesize(cursor) + payloadsize(cursor) ){
copy dataof(n) into dataof(cursor) copy payload(n) into payload(cursor)
unlink_entry(n, nil) unlink_entry(n, nil)
return return
} }
n = prev_entry() p = prev_entry(cursor)
if( n fits pageof(cursor) ){ if( payloadsize(p) <= freesize(cursor) + payloadsize(cursor) ){
if( olddata!=nil ) copy dataof(cursor) into olddata copy payload(p) into payload(cursor)
copy dataof(n) into dataof(cursor) unlink_entry(p, nil)
unlink_entry(n, nil)
return return
} }
unlink_entry(n, leafdata) unlink(n, leafdata)
move cursor data and ptr into olddata, oldptr pageptr = cursor.pageptr
add_to_page(cursor, leafdata, oldptr) nextpgno = pageptr.aCell[cursor.idx].pgno;
convert_cursor_to_free_block(cursor)
add_to_page(pageptr, leafdata, nextpgno)
return return
} }
move cursor data into olddata pageptr = cursor.pageptr;
if( !underfull(pageof(cursor)) ) return convert_cursor_to_free_block(cursor)
if( usage(pageptr)<0.65 ){
consolidate(pageptr)
}
}
consolidate(pageptr){
parentpage = parentof(pageptr)
idx = index_of_page(parentpage, pageptr);
leftsibling = parentpage.cell[idx].pgno;
rightsibling = parentpage.cell[idx+1].pgno;
if( idx>0 ){
cursor = makecursor(pageptr,idx-1)
if( try_to_move_down(cursor) ) return
}
if( idx<max ){
cursor = makecursor(pageptr,idx)
try_to_move_down(cursor)
}
return
}
try_to_move_down(cursor){
pageptr = cursor.pageptr
if( payload(cursor)+sizeof(left)+sizeof(right)<=pagesize ){
put cursor and content of left into right
remove cursor from pageptr
if( pageptr is root ){
if( cellcount(pageptr)==0 ){
copy child into pageptr
update parent field of child
}
}else if( usage(pageptr)<0.65 ){
try_to_move_down(cursor)
}
}
}
cursor_move_next(cursor){
if( cursor.incr_noop ){
cursor.incr_noop = FALSE;
return;
}
if( is_leaf(cursor.pageptr) ){
if( cursor.idx==cursor.pageptr.ncell ){
if( cursor.pageptr==root ){
nil cursor
return
}
cursor_move_up(cursor)
cursor_move_next(cursor)
}else{
cursor.idx++;
}
return
}
pgno = next_pgno(cursor)
loop {
cursor.pageptr = get(pgno);
if( is_leaf(cursor.pageptr) ) break;
pgno = first_pgno(pageptr);
}
cursor.idx = 0;
} }

View File

@ -21,7 +21,7 @@
** http://www.hwaci.com/drh/ ** http://www.hwaci.com/drh/
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.3 2001/04/29 23:32:56 drh Exp $ ** $Id: btree.c,v 1.4 2001/05/11 11:02:47 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "pager.h" #include "pager.h"
@ -29,6 +29,15 @@
#include <assert.h> #include <assert.h>
typedef unsigned int u32; typedef unsigned int u32;
typedef unsigned short int u16;
/*
** Forward declarations of structures used only in this file.
*/
typedef struct Page1Header Page1Header;
typedef struct PageHdr PageHdr;
typedef struct Cell Cell;
typedef struct FreeBlk FreeBlk;
/* /*
@ -42,6 +51,12 @@ typedef unsigned int u32;
#define MAGIC_1 0x7264dc61 #define MAGIC_1 0x7264dc61
#define MAGIC_2 0x54e55d9e #define MAGIC_2 0x54e55d9e
struct Page1Header {
u32 magic1;
u32 magic2;
Pgno firstList;
};
/* /*
** Each database page has a header as follows: ** Each database page has a header as follows:
** **
@ -57,6 +72,22 @@ typedef unsigned int u32;
** nByte Number of free bytes in this block ** nByte Number of free bytes in this block
** next_free Next free block or 0 if this is the end ** next_free Next free block or 0 if this is the end
*/ */
struct PageHdr {
Pgno pgno; /* Child page that comes after all cells on this page */
u16 firstCell; /* Index in MemPage.aPage[] of the first cell */
u16 firstFree; /* Index in MemPage.aPage[] of the first free block */
};
struct Cell {
Pgno pgno; /* Child page that comes before this cell */
u16 nKey; /* Number of bytes in the key */
u16 iNext; /* Index in MemPage.aPage[] of next cell in sorted order */
u32 nData; /* Number of bytes of data */
char aData[4]; /* Key and data */
};
struct FreeBlk {
u16 iSize; /* Number of u32-sized slots in the block of free space */
u16 iNext; /* Index in MemPage.aPage[] of the next free block */
};
/* /*
** The maximum number of database entries that can be held in a single ** The maximum number of database entries that can be held in a single
@ -73,7 +104,7 @@ typedef unsigned int u32;
** be at least 4 bytes in the key/data packet, so each entry consumes at ** be at least 4 bytes in the key/data packet, so each entry consumes at
** least 20 bytes of space on the page. ** least 20 bytes of space on the page.
*/ */
#define MX_CELL ((SQLITE_PAGE_SIZE-12)/20) #define MX_CELL ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/sizeof(Cell))
/* /*
** The maximum amount of data (in bytes) that can be stored locally for a ** The maximum amount of data (in bytes) that can be stored locally for a
@ -109,7 +140,7 @@ struct MemPage {
Pgno left; /* Left sibling page. 0==none */ Pgno left; /* Left sibling page. 0==none */
Pgno right; /* Right sibling page. 0==none */ Pgno right; /* Right sibling page. 0==none */
int idxStart; /* Index in aPage[] of real data */ int idxStart; /* Index in aPage[] of real data */
int nFree; /* Number of free elements of aPage[] */ int nFree; /* Number of free slots of aPage[] */
int nCell; /* Number of entries on this page */ int nCell; /* Number of entries on this page */
u32 *aCell[MX_CELL]; /* All entires in sorted order */ u32 *aCell[MX_CELL]; /* All entires in sorted order */
} }
@ -133,6 +164,17 @@ struct Btree {
}; };
typedef Btree Bt; typedef Btree Bt;
/*
** A cursor is a pointer to a particular entry in the BTree.
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
*/
struct Cursor {
Btree *pBt; /* The pointer back to the BTree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
int skip_incr; /* */
};
/* /*
** The maximum depth of a cursor ** The maximum depth of a cursor
@ -163,83 +205,25 @@ struct BtCursor {
BtIdxpt aLevel[MX_LEVEL]; /* The index levels */ BtIdxpt aLevel[MX_LEVEL]; /* The index levels */
}; };
/*
** Defragment the page given. All of the free space
** is collected into one big block at the end of the
** page.
*/
static void defragmentPage(MemPage *pPage){
}
/* /*
** Mark a section of the memory block as in-use. ** Mark a section of the memory block as in-use.
*/ */
static void useSpace(MemPage *pPage, int start, int size){ static void useSpace(MemPage *pPage, int start, int size){
int i;
FreeBlk *p;
/* Some basic sanity checking */
assert( pPage && pPage->isInit );
assert( pPage->nFree>0 && pPage->nFree<=MX_FREE );
assert( pPage->nFreeSlot >= size );
assert( start > pPage->idxStart );
assert( size>0 );
assert( start + size < SQLITE_PAGE_SIZE/sizeof(pPage->aPage[0]) );
/* Search for the freeblock that describes the space to be used */
for(i=0; i<pPage->nFree; i++){
p = &pPage->aFree[i]
if( p->idx<=start && p->idx+p->size>start ) break;
}
/* The freeblock must contain all the space that is to be used */
assert( i<pPage->nFree );
assert( p->idx+p->size >= start+size );
/* Remove the used space from the freeblock */
if( p->idx==start ){
/* The space is at the beginning of the block
p->size -= size;
if( p->size==0 ){
*p = pPage->aFree[pPage->nFree-1];
pPage->nFree--;
}
}else if( p->idx+p->size==start+size ){
/* Space at the end of the block */
p->size -= size;
}else{
/* Space in the middle of the freeblock. */
FreeBlk *pNew;
assert( p->nFreeSlot < MX_FREE );
pNew->idx = start+size;
pNew->size = p->idx+p->size - pNew->idx;
p->size = start - p->idx;
}
pPage->nFreeSlot -= size;
} }
/* /*
** Return a section of the MemPage.aPage[] to the freelist. ** Return a section of the MemPage.aPage[] to the freelist.
*/ */
static void freeSpace(MemPage *pPage, int start, int size){ static void freeSpace(MemPage *pPage, int start, int size){
int end = start+size;
int i;
FreeBlk *pMatch = 0;
FreeBlk *
for(i=0; i<pPage->nFreeSlot; i++){
FreeBlk *p = &pPage->aFree[i];
if( p->idx==end+1 ){
if( pMatch ){
}else{
p->idx = start;
p->size += size;
pMatch = p;
}
}
if( p->idx+p->size+1==start ){
p->size += size;
break;
}
}
}
/*
** Defragment the freespace
*/
static void defragmentSpace(MemPage *pPage){
} }
/* /*