146132Smao /*- 261196Sbostic * Copyright (c) 1990, 1993 361196Sbostic * The Regents of the University of California. All rights reserved. 446132Smao * 546132Smao * This code is derived from software contributed to Berkeley by 646132Smao * Mike Olson. 746132Smao * 846132Smao * %sccs.include.redist.c% 946132Smao */ 1046132Smao 1146132Smao #if defined(LIBC_SCCS) && !defined(lint) 12*65021Sbostic static char sccsid[] = "@(#)bt_search.c 8.3 (Berkeley) 12/03/93"; 1346132Smao #endif /* LIBC_SCCS and not lint */ 1446132Smao 1546132Smao #include <sys/types.h> 1656739Sbostic 1750989Sbostic #include <stdio.h> 1856739Sbostic 1957932Sbostic #include <db.h> 2046132Smao #include "btree.h" 2146132Smao 22*65021Sbostic static EPG *bt_snext __P((BTREE *, PAGE *, const DBT *, int *)); 23*65021Sbostic static EPG *bt_sprev __P((BTREE *, PAGE *, const DBT *, int *)); 24*65021Sbostic 2546132Smao /* 2650989Sbostic * __BT_SEARCH -- Search a btree for a key. 2746132Smao * 2850989Sbostic * Parameters: 2950989Sbostic * t: tree to search 3050989Sbostic * key: key to find 3150989Sbostic * exactp: pointer to exact match flag 3246132Smao * 3350989Sbostic * Returns: 3464484Sbostic * The EPG for matching record, if any, or the EPG for the location 3564484Sbostic * of the key, if it were inserted into the tree, is entered into 3664484Sbostic * the bt_cur field of the tree. A pointer to the field is returned. 3746132Smao */ 3850989Sbostic EPG * 3950989Sbostic __bt_search(t, key, exactp) 4050989Sbostic BTREE *t; 4150989Sbostic const DBT *key; 4250989Sbostic int *exactp; 4346132Smao { 44*65021Sbostic PAGE *h, *n; 45*65021Sbostic indx_t index; 4650989Sbostic pgno_t pg; 47*65021Sbostic int base, cmp, lim; 4846132Smao 4957449Sbostic BT_CLR(t); 5050989Sbostic for (pg = P_ROOT;;) { 5150989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 5250989Sbostic return (NULL); 5346132Smao 5450989Sbostic /* Do a binary search on the current page. */ 5564484Sbostic t->bt_cur.page = h; 5650989Sbostic for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) { 5764484Sbostic t->bt_cur.index = index = base + (lim >> 1); 5864484Sbostic if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) { 5950989Sbostic if (h->flags & P_BLEAF) { 6050989Sbostic *exactp = 1; 6164484Sbostic return (&t->bt_cur); 6250989Sbostic } 6350989Sbostic goto next; 6446132Smao } 6550989Sbostic if (cmp > 0) { 6650989Sbostic base = index + 1; 6750989Sbostic --lim; 6846132Smao } 6946132Smao } 7046132Smao 71*65021Sbostic /* 72*65021Sbostic * If it's a leaf page, and duplicates aren't allowed, we're 73*65021Sbostic * done. If duplicates are allowed, it's possible that the 74*65021Sbostic * matching spanned pages, and were later deleted, so we could 75*65021Sbostic * be on the wrong page. If we're at the start or end of a 76*65021Sbostic * page, check. 77*65021Sbostic */ 7850989Sbostic if (h->flags & P_BLEAF) { 7964484Sbostic t->bt_cur.index = base; 8050989Sbostic *exactp = 0; 81*65021Sbostic if (!ISSET(t, B_NODUPS)) { 82*65021Sbostic if (base == 0 && h->prevpg != P_INVALID) 83*65021Sbostic return (bt_sprev(t, h, key, exactp)); 84*65021Sbostic if (base == NEXTINDEX(h) && 85*65021Sbostic h->nextpg != P_INVALID) 86*65021Sbostic return (bt_snext(t, h, key, exactp)); 87*65021Sbostic } 8864484Sbostic return (&t->bt_cur); 8946132Smao } 9046132Smao 9157448Sbostic /* 9257448Sbostic * No match found. Base is the smallest index greater than 9357448Sbostic * key and may be zero or a last + 1 index. If it's non-zero, 9457448Sbostic * decrement by one, and record the internal page which should 9557448Sbostic * be a parent page for the key. If a split later occurs, the 9657448Sbostic * inserted page will be to the right of the saved page. 9757448Sbostic */ 9857448Sbostic index = base ? base - 1 : base; 9957448Sbostic 10051105Sbostic next: if (__bt_push(t, h->pgno, index) == RET_ERROR) 10150989Sbostic return (NULL); 10250989Sbostic pg = GETBINTERNAL(h, index)->pgno; 10350989Sbostic mpool_put(t->bt_mp, h, 0); 10446132Smao } 10546132Smao } 106*65021Sbostic 107*65021Sbostic static EPG * 108*65021Sbostic bt_snext(t, h, key, exactp) 109*65021Sbostic BTREE *t; 110*65021Sbostic PAGE *h; 111*65021Sbostic const DBT *key; 112*65021Sbostic int *exactp; 113*65021Sbostic { 114*65021Sbostic EPG e; 115*65021Sbostic PAGE *tp; 116*65021Sbostic pgno_t pg; 117*65021Sbostic 118*65021Sbostic /* Skip until reach the end of the tree or a key. */ 119*65021Sbostic for (pg = h->nextpg; pg != P_INVALID;) { 120*65021Sbostic if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) { 121*65021Sbostic mpool_put(t->bt_mp, h, 0); 122*65021Sbostic return (NULL); 123*65021Sbostic } 124*65021Sbostic if (NEXTINDEX(tp) != 0) 125*65021Sbostic break; 126*65021Sbostic pg = tp->prevpg; 127*65021Sbostic mpool_put(t->bt_mp, tp, 0); 128*65021Sbostic } 129*65021Sbostic /* 130*65021Sbostic * The key is either an exact match, or not as good as 131*65021Sbostic * the one we already have. 132*65021Sbostic */ 133*65021Sbostic if (pg != P_INVALID) { 134*65021Sbostic e.page = tp; 135*65021Sbostic e.index = NEXTINDEX(tp) - 1; 136*65021Sbostic if (__bt_cmp(t, key, &e) == 0) { 137*65021Sbostic mpool_put(t->bt_mp, h, 0); 138*65021Sbostic t->bt_cur = e; 139*65021Sbostic *exactp = 1; 140*65021Sbostic } 141*65021Sbostic } 142*65021Sbostic return (&t->bt_cur); 143*65021Sbostic } 144*65021Sbostic 145*65021Sbostic static EPG * 146*65021Sbostic bt_sprev(t, h, key, exactp) 147*65021Sbostic BTREE *t; 148*65021Sbostic PAGE *h; 149*65021Sbostic const DBT *key; 150*65021Sbostic int *exactp; 151*65021Sbostic { 152*65021Sbostic EPG e; 153*65021Sbostic PAGE *tp; 154*65021Sbostic pgno_t pg; 155*65021Sbostic 156*65021Sbostic /* Skip until reach the beginning of the tree or a key. */ 157*65021Sbostic for (pg = h->prevpg; pg != P_INVALID;) { 158*65021Sbostic if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) { 159*65021Sbostic mpool_put(t->bt_mp, h, 0); 160*65021Sbostic return (NULL); 161*65021Sbostic } 162*65021Sbostic if (NEXTINDEX(tp) != 0) 163*65021Sbostic break; 164*65021Sbostic pg = tp->prevpg; 165*65021Sbostic mpool_put(t->bt_mp, tp, 0); 166*65021Sbostic } 167*65021Sbostic /* 168*65021Sbostic * The key is either an exact match, or not as good as 169*65021Sbostic * the one we already have. 170*65021Sbostic */ 171*65021Sbostic if (pg != P_INVALID) { 172*65021Sbostic e.page = tp; 173*65021Sbostic e.index = NEXTINDEX(tp) - 1; 174*65021Sbostic if (__bt_cmp(t, key, &e) == 0) { 175*65021Sbostic mpool_put(t->bt_mp, h, 0); 176*65021Sbostic t->bt_cur = e; 177*65021Sbostic *exactp = 1; 178*65021Sbostic } 179*65021Sbostic } 180*65021Sbostic return (&t->bt_cur); 181*65021Sbostic } 182