1*46132Smao /*- 2*46132Smao * Copyright (c) 1990 The Regents of the University of California. 3*46132Smao * All rights reserved. 4*46132Smao * 5*46132Smao * This code is derived from software contributed to Berkeley by 6*46132Smao * Mike Olson. 7*46132Smao * 8*46132Smao * %sccs.include.redist.c% 9*46132Smao */ 10*46132Smao 11*46132Smao #if defined(LIBC_SCCS) && !defined(lint) 12*46132Smao static char sccsid[] = "@(#)bt_search.c 5.1 (Berkeley) 01/23/91"; 13*46132Smao #endif /* LIBC_SCCS and not lint */ 14*46132Smao 15*46132Smao #include <sys/types.h> 16*46132Smao #include <db.h> 17*46132Smao #include "btree.h" 18*46132Smao 19*46132Smao /* 20*46132Smao * _BT_FIRST -- Find the first item in the tree that matches the supplied 21*46132Smao * key. 22*46132Smao * 23*46132Smao * This routine supports deletion. When the user supplies a key to 24*46132Smao * be deleted, we find the first one, and iteratively delete all the 25*46132Smao * matching ones that follow it. 26*46132Smao * 27*46132Smao * Parameters: 28*46132Smao * t -- btree in which to find first occurrence 29*46132Smao * key -- key to find 30*46132Smao * 31*46132Smao * Returns: 32*46132Smao * The BTITEM for the matching item. If there's no match, 33*46132Smao * this may point to the first item > than the supplied key, 34*46132Smao * or off the end of the page. 35*46132Smao * 36*46132Smao * Warnings: 37*46132Smao * The BTITEM returned is in static space and will be overwritten 38*46132Smao * by the next search of any kind in any btree. 39*46132Smao */ 40*46132Smao 41*46132Smao BTITEM * 42*46132Smao _bt_first(t, key) 43*46132Smao BTREE_P t; 44*46132Smao DBT *key; 45*46132Smao { 46*46132Smao BTHEADER *h; 47*46132Smao BTITEM *item; 48*46132Smao index_t next; 49*46132Smao int r; 50*46132Smao 51*46132Smao /* find any matching item */ 52*46132Smao item = _bt_search(t, key); 53*46132Smao h = t->bt_curpage; 54*46132Smao next = NEXTINDEX(h); 55*46132Smao 56*46132Smao /* if we're off the end of the page, search failed and we're done */ 57*46132Smao if (item->bti_index >= next) 58*46132Smao return (item); 59*46132Smao 60*46132Smao /* as long as we have an exact match, walk backwards */ 61*46132Smao while ((r = _bt_cmp(t, key->data, item->bti_index)) == 0) { 62*46132Smao 63*46132Smao /* at start of page? */ 64*46132Smao if (item->bti_index == 0) { 65*46132Smao 66*46132Smao /* if no prev page, we're done */ 67*46132Smao if (h->h_prevpg == P_NONE) 68*46132Smao return (item); 69*46132Smao 70*46132Smao /* walk backward, skipping empty pages */ 71*46132Smao do { 72*46132Smao if (_bt_getpage(t, h->h_prevpg) == RET_ERROR) 73*46132Smao return ((BTITEM *) NULL); 74*46132Smao h = t->bt_curpage; 75*46132Smao } while (NEXTINDEX(h) == 0 && h->h_prevpg != P_NONE); 76*46132Smao 77*46132Smao if (NEXTINDEX(h) != 0) 78*46132Smao item->bti_index = NEXTINDEX(h) - 1; 79*46132Smao else 80*46132Smao item->bti_index = 0; 81*46132Smao 82*46132Smao item->bti_pgno = h->h_pgno; 83*46132Smao } else { 84*46132Smao item->bti_index--; 85*46132Smao } 86*46132Smao } 87*46132Smao 88*46132Smao /* if we went too far backwards, step forward one entry */ 89*46132Smao if (r > 0) { 90*46132Smao if (++(item->bti_index) >= NEXTINDEX(h) 91*46132Smao && h->h_nextpg != P_NONE) { 92*46132Smao 93*46132Smao /* walk forward, skipping empty pages */ 94*46132Smao do { 95*46132Smao if (_bt_getpage(t, h->h_nextpg) == RET_ERROR) 96*46132Smao return ((BTITEM *) NULL); 97*46132Smao h = t->bt_curpage; 98*46132Smao } while (h->h_nextpg != P_NONE && NEXTINDEX(h) == 0); 99*46132Smao 100*46132Smao item->bti_index = 0; 101*46132Smao item->bti_pgno = h->h_pgno; 102*46132Smao } 103*46132Smao } 104*46132Smao 105*46132Smao /* got it */ 106*46132Smao return (item); 107*46132Smao } 108*46132Smao 109*46132Smao /* 110*46132Smao * _BT_SEARCH, _BT_SEARCHR -- Search for a particular key in the tree. 111*46132Smao * 112*46132Smao * Parameters: 113*46132Smao * t -- btree in which to search 114*46132Smao * key -- key to find 115*46132Smao * 116*46132Smao * Returns: 117*46132Smao * BTITEM for matching item, if any, or the BTITEM for the 118*46132Smao * location of the key, if it were in the tree. 119*46132Smao * 120*46132Smao * Warnings: 121*46132Smao * The BTITEM returned is in static memory, and will be 122*46132Smao * overwritten by the next search of any kind in any tree. 123*46132Smao */ 124*46132Smao 125*46132Smao BTITEM * 126*46132Smao _bt_search(t, key) 127*46132Smao BTREE_P t; 128*46132Smao DBT *key; 129*46132Smao { 130*46132Smao /* we want to start all of our searches at the root */ 131*46132Smao if (_bt_getpage(t, (pgno_t) P_ROOT) == RET_ERROR) 132*46132Smao return ((BTITEM *) NULL); 133*46132Smao 134*46132Smao return (_bt_searchr(t, key)); 135*46132Smao } 136*46132Smao 137*46132Smao BTITEM * 138*46132Smao _bt_searchr(t, key) 139*46132Smao BTREE_P t; 140*46132Smao DBT *key; 141*46132Smao { 142*46132Smao BTHEADER *h = t->bt_curpage; 143*46132Smao index_t index; 144*46132Smao IDATUM *id; 145*46132Smao DATUM *d; 146*46132Smao static BTITEM item; 147*46132Smao 148*46132Smao /* do a binary search on the current page */ 149*46132Smao index = _bt_binsrch(t, &(key->data[0])); 150*46132Smao 151*46132Smao /* 152*46132Smao * At this point, the binary search terminated because the endpoints 153*46132Smao * got too close together, or we have a match. Figure out which 154*46132Smao * case applies and decide what to do based on the page type. 155*46132Smao */ 156*46132Smao if (h->h_flags & F_LEAF) { 157*46132Smao item.bti_pgno = h->h_pgno; 158*46132Smao item.bti_index = index; 159*46132Smao if (index < NEXTINDEX(h)) 160*46132Smao d = (DATUM *) GETDATUM(h,index); 161*46132Smao else 162*46132Smao d = (DATUM *) NULL; 163*46132Smao 164*46132Smao item.bti_datum = d; 165*46132Smao return(&item); 166*46132Smao } else { 167*46132Smao id = (IDATUM *) GETDATUM(h, index); 168*46132Smao if (_bt_push(t, h->h_pgno) == RET_ERROR) 169*46132Smao return ((BTITEM *) NULL); 170*46132Smao if (_bt_getpage(t, id->i_pgno) == RET_ERROR) 171*46132Smao return ((BTITEM *) NULL); 172*46132Smao return (_bt_searchr(t, key)); 173*46132Smao } 174*46132Smao } 175*46132Smao 176*46132Smao /* 177*46132Smao * _BT_BINSRCH -- Do a binary search for a given key on the current page. 178*46132Smao * 179*46132Smao * Searches on internal pages are handled slightly differently from 180*46132Smao * searches on leaf pages. This is because internal page searches 181*46132Smao * find the largest item <= key in the tree, and leaf searches find 182*46132Smao * the smallest item >= key. This guarantees that leaf page searches 183*46132Smao * leave us pointing at the item's correct position, and internal 184*46132Smao * searches descend the tree correctly. 185*46132Smao * 186*46132Smao * Parameters: 187*46132Smao * t -- tree to search 188*46132Smao * key -- key we're looking for 189*46132Smao * 190*46132Smao * Returns: 191*46132Smao * Index of the line pointer array entry for the (closest) 192*46132Smao * match to key on the current page, with "closest" as defined 193*46132Smao * above. 194*46132Smao */ 195*46132Smao 196*46132Smao index_t 197*46132Smao _bt_binsrch(t, key) 198*46132Smao BTREE_P t; 199*46132Smao char *key; 200*46132Smao { 201*46132Smao index_t lbound, ubound, cur; 202*46132Smao BTHEADER *h = t->bt_curpage; 203*46132Smao int match = 0; 204*46132Smao int r; 205*46132Smao 206*46132Smao lbound = 0; 207*46132Smao ubound = NEXTINDEX(h); 208*46132Smao if (ubound > 0) 209*46132Smao --ubound; 210*46132Smao 211*46132Smao /* do a binary search on the current page */ 212*46132Smao while ((ubound - lbound) > 1) { 213*46132Smao cur = lbound + ((ubound - lbound) / 2); 214*46132Smao r = _bt_cmp(t, key, cur); 215*46132Smao 216*46132Smao if (r > 0) 217*46132Smao lbound = cur + 1; 218*46132Smao else if (r < 0) 219*46132Smao ubound = cur; 220*46132Smao else { 221*46132Smao match++; 222*46132Smao break; 223*46132Smao } 224*46132Smao } 225*46132Smao 226*46132Smao /* 227*46132Smao * At this point, the binary search terminated because the endpoints 228*46132Smao * got too close together, or we have a match. Figure out which 229*46132Smao * case applies, decide what to do based on the page type (leaf or 230*46132Smao * internal), and do the right thing. 231*46132Smao */ 232*46132Smao if (match) { 233*46132Smao return (cur); 234*46132Smao } else if (ubound != lbound) { 235*46132Smao if (h->h_flags & F_LEAF) { 236*46132Smao r = _bt_cmp(t, key, lbound); 237*46132Smao if (r <= 0) { 238*46132Smao return (lbound); 239*46132Smao } 240*46132Smao } else { 241*46132Smao r = _bt_cmp(t, key, ubound); 242*46132Smao 243*46132Smao /* for internal nodes, move as far left as possible */ 244*46132Smao if (r < 0) { 245*46132Smao r = _bt_cmp(t, key, lbound); 246*46132Smao if (r < 0 && lbound > 0) 247*46132Smao --lbound; 248*46132Smao return (lbound); 249*46132Smao } else { 250*46132Smao return (ubound); 251*46132Smao } 252*46132Smao } 253*46132Smao } 254*46132Smao 255*46132Smao if (h->h_flags & F_LEAF) { 256*46132Smao if (ubound < NEXTINDEX(h)) { 257*46132Smao r = _bt_cmp(t, key, ubound); 258*46132Smao if (r > 0) 259*46132Smao ubound++; 260*46132Smao } 261*46132Smao } else { 262*46132Smao /* for internal pages, move as far left as possible */ 263*46132Smao if (ubound == NEXTINDEX(h)) 264*46132Smao ubound--; 265*46132Smao 266*46132Smao while (_bt_cmp(t, key, ubound) < 0) 267*46132Smao ubound--; 268*46132Smao } 269*46132Smao return (ubound); 270*46132Smao } 271