bt_get.c revision 1.2 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[] = "from: @(#)bt_get.c 8.1 (Berkeley) 6/4/93";*/
39 static char rcsid[] = "$Id: bt_get.c,v 1.2 1993/08/01 18:43:56 mycroft Exp $";
40 #endif /* LIBC_SCCS and not lint */
41
42 #include <sys/types.h>
43
44 #include <errno.h>
45 #include <stddef.h>
46 #include <stdio.h>
47
48 #include <db.h>
49 #include "btree.h"
50
51 /*
52 * __BT_GET -- Get a record from the btree.
53 *
54 * Parameters:
55 * dbp: pointer to access method
56 * key: key to find
57 * data: data to return
58 * flag: currently unused
59 *
60 * Returns:
61 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
62 */
63 int
64 __bt_get(dbp, key, data, flags)
65 const DB *dbp;
66 const DBT *key;
67 DBT *data;
68 u_int flags;
69 {
70 BTREE *t;
71 EPG *e;
72 int exact, status;
73
74 if (flags) {
75 errno = EINVAL;
76 return (RET_ERROR);
77 }
78 t = dbp->internal;
79 if ((e = __bt_search(t, key, &exact)) == NULL)
80 return (RET_ERROR);
81 if (!exact) {
82 mpool_put(t->bt_mp, e->page, 0);
83 return (RET_SPECIAL);
84 }
85
86 /*
87 * A special case is if we found the record but it's flagged for
88 * deletion. In this case, we want to find another record with the
89 * same key, if it exists. Rather than look around the tree we call
90 * __bt_first and have it redo the search, as __bt_first will not
91 * return keys marked for deletion. Slow, but should never happen.
92 */
93 if (ISSET(t, B_DELCRSR) && e->page->pgno == t->bt_bcursor.pgno &&
94 e->index == t->bt_bcursor.index) {
95 mpool_put(t->bt_mp, e->page, 0);
96 if ((e = __bt_first(t, key, &exact)) == NULL)
97 return (RET_ERROR);
98 if (!exact)
99 return (RET_SPECIAL);
100 }
101
102 status = __bt_ret(t, e, NULL, data);
103 mpool_put(t->bt_mp, e->page, 0);
104 return (status);
105 }
106
107 /*
108 * __BT_FIRST -- Find the first entry.
109 *
110 * Parameters:
111 * t: the tree
112 * key: the key
113 *
114 * Returns:
115 * The first entry in the tree greater than or equal to key.
116 */
117 EPG *
118 __bt_first(t, key, exactp)
119 BTREE *t;
120 const DBT *key;
121 int *exactp;
122 {
123 register PAGE *h;
124 register EPG *e;
125 EPG save;
126 pgno_t cpgno, pg;
127 indx_t cindex;
128 int found;
129
130 /*
131 * Find any matching record; __bt_search pins the page. Only exact
132 * matches are tricky, otherwise just return the location of the key
133 * if it were to be inserted into the tree.
134 */
135 if ((e = __bt_search(t, key, exactp)) == NULL)
136 return (NULL);
137 if (!*exactp)
138 return (e);
139
140 if (ISSET(t, B_DELCRSR)) {
141 cpgno = t->bt_bcursor.pgno;
142 cindex = t->bt_bcursor.index;
143 } else {
144 cpgno = P_INVALID;
145 cindex = 0; /* GCC thinks it's uninitialized. */
146 }
147
148 /*
149 * Walk backwards, skipping empty pages, as long as the entry matches
150 * and there are keys left in the tree. Save a copy of each match in
151 * case we go too far. A special case is that we don't return a match
152 * on records that the cursor references that have already been flagged
153 * for deletion.
154 */
155 save = *e;
156 h = e->page;
157 found = 0;
158 do {
159 if (cpgno != h->pgno || cindex != e->index) {
160 if (save.page->pgno != e->page->pgno) {
161 mpool_put(t->bt_mp, save.page, 0);
162 save = *e;
163 } else
164 save.index = e->index;
165 found = 1;
166 }
167 /*
168 * Make a special effort not to unpin the page the last (or
169 * original) match was on, but also make sure it's unpinned
170 * if an error occurs.
171 */
172 while (e->index == 0) {
173 if (h->prevpg == P_INVALID)
174 goto done1;
175 if (h->pgno != save.page->pgno)
176 mpool_put(t->bt_mp, h, 0);
177 if ((h = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL) {
178 if (h->pgno == save.page->pgno)
179 mpool_put(t->bt_mp, save.page, 0);
180 return (NULL);
181 }
182 e->page = h;
183 e->index = NEXTINDEX(h);
184 }
185 --e->index;
186 } while (__bt_cmp(t, key, e) == 0);
187
188 /*
189 * Reach here with the last page that was looked at pinned, which may
190 * or may not be the same as the last (or original) match page. If
191 * it's not useful, release it.
192 */
193 done1: if (h->pgno != save.page->pgno)
194 mpool_put(t->bt_mp, h, 0);
195
196 /*
197 * If still haven't found a record, the only possibility left is the
198 * next one. Move forward one slot, skipping empty pages and check.
199 */
200 if (!found) {
201 h = save.page;
202 if (++save.index == NEXTINDEX(h)) {
203 do {
204 pg = h->nextpg;
205 mpool_put(t->bt_mp, h, 0);
206 if (pg == P_INVALID) {
207 *exactp = 0;
208 return (e);
209 }
210 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
211 return (NULL);
212 } while ((save.index = NEXTINDEX(h)) == 0);
213 save.page = h;
214 }
215 if (__bt_cmp(t, key, &save) != 0) {
216 *exactp = 0;
217 return (e);
218 }
219 }
220 *e = save;
221 *exactp = 1;
222 return (e);
223 }
224