xref: /csrg-svn/lib/libc/db/btree/bt_search.c (revision 65021)
146132Smao /*-
261196Sbostic  * Copyright (c) 1990, 1993
361196Sbostic  *	The Regents of the University of California.  All rights reserved.
446132Smao  *
546132Smao  * This code is derived from software contributed to Berkeley by
646132Smao  * Mike Olson.
746132Smao  *
846132Smao  * %sccs.include.redist.c%
946132Smao  */
1046132Smao 
1146132Smao #if defined(LIBC_SCCS) && !defined(lint)
12*65021Sbostic static char sccsid[] = "@(#)bt_search.c	8.3 (Berkeley) 12/03/93";
1346132Smao #endif /* LIBC_SCCS and not lint */
1446132Smao 
1546132Smao #include <sys/types.h>
1656739Sbostic 
1750989Sbostic #include <stdio.h>
1856739Sbostic 
1957932Sbostic #include <db.h>
2046132Smao #include "btree.h"
2146132Smao 
22*65021Sbostic static EPG *bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
23*65021Sbostic static EPG *bt_sprev __P((BTREE *, PAGE *, const DBT *, int *));
24*65021Sbostic 
2546132Smao /*
2650989Sbostic  * __BT_SEARCH -- Search a btree for a key.
2746132Smao  *
2850989Sbostic  * Parameters:
2950989Sbostic  *	t:	tree to search
3050989Sbostic  *	key:	key to find
3150989Sbostic  *	exactp:	pointer to exact match flag
3246132Smao  *
3350989Sbostic  * Returns:
3464484Sbostic  *	The EPG for matching record, if any, or the EPG for the location
3564484Sbostic  *	of the key, if it were inserted into the tree, is entered into
3664484Sbostic  *	the bt_cur field of the tree.  A pointer to the field is returned.
3746132Smao  */
3850989Sbostic EPG *
3950989Sbostic __bt_search(t, key, exactp)
4050989Sbostic 	BTREE *t;
4150989Sbostic 	const DBT *key;
4250989Sbostic 	int *exactp;
4346132Smao {
44*65021Sbostic 	PAGE *h, *n;
45*65021Sbostic 	indx_t index;
4650989Sbostic 	pgno_t pg;
47*65021Sbostic 	int base, cmp, lim;
4846132Smao 
4957449Sbostic 	BT_CLR(t);
5050989Sbostic 	for (pg = P_ROOT;;) {
5150989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
5250989Sbostic 			return (NULL);
5346132Smao 
5450989Sbostic 		/* Do a binary search on the current page. */
5564484Sbostic 		t->bt_cur.page = h;
5650989Sbostic 		for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
5764484Sbostic 			t->bt_cur.index = index = base + (lim >> 1);
5864484Sbostic 			if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
5950989Sbostic 				if (h->flags & P_BLEAF) {
6050989Sbostic 					*exactp = 1;
6164484Sbostic 					return (&t->bt_cur);
6250989Sbostic 				}
6350989Sbostic 				goto next;
6446132Smao 			}
6550989Sbostic 			if (cmp > 0) {
6650989Sbostic 				base = index + 1;
6750989Sbostic 				--lim;
6846132Smao 			}
6946132Smao 		}
7046132Smao 
71*65021Sbostic 		/*
72*65021Sbostic 		 * If it's a leaf page, and duplicates aren't allowed, we're
73*65021Sbostic 		 * done.  If duplicates are allowed, it's possible that the
74*65021Sbostic 		 * matching spanned pages, and were later deleted, so we could
75*65021Sbostic 		 * be on the wrong page.  If we're at the start or end of a
76*65021Sbostic 		 * page, check.
77*65021Sbostic 		 */
7850989Sbostic 		if (h->flags & P_BLEAF) {
7964484Sbostic 			t->bt_cur.index = base;
8050989Sbostic 			*exactp = 0;
81*65021Sbostic 			if (!ISSET(t, B_NODUPS)) {
82*65021Sbostic 				if (base == 0 && h->prevpg != P_INVALID)
83*65021Sbostic 					return (bt_sprev(t, h, key, exactp));
84*65021Sbostic 				if (base == NEXTINDEX(h) &&
85*65021Sbostic 				    h->nextpg != P_INVALID)
86*65021Sbostic 					return (bt_snext(t, h, key, exactp));
87*65021Sbostic 			}
8864484Sbostic 			return (&t->bt_cur);
8946132Smao 		}
9046132Smao 
9157448Sbostic 		/*
9257448Sbostic 		 * No match found.  Base is the smallest index greater than
9357448Sbostic 		 * key and may be zero or a last + 1 index.  If it's non-zero,
9457448Sbostic 		 * decrement by one, and record the internal page which should
9557448Sbostic 		 * be a parent page for the key.  If a split later occurs, the
9657448Sbostic 		 * inserted page will be to the right of the saved page.
9757448Sbostic 		 */
9857448Sbostic 		index = base ? base - 1 : base;
9957448Sbostic 
10051105Sbostic next:		if (__bt_push(t, h->pgno, index) == RET_ERROR)
10150989Sbostic 			return (NULL);
10250989Sbostic 		pg = GETBINTERNAL(h, index)->pgno;
10350989Sbostic 		mpool_put(t->bt_mp, h, 0);
10446132Smao 	}
10546132Smao }
106*65021Sbostic 
107*65021Sbostic static EPG *
108*65021Sbostic bt_snext(t, h, key, exactp)
109*65021Sbostic 	BTREE *t;
110*65021Sbostic 	PAGE *h;
111*65021Sbostic 	const DBT *key;
112*65021Sbostic 	int *exactp;
113*65021Sbostic {
114*65021Sbostic 	EPG e;
115*65021Sbostic 	PAGE *tp;
116*65021Sbostic 	pgno_t pg;
117*65021Sbostic 
118*65021Sbostic 	/* Skip until reach the end of the tree or a key. */
119*65021Sbostic 	for (pg = h->nextpg; pg != P_INVALID;) {
120*65021Sbostic 		if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
121*65021Sbostic 			mpool_put(t->bt_mp, h, 0);
122*65021Sbostic 			return (NULL);
123*65021Sbostic 		}
124*65021Sbostic 		if (NEXTINDEX(tp) != 0)
125*65021Sbostic 			break;
126*65021Sbostic 		pg = tp->prevpg;
127*65021Sbostic 		mpool_put(t->bt_mp, tp, 0);
128*65021Sbostic 	}
129*65021Sbostic 	/*
130*65021Sbostic 	 * The key is either an exact match, or not as good as
131*65021Sbostic 	 * the one we already have.
132*65021Sbostic 	 */
133*65021Sbostic 	if (pg != P_INVALID) {
134*65021Sbostic 		e.page = tp;
135*65021Sbostic 		e.index = NEXTINDEX(tp) - 1;
136*65021Sbostic 		if (__bt_cmp(t, key, &e) == 0) {
137*65021Sbostic 			mpool_put(t->bt_mp, h, 0);
138*65021Sbostic 			t->bt_cur = e;
139*65021Sbostic 			*exactp = 1;
140*65021Sbostic 		}
141*65021Sbostic 	}
142*65021Sbostic 	return (&t->bt_cur);
143*65021Sbostic }
144*65021Sbostic 
145*65021Sbostic static EPG *
146*65021Sbostic bt_sprev(t, h, key, exactp)
147*65021Sbostic 	BTREE *t;
148*65021Sbostic 	PAGE *h;
149*65021Sbostic 	const DBT *key;
150*65021Sbostic 	int *exactp;
151*65021Sbostic {
152*65021Sbostic 	EPG e;
153*65021Sbostic 	PAGE *tp;
154*65021Sbostic 	pgno_t pg;
155*65021Sbostic 
156*65021Sbostic 	/* Skip until reach the beginning of the tree or a key. */
157*65021Sbostic 	for (pg = h->prevpg; pg != P_INVALID;) {
158*65021Sbostic 		if ((tp = mpool_get(t->bt_mp, pg, 0)) == NULL) {
159*65021Sbostic 			mpool_put(t->bt_mp, h, 0);
160*65021Sbostic 			return (NULL);
161*65021Sbostic 		}
162*65021Sbostic 		if (NEXTINDEX(tp) != 0)
163*65021Sbostic 			break;
164*65021Sbostic 		pg = tp->prevpg;
165*65021Sbostic 		mpool_put(t->bt_mp, tp, 0);
166*65021Sbostic 	}
167*65021Sbostic 	/*
168*65021Sbostic 	 * The key is either an exact match, or not as good as
169*65021Sbostic 	 * the one we already have.
170*65021Sbostic 	 */
171*65021Sbostic 	if (pg != P_INVALID) {
172*65021Sbostic 		e.page = tp;
173*65021Sbostic 		e.index = NEXTINDEX(tp) - 1;
174*65021Sbostic 		if (__bt_cmp(t, key, &e) == 0) {
175*65021Sbostic 			mpool_put(t->bt_mp, h, 0);
176*65021Sbostic 			t->bt_cur = e;
177*65021Sbostic 			*exactp = 1;
178*65021Sbostic 		}
179*65021Sbostic 	}
180*65021Sbostic 	return (&t->bt_cur);
181*65021Sbostic }
182