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