From 365d68f7f109dec2ab8ad0e30bc864055d7dedca Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 May 2001 11:02:46 +0000 Subject: [PATCH] :-) (CVS 216) FossilOrigin-Name: c3e521190f02120a34f1e9244fe1ea3a975a6caa --- manifest | 14 +++--- manifest.uuid | 2 +- notes/notes2.txt | 125 +++++++++++++++++++++++++++++++++++------------ src/btree.c | 124 ++++++++++++++++++++-------------------------- 4 files changed, 156 insertions(+), 109 deletions(-) diff --git a/manifest b/manifest index b9f7b61654..8a56566118 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C :-)\s(CVS\s215) -D 2001-04-29T23:32:56 +C :-)\s(CVS\s216) +D 2001-05-11T11:02:47 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in acef0f0275a5ca8e68bda165f7f05d810a207664 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 @@ -9,10 +9,10 @@ F configure.in e7465c88bbfb76882f97769c2dd90dbba8eca5db F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464 -F notes/notes2.txt 80a0c3e3a0063b81fa8df6aab01bd014353dde01 +F notes/notes2.txt 49b4d7ba35f183feb1fb098a27272b82f5c76eca F notes/notes3.txt cd5e7bd2167d7ef89b1077abdfa68f0af6337744 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 -F src/btree.c eb7eec19f54e758c86a231f97fd366cc2d4cffc1 +F src/btree.c 9b985eede929ce3f1a6ad510ecd04c197ce092f7 F src/btree.h f21c240d0c95f93e2a128106d04a6c448ed0eb94 F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651 F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af @@ -106,7 +106,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P 73a1ed61265040925f1a41c9c0cfeea50db70b01 -R 6983c25437d4d42e0292396f95237df8 +P 624ccbca98be33a26c2af72d2d91c78f8a06ae9c +R dd7612c12a95a523d5ea5cc83b2e1f75 U drh -Z 352332e9d2b2a7ec788ddf63618fa616 +Z 7bf915d3af7096b69289ffd2ecea3428 diff --git a/manifest.uuid b/manifest.uuid index 8fb1accbfd..5a727989b2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -624ccbca98be33a26c2af72d2d91c78f8a06ae9c \ No newline at end of file +c3e521190f02120a34f1e9244fe1ea3a975a6caa \ No newline at end of file diff --git a/notes/notes2.txt b/notes/notes2.txt index 2420530d0f..5fddce272c 100644 --- a/notes/notes2.txt +++ b/notes/notes2.txt @@ -1,48 +1,111 @@ How to do a B*Tree insert: -add_to_page(cursor, data, ptr){ - if( data_fits_on_page ){ add data to page; return; } - if( page==root ){ - split currentpage+(data+ptr) into lowerpart, center, upperpart - newpage1 = lowerpart; - newpage2 = upperpart; - page = ptr(newpage1) + center + ptr(newpage2); - return; +add_to_page(pageptr, data, pgno){ + pgno.parent = pageptr + if( data+pgno fits on pageptr ){ + add data+pgno to pageptr + return + } + if( pageptr==root ){ + split pageptr+(data+pgno) into newpage1, center, newpage2 + pageptr = ptr(newpage1) + center + ptr(newpage2); + return } if( move_some_data_left || move_some_data_right ){ - add data to page + add data+pgno to pageptr return } - split currentpage+(data+ptr) into lowerpart, center, upperpart - newpage = upperpart - currentpage = lowerpart - pop cursor one level - add_to_page(cursor, center, ptr(newpage)); + split pageptr+(data+pgno) into pageptr, center, newpage + add_to_page(parent(pageptr), center, ptr(newpage)); + newpage.parent = parent(pageptr) } +Cursor: pageptr, idx + unlink_entry(cursor, olddata){ - if( !is_a_leaf ){ - n = next_entry() - if( n fits pageof(cursor) ){ - if( olddata!=nil ) copy dataof(cursor) into olddata - copy dataof(n) into dataof(cursor) + if( cursor.pageptr is not a leaf page ){ + if( olddata!=nil) copy payload(cursor) into olddata + n = next_entry(cursor) + if( payloadsize(n) <= freesize(cursor) + payloadsize(cursor) ){ + copy payload(n) into payload(cursor) unlink_entry(n, nil) return } - n = prev_entry() - if( n fits pageof(cursor) ){ - if( olddata!=nil ) copy dataof(cursor) into olddata - copy dataof(n) into dataof(cursor) - unlink_entry(n, nil) + p = prev_entry(cursor) + if( payloadsize(p) <= freesize(cursor) + payloadsize(cursor) ){ + copy payload(p) into payload(cursor) + unlink_entry(p, nil) return } - unlink_entry(n, leafdata) - move cursor data and ptr into olddata, oldptr - add_to_page(cursor, leafdata, oldptr) + unlink(n, leafdata) + pageptr = cursor.pageptr + nextpgno = pageptr.aCell[cursor.idx].pgno; + convert_cursor_to_free_block(cursor) + add_to_page(pageptr, leafdata, nextpgno) return } - move cursor data into olddata - if( !underfull(pageof(cursor)) ) return - - + pageptr = cursor.pageptr; + 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 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_2 0x54e55d9e +struct Page1Header { + u32 magic1; + u32 magic2; + Pgno firstList; +}; + /* ** Each database page has a header as follows: ** @@ -57,6 +72,22 @@ typedef unsigned int u32; ** nByte Number of free bytes in this block ** 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 @@ -73,7 +104,7 @@ typedef unsigned int u32; ** be at least 4 bytes in the key/data packet, so each entry consumes at ** 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 @@ -109,7 +140,7 @@ struct MemPage { Pgno left; /* Left sibling page. 0==none */ Pgno right; /* Right sibling page. 0==none */ 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 */ u32 *aCell[MX_CELL]; /* All entires in sorted order */ } @@ -133,6 +164,17 @@ struct Btree { }; 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 @@ -163,83 +205,25 @@ struct BtCursor { 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. */ 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; inFree; 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( inFree ); - 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. */ static void freeSpace(MemPage *pPage, int start, int size){ - int end = start+size; - int i; - FreeBlk *pMatch = 0; - FreeBlk * - for(i=0; inFreeSlot; 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){ } /*