1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Olson. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #if defined(LIBC_SCCS) && !defined(lint) 38 static char sccsid[] = "@(#)bt_search.c 8.6 (Berkeley) 3/15/94"; 39 #endif /* LIBC_SCCS and not lint */ 40 41 #include <sys/types.h> 42 43 #include <stdio.h> 44 45 #include <db.h> 46 #include "btree.h" 47 48 static int bt_snext __P((BTREE *, PAGE *, const DBT *, int *)); 49 static int bt_sprev __P((BTREE *, PAGE *, const DBT *, int *)); 50 51 /* 52 * __BT_SEARCH -- Search a btree for a key. 53 * 54 * Parameters: 55 * t: tree to search 56 * key: key to find 57 * exactp: pointer to exact match flag 58 * 59 * Returns: 60 * The EPG for matching record, if any, or the EPG for the location 61 * of the key, if it were inserted into the tree, is entered into 62 * the bt_cur field of the tree. A pointer to the field is returned. 63 */ 64 EPG * 65 __bt_search(t, key, exactp) 66 BTREE *t; 67 const DBT *key; 68 int *exactp; 69 { 70 PAGE *h; 71 indx_t base, index, lim; 72 pgno_t pg; 73 int cmp; 74 75 BT_CLR(t); 76 for (pg = P_ROOT;;) { 77 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 78 return (NULL); 79 80 /* Do a binary search on the current page. */ 81 t->bt_cur.page = h; 82 for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) { 83 t->bt_cur.index = index = base + (lim >> 1); 84 if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) { 85 if (h->flags & P_BLEAF) { 86 *exactp = 1; 87 return (&t->bt_cur); 88 } 89 goto next; 90 } 91 if (cmp > 0) { 92 base = index + 1; 93 --lim; 94 } 95 } 96 97 /* 98 * If it's a leaf page, and duplicates aren't allowed, we're 99 * done. If duplicates are allowed, it's possible that there 100 * were duplicate keys on duplicate pages, and they were later 101 * deleted, so we could be on a page with no matches while 102 * there are matches on other pages. If we're at the start or 103 * end of a page, check on both sides. 104 */ 105 if (h->flags & P_BLEAF) { 106 t->bt_cur.index = base; 107 *exactp = 0; 108 if (!ISSET(t, B_NODUPS)) { 109 if (base == 0 && 110 bt_sprev(t, h, key, exactp)) 111 return (&t->bt_cur); 112 if (base == NEXTINDEX(h) && 113 bt_snext(t, h, key, exactp)) 114 return (&t->bt_cur); 115 } 116 return (&t->bt_cur); 117 } 118 119 /* 120 * No match found. Base is the smallest index greater than 121 * key and may be zero or a last + 1 index. If it's non-zero, 122 * decrement by one, and record the internal page which should 123 * be a parent page for the key. If a split later occurs, the 124 * inserted page will be to the right of the saved page. 125 */ 126 index = base ? base - 1 : base; 127 128 next: if (__bt_push(t, h->pgno, index) == RET_ERROR) 129 return (NULL); 130 pg = GETBINTERNAL(h, index)->pgno; 131 mpool_put(t->bt_mp, h, 0); 132 } 133 } 134 135 /* 136 * BT_SNEXT -- Check for an exact match after the key. 137 * 138 * Parameters: 139 * t: tree to search 140 * h: current page. 141 * key: key to find 142 * exactp: pointer to exact match flag 143 * 144 * Returns: 145 * If an exact match found. 146 */ 147 static int 148 bt_snext(t, h, key, exactp) 149 BTREE *t; 150 PAGE *h; 151 const DBT *key; 152 int *exactp; 153 { 154 EPG e; 155 PAGE *tp; 156 pgno_t pg; 157 158 /* Skip until reach the end of the tree or a key. */ 159 for (pg = h->nextpg; pg != P_INVALID;) { 160 if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) { 161 mpool_put(t->bt_mp, h, 0); 162 return (NULL); 163 } 164 if (NEXTINDEX(tp) != 0) 165 break; 166 pg = tp->prevpg; 167 mpool_put(t->bt_mp, tp, 0); 168 } 169 /* 170 * The key is either an exact match, or not as good as 171 * the one we already have. 172 */ 173 if (pg != P_INVALID) { 174 e.page = tp; 175 e.index = NEXTINDEX(tp) - 1; 176 if (__bt_cmp(t, key, &e) == 0) { 177 mpool_put(t->bt_mp, h, 0); 178 t->bt_cur = e; 179 *exactp = 1; 180 return (1); 181 } 182 } 183 return (0); 184 } 185 186 /* 187 * BT_SPREV -- Check for an exact match before the key. 188 * 189 * Parameters: 190 * t: tree to search 191 * h: current page. 192 * key: key to find 193 * exactp: pointer to exact match flag 194 * 195 * Returns: 196 * If an exact match found. 197 */ 198 static int 199 bt_sprev(t, h, key, exactp) 200 BTREE *t; 201 PAGE *h; 202 const DBT *key; 203 int *exactp; 204 { 205 EPG e; 206 PAGE *tp; 207 pgno_t pg; 208 209 /* Skip until reach the beginning of the tree or a key. */ 210 for (pg = h->prevpg; pg != P_INVALID;) { 211 if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) { 212 mpool_put(t->bt_mp, h, 0); 213 return (NULL); 214 } 215 if (NEXTINDEX(tp) != 0) 216 break; 217 pg = tp->prevpg; 218 mpool_put(t->bt_mp, tp, 0); 219 } 220 /* 221 * The key is either an exact match, or not as good as 222 * the one we already have. 223 */ 224 if (pg != P_INVALID) { 225 e.page = tp; 226 e.index = NEXTINDEX(tp) - 1; 227 if (__bt_cmp(t, key, &e) == 0) { 228 mpool_put(t->bt_mp, h, 0); 229 t->bt_cur = e; 230 *exactp = 1; 231 return (1); 232 } 233 } 234 return (0); 235 } 236