bt_search.c revision 1.5 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 /* from: static char sccsid[] = "@(#)bt_search.c 8.4 (Berkeley) 12/10/93"; */
39 static char *rcsid = "$Id: bt_search.c,v 1.5 1994/01/24 03:59:45 cgd Exp $";
40 #endif /* LIBC_SCCS and not lint */
41
42 #include <sys/types.h>
43
44 #include <stdio.h>
45
46 #include <db.h>
47 #include "btree.h"
48
49 static int bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
50 static int bt_sprev __P((BTREE *, PAGE *, const DBT *, int *));
51
52 /*
53 * __BT_SEARCH -- Search a btree for a key.
54 *
55 * Parameters:
56 * t: tree to search
57 * key: key to find
58 * exactp: pointer to exact match flag
59 *
60 * Returns:
61 * The EPG for matching record, if any, or the EPG for the location
62 * of the key, if it were inserted into the tree, is entered into
63 * the bt_cur field of the tree. A pointer to the field is returned.
64 */
65 EPG *
66 __bt_search(t, key, exactp)
67 BTREE *t;
68 const DBT *key;
69 int *exactp;
70 {
71 PAGE *h, *n;
72 indx_t index;
73 pgno_t pg;
74 int base, cmp, lim;
75
76 BT_CLR(t);
77 for (pg = P_ROOT;;) {
78 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
79 return (NULL);
80
81 /* Do a binary search on the current page. */
82 t->bt_cur.page = h;
83 for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
84 t->bt_cur.index = index = base + (lim >> 1);
85 if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
86 if (h->flags & P_BLEAF) {
87 *exactp = 1;
88 return (&t->bt_cur);
89 }
90 goto next;
91 }
92 if (cmp > 0) {
93 base = index + 1;
94 --lim;
95 }
96 }
97
98 /*
99 * If it's a leaf page, and duplicates aren't allowed, we're
100 * done. If duplicates are allowed, it's possible that there
101 * were duplicate keys on duplicate pages, and they were later
102 * deleted, so we could be on a page with no matches while
103 * there are matches on other pages. If we're at the start or
104 * end of a page, check on both sides.
105 */
106 if (h->flags & P_BLEAF) {
107 t->bt_cur.index = base;
108 *exactp = 0;
109 if (!ISSET(t, B_NODUPS)) {
110 if (base == 0 &&
111 bt_sprev(t, h, key, exactp))
112 return (&t->bt_cur);
113 if (base == NEXTINDEX(h) &&
114 bt_snext(t, h, key, exactp))
115 return (&t->bt_cur);
116 }
117 return (&t->bt_cur);
118 }
119
120 /*
121 * No match found. Base is the smallest index greater than
122 * key and may be zero or a last + 1 index. If it's non-zero,
123 * decrement by one, and record the internal page which should
124 * be a parent page for the key. If a split later occurs, the
125 * inserted page will be to the right of the saved page.
126 */
127 index = base ? base - 1 : base;
128
129 next: if (__bt_push(t, h->pgno, index) == RET_ERROR)
130 return (NULL);
131 pg = GETBINTERNAL(h, index)->pgno;
132 mpool_put(t->bt_mp, h, 0);
133 }
134 }
135
136 /*
137 * BT_SNEXT -- Check for an exact match after the key.
138 *
139 * Parameters:
140 * t: tree to search
141 * h: current page.
142 * key: key to find
143 * exactp: pointer to exact match flag
144 *
145 * Returns:
146 * If an exact match found.
147 */
148 static int
149 bt_snext(t, h, key, exactp)
150 BTREE *t;
151 PAGE *h;
152 const DBT *key;
153 int *exactp;
154 {
155 EPG e;
156 PAGE *tp;
157 pgno_t pg;
158
159 /* Skip until reach the end of the tree or a key. */
160 for (pg = h->nextpg; pg != P_INVALID;) {
161 if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
162 mpool_put(t->bt_mp, h, 0);
163 return (NULL);
164 }
165 if (NEXTINDEX(tp) != 0)
166 break;
167 pg = tp->prevpg;
168 mpool_put(t->bt_mp, tp, 0);
169 }
170 /*
171 * The key is either an exact match, or not as good as
172 * the one we already have.
173 */
174 if (pg != P_INVALID) {
175 e.page = tp;
176 e.index = NEXTINDEX(tp) - 1;
177 if (__bt_cmp(t, key, &e) == 0) {
178 mpool_put(t->bt_mp, h, 0);
179 t->bt_cur = e;
180 *exactp = 1;
181 return (1);
182 }
183 }
184 return (0);
185 }
186
187 /*
188 * BT_SPREV -- Check for an exact match before the key.
189 *
190 * Parameters:
191 * t: tree to search
192 * h: current page.
193 * key: key to find
194 * exactp: pointer to exact match flag
195 *
196 * Returns:
197 * If an exact match found.
198 */
199 static int
200 bt_sprev(t, h, key, exactp)
201 BTREE *t;
202 PAGE *h;
203 const DBT *key;
204 int *exactp;
205 {
206 EPG e;
207 PAGE *tp;
208 pgno_t pg;
209
210 /* Skip until reach the beginning of the tree or a key. */
211 for (pg = h->prevpg; pg != P_INVALID;) {
212 if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
213 mpool_put(t->bt_mp, h, 0);
214 return (NULL);
215 }
216 if (NEXTINDEX(tp) != 0)
217 break;
218 pg = tp->prevpg;
219 mpool_put(t->bt_mp, tp, 0);
220 }
221 /*
222 * The key is either an exact match, or not as good as
223 * the one we already have.
224 */
225 if (pg != P_INVALID) {
226 e.page = tp;
227 e.index = NEXTINDEX(tp) - 1;
228 if (__bt_cmp(t, key, &e) == 0) {
229 mpool_put(t->bt_mp, h, 0);
230 t->bt_cur = e;
231 *exactp = 1;
232 return (1);
233 }
234 }
235 return (0);
236 }
237