diff options
Diffstat (limited to 'db2/btree/bt_rsearch.c')
-rw-r--r-- | db2/btree/bt_rsearch.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/db2/btree/bt_rsearch.c b/db2/btree/bt_rsearch.c new file mode 100644 index 0000000000..ee26221e25 --- /dev/null +++ b/db2/btree/bt_rsearch.c @@ -0,0 +1,347 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#ifndef lint +static const char sccsid[] = "@(#)bt_rsearch.c 10.8 (Sleepycat) 8/24/97"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" + +/* + * __bam_rsearch -- + * Search a btree for a record number. + * + * PUBLIC: int __bam_rsearch __P((DB *, db_recno_t *, u_int, int, int *)); + */ +int +__bam_rsearch(dbp, recnop, flags, stop, exactp) + DB *dbp; + db_recno_t *recnop; + u_int flags; + int stop, *exactp; +{ + BINTERNAL *bi; + BTREE *t; + DB_LOCK lock; + PAGE *h; + RINTERNAL *ri; + db_indx_t indx, top; + db_pgno_t pg; + db_recno_t recno, total; + int isappend, ret, stack; + + t = dbp->internal; + + /* + * We test for groups of flags, S_APPEND is the only one that can be + * OR'd into the set. Clear it now so that the tests for equality + * will work. + */ + if ((isappend = LF_ISSET(S_APPEND)) != 0) + LF_CLR(S_APPEND); + + /* + * There are several ways we search a btree tree. The flags argument + * specifies if we're acquiring read or write locks and if we are + * locking pairs of pages. See btree.h for more details. + * + * If write-locking pages, we need to know whether or not to acquire a + * write lock on a page before getting it. This depends on how deep it + * is in tree, which we don't know until we acquire the root page. So, + * if we need to lock the root page we may have to upgrade it later, + * because we won't get the correct lock initially. + * + * Retrieve the root page. + */ + pg = PGNO_ROOT; + if ((ret = __bam_lget(dbp, 0, PGNO_ROOT, + flags == S_INSERT || flags == S_DELETE ? + DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0) + return (ret); + if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) { + (void)__BT_LPUT(dbp, lock); + return (ret); + } + total = RE_NREC(h); + + /* + * If appending to the tree, set the record number now -- we have the + * root page locked. + * + * Delete only deletes exact matches, read only returns exact matches. + * Note, this is different from __bam_search(), which returns non-exact + * matches for read. + * + * The record may not exist. We can only return the correct location + * for the record immediately after the last record in the tree, so do + * a fast check now. + */ + if (isappend) { + *exactp = 0; + *recnop = recno = total + 1; + } else { + recno = *recnop; + if (recno <= total) + *exactp = 1; + else { + *exactp = 0; + if (flags == S_DELETE || + flags == S_FIND || recno > total + 1) { + (void)memp_fput(dbp->mpf, h, 0); + (void)__BT_LPUT(dbp, lock); + return (DB_NOTFOUND); + } + } + } + + /* Decide if we're building a stack based on the operation. */ + BT_STK_CLR(t); + stack = flags == S_DELETE || flags == S_INSERT; + + /* + * Decide if we need to save this page; if we do, write lock it, and + * start to build a stack. + */ + if (LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) { + (void)memp_fput(dbp->mpf, h, 0); + if ((ret = __bam_lget(dbp, 1, pg, DB_LOCK_WRITE, &lock)) != 0) + return (ret); + if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) { + (void)__BT_LPUT(dbp, lock); + return (ret); + } + stack = 1; + } + + /* Records in the tree are 0-based, and record numbers are 1-based. */ + --recno; + + for (total = 0;;) { + switch (TYPE(h)) { + case P_LBTREE: + BT_STK_ENTER(t, h, (recno - total) * P_INDX, lock, ret); + return (ret); + case P_IBTREE: + for (indx = 0, top = NUM_ENT(h);;) { + bi = GET_BINTERNAL(h, indx); + if (++indx == top || total + bi->nrecs > recno) + break; + total += bi->nrecs; + } + pg = bi->pgno; + break; + case P_LRECNO: + BT_STK_ENTER(t, h, recno - total, lock, ret); + return (ret); + case P_IRECNO: + for (indx = 0, top = NUM_ENT(h);;) { + ri = GET_RINTERNAL(h, indx); + if (++indx == top || total + ri->nrecs > recno) + break; + total += ri->nrecs; + } + pg = ri->pgno; + break; + default: + return (__db_pgfmt(dbp, h->pgno)); + } + --indx; + + if (stack) { + /* Return if this is the lowest page wanted. */ + if (LF_ISSET(S_PARENT) && stop == h->level) { + BT_STK_ENTER(t, h, indx, lock, ret); + return (ret); + } + BT_STK_PUSH(t, h, indx, lock, ret); + if (ret) + goto err; + + if ((ret = __bam_lget(dbp, 0, pg, + LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ, + &lock)) != 0) + goto err; + } else { + (void)memp_fput(dbp->mpf, h, 0); + + /* + * Decide if we want to return a pointer to the next + * page in the stack. If we do, write lock it and + * never unlock it. + */ + if (LF_ISSET(S_PARENT) && + (u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) + stack = 1; + + if ((ret = __bam_lget(dbp, 1, pg, + LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ, + &lock)) != 0) + goto err; + } + + if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) + goto err; + } + /* NOTREACHED */ + +err: BT_STK_POP(t); + __bam_stkrel(dbp); + return (ret); +} + +/* + * __bam_adjust -- + * Adjust the tree after adding or deleting a record. + * + * PUBLIC: int __bam_adjust __P((DB *, BTREE *, int)); + */ +int +__bam_adjust(dbp, t, adjust) + DB *dbp; + BTREE *t; + int adjust; +{ + EPG *epg; + PAGE *h; + int ret; + + /* Update the record counts for the tree. */ + for (epg = t->bt_sp; epg <= t->bt_csp; ++epg) { + h = epg->page; + if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO) { + if (DB_LOGGING(dbp) && + (ret = __bam_cadjust_log(dbp->dbenv->lg_info, + dbp->txn, &LSN(h), 0, dbp->log_fileid, + PGNO(h), &LSN(h), (u_int32_t)epg->indx, + (int32_t)adjust, 1)) != 0) + return (ret); + + if (TYPE(h) == P_IBTREE) + GET_BINTERNAL(h, epg->indx)->nrecs += adjust; + else + GET_RINTERNAL(h, epg->indx)->nrecs += adjust; + + if (PGNO(h) == PGNO_ROOT) + RE_NREC_ADJ(h, adjust); + + if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + } + } + return (0); +} + +/* + * __bam_nrecs -- + * Return the number of records in the tree. + * + * PUBLIC: int __bam_nrecs __P((DB *, db_recno_t *)); + */ +int +__bam_nrecs(dbp, rep) + DB *dbp; + db_recno_t *rep; +{ + DB_LOCK lock; + PAGE *h; + db_pgno_t pgno; + int ret; + + pgno = PGNO_ROOT; + if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &lock)) != 0) + return (ret); + if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0) + return (ret); + + *rep = RE_NREC(h); + + (void)memp_fput(dbp->mpf, h, 0); + (void)__BT_TLPUT(dbp, lock); + + return (0); +} + +/* + * __bam_total -- + * Return the number of records below a page. + * + * PUBLIC: db_recno_t __bam_total __P((PAGE *)); + */ +db_recno_t +__bam_total(h) + PAGE *h; +{ + db_recno_t recs; + db_indx_t nxt, top; + + switch (TYPE(h)) { + case P_LBTREE: + recs = NUM_ENT(h) / 2; + break; + case P_IBTREE: + for (recs = 0, nxt = 0, top = NUM_ENT(h); nxt < top; ++nxt) + recs += GET_BINTERNAL(h, nxt)->nrecs; + break; + case P_LRECNO: + recs = NUM_ENT(h); + break; + case P_IRECNO: + for (recs = 0, nxt = 0, top = NUM_ENT(h); nxt < top; ++nxt) + recs += GET_RINTERNAL(h, nxt)->nrecs; + break; + default: + abort(); + } + return (recs); +} |