** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.111 2004/05/07 17:57:50 drh Exp $
+** $Id: btree.c,v 1.112 2004/05/07 23:50:57 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
u8 wrFlag; /* True if writable */
- u8 eSkip; /* Determines if next step operation is a no-op */
u8 iMatch; /* compare result from last sqlite3BtreeMoveto() */
+ u8 isValid; /* TRUE if points to a valid entry */
+ u8 status; /* Set to SQLITE_ABORT if cursors is invalidated */
};
-/*
-** Legal values for BtCursor.eSkip.
-*/
-#define SKIP_NONE 0 /* Always step the cursor */
-#define SKIP_NEXT 1 /* The next sqlite3BtreeNext() is a no-op */
-#define SKIP_PREV 2 /* The next sqlite3BtreePrevious() is a no-op */
-#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
-
/*
** Read or write a two-, four-, and eight-byte big-endian integer values.
*/
if( !pPage->leaf ){
n += 4;
}
+ memcpy(&newPage[hdr], &oldPage[hdr], n-hdr);
start = n;
pc = get2byte(&oldPage[addr]);
i = 0;
size = cellSize(pPage, &oldPage[pc]);
memcpy(&newPage[n], &oldPage[pc], size);
put2byte(&newPage[addr],n);
- pPage->aCell[i] = &oldPage[n];
+ pPage->aCell[i++] = &oldPage[n];
n += size;
addr = pc;
pc = get2byte(&oldPage[pc]);
}
+ assert( i==pPage->nCell );
leftover = pPage->pBt->pageSize - n;
assert( leftover>=0 );
assert( pPage->nFree==leftover );
leftover = 0;
n = pPage->pBt->pageSize;
}
- memcpy(&oldPage[start], &newPage[start], n-start);
+ memcpy(&oldPage[hdr], &newPage[hdr], n-hdr);
if( leftover==0 ){
- put2byte(&oldPage[hdr+3], 0);
+ put2byte(&oldPage[hdr+1], 0);
}else if( leftover>=4 ){
- put2byte(&oldPage[hdr+3], n);
+ put2byte(&oldPage[hdr+1], n);
put2byte(&oldPage[n], 0);
put2byte(&oldPage[n+2], leftover);
memset(&oldPage[n+4], 0, leftover-4);
}
+ oldPage[hdr+5] = 0;
}
/*
return rc;
}
+/*
+** Invalidate all cursors
+*/
+static void invalidateCursors(Btree *pBt){
+ BtCursor *pCur;
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ MemPage *pPage = pCur->pPage;
+ if( pPage && !pPage->isInit ){
+ releasePage(pPage);
+ pCur->pPage = 0;
+ pCur->isValid = 0;
+ pCur->status = SQLITE_ABORT;
+ }
+ }
+}
+
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
*/
int sqlite3BtreeRollback(Btree *pBt){
int rc;
- BtCursor *pCur;
if( pBt->inTrans==0 ) return SQLITE_OK;
pBt->inTrans = 0;
pBt->inStmt = 0;
rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_rollback(pBt->pPager);
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- MemPage *pPage = pCur->pPage;
- if( pPage && !pPage->isInit ){
- releasePage(pPage);
- pCur->pPage = 0;
- }
- }
+ invalidateCursors(pBt);
unlockBtreeIfUnused(pBt);
return rc;
}
*/
int sqlite3BtreeRollbackStmt(Btree *pBt){
int rc;
- BtCursor *pCur;
if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK;
rc = sqlite3pager_stmt_rollback(pBt->pPager);
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- MemPage *pPage = pCur->pPage;
- if( pPage && !pPage->isInit ){
- releasePage(pPage);
- pCur->pPage = 0;
- }
- }
+ invalidateCursors(pBt);
pBt->inStmt = 0;
return rc;
}
pCur->pBt = pBt;
pCur->wrFlag = wrFlag;
pCur->idx = 0;
- pCur->eSkip = SKIP_INVALID;
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
pCur->pNext->pPrev = pCur;
pCur->pShared = pCur;
}
pBt->pCursor = pCur;
+ pCur->isValid = 0;
+ pCur->status = SQLITE_OK;
*ppCur = pCur;
return SQLITE_OK;
*/
int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){
MemPage *pPage;
+ unsigned char *cell;
- pPage = pCur->pPage;
- assert( pPage!=0 );
- if( pCur->idx >= pPage->nCell ){
+ if( !pCur->isValid ){
*pSize = 0;
}else{
- unsigned char *cell = pPage->aCell[pCur->idx];
+ pPage = pCur->pPage;
+ assert( pPage!=0 );
+ assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+ cell = pPage->aCell[pCur->idx];
cell += 2; /* Skip the offset to the next cell */
if( !pPage->leaf ){
cell += 4; /* Skip the child pointer */
int maxLocal, ovflSize;
assert( pCur!=0 && pCur->pPage!=0 );
+ assert( pCur->isValid );
pBt = pCur->pBt;
pPage = pCur->pPage;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
** the available payload.
*/
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- MemPage *pPage;
-
assert( amt>=0 );
assert( offset>=0 );
- assert( pCur->pPage!=0 );
- pPage = pCur->pPage;
- if( pCur->idx >= pPage->nCell || pPage->intKey ){
- assert( amt==0 );
- return SQLITE_OK;
+ if( pCur->isValid==0 ){
+ return pCur->status;
}
+ assert( pCur->pPage!=0 );
+ assert( pCur->pPage->intKey==0 );
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
Btree *pBt;
u64 nData, nKey;
- assert( pCur!=0 && pCur->pPage!=0 );
+ assert( pCur!=0 );
+ if( !pCur->isValid ){
+ return 0;
+ }
+ assert( pCur->pPage!=0 );
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
pBt = pCur->pBt;
pPage = pCur->pPage;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+ assert( pPage->intKey==0 );
aPayload = pPage->aCell[pCur->idx];
aPayload += 2; /* Skip the next cell index */
if( !pPage->leaf ){
aPayload += getVarint(aPayload, &nData);
}
aPayload += getVarint(aPayload, &nKey);
- if( pPage->intKey || nKey>pBt->maxLocal ){
+ if( nKey>pBt->maxLocal ){
return 0;
}
return aPayload;
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
MemPage *pPage;
+ unsigned char *cell;
+ u64 size;
+ if( !pCur->isValid ){
+ return pCur->status ? pCur->status : SQLITE_INTERNAL;
+ }
pPage = pCur->pPage;
assert( pPage!=0 );
- if( pCur->idx >= pPage->nCell || pPage->zeroData ){
+ assert( pPage->isInit );
+ if( pPage->zeroData ){
*pSize = 0;
}else{
- unsigned char *cell;
- u64 size;
+ assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
cell = pPage->aCell[pCur->idx];
cell += 2; /* Skip the offset to the next cell */
if( !pPage->leaf ){
** the available payload.
*/
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- MemPage *pPage;
-
+ if( !pCur->isValid ){
+ return pCur->status ? pCur->status : SQLITE_INTERNAL;
+ }
assert( amt>=0 );
assert( offset>=0 );
assert( pCur->pPage!=0 );
- pPage = pCur->pPage;
- if( pCur->idx >= pPage->nCell ){
- return 0;
- }
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
return getPayload(pCur, offset, amt, pBuf, 1);
}
MemPage *pOldPage;
Btree *pBt = pCur->pBt;
+ assert( pCur->isValid );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc;
pNewPage->idxParent = pCur->idx;
MemPage *pPage;
int idxParent;
+ assert( pCur->isValid );
pPage = pCur->pPage;
assert( pPage!=0 );
assert( !isRootPage(pPage) );
Btree *pBt = pCur->pBt;
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0);
- if( rc ) return rc;
+ if( rc ){
+ pCur->isValid = 0;
+ return rc;
+ }
releasePage(pCur->pPage);
pCur->pPage = pRoot;
pCur->idx = 0;
assert( subpage>0 );
rc = moveToChild(pCur, subpage);
}
+ pCur->isValid = pCur->pPage->nCell>0;
return rc;
}
int rc;
MemPage *pPage;
+ assert( pCur->isValid );
while( !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
pgno = get4byte(&pPage->aCell[pCur->idx][2]);
int rc;
MemPage *pPage;
+ assert( pCur->isValid );
while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+6]);
pCur->idx = pPage->nCell;
*/
int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc;
- if( pCur->pPage==0 ) return SQLITE_ABORT;
+ if( pCur->status ){
+ return pCur->status;
+ }
rc = moveToRoot(pCur);
if( rc ) return rc;
- if( pCur->pPage->nCell==0 ){
+ if( pCur->isValid==0 ){
+ assert( pCur->pPage->nCell==0 );
*pRes = 1;
return SQLITE_OK;
}
+ assert( pCur->pPage->nCell>0 );
*pRes = 0;
rc = moveToLeftmost(pCur);
- pCur->eSkip = SKIP_NONE;
return rc;
}
*/
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
- if( pCur->pPage==0 ) return SQLITE_ABORT;
+ if( pCur->status ){
+ return pCur->status;
+ }
rc = moveToRoot(pCur);
if( rc ) return rc;
- assert( pCur->pPage->isInit );
- if( pCur->pPage->nCell==0 ){
+ if( pCur->isValid==0 ){
+ assert( pCur->pPage->nCell==0 );
*pRes = 1;
return SQLITE_OK;
}
+ assert( pCur->isValid );
*pRes = 0;
rc = moveToRightmost(pCur);
- pCur->eSkip = SKIP_NONE;
return rc;
}
*/
int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
int rc;
- if( pCur->pPage==0 ) return SQLITE_ABORT;
- pCur->eSkip = SKIP_NONE;
+
+ if( pCur->status ){
+ return pCur->status;
+ }
rc = moveToRoot(pCur);
if( rc ) return rc;
+ assert( pCur->pPage );
+ assert( pCur->pPage->isInit );
+ if( pCur->isValid==0 ){
+ assert( pCur->pPage->nCell==0 );
+ return SQLITE_OK;
+ }
for(;;){
int lwr, upr;
Pgno chldPg;
}
if( chldPg==0 ){
pCur->iMatch = c;
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
if( pRes ) *pRes = c;
return SQLITE_OK;
}
pCur->idx = lwr;
rc = moveToChild(pCur, chldPg);
- if( rc ) return rc;
+ if( rc ){
+ return rc;
+ }
}
/* NOT REACHED */
}
+/*
+** Return TRUE if the cursor is not pointing at an entry of the table.
+**
+** TRUE will be returned after a call to sqlite3BtreeNext() moves
+** past the last entry in the table or sqlite3BtreePrev() moves past
+** the first entry. TRUE is also returned if the table is empty.
+*/
+int sqlite3BtreeEof(BtCursor *pCur){
+ return pCur->isValid==0;
+}
+
/*
** Advance the cursor to the next entry in the database. If
** successful then set *pRes=0. If the cursor
int rc;
MemPage *pPage = pCur->pPage;
assert( pRes!=0 );
- if( pPage==0 ){
- *pRes = 1;
- return SQLITE_ABORT;
- }
- assert( pPage->isInit );
- assert( pCur->eSkip!=SKIP_INVALID );
- if( pPage->nCell==0 ){
+ if( pCur->isValid==0 ){
*pRes = 1;
return SQLITE_OK;
}
+ assert( pPage->isInit );
assert( pCur->idx<pPage->nCell );
- if( pCur->eSkip==SKIP_NEXT ){
- pCur->eSkip = SKIP_NONE;
- *pRes = 0;
- return SQLITE_OK;
- }
- pCur->eSkip = SKIP_NONE;
pCur->idx++;
if( pCur->idx>=pPage->nCell ){
if( !pPage->leaf ){
do{
if( isRootPage(pPage) ){
*pRes = 1;
+ pCur->isValid = 0;
return SQLITE_OK;
}
moveToParent(pCur);
int rc;
Pgno pgno;
MemPage *pPage;
- pPage = pCur->pPage;
- if( pPage==0 ){
- *pRes = 1;
- return SQLITE_ABORT;
- }
- assert( pPage->isInit );
- assert( pCur->eSkip!=SKIP_INVALID );
- if( pPage->nCell==0 ){
+ if( pCur->isValid==0 ){
*pRes = 1;
return SQLITE_OK;
}
- if( pCur->eSkip==SKIP_PREV ){
- pCur->eSkip = SKIP_NONE;
- *pRes = 0;
- return SQLITE_OK;
- }
- pCur->eSkip = SKIP_NONE;
+ pPage = pCur->pPage;
+ assert( pPage->isInit );
assert( pCur->idx>=0 );
if( !pPage->leaf ){
pgno = get4byte(&pPage->aCell[pCur->idx][2]);
}else{
while( pCur->idx==0 ){
if( isRootPage(pPage) ){
- if( pRes ) *pRes = 1;
+ pCur->isValid = 0;
+ *pRes = 1;
return SQLITE_OK;
}
moveToParent(pCur);
unsigned char *oldCell;
unsigned char newCell[MX_CELL_SIZE];
- if( pCur->pPage==0 ){
- return SQLITE_ABORT; /* A rollback destroyed this cursor */
+ if( pCur->status ){
+ return pCur->status; /* A rollback destroyed this cursor */
}
if( !pBt->inTrans || nKey+nData==0 ){
/* Must start a transaction before doing an insert */
/* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
/* fflush(stdout); */
moveToRoot(pCur);
- pCur->eSkip = SKIP_INVALID;
return rc;
}
Btree *pBt = pCur->pBt;
assert( pPage->isInit );
- if( pCur->pPage==0 ){
- return SQLITE_ABORT; /* A rollback destroyed this cursor */
+ if( pCur->status ){
+ return pCur->status; /* A rollback destroyed this cursor */
}
if( !pBt->inTrans ){
/* Must start a transaction before doing a delete */
nFree = 0;
i = 0;
idx = get2byte(&pPage->aData[hdrOffset+1]);
- while( idx>0 && idx<SQLITE_USABLE_SIZE ){
+ while( idx>0 && idx<pPage->pBt->pageSize ){
int sz = get2byte(&pPage->aData[idx+2]);
sprintf(range,"%d..%d", idx, idx+sz-1);
nFree += sz;
aResult[4] = pPage->nFree;
cnt = 0;
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
- while( idx>0 && idx<SQLITE_USABLE_SIZE ){
+ while( idx>0 && idx<pPage->pBt->pageSize ){
cnt++;
idx = get2byte(&pPage->aData[idx]);
}
if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
if( pBtTo->pCursor ) return SQLITE_BUSY;
- memcpy(pBtTo->pPage1, pBtFrom->pPage1, SQLITE_USABLE_SIZE);
+ memcpy(pBtTo->pPage1, pBtFrom->pPage1, pBtFrom->pageSize);
rc = sqlite3pager_overwrite(pBtTo->pPager, 1, pBtFrom->pPage1);
nToPage = sqlite3pager_pagecount(pBtTo->pPager);
nPage = sqlite3pager_pagecount(pBtFrom->pPager);
# This file implements regression tests for SQLite library. The
# focus of this script is btree database backend
#
-# $Id: btree.test,v 1.16 2004/05/07 17:57:50 drh Exp $
+# $Id: btree.test,v 1.17 2004/05/07 23:50:58 drh Exp $
set testdir [file dirname $argv0]
do_test btree-3.19 {
btree_data $::c1
} {6.00}
-do_test btree-3.20 {
+do_test btree-3.20.1 {
btree_next $::c1
btree_key $::c1
} {0}
+do_test btree-3.20.2 {
+ btree_eof $::c1
+} {1}
do_test btree-3.21 {
- btree_data $::c1
-} {}
+ set rc [catch {btree_data $::c1} res]
+ lappend rc $res
+} {1 SQLITE_INTERNAL}
# Commit the changes, reopen and reread the data
#
btree_key $::c1
} {0}
do_test btree-3.40 {
- btree_data $::c1
-} {}
+ set rc [catch {btree_data $::c1} res]
+ lappend rc $res
+} {1 SQLITE_INTERNAL}
do_test btree-3.41 {
lindex [btree_pager_stats $::b1] 1
} {1}
set r {}
while 1 {
set key [btree_key $::c1]
- if {$key==0} break
+ if {[btree_eof $::c1]} break
lappend r $key
lappend r [btree_data $::c1]
btree_next $::c1
set r {}
while 1 {
set key [btree_key $::c1]
- if {$key==0} break
+ if {[btree_eof $::c1]} break
lappend r $key
lappend r [btree_data $::c1]
btree_next $::c1
btree_first $::c1
while 1 {
set key [btree_key $::c1]
- if {$key==0} break
+ if {[btree_eof $::c1]} break
lappend r $key
lappend r [btree_data $::c1]
btree_next $::c1
proc select_all {cursor} {
set r {}
- btree_move_to $cursor {}
- while 1 {
- set key [btree_key $cursor]
- if {$key==""} break
- lappend r $key
- lappend r [btree_data $cursor]
- btree_next $cursor
- }
- return $r
-}
-proc select_all_intkey {cursor} {
- set r {}
- btree_move_to $cursor 0
- while 1 {
+ btree_first $cursor
+ while {![btree_eof $cursor]} {
set key [btree_key $cursor]
- if {$key==0} break
lappend r $key
lappend r [btree_data $cursor]
btree_next $cursor
}
proc select_keys {cursor} {
set r {}
- btree_move_to $cursor {}
- while 1 {
+ btree_first $cursor
+ while {![btree_eof $cursor]} {
set key [btree_key $cursor]
- if {$key==""} break
lappend r $key
btree_next $cursor
}
} {2}
do_test btree-6.2.3 {
btree_insert $::c2 ten 10
+ btree_move_to $::c2 ten
btree_key $::c2
} {ten}
do_test btree-6.3 {
lindex [btree_pager_stats $::b1] 1
} {2}
do_test btree-6.3.1 {
- select_all_intkey $::c1
+ select_all $::c1
} {200 2.00 300 3.00 400 4.00 500 5.00 600 6.00}
#btree_page_dump $::b1 3
do_test btree-6.4 {
btree_key $::c2
} {}
-# If we drop table 2 it just clears the table. Table 2 always exists.
+# If we drop table 1 it just clears the table. Table 1 always exists.
#
do_test btree-6.10 {
btree_close_cursor $::c1
- btree_drop_table $::b1 2
- set ::c1 [btree_cursor $::b1 2 1]
- btree_move_to $::c1 {}
- btree_key $::c1
-} {}
+ btree_drop_table $::b1 1
+ set ::c1 [btree_cursor $::b1 1 1]
+ btree_first $::c1
+ btree_eof $::c1
+} {1}
do_test btree-6.11 {
btree_commit $::b1
select_all $::c1
do_test btree-6.13 {
btree_close_cursor $::c2
lindex [btree_pager_stats $::b1] 1
-} {2}
+} {1}
# Check to see that pages defragment properly. To do this test we will
#
-# 1. Fill the first page table 2 with data.
-# 2. Delete every other entry of table 2.
+# 1. Fill the first page of table 1 with data.
+# 2. Delete every other entry of table 1.
# 3. Insert a single entry that requires more contiguous
# space than is available.
#
catch {unset key}
catch {unset data}
do_test btree-7.2 {
- for {set i 0} {$i<36} {incr i} {
- set key [format %03d $i]
- set data "*** $key ***"
+ # Each record will be 10 bytes in size.
+ # + 100 bytes of database header
+ # + 6 bytes of table header
+ # + 91*10=910 bytes of cells
+ # Totals 1016 bytes. 8 bytes left over
+ # Keys are 1000 through 1090.
+ for {set i 1000} {$i<1091} {incr i} {
+ set key $i
+ set data [format %5d $i]
btree_insert $::c1 $key $data
}
lrange [btree_cursor_dump $::c1] 4 5
} {8 1}
do_test btree-7.3 {
- btree_move_to $::c1 000
- while {[btree_key $::c1]!=""} {
+ for {set i 1001} {$i<1091} {incr i 2} {
+ btree_move_to $::c1 $i
btree_delete $::c1
- btree_next $::c1
- btree_next $::c1
}
+ # Freed 45 blocks. Total freespace is 458
+ # Keys remaining are even numbers between 1000 and 1090, inclusive
lrange [btree_cursor_dump $::c1] 4 5
-} {512 19}
+} {458 46}
#btree_page_dump $::b1 2
do_test btree-7.4 {
- btree_insert $::c1 018 {*** 018 ***+++}
+ # The largest free block is 10 bytes long. So if we insert
+ # a record bigger than 10 bytes it should force a defrag
+ # The record is 20 bytes long.
+ btree_insert $::c1 2000 {123456789_12345}
+ btree_move_to $::c1 2000
btree_key $::c1
-} {018}
+} {2000}
do_test btree-7.5 {
lrange [btree_cursor_dump $::c1] 4 5
-} {480 1}
+} {438 1}
#btree_page_dump $::b1 2
# Delete an entry to make a hole of a known size, then immediately recreate
# that entry. This tests the path into allocateSpace where the hole exactly
# matches the size of the desired space.
#
+# Keys are even numbers between 1000 and 1090 and one record of 2000.
+# There are 47 keys total.
+#
do_test btree-7.6 {
- btree_move_to $::c1 007
+ btree_move_to $::c1 1006
btree_delete $::c1
- btree_move_to $::c1 011
+ btree_move_to $::c1 1010
btree_delete $::c1
} {}
do_test btree-7.7 {
- lindex [btree_cursor_dump $::c1] 5
-} {3}
+ lrange [btree_cursor_dump $::c1] 4 5
+} {458 3} ;# Create two new holes of 10 bytes each
#btree_page_dump $::b1 2
do_test btree-7.8 {
- btree_insert $::c1 007 {*** 007 ***}
- lindex [btree_cursor_dump $::c1] 5
-} {2}
+ btree_insert $::c1 1006 { 1006}
+ lrange [btree_cursor_dump $::c1] 4 5
+} {448 2} ;# Filled in the first hole
#btree_page_dump $::b1 2
# Make sure the freeSpace() routine properly coaleses adjacent memory blocks
#
do_test btree-7.9 {
- btree_move_to $::c1 013
+ btree_move_to $::c1 1012
btree_delete $::c1
lrange [btree_cursor_dump $::c1] 4 5
-} {536 2}
+} {458 2} ;# Coalesce with the whole before
do_test btree-7.10 {
- btree_move_to $::c1 009
+ btree_move_to $::c1 1008
btree_delete $::c1
lrange [btree_cursor_dump $::c1] 4 5
-} {564 2}
+} {468 2} ;# Coalesce with whole after
do_test btree-7.11 {
- btree_move_to $::c1 018
+ btree_move_to $::c1 1030
btree_delete $::c1
lrange [btree_cursor_dump $::c1] 4 5
-} {596 2}
+} {478 3} ;# Make a new hole
do_test btree-7.13 {
- btree_move_to $::c1 033
+ btree_move_to $::c1 1034
btree_delete $::c1
lrange [btree_cursor_dump $::c1] 4 5
-} {624 3}
+} {488 4} ;# Make another hole
do_test btree-7.14 {
- btree_move_to $::c1 035
+ btree_move_to $::c1 1032
btree_delete $::c1
lrange [btree_cursor_dump $::c1] 4 5
-} {652 2}
+} {498 3} ;# The freed space should coalesce on both ends
#btree_page_dump $::b1 2
do_test btree-7.15 {
lindex [btree_pager_stats $::b1] 1
-} {2}
+} {1}
# Check to see that data on overflow pages work correctly.
#
do_test btree-8.1 {
set data "*** This is a very long key "
- while {[string length $data]<256} {append data $data}
+ while {[string length $data]<1234} {append data $data}
set ::data $data
- btree_insert $::c1 020 $data
+ btree_insert $::c1 2020 $data
} {}
#btree_page_dump $::b1 2
do_test btree-8.1.1 {
lindex [btree_pager_stats $::b1] 1
-} {2}
+} {1}
#btree_pager_ref_dump $::b1
do_test btree-8.2 {
+ btree_move_to $::c1 2020
string length [btree_data $::c1]
} [string length $::data]
do_test btree-8.3 {
set data "*** This is an even longer key"
while {[string length $data]<2000} {append data $data}
set ::data $data
- btree_insert $::c1 020 $data
+ btree_insert $::c1 2030 $data
} {}
do_test btree-8.6 {
+ btree_move_to 2030
string length [btree_data $::c1]
} [string length $::data]
do_test btree-8.7 {
btree_close_cursor $::c1
btree_close $::b1
set ::b1 [btree_open test1.bt 2000 0]
- set ::c1 [btree_cursor $::b1 2 1]
- btree_move_to $::c1 020
+ set ::c1 [btree_cursor $::b1 1 1]
+ btree_move_to $::c1 2030
btree_data $::c1
} $::data
do_test btree-8.10 {
} {}
do_test btree-8.11 {
lindex [btree_get_meta $::b1] 0
-} [expr {int(([string length $::data]-238+1019)/1020)}]
+} {}
# Now check out keys on overflow pages.
#