]>
git.saurik.com Git - apple/libc.git/blob - db/btree/FreeBSD/bt_seq.c
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 * 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.
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
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid
[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
39 #endif /* LIBC_SCCS and not lint */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: src/lib/libc/db/btree/bt_seq.c,v 1.3 2002/03/21 22:46:25 obrien Exp $");
43 #include <sys/types.h>
53 static int __bt_first(BTREE
*, const DBT
*, EPG
*, int *);
54 static int __bt_seqadv(BTREE
*, EPG
*, int);
55 static int __bt_seqset(BTREE
*, EPG
*, DBT
*, int);
58 * Sequential scan support.
60 * The tree can be scanned sequentially, starting from either end of the
61 * tree or from any specific key. A scan request before any scanning is
62 * done is initialized as starting from the least node.
67 * Btree sequential scan interface.
70 * dbp: pointer to access method
71 * key: key for positioning and return value
72 * data: data return value
73 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
76 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
79 __bt_seq(dbp
, key
, data
, flags
)
90 /* Toss any page pinned across calls. */
91 if (t
->bt_pinned
!= NULL
) {
92 mpool_put(t
->bt_mp
, t
->bt_pinned
, 0);
97 * If scan unitialized as yet, or starting at a specific record, set
98 * the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
99 * the page the cursor references if they're successful.
104 if (F_ISSET(&t
->bt_cursor
, CURS_INIT
)) {
105 status
= __bt_seqadv(t
, &e
, flags
);
112 status
= __bt_seqset(t
, &e
, key
, flags
);
119 if (status
== RET_SUCCESS
) {
120 __bt_setcur(t
, e
.page
->pgno
, e
.index
);
123 __bt_ret(t
, &e
, key
, &t
->bt_rkey
, data
, &t
->bt_rdata
, 0);
126 * If the user is doing concurrent access, we copied the
127 * key/data, toss the page.
129 if (F_ISSET(t
, B_DB_LOCK
))
130 mpool_put(t
->bt_mp
, e
.page
, 0);
132 t
->bt_pinned
= e
.page
;
139 * Set the sequential scan to a specific key.
143 * ep: storage for returned key
144 * key: key for initial scan position
145 * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
148 * Pins the page the cursor references.
151 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
154 __bt_seqset(t
, ep
, key
, flags
)
165 * Find the first, last or specific key in the tree and point the
166 * cursor at it. The cursor may not be moved until a new key has
170 case R_CURSOR
: /* Keyed scan. */
172 * Find the first instance of the key or the smallest key
173 * which is greater than or equal to the specified key.
175 if (key
->data
== NULL
|| key
->size
== 0) {
179 return (__bt_first(t
, key
, ep
, &exact
));
180 case R_FIRST
: /* First record. */
182 /* Walk down the left-hand side of the tree. */
183 for (pg
= P_ROOT
;;) {
184 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
187 /* Check for an empty tree. */
188 if (NEXTINDEX(h
) == 0) {
189 mpool_put(t
->bt_mp
, h
, 0);
190 return (RET_SPECIAL
);
193 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
195 pg
= GETBINTERNAL(h
, 0)->pgno
;
196 mpool_put(t
->bt_mp
, h
, 0);
201 case R_LAST
: /* Last record. */
203 /* Walk down the right-hand side of the tree. */
204 for (pg
= P_ROOT
;;) {
205 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
208 /* Check for an empty tree. */
209 if (NEXTINDEX(h
) == 0) {
210 mpool_put(t
->bt_mp
, h
, 0);
211 return (RET_SPECIAL
);
214 if (h
->flags
& (P_BLEAF
| P_RLEAF
))
216 pg
= GETBINTERNAL(h
, NEXTINDEX(h
) - 1)->pgno
;
217 mpool_put(t
->bt_mp
, h
, 0);
221 ep
->index
= NEXTINDEX(h
) - 1;
224 return (RET_SUCCESS
);
229 * Advance the sequential scan.
233 * flags: R_NEXT, R_PREV
236 * Pins the page the new key/data record is on.
239 * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
242 __bt_seqadv(t
, ep
, flags
)
254 * There are a couple of states that we can be in. The cursor has
255 * been initialized by the time we get here, but that's all we know.
260 * The cursor was deleted where there weren't any duplicate records,
261 * so the key was saved. Find out where that key would go in the
262 * current tree. It doesn't matter if the returned key is an exact
263 * match or not -- if it's an exact match, the record was added after
264 * the delete so we can just return it. If not, as long as there's
265 * a record there, return it.
267 if (F_ISSET(c
, CURS_ACQUIRE
))
268 return (__bt_first(t
, &c
->key
, ep
, &exact
));
270 /* Get the page referenced by the cursor. */
271 if ((h
= mpool_get(t
->bt_mp
, c
->pg
.pgno
, 0)) == NULL
)
275 * Find the next/previous record in the tree and point the cursor at
276 * it. The cursor may not be moved until a new key has been found.
279 case R_NEXT
: /* Next record. */
281 * The cursor was deleted in duplicate records, and moved
282 * forward to a record that has yet to be returned. Clear
283 * that flag, and return the record.
285 if (F_ISSET(c
, CURS_AFTER
))
288 if (++index
== NEXTINDEX(h
)) {
290 mpool_put(t
->bt_mp
, h
, 0);
292 return (RET_SPECIAL
);
293 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
298 case R_PREV
: /* Previous record. */
300 * The cursor was deleted in duplicate records, and moved
301 * backward to a record that has yet to be returned. Clear
302 * that flag, and return the record.
304 if (F_ISSET(c
, CURS_BEFORE
)) {
305 usecurrent
: F_CLR(c
, CURS_AFTER
| CURS_BEFORE
);
307 ep
->index
= c
->pg
.index
;
308 return (RET_SUCCESS
);
313 mpool_put(t
->bt_mp
, h
, 0);
315 return (RET_SPECIAL
);
316 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
318 index
= NEXTINDEX(h
) - 1;
326 return (RET_SUCCESS
);
331 * Find the first entry.
337 * exactp: pointer to exact match flag
340 * The first entry in the tree greater than or equal to key,
341 * or RET_SPECIAL if no such key exists.
344 __bt_first(t
, key
, erval
, exactp
)
355 * Find any matching record; __bt_search pins the page.
357 * If it's an exact match and duplicates are possible, walk backwards
358 * in the tree until we find the first one. Otherwise, make sure it's
359 * a valid key (__bt_search may return an index just past the end of a
360 * page) and return it.
362 if ((ep
= __bt_search(t
, key
, exactp
)) == NULL
)
365 if (F_ISSET(t
, B_NODUPS
)) {
367 return (RET_SUCCESS
);
371 * Walk backwards, as long as the entry matches and there are
372 * keys left in the tree. Save a copy of each match in case
378 if (save
.page
->pgno
!= ep
->page
->pgno
) {
379 mpool_put(t
->bt_mp
, save
.page
, 0);
382 save
.index
= ep
->index
;
385 * Don't unpin the page the last (or original) match
386 * was on, but make sure it's unpinned if an error
389 if (ep
->index
== 0) {
390 if (h
->prevpg
== P_INVALID
)
392 if (h
->pgno
!= save
.page
->pgno
)
393 mpool_put(t
->bt_mp
, h
, 0);
394 if ((h
= mpool_get(t
->bt_mp
,
395 h
->prevpg
, 0)) == NULL
) {
396 if (h
->pgno
== save
.page
->pgno
)
402 ep
->index
= NEXTINDEX(h
);
405 } while (__bt_cmp(t
, key
, ep
) == 0);
408 * Reach here with the last page that was looked at pinned,
409 * which may or may not be the same as the last (or original)
410 * match page. If it's not useful, release it.
412 if (h
->pgno
!= save
.page
->pgno
)
413 mpool_put(t
->bt_mp
, h
, 0);
416 return (RET_SUCCESS
);
419 /* If at the end of a page, find the next entry. */
420 if (ep
->index
== NEXTINDEX(ep
->page
)) {
423 mpool_put(t
->bt_mp
, h
, 0);
425 return (RET_SPECIAL
);
426 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
432 return (RET_SUCCESS
);
437 * Set the cursor to an entry in the tree.
445 __bt_setcur(t
, pgno
, index
)
450 /* Lose any already deleted key. */
451 if (t
->bt_cursor
.key
.data
!= NULL
) {
452 free(t
->bt_cursor
.key
.data
);
453 t
->bt_cursor
.key
.size
= 0;
454 t
->bt_cursor
.key
.data
= NULL
;
456 F_CLR(&t
->bt_cursor
, CURS_ACQUIRE
| CURS_AFTER
| CURS_BEFORE
);
458 /* Update the cursor. */
459 t
->bt_cursor
.pg
.pgno
= pgno
;
460 t
->bt_cursor
.pg
.index
= index
;
461 F_SET(&t
->bt_cursor
, CURS_INIT
);