bt_search.c revision 1.6 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