]>
git.saurik.com Git - apple/libc.git/blob - db/btree/FreeBSD/bt_seq.c
b0b8b04ede2f973a9e7e725404f2819f6d66af0c
2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #if defined(LIBC_SCCS) && !defined(lint)
34 static char sccsid
[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
35 #endif /* LIBC_SCCS and not lint */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD: src/lib/libc/db/btree/bt_seq.c,v 1.7 2009/03/04 00:58:04 delphij Exp $");
39 #include <sys/types.h>
49 static int __bt_first(BTREE
*, const DBT
*, EPG
*, int *);
50 static int __bt_seqadv(BTREE
*, EPG
*, int);
51 static int __bt_seqset(BTREE
*, EPG
*, DBT
*, int);
54 * Sequential scan support.
56 * The tree can be scanned sequentially, starting from either end of the
57 * tree or from any specific key. A scan request before any scanning is
58 * done is initialized as starting from the least node.
63 * Btree sequential scan interface.
66 * dbp: pointer to access method
67 * key: key for positioning and return value
68 * data: data return value
69 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
72 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
75 __bt_seq(const DB
*dbp
, DBT
*key
, DBT
*data
, u_int flags
)
83 /* Toss any page pinned across calls. */
84 if (t
->bt_pinned
!= NULL
) {
85 mpool_put(t
->bt_mp
, t
->bt_pinned
, 0);
90 * If scan unitialized as yet, or starting at a specific record, set
91 * the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
92 * the page the cursor references if they're successful.
97 if (F_ISSET(&t
->bt_cursor
, CURS_INIT
)) {
98 status
= __bt_seqadv(t
, &e
, flags
);
105 status
= __bt_seqset(t
, &e
, key
, flags
);
112 if (status
== RET_SUCCESS
) {
113 __bt_setcur(t
, e
.page
->pgno
, e
.index
);
116 __bt_ret(t
, &e
, key
, &t
->bt_rkey
, data
, &t
->bt_rdata
, 0);
119 * If the user is doing concurrent access, we copied the
120 * key/data, toss the page.
122 if (F_ISSET(t
, B_DB_LOCK
))
123 mpool_put(t
->bt_mp
, e
.page
, 0);
125 t
->bt_pinned
= e
.page
;
132 * Set the sequential scan to a specific key.
136 * ep: storage for returned key
137 * key: key for initial scan position
138 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
141 * Pins the page the cursor references.
144 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
147 __bt_seqset(BTREE
*t
, EPG
*ep
, DBT
*key
, int flags
)
154 * Find the first, last or specific key in the tree and point the
155 * cursor at it. The cursor may not be moved until a new key has
159 case R_CURSOR
: /* Keyed scan. */
161 * Find the first instance of the key or the smallest key
162 * which is greater than or equal to the specified key.
164 if (key
->data
== NULL
|| key
->size
== 0) {
168 return (__bt_first(t
, key
, ep
, &exact
));
169 case R_FIRST
: /* First record. */
171 /* Walk down the left-hand side of the tree. */
172 for (pg
= P_ROOT
;;) {
173 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
176 /* Check for an empty tree. */
177 if (NEXTINDEX(h
) == 0) {
178 mpool_put(t
->bt_mp
, h
, 0);
179 return (RET_SPECIAL
);
182 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
184 pg
= GETBINTERNAL(h
, 0)->pgno
;
185 mpool_put(t
->bt_mp
, h
, 0);
190 case R_LAST
: /* Last record. */
192 /* Walk down the right-hand side of the tree. */
193 for (pg
= P_ROOT
;;) {
194 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
197 /* Check for an empty tree. */
198 if (NEXTINDEX(h
) == 0) {
199 mpool_put(t
->bt_mp
, h
, 0);
200 return (RET_SPECIAL
);
203 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
205 pg
= GETBINTERNAL(h
, NEXTINDEX(h
) - 1)->pgno
;
206 mpool_put(t
->bt_mp
, h
, 0);
210 ep
->index
= NEXTINDEX(h
) - 1;
213 return (RET_SUCCESS
);
218 * Advance the sequential scan.
222 * flags: R_NEXT, R_PREV
225 * Pins the page the new key/data record is on.
228 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
231 __bt_seqadv(BTREE
*t
, EPG
*ep
, int flags
)
240 * There are a couple of states that we can be in. The cursor has
241 * been initialized by the time we get here, but that's all we know.
246 * The cursor was deleted where there weren't any duplicate records,
247 * so the key was saved. Find out where that key would go in the
248 * current tree. It doesn't matter if the returned key is an exact
249 * match or not -- if it's an exact match, the record was added after
250 * the delete so we can just return it. If not, as long as there's
251 * a record there, return it.
253 if (F_ISSET(c
, CURS_ACQUIRE
))
254 return (__bt_first(t
, &c
->key
, ep
, &exact
));
256 /* Get the page referenced by the cursor. */
257 if ((h
= mpool_get(t
->bt_mp
, c
->pg
.pgno
, 0)) == NULL
)
261 * Find the next/previous record in the tree and point the cursor at
262 * it. The cursor may not be moved until a new key has been found.
265 case R_NEXT
: /* Next record. */
267 * The cursor was deleted in duplicate records, and moved
268 * forward to a record that has yet to be returned. Clear
269 * that flag, and return the record.
271 if (F_ISSET(c
, CURS_AFTER
))
274 if (++idx
== NEXTINDEX(h
)) {
276 mpool_put(t
->bt_mp
, h
, 0);
278 return (RET_SPECIAL
);
279 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
284 case R_PREV
: /* Previous record. */
286 * The cursor was deleted in duplicate records, and moved
287 * backward to a record that has yet to be returned. Clear
288 * that flag, and return the record.
290 if (F_ISSET(c
, CURS_BEFORE
)) {
291 usecurrent
: F_CLR(c
, CURS_AFTER
| CURS_BEFORE
);
293 ep
->index
= c
->pg
.index
;
294 return (RET_SUCCESS
);
299 mpool_put(t
->bt_mp
, h
, 0);
301 return (RET_SPECIAL
);
302 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
304 idx
= NEXTINDEX(h
) - 1;
312 return (RET_SUCCESS
);
317 * Find the first entry.
323 * exactp: pointer to exact match flag
326 * The first entry in the tree greater than or equal to key,
327 * or RET_SPECIAL if no such key exists.
330 __bt_first(BTREE
*t
, const DBT
*key
, EPG
*erval
, int *exactp
)
337 * Find any matching record; __bt_search pins the page.
339 * If it's an exact match and duplicates are possible, walk backwards
340 * in the tree until we find the first one. Otherwise, make sure it's
341 * a valid key (__bt_search may return an index just past the end of a
342 * page) and return it.
344 if ((ep
= __bt_search(t
, key
, exactp
)) == NULL
)
347 if (F_ISSET(t
, B_NODUPS
)) {
349 return (RET_SUCCESS
);
353 * Walk backwards, as long as the entry matches and there are
354 * keys left in the tree. Save a copy of each match in case
360 if (save
.page
->pgno
!= ep
->page
->pgno
) {
361 mpool_put(t
->bt_mp
, save
.page
, 0);
364 save
.index
= ep
->index
;
367 * Don't unpin the page the last (or original) match
368 * was on, but make sure it's unpinned if an error
371 if (ep
->index
== 0) {
373 if (h
->prevpg
== P_INVALID
)
375 if (h
->pgno
!= save
.page
->pgno
)
376 mpool_put(t
->bt_mp
, h
, 0);
377 if ((hprev
= mpool_get(t
->bt_mp
,
378 h
->prevpg
, 0)) == NULL
) {
379 if (h
->pgno
== save
.page
->pgno
)
384 ep
->page
= h
= hprev
;
385 ep
->index
= NEXTINDEX(h
);
388 } while (__bt_cmp(t
, key
, ep
) == 0);
391 * Reach here with the last page that was looked at pinned,
392 * which may or may not be the same as the last (or original)
393 * match page. If it's not useful, release it.
395 if (h
->pgno
!= save
.page
->pgno
)
396 mpool_put(t
->bt_mp
, h
, 0);
399 return (RET_SUCCESS
);
402 /* If at the end of a page, find the next entry. */
403 if (ep
->index
== NEXTINDEX(ep
->page
)) {
406 mpool_put(t
->bt_mp
, h
, 0);
408 return (RET_SPECIAL
);
409 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
415 return (RET_SUCCESS
);
420 * Set the cursor to an entry in the tree.
428 __bt_setcur(BTREE
*t
, pgno_t pgno
, u_int idx
)
430 /* Lose any already deleted key. */
431 if (t
->bt_cursor
.key
.data
!= NULL
) {
432 free(t
->bt_cursor
.key
.data
);
433 t
->bt_cursor
.key
.size
= 0;
434 t
->bt_cursor
.key
.data
= NULL
;
436 F_CLR(&t
->bt_cursor
, CURS_ACQUIRE
| CURS_AFTER
| CURS_BEFORE
);
438 /* Update the cursor. */
439 t
->bt_cursor
.pg
.pgno
= pgno
;
440 t
->bt_cursor
.pg
.index
= idx
;
441 F_SET(&t
->bt_cursor
, CURS_INIT
);