/*
* REC_TOTAL -- Return the number of recno entries below a page.
*
* Parameters:
* h: page
*
* Returns:
* The number of recno entries below a page.
*
* XXX
* These values could be set by the bt_psplit routine. The problem is that the
* entry has to be popped off of the stack etc. or the values have to be passed
* all the way back to bt_split/bt_rroot and it's not very clean.
*/
static recno_t
rec_total(PAGE *h)
{
recno_t recs;
indx_t nxt, top;
for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
recs += GETRINTERNAL(h, nxt)->nrecs;
return (recs);
}
/*
* __REC_DLEAF -- Delete a single record from a recno leaf page.
*
* Parameters:
* t: tree
* idx: index on current page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_dleaf(BTREE *t, PAGE *h, u_int32_t idx)
{
RLEAF *rl;
indx_t *ip, cnt, offset;
u_int32_t nbytes;
char *from;
void *to;
/*
* Delete a record from a recno leaf page. Internal records are never
* deleted from internal pages, regardless of the records that caused
* them to be added being deleted. Pages made empty by deletion are
* not reclaimed. They are, however, made available for reuse.
*
* Pack the remaining entries at the end of the page, shift the indices
* down, overwriting the deleted record and its index. If the record
* uses overflow pages, make them available for reuse.
*/
to = rl = GETRLEAF(h, idx);
if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
return (RET_ERROR);
nbytes = NRLEAF(rl);
/*
* Compress the key/data pairs. Compress and adjust the [BR]LEAF
* offsets. Reset the headers.
*/
from = (char *)h + h->upper;
memmove(from + nbytes, from, (char *)to - from);
h->upper += nbytes;
offset = h->linp[idx];
for (cnt = &h->linp[idx] - (ip = &h->linp[0]); cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nbytes;
for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
h->lower -= sizeof(indx_t);
--t->bt_nrecs;
return (RET_SUCCESS);
}
/*
* __bt_sprev --
* Check for an exact match before the key.
*
* Parameters:
* t: tree
* h: current page
* key: key
* exactp: pointer to exact match flag
*
* Returns:
* If an exact match found.
*/
static int
__bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
{
EPG e;
/*
* Get the previous page. The key is either an exact
* match, or not as good as the one we already have.
*/
if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (0);
e.index = NEXTINDEX(e.page) - 1;
if (__bt_cmp(t, key, &e) == 0) {
mpool_put(t->bt_mp, h, 0);
t->bt_cur = e;
*exactp = 1;
return (1);
}
mpool_put(t->bt_mp, e.page, 0);
return (0);
}
/*
* __bt_seqset --
* Set the sequential scan to a specific key.
*
* Parameters:
* t: tree
* ep: storage for returned key
* key: key for initial scan position
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
*
* Side effects:
* Pins the page the cursor references.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags)
{
PAGE *h;
pgno_t pg;
int exact;
/*
* Find the first, last or specific key in the tree and point the
* cursor at it. The cursor may not be moved until a new key has
* been found.
*/
switch (flags) {
case R_CURSOR: /* Keyed scan. */
/*
* Find the first instance of the key or the smallest key
* which is greater than or equal to the specified key.
*/
if (key->data == NULL || key->size == 0) {
errno = EINVAL;
return (RET_ERROR);
}
return (__bt_first(t, key, ep, &exact));
case R_FIRST: /* First record. */
case R_NEXT:
/* Walk down the left-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, 0)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = 0;
break;
case R_LAST: /* Last record. */
case R_PREV:
/* Walk down the right-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = NEXTINDEX(h) - 1;
break;
}
return (RET_SUCCESS);
}
开发者ID:Spenser309,项目名称:CS551,代码行数:85,代码来源:bt_seq.c
示例8: __bt_delete
/*
* __bt_delete
* Delete the item(s) referenced by a key.
*
* Return RET_SPECIAL if the key is not found.
*/
int
__bt_delete(const DB *dbp, const DBT *key, u_int flags)
{
BTREE *t;
CURSOR *c;
PAGE *h;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Check for change to a read-only tree. */
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
status = __bt_bdelete(t, key);
break;
case R_CURSOR:
/*
* If flags is R_CURSOR, delete the cursor. Must already
* have started a scan and not have already deleted it.
*/
c = &t->bt_cursor;
if (F_ISSET(c, CURS_INIT)) {
if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* If the page is about to be emptied, we'll need to
* delete it, which means we have to acquire a stack.
*/
if (NEXTINDEX(h) == 1)
if (__bt_stkacq(t, &h, &t->bt_cursor))
return (RET_ERROR);
status = __bt_dleaf(t, NULL, h, c->pg.index);
if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp,
h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
break;
}
/* FALLTHROUGH */
default:
errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS)
F_SET(t, B_MODIFIED);
return (status);
}
/*
* __bt_bdelete --
* Delete all key/data pairs matching the specified key.
*
* Parameters:
* t: tree
* key: key to delete
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
static int
__bt_bdelete(BTREE *t, const DBT *key)
{
EPG *e;
PAGE *h;
int deleted, exact, redo;
deleted = 0;
/* Find any matching record; __bt_search pins the page. */
loop: if ((e = __bt_search(t, key, &exact)) == NULL)
return (deleted ? RET_SUCCESS : RET_ERROR);
if (!exact) {
mpool_put(t->bt_mp, e->page, 0);
return (deleted ? RET_SUCCESS : RET_SPECIAL);
}
/*
* Delete forward, then delete backward, from the found key. If
* there are duplicates and we reach either side of the page, do
* the key search again, so that we get them all.
*/
redo = 0;
h = e->page;
do {
if (__bt_dleaf(t, key, h, e->index)) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (F_ISSET(t, B_NODUPS)) {
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
deleted = 1;
} while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
/* Check for right-hand edge of the page. */
if (e->index == NEXTINDEX(h))
redo = 1;
/* Delete from the key to the beginning of the page. */
while (e->index-- > 0) {
if (__bt_cmp(t, key, e) != 0)
break;
if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (e->index == 0)
redo = 1;
}
/* Check for an empty page. */
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
goto loop;
}
/* Put the page. */
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
if (redo)
goto loop;
return (RET_SUCCESS);
}
/*
* __bt_pdelete --
* Delete a single page from the tree.
*
* Parameters:
* t: tree
* h: leaf page
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side-effects:
* mpool_put's the page
*/
static int
__bt_pdelete(BTREE *t, PAGE *h)
{
BINTERNAL *bi;
PAGE *pg;
EPGNO *parent;
indx_t cnt, idx, *ip, offset;
u_int32_t nksize;
char *from;
/*
* Walk the parent page stack -- a LIFO stack of the pages that were
* traversed when we searched for the page where the delete occurred.
* Each stack entry is a page number and a page index offset. The
* offset is for the page traversed on the search. We've just deleted
* a page, so we have to delete the key from the parent page.
*
* If the delete from the parent page makes it empty, this process may
* continue all the way up the tree. We stop if we reach the root page
* (which is never deleted, it's just not worth the effort) or if the
* delete does not empty the page.
*/
while ((parent = BT_POP(t)) != NULL) {
/* Get the parent page. */
if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (RET_ERROR);
idx = parent->index;
bi = GETBINTERNAL(pg, idx);
/* Free any overflow pages. */
if (bi->flags & P_BIGKEY &&
__ovfl_delete(t, bi->bytes) == RET_ERROR) {
mpool_put(t->bt_mp, pg, 0);
return (RET_ERROR);
}
/*
* Free the parent if it has only the one key and it's not the
* root page. If it's the rootpage, turn it back into an empty
* leaf page.
*/
if (NEXTINDEX(pg) == 1) {
if (pg->pgno == P_ROOT) {
pg->lower = BTDATAOFF;
pg->upper = t->bt_psize;
pg->flags = P_BLEAF;
} else {
if (__bt_relink(t, pg) || __bt_free(t, pg))
return (RET_ERROR);
continue;
}
} else {
/* Pack remaining key items at the end of the page. */
nksize = NBINTERNAL(bi->ksize);
from = (char *)pg + pg->upper;
memmove(from + nksize, from, (char *)bi - from);
pg->upper += nksize;
/* Adjust indices' offsets, shift the indices down. */
offset = pg->linp[idx];
for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nksize;
for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
pg->lower -= sizeof(indx_t);
}
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
break;
}
/* Free the leaf page, as long as it wasn't the root. */
if (h->pgno == P_ROOT) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
return (__bt_relink(t, h) || __bt_free(t, h));
}
/*
* __bt_stkacq --
* Acquire a stack so we can delete a cursor entry.
*
* Parameters:
* t: tree
* hp: pointer to current, pinned PAGE pointer
* c: pointer to the cursor
*
* Returns:
* 0 on success, 1 on failure
*/
static int
__bt_stkacq(BTREE *t, PAGE **hp, CURSOR *c)
{
BINTERNAL *bi;
EPG *e;
EPGNO *parent;
PAGE *h;
indx_t idx;
pgno_t pgno;
recno_t nextpg, prevpg;
int exact, level;
/*
* Find the first occurrence of the key in the tree. Toss the
* currently locked page so we don't hit an already-locked page.
*/
h = *hp;
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/* See if we got it in one shot. */
if (h->pgno == c->pg.pgno)
goto ret;
/*
* Move right, looking for the page. At each move we have to move
* up the stack until we don't have to move to the next page. If
* we have to change pages at an internal level, we have to fix the
* stack back up.
*/
while (h->pgno != c->pg.pgno) {
if ((nextpg = h->nextpg) == P_INVALID)
break;
mpool_put(t->bt_mp, h, 0);
/* Move up the stack. */
for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (1);
/* Move to the next index. */
if (parent->index != NEXTINDEX(h) - 1) {
idx = parent->index + 1;
BT_PUSH(t, h->pgno, idx);
break;
}
mpool_put(t->bt_mp, h, 0);
}
/* Restore the stack. */
while (level--) {
/* Push the next level down onto the stack. */
bi = GETBINTERNAL(h, idx);
pgno = bi->pgno;
BT_PUSH(t, pgno, 0);
/* Lose the currently pinned page. */
mpool_put(t->bt_mp, h, 0);
/* Get the next level down. */
if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
return (1);
idx = 0;
}
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
return (1);
}
if (h->pgno == c->pg.pgno)
goto ret;
/* Reacquire the original stack. */
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/*
* Move left, looking for the page. At each move we have to move
* up the stack until we don't have to change pages to move to the
* next page. If we have to change pages at an internal level, we
* have to fix the stack back up.
*/
while (h->pgno != c->pg.pgno) {
//.........这里部分代码省略.........
/*
* __bt_seqadvance --
* Advance the sequential scan.
*
* Parameters:
* t: tree
* flags: R_NEXT, R_PREV
*
* Side effects:
* Pins the page the new key/data record is on.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqadv(BTREE *t, EPG *ep, int flags)
{
CURSOR *c;
PAGE *h;
indx_t idx = 0; /* pacify gcc */
pgno_t pg;
int exact;
/*
* There are a couple of states that we can be in. The cursor has
* been initialized by the time we get here, but that's all we know.
*/
c = &t->bt_cursor;
/*
* The cursor was deleted where there weren't any duplicate records,
* so the key was saved. Find out where that key would go in the
* current tree. It doesn't matter if the returned key is an exact
* match or not -- if it's an exact match, the record was added after
* the delete so we can just return it. If not, as long as there's
* a record there, return it.
*/
if (F_ISSET(c, CURS_ACQUIRE))
return (__bt_first(t, &c->key, ep, &exact));
/* Get the page referenced by the cursor. */
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* Find the next/previous record in the tree and point the cursor at
* it. The cursor may not be moved until a new key has been found.
*/
switch (flags) {
case R_NEXT: /* Next record. */
/*
* The cursor was deleted in duplicate records, and moved
* forward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_AFTER))
goto usecurrent;
idx = c->pg.index;
if (++idx == NEXTINDEX(h)) {
pg = h->nextpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = 0;
}
break;
case R_PREV: /* Previous record. */
/*
* The cursor was deleted in duplicate records, and moved
* backward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_BEFORE)) {
usecurrent: F_CLR(c, CURS_AFTER | CURS_BEFORE);
ep->page = h;
ep->index = c->pg.index;
return (RET_SUCCESS);
}
idx = c->pg.index;
if (idx == 0) {
pg = h->prevpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = NEXTINDEX(h) - 1;
} else
--idx;
break;
}
ep->page = h;
ep->index = idx;
return (RET_SUCCESS);
}
开发者ID:Spenser309,项目名称:CS551,代码行数:98,代码来源:bt_seq.c
示例16: __bt_search
/*
* __bt_search --
* Search a btree for a key.
*
* Parameters:
* t: tree to search
* key: key to find
* exactp: pointer to exact match flag
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__bt_search(BTREE *t, const DBT *key, int *exactp)
{
PAGE *h;
indx_t base, idx, lim;
pgno_t pg;
int cmp;
BT_CLR(t);
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (NULL);
/* Do a binary search on the current page. */
t->bt_cur.page = h;
for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
t->bt_cur.index = idx = base + (lim >> 1);
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
if (h->flags & P_BLEAF) {
*exactp = 1;
return (&t->bt_cur);
}
goto next;
}
if (cmp > 0) {
base = idx + 1;
--lim;
}
}
/*
* If it's a leaf page, we're almost done. If no duplicates
* are allowed, or we have an exact match, we're done. Else,
* it's possible that there were matching keys on this page,
* which later deleted, and we're on a page with no matches
* while there are matches on other pages. If at the start or
* end of a page, check the adjacent page.
*/
if (h->flags & P_BLEAF) {
if (!F_ISSET(t, B_NODUPS)) {
if (base == 0 &&
h->prevpg != P_INVALID &&
__bt_sprev(t, h, key, exactp))
return (&t->bt_cur);
if (base == NEXTINDEX(h) &&
h->nextpg != P_INVALID &&
__bt_snext(t, h, key, exactp))
return (&t->bt_cur);
}
*exactp = 0;
t->bt_cur.index = base;
return (&t->bt_cur);
}
/*
* No match found. Base is the smallest index greater than
* key and may be zero or a last + 1 index. If it's non-zero,
* decrement by one, and record the internal page which should
* be a parent page for the key. If a split later occurs, the
* inserted page will be to the right of the saved page.
*/
idx = base ? base - 1 : base;
next: BT_PUSH(t, h->pgno, idx);
pg = GETBINTERNAL(h, idx)->pgno;
mpool_put(t->bt_mp, h, 0);
}
}
//.........这里部分代码省略.........
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
goto err2;
/*
* The new key goes ONE AFTER the index, because the split
* was to the right.
*/
skip = parent->index + 1;
/*
* Calculate the space needed on the parent page.
*
* Prefix trees: space hack when inserting into BINTERNAL
* pages. Retain only what's needed to distinguish between
* the new entry and the LAST entry on the page to its left.
* If the keys compare equal, retain the entire key. Note,
* we don't touch overflow keys, and the entire key must be
* retained for the next-to-left most key on the leftmost
* page of each level, or the search will fail. Applicable
* ONLY to internal pages that have leaf pages as children.
* Further reduction of the key between pairs of internal
* pages loses too much information.
*/
switch (rchild->flags & P_TYPE) {
case P_BINTERNAL:
bi = GETBINTERNAL(rchild, 0);
nbytes = NBINTERNAL(bi->ksize);
break;
case P_BLEAF:
bl = GETBLEAF(rchild, 0);
nbytes = NBINTERNAL(bl->ksize);
if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
(h->prevpg != P_INVALID || skip > 1)) {
tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
a.size = tbl->ksize;
a.data = tbl->bytes;
b.size = bl->ksize;
b.data = bl->bytes;
nksize = t->bt_pfx(&a, &b);
n = NBINTERNAL(nksize);
if (n < nbytes) {
#ifdef STATISTICS
bt_pfxsaved += nbytes - n;
#endif
nbytes = n;
} else
nksize = 0;
} else
nksize = 0;
break;
case P_RINTERNAL:
case P_RLEAF:
nbytes = NRINTERNAL;
break;
default:
abort();
}
/* Split the parent page if necessary or shift the indices. */
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
sp = h;
h = h->pgno == P_ROOT ?
bt_root(t, h, &l, &r, &skip, nbytes) :
bt_page(t, h, &l, &r, &skip, nbytes);
if (h == NULL)
goto err1;
/*
* BT_PSPLIT -- Do the real work of splitting the page.
*
* Parameters:
* t: tree
* h: page to be split
* l: page to put lower half of data
* r: page to put upper half of data
* pskip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert.
*/
static PAGE *
bt_psplit(BTREE *t, PAGE *h, PAGE *l, PAGE *r, indx_t *pskip, size_t ilen)
{
BINTERNAL *bi;
BLEAF *bl;
CURSOR *c;
RLEAF *rl;
PAGE *rval;
void *src;
indx_t full, half, nxt, off, skip, top, used;
u_int32_t nbytes;
int bigkeycnt, isbigkey;
/*
* Split the data to the left and right pages. Leave the skip index
* open. Additionally, make some effort not to split on an overflow
* key. This makes internal page processing faster and can save
* space as overflow keys used by internal pages are never deleted.
*/
bigkeycnt = 0;
skip = *pskip;
full = t->bt_psize - BTDATAOFF;
half = full / 2;
used = 0;
for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
if (skip == off) {
nbytes = ilen;
isbigkey = 0; /* XXX: not really known. */
} else
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
src = bi = GETBINTERNAL(h, nxt);
nbytes = NBINTERNAL(bi->ksize);
isbigkey = bi->flags & P_BIGKEY;
break;
case P_BLEAF:
src = bl = GETBLEAF(h, nxt);
nbytes = NBLEAF(bl);
isbigkey = bl->flags & P_BIGKEY;
break;
case P_RINTERNAL:
src = GETRINTERNAL(h, nxt);
nbytes = NRINTERNAL;
isbigkey = 0;
break;
case P_RLEAF:
src = rl = GETRLEAF(h, nxt);
nbytes = NRLEAF(rl);
isbigkey = 0;
break;
default:
abort();
}
/*
* If the key/data pairs are substantial fractions of the max
* possible size for the page, it's possible to get situations
* where we decide to try and copy too much onto the left page.
* Make sure that doesn't happen.
*/
if ((skip <= off && used + nbytes + sizeof(indx_t) >= full) ||
nxt == top - 1) {
--off;
break;
}
/* Copy the key/data pair, if not the skipped index. */
if (skip != off) {
++nxt;
l->linp[off] = l->upper -= nbytes;
memmove((char *)l + l->upper, src, nbytes);
}
used += nbytes + sizeof(indx_t);
if (used >= half) {
if (!isbigkey || bigkeycnt == 3)
break;
else
++bigkeycnt;
}
}
/*
* Off is the last offset that's valid for the left page.
* Nxt is the first offset to be placed on the right page.
//.........这里部分代码省略.........
/*
* __bt_search --
* Search a btree for a key.
*
* Parameters:
* t: tree to search
* key: key to find
* exactp: pointer to exact match flag
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__bt_search_st(BTREE *t,const DBT *key,int *exactp)
{
/*
* 1.Read from root of the btree in NTT
* 2.reconstruct the node
*/
PAGE *h=NULL; /* h is a logical B-Tree node, either a disk mode node or a virtual node in memory construct by log */
indx_t base, index, lim;
pgno_t pg; //node id of the page
int cmp;
BT_CLR(t); /* @mx it initializes t->bt_sp */
err_debug(("Searh Btree"));
for (pg = P_ROOT;;) {
err_debug(("~^"));
err_debug(("Read Node %ud",pg));
h = read_node(t,pg);
//__bt_dpage(h);
err_debug(("~$End Read"));
if(h==NULL)
return (NULL);
/* ??? not so clear about the binary search */
/* Do a binary search on the current page. */
t->bt_cur.page = h;
for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
t->bt_cur.index = index = base + (lim >> 1);
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
if (h->flags & P_BLEAF) {
*exactp = 1;
err_debug(("End Search"));
return (&t->bt_cur);
}
goto next;
}
if (cmp > 0) {
base = index + 1;
--lim;
}
}
/*
* If it's a leaf page, we're almost done. If no duplicates
* are allowed, or we have an exact match, we're done. Else,
* it's possible that there were matching keys on this page,
* which later deleted, and we're on a page with no matches
* while there are matches on other pages. If at the start or
* end of a page, check the adjacent page.
*
* TODO: what about this condition for log mode ?
*/
if (h->flags & P_BLEAF) {
#if 0
if (!F_ISSET(t, B_NODUPS)) {
if (base == 0 &&
h->prevpg != P_INVALID &&
__bt_sprev(t, h, key, exactp))
err_debug(("End Search"));
return (&t->bt_cur);
if (base == NEXTINDEX(h) &&
h->nextpg != P_INVALID &&
__bt_snext(t, h, key, exactp))
err_debug(("End Search\n"));
return (&t->bt_cur);
}
#endif
*exactp = 0;
t->bt_cur.index = base;
err_debug(("End Search"));
return (&t->bt_cur);
}
/*
* No match found. Base is the smallest index greater than
* key and may be zero or a last + 1 index. If it's non-zero,
* decrement by one, and record the internal page which should
* be a parent page for the key. If a split later occurs, the
* inserted page will be to the right of the saved page.
*/
index = base ? base - 1 : base;
next: BT_PUSH(t, pg, index);
pg = GETBINTERNAL(h, index)->pgno;
Mpool_put(t->bt_mp, h, 0);
}
//.........这里部分代码省略.........
请发表评论