bt_search.c revision 1.16 1 /* $NetBSD: bt_search.c,v 1.16 2008/09/10 17:52:35 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 1990, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Mike Olson.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: bt_search.c,v 1.16 2008/09/10 17:52:35 joerg Exp $");
37
38 #include "namespace.h"
39 #include <sys/types.h>
40
41 #include <assert.h>
42 #include <stdio.h>
43
44 #include <db.h>
45 #include "btree.h"
46
47 static int __bt_snext(BTREE *, PAGE *, const DBT *, int *);
48 static int __bt_sprev(BTREE *, PAGE *, const DBT *, int *);
49
50 /*
51 * __bt_search --
52 * 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(BTREE *t, const DBT *key, int *exactp)
66 {
67 PAGE *h;
68 indx_t base, idx, lim;
69 pgno_t pg;
70 int cmp;
71
72 BT_CLR(t);
73 for (pg = P_ROOT;;) {
74 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
75 return (NULL);
76
77 /* Do a binary search on the current page. */
78 t->bt_cur.page = h;
79 for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
80 t->bt_cur.index = idx = base + ((uint32_t)lim >> 1);
81 if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
82 if (h->flags & P_BLEAF) {
83 *exactp = 1;
84 return (&t->bt_cur);
85 }
86 goto next;
87 }
88 if (cmp > 0) {
89 base = idx + 1;
90 --lim;
91 }
92 }
93
94 /*
95 * If it's a leaf page, we're almost done. If no duplicates
96 * are allowed, or we have an exact match, we're done. Else,
97 * it's possible that there were matching keys on this page,
98 * which later deleted, and we're on a page with no matches
99 * while there are matches on other pages. If at the start or
100 * end of a page, check the adjacent page.
101 */
102 if (h->flags & P_BLEAF) {
103 if (!F_ISSET(t, B_NODUPS)) {
104 if (base == 0 &&
105 h->prevpg != P_INVALID &&
106 __bt_sprev(t, h, key, exactp))
107 return (&t->bt_cur);
108 if (base == NEXTINDEX(h) &&
109 h->nextpg != P_INVALID &&
110 __bt_snext(t, h, key, exactp))
111 return (&t->bt_cur);
112 }
113 *exactp = 0;
114 t->bt_cur.index = base;
115 return (&t->bt_cur);
116 }
117
118 /*
119 * No match found. Base is the smallest index greater than
120 * key and may be zero or a last + 1 index. If it's non-zero,
121 * decrement by one, and record the internal page which should
122 * be a parent page for the key. If a split later occurs, the
123 * inserted page will be to the right of the saved page.
124 */
125 idx = base ? base - 1 : base;
126
127 next: BT_PUSH(t, h->pgno, idx);
128 pg = GETBINTERNAL(h, idx)->pgno;
129 mpool_put(t->bt_mp, h, 0);
130 }
131 }
132
133 /*
134 * __bt_snext --
135 * Check for an exact match after the key.
136 *
137 * Parameters:
138 * t: tree
139 * h: current page
140 * key: key
141 * exactp: pointer to exact match flag
142 *
143 * Returns:
144 * If an exact match found.
145 */
146 static int
147 __bt_snext(BTREE *t, PAGE *h, const DBT *key, int *exactp)
148 {
149 EPG e;
150
151 /*
152 * Get the next page. The key is either an exact
153 * match, or not as good as the one we already have.
154 */
155 if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
156 return (0);
157 e.index = 0;
158 if (__bt_cmp(t, key, &e) == 0) {
159 mpool_put(t->bt_mp, h, 0);
160 t->bt_cur = e;
161 *exactp = 1;
162 return (1);
163 }
164 mpool_put(t->bt_mp, e.page, 0);
165 return (0);
166 }
167
168 /*
169 * __bt_sprev --
170 * Check for an exact match before the key.
171 *
172 * Parameters:
173 * t: tree
174 * h: current page
175 * key: key
176 * exactp: pointer to exact match flag
177 *
178 * Returns:
179 * If an exact match found.
180 */
181 static int
182 __bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
183 {
184 EPG e;
185
186 /*
187 * Get the previous page. The key is either an exact
188 * match, or not as good as the one we already have.
189 */
190 if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
191 return (0);
192 e.index = NEXTINDEX(e.page) - 1;
193 if (__bt_cmp(t, key, &e) == 0) {
194 mpool_put(t->bt_mp, h, 0);
195 t->bt_cur = e;
196 *exactp = 1;
197 return (1);
198 }
199 mpool_put(t->bt_mp, e.page, 0);
200 return (0);
201 }
202