Home | History | Annotate | Line # | Download | only in btree
bt_seq.c revision 1.11.12.1
      1  1.11.12.1   nathanw /*	$NetBSD: bt_seq.c,v 1.11.12.1 2002/01/28 20:50:23 nathanw Exp $	*/
      2        1.6       cgd 
      3        1.1       cgd /*-
      4        1.7       cgd  * Copyright (c) 1990, 1993, 1994
      5        1.1       cgd  *	The Regents of the University of California.  All rights reserved.
      6        1.1       cgd  *
      7        1.1       cgd  * This code is derived from software contributed to Berkeley by
      8        1.1       cgd  * Mike Olson.
      9        1.1       cgd  *
     10        1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11        1.1       cgd  * modification, are permitted provided that the following conditions
     12        1.1       cgd  * are met:
     13        1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14        1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15        1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17        1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18        1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     19        1.1       cgd  *    must display the following acknowledgement:
     20        1.1       cgd  *	This product includes software developed by the University of
     21        1.1       cgd  *	California, Berkeley and its contributors.
     22        1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     23        1.1       cgd  *    may be used to endorse or promote products derived from this software
     24        1.1       cgd  *    without specific prior written permission.
     25        1.1       cgd  *
     26        1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27        1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28        1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29        1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30        1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31        1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32        1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33        1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34        1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35        1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36        1.1       cgd  * SUCH DAMAGE.
     37        1.1       cgd  */
     38        1.1       cgd 
     39        1.9  christos #include <sys/cdefs.h>
     40        1.1       cgd #if defined(LIBC_SCCS) && !defined(lint)
     41        1.6       cgd #if 0
     42        1.7       cgd static char sccsid[] = "@(#)bt_seq.c	8.7 (Berkeley) 7/20/94";
     43        1.6       cgd #else
     44  1.11.12.1   nathanw __RCSID("$NetBSD: bt_seq.c,v 1.11.12.1 2002/01/28 20:50:23 nathanw Exp $");
     45        1.6       cgd #endif
     46        1.1       cgd #endif /* LIBC_SCCS and not lint */
     47        1.1       cgd 
     48       1.10       jtc #include "namespace.h"
     49        1.1       cgd #include <sys/types.h>
     50        1.1       cgd 
     51        1.1       cgd #include <errno.h>
     52        1.1       cgd #include <stddef.h>
     53        1.1       cgd #include <stdio.h>
     54        1.1       cgd #include <stdlib.h>
     55        1.1       cgd 
     56        1.1       cgd #include <db.h>
     57        1.1       cgd #include "btree.h"
     58        1.1       cgd 
     59        1.7       cgd static int __bt_first __P((BTREE *, const DBT *, EPG *, int *));
     60        1.7       cgd static int __bt_seqadv __P((BTREE *, EPG *, int));
     61        1.7       cgd static int __bt_seqset __P((BTREE *, EPG *, DBT *, int));
     62        1.1       cgd 
     63        1.1       cgd /*
     64        1.1       cgd  * Sequential scan support.
     65        1.1       cgd  *
     66        1.7       cgd  * The tree can be scanned sequentially, starting from either end of the
     67        1.7       cgd  * tree or from any specific key.  A scan request before any scanning is
     68        1.7       cgd  * done is initialized as starting from the least node.
     69        1.1       cgd  */
     70        1.1       cgd 
     71        1.1       cgd /*
     72        1.7       cgd  * __bt_seq --
     73        1.7       cgd  *	Btree sequential scan interface.
     74        1.1       cgd  *
     75        1.1       cgd  * Parameters:
     76        1.1       cgd  *	dbp:	pointer to access method
     77        1.1       cgd  *	key:	key for positioning and return value
     78        1.1       cgd  *	data:	data return value
     79        1.1       cgd  *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
     80        1.1       cgd  *
     81        1.1       cgd  * Returns:
     82        1.1       cgd  *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
     83        1.1       cgd  */
     84        1.1       cgd int
     85        1.1       cgd __bt_seq(dbp, key, data, flags)
     86        1.1       cgd 	const DB *dbp;
     87        1.1       cgd 	DBT *key, *data;
     88        1.1       cgd 	u_int flags;
     89        1.1       cgd {
     90        1.1       cgd 	BTREE *t;
     91        1.1       cgd 	EPG e;
     92        1.1       cgd 	int status;
     93        1.1       cgd 
     94        1.4       cgd 	t = dbp->internal;
     95        1.4       cgd 
     96        1.4       cgd 	/* Toss any page pinned across calls. */
     97        1.4       cgd 	if (t->bt_pinned != NULL) {
     98        1.4       cgd 		mpool_put(t->bt_mp, t->bt_pinned, 0);
     99        1.4       cgd 		t->bt_pinned = NULL;
    100        1.4       cgd 	}
    101        1.4       cgd 
    102        1.1       cgd 	/*
    103        1.1       cgd 	 * If scan unitialized as yet, or starting at a specific record, set
    104        1.7       cgd 	 * the scan to a specific key.  Both __bt_seqset and __bt_seqadv pin
    105        1.7       cgd 	 * the page the cursor references if they're successful.
    106        1.1       cgd 	 */
    107        1.7       cgd 	switch (flags) {
    108        1.1       cgd 	case R_NEXT:
    109        1.1       cgd 	case R_PREV:
    110        1.7       cgd 		if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
    111       1.11  christos 			status = __bt_seqadv(t, &e, (int)flags);
    112        1.1       cgd 			break;
    113        1.1       cgd 		}
    114        1.1       cgd 		/* FALLTHROUGH */
    115        1.1       cgd 	case R_FIRST:
    116        1.1       cgd 	case R_LAST:
    117        1.7       cgd 	case R_CURSOR:
    118       1.11  christos 		status = __bt_seqset(t, &e, key, (int)flags);
    119        1.1       cgd 		break;
    120        1.1       cgd 	default:
    121        1.1       cgd 		errno = EINVAL;
    122        1.1       cgd 		return (RET_ERROR);
    123        1.1       cgd 	}
    124        1.1       cgd 
    125        1.1       cgd 	if (status == RET_SUCCESS) {
    126       1.11  christos 		__bt_setcur(t, e.page->pgno, (u_int)e.index);
    127        1.1       cgd 
    128        1.7       cgd 		status =
    129        1.7       cgd 		    __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
    130        1.4       cgd 
    131        1.4       cgd 		/*
    132        1.4       cgd 		 * If the user is doing concurrent access, we copied the
    133        1.4       cgd 		 * key/data, toss the page.
    134        1.4       cgd 		 */
    135        1.7       cgd 		if (F_ISSET(t, B_DB_LOCK))
    136        1.4       cgd 			mpool_put(t->bt_mp, e.page, 0);
    137        1.4       cgd 		else
    138        1.4       cgd 			t->bt_pinned = e.page;
    139        1.1       cgd 	}
    140        1.1       cgd 	return (status);
    141        1.1       cgd }
    142        1.1       cgd 
    143        1.1       cgd /*
    144        1.7       cgd  * __bt_seqset --
    145        1.7       cgd  *	Set the sequential scan to a specific key.
    146        1.1       cgd  *
    147        1.1       cgd  * Parameters:
    148        1.1       cgd  *	t:	tree
    149        1.1       cgd  *	ep:	storage for returned key
    150        1.1       cgd  *	key:	key for initial scan position
    151        1.1       cgd  *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
    152        1.1       cgd  *
    153        1.1       cgd  * Side effects:
    154        1.1       cgd  *	Pins the page the cursor references.
    155        1.1       cgd  *
    156        1.1       cgd  * Returns:
    157        1.1       cgd  *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
    158        1.1       cgd  */
    159        1.1       cgd static int
    160        1.7       cgd __bt_seqset(t, ep, key, flags)
    161        1.1       cgd 	BTREE *t;
    162        1.1       cgd 	EPG *ep;
    163        1.1       cgd 	DBT *key;
    164        1.1       cgd 	int flags;
    165        1.1       cgd {
    166        1.1       cgd 	PAGE *h;
    167        1.1       cgd 	pgno_t pg;
    168        1.1       cgd 	int exact;
    169        1.1       cgd 
    170        1.1       cgd 	/*
    171        1.7       cgd 	 * Find the first, last or specific key in the tree and point the
    172        1.7       cgd 	 * cursor at it.  The cursor may not be moved until a new key has
    173        1.7       cgd 	 * been found.
    174        1.1       cgd 	 */
    175        1.7       cgd 	switch (flags) {
    176        1.1       cgd 	case R_CURSOR:				/* Keyed scan. */
    177        1.1       cgd 		/*
    178        1.7       cgd 		 * Find the first instance of the key or the smallest key
    179        1.7       cgd 		 * which is greater than or equal to the specified key.
    180        1.1       cgd 		 */
    181        1.1       cgd 		if (key->data == NULL || key->size == 0) {
    182        1.1       cgd 			errno = EINVAL;
    183        1.1       cgd 			return (RET_ERROR);
    184        1.1       cgd 		}
    185        1.7       cgd 		return (__bt_first(t, key, ep, &exact));
    186        1.1       cgd 	case R_FIRST:				/* First record. */
    187        1.1       cgd 	case R_NEXT:
    188        1.1       cgd 		/* Walk down the left-hand side of the tree. */
    189        1.1       cgd 		for (pg = P_ROOT;;) {
    190        1.1       cgd 			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
    191        1.1       cgd 				return (RET_ERROR);
    192        1.7       cgd 
    193        1.7       cgd 			/* Check for an empty tree. */
    194        1.7       cgd 			if (NEXTINDEX(h) == 0) {
    195        1.7       cgd 				mpool_put(t->bt_mp, h, 0);
    196        1.7       cgd 				return (RET_SPECIAL);
    197        1.7       cgd 			}
    198        1.7       cgd 
    199        1.1       cgd 			if (h->flags & (P_BLEAF | P_RLEAF))
    200        1.1       cgd 				break;
    201        1.1       cgd 			pg = GETBINTERNAL(h, 0)->pgno;
    202        1.1       cgd 			mpool_put(t->bt_mp, h, 0);
    203        1.1       cgd 		}
    204        1.1       cgd 		ep->page = h;
    205        1.1       cgd 		ep->index = 0;
    206        1.1       cgd 		break;
    207        1.1       cgd 	case R_LAST:				/* Last record. */
    208        1.1       cgd 	case R_PREV:
    209        1.1       cgd 		/* Walk down the right-hand side of the tree. */
    210        1.1       cgd 		for (pg = P_ROOT;;) {
    211        1.1       cgd 			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
    212        1.1       cgd 				return (RET_ERROR);
    213        1.7       cgd 
    214        1.7       cgd 			/* Check for an empty tree. */
    215        1.7       cgd 			if (NEXTINDEX(h) == 0) {
    216        1.7       cgd 				mpool_put(t->bt_mp, h, 0);
    217        1.7       cgd 				return (RET_SPECIAL);
    218        1.7       cgd 			}
    219        1.7       cgd 
    220        1.1       cgd 			if (h->flags & (P_BLEAF | P_RLEAF))
    221        1.1       cgd 				break;
    222        1.1       cgd 			pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
    223        1.1       cgd 			mpool_put(t->bt_mp, h, 0);
    224        1.1       cgd 		}
    225        1.1       cgd 
    226        1.1       cgd 		ep->page = h;
    227        1.1       cgd 		ep->index = NEXTINDEX(h) - 1;
    228        1.1       cgd 		break;
    229        1.1       cgd 	}
    230        1.1       cgd 	return (RET_SUCCESS);
    231        1.1       cgd }
    232        1.1       cgd 
    233        1.1       cgd /*
    234        1.7       cgd  * __bt_seqadvance --
    235        1.7       cgd  *	Advance the sequential scan.
    236        1.1       cgd  *
    237        1.1       cgd  * Parameters:
    238        1.1       cgd  *	t:	tree
    239        1.1       cgd  *	flags:	R_NEXT, R_PREV
    240        1.1       cgd  *
    241        1.1       cgd  * Side effects:
    242        1.1       cgd  *	Pins the page the new key/data record is on.
    243        1.1       cgd  *
    244        1.1       cgd  * Returns:
    245        1.1       cgd  *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
    246        1.1       cgd  */
    247        1.1       cgd static int
    248        1.7       cgd __bt_seqadv(t, ep, flags)
    249        1.1       cgd 	BTREE *t;
    250        1.7       cgd 	EPG *ep;
    251        1.1       cgd 	int flags;
    252        1.1       cgd {
    253        1.7       cgd 	CURSOR *c;
    254        1.1       cgd 	PAGE *h;
    255  1.11.12.1   nathanw 	indx_t idx = 0;	/* pacify gcc */
    256        1.1       cgd 	pgno_t pg;
    257        1.7       cgd 	int exact;
    258        1.7       cgd 
    259        1.7       cgd 	/*
    260        1.7       cgd 	 * There are a couple of states that we can be in.  The cursor has
    261        1.7       cgd 	 * been initialized by the time we get here, but that's all we know.
    262        1.7       cgd 	 */
    263        1.7       cgd 	c = &t->bt_cursor;
    264        1.1       cgd 
    265        1.7       cgd 	/*
    266        1.7       cgd 	 * The cursor was deleted where there weren't any duplicate records,
    267        1.7       cgd 	 * so the key was saved.  Find out where that key would go in the
    268        1.7       cgd 	 * current tree.  It doesn't matter if the returned key is an exact
    269        1.7       cgd 	 * match or not -- if it's an exact match, the record was added after
    270        1.7       cgd 	 * the delete so we can just return it.  If not, as long as there's
    271        1.7       cgd 	 * a record there, return it.
    272        1.7       cgd 	 */
    273        1.7       cgd 	if (F_ISSET(c, CURS_ACQUIRE))
    274        1.7       cgd 		return (__bt_first(t, &c->key, ep, &exact));
    275        1.1       cgd 
    276        1.7       cgd 	/* Get the page referenced by the cursor. */
    277        1.7       cgd 	if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
    278        1.1       cgd 		return (RET_ERROR);
    279        1.1       cgd 
    280        1.1       cgd 	/*
    281        1.7       cgd  	 * Find the next/previous record in the tree and point the cursor at
    282        1.7       cgd 	 * it.  The cursor may not be moved until a new key has been found.
    283        1.1       cgd 	 */
    284        1.7       cgd 	switch (flags) {
    285        1.1       cgd 	case R_NEXT:			/* Next record. */
    286        1.7       cgd 		/*
    287        1.7       cgd 		 * The cursor was deleted in duplicate records, and moved
    288        1.7       cgd 		 * forward to a record that has yet to be returned.  Clear
    289        1.7       cgd 		 * that flag, and return the record.
    290        1.7       cgd 		 */
    291        1.7       cgd 		if (F_ISSET(c, CURS_AFTER))
    292        1.7       cgd 			goto usecurrent;
    293  1.11.12.1   nathanw 		idx = c->pg.index;
    294  1.11.12.1   nathanw 		if (++idx == NEXTINDEX(h)) {
    295        1.7       cgd 			pg = h->nextpg;
    296        1.7       cgd 			mpool_put(t->bt_mp, h, 0);
    297        1.7       cgd 			if (pg == P_INVALID)
    298        1.7       cgd 				return (RET_SPECIAL);
    299        1.7       cgd 			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
    300        1.7       cgd 				return (RET_ERROR);
    301  1.11.12.1   nathanw 			idx = 0;
    302        1.1       cgd 		}
    303        1.1       cgd 		break;
    304        1.1       cgd 	case R_PREV:			/* Previous record. */
    305        1.7       cgd 		/*
    306        1.7       cgd 		 * The cursor was deleted in duplicate records, and moved
    307        1.7       cgd 		 * backward to a record that has yet to be returned.  Clear
    308        1.7       cgd 		 * that flag, and return the record.
    309        1.7       cgd 		 */
    310        1.7       cgd 		if (F_ISSET(c, CURS_BEFORE)) {
    311        1.7       cgd usecurrent:		F_CLR(c, CURS_AFTER | CURS_BEFORE);
    312        1.7       cgd 			ep->page = h;
    313        1.7       cgd 			ep->index = c->pg.index;
    314        1.7       cgd 			return (RET_SUCCESS);
    315        1.7       cgd 		}
    316  1.11.12.1   nathanw 		idx = c->pg.index;
    317  1.11.12.1   nathanw 		if (idx == 0) {
    318        1.7       cgd 			pg = h->prevpg;
    319        1.7       cgd 			mpool_put(t->bt_mp, h, 0);
    320        1.7       cgd 			if (pg == P_INVALID)
    321        1.7       cgd 				return (RET_SPECIAL);
    322        1.7       cgd 			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
    323        1.7       cgd 				return (RET_ERROR);
    324  1.11.12.1   nathanw 			idx = NEXTINDEX(h) - 1;
    325        1.7       cgd 		} else
    326  1.11.12.1   nathanw 			--idx;
    327        1.1       cgd 		break;
    328        1.1       cgd 	}
    329        1.1       cgd 
    330        1.7       cgd 	ep->page = h;
    331  1.11.12.1   nathanw 	ep->index = idx;
    332        1.7       cgd 	return (RET_SUCCESS);
    333        1.7       cgd }
    334        1.7       cgd 
    335        1.7       cgd /*
    336        1.7       cgd  * __bt_first --
    337        1.7       cgd  *	Find the first entry.
    338        1.7       cgd  *
    339        1.7       cgd  * Parameters:
    340        1.7       cgd  *	t:	the tree
    341        1.7       cgd  *    key:	the key
    342        1.7       cgd  *  erval:	return EPG
    343        1.7       cgd  * exactp:	pointer to exact match flag
    344        1.7       cgd  *
    345        1.7       cgd  * Returns:
    346        1.7       cgd  *	The first entry in the tree greater than or equal to key,
    347        1.7       cgd  *	or RET_SPECIAL if no such key exists.
    348        1.7       cgd  */
    349        1.7       cgd static int
    350        1.7       cgd __bt_first(t, key, erval, exactp)
    351        1.7       cgd 	BTREE *t;
    352        1.7       cgd 	const DBT *key;
    353        1.7       cgd 	EPG *erval;
    354        1.7       cgd 	int *exactp;
    355        1.7       cgd {
    356        1.7       cgd 	PAGE *h;
    357        1.7       cgd 	EPG *ep, save;
    358        1.7       cgd 	pgno_t pg;
    359        1.1       cgd 
    360        1.1       cgd 	/*
    361        1.7       cgd 	 * Find any matching record; __bt_search pins the page.
    362        1.7       cgd 	 *
    363        1.7       cgd 	 * If it's an exact match and duplicates are possible, walk backwards
    364        1.7       cgd 	 * in the tree until we find the first one.  Otherwise, make sure it's
    365        1.7       cgd 	 * a valid key (__bt_search may return an index just past the end of a
    366        1.7       cgd 	 * page) and return it.
    367        1.1       cgd 	 */
    368        1.7       cgd 	if ((ep = __bt_search(t, key, exactp)) == NULL)
    369        1.8        pk 		return (0);
    370        1.7       cgd 	if (*exactp) {
    371        1.7       cgd 		if (F_ISSET(t, B_NODUPS)) {
    372        1.7       cgd 			*erval = *ep;
    373        1.7       cgd 			return (RET_SUCCESS);
    374        1.7       cgd 		}
    375        1.7       cgd 
    376        1.7       cgd 		/*
    377        1.7       cgd 		 * Walk backwards, as long as the entry matches and there are
    378        1.7       cgd 		 * keys left in the tree.  Save a copy of each match in case
    379        1.7       cgd 		 * we go too far.
    380        1.7       cgd 		 */
    381        1.7       cgd 		save = *ep;
    382        1.7       cgd 		h = ep->page;
    383        1.7       cgd 		do {
    384        1.7       cgd 			if (save.page->pgno != ep->page->pgno) {
    385        1.7       cgd 				mpool_put(t->bt_mp, save.page, 0);
    386        1.7       cgd 				save = *ep;
    387        1.7       cgd 			} else
    388        1.7       cgd 				save.index = ep->index;
    389        1.7       cgd 
    390        1.7       cgd 			/*
    391        1.7       cgd 			 * Don't unpin the page the last (or original) match
    392        1.7       cgd 			 * was on, but make sure it's unpinned if an error
    393        1.7       cgd 			 * occurs.
    394        1.7       cgd 			 */
    395        1.7       cgd 			if (ep->index == 0) {
    396        1.7       cgd 				if (h->prevpg == P_INVALID)
    397        1.7       cgd 					break;
    398        1.7       cgd 				if (h->pgno != save.page->pgno)
    399        1.7       cgd 					mpool_put(t->bt_mp, h, 0);
    400        1.7       cgd 				if ((h = mpool_get(t->bt_mp,
    401        1.7       cgd 				    h->prevpg, 0)) == NULL) {
    402        1.7       cgd 					if (h->pgno == save.page->pgno)
    403        1.7       cgd 						mpool_put(t->bt_mp,
    404        1.7       cgd 						    save.page, 0);
    405        1.7       cgd 					return (RET_ERROR);
    406        1.7       cgd 				}
    407        1.7       cgd 				ep->page = h;
    408        1.7       cgd 				ep->index = NEXTINDEX(h);
    409        1.7       cgd 			}
    410        1.7       cgd 			--ep->index;
    411        1.7       cgd 		} while (__bt_cmp(t, key, ep) == 0);
    412        1.7       cgd 
    413        1.7       cgd 		/*
    414        1.7       cgd 		 * Reach here with the last page that was looked at pinned,
    415        1.7       cgd 		 * which may or may not be the same as the last (or original)
    416        1.7       cgd 		 * match page.  If it's not useful, release it.
    417        1.7       cgd 		 */
    418        1.7       cgd 		if (h->pgno != save.page->pgno)
    419        1.7       cgd 			mpool_put(t->bt_mp, h, 0);
    420        1.7       cgd 
    421        1.7       cgd 		*erval = save;
    422        1.7       cgd 		return (RET_SUCCESS);
    423        1.7       cgd 	}
    424        1.7       cgd 
    425        1.7       cgd 	/* If at the end of a page, find the next entry. */
    426        1.7       cgd 	if (ep->index == NEXTINDEX(ep->page)) {
    427        1.7       cgd 		h = ep->page;
    428        1.7       cgd 		pg = h->nextpg;
    429        1.7       cgd 		mpool_put(t->bt_mp, h, 0);
    430        1.7       cgd 		if (pg == P_INVALID)
    431        1.7       cgd 			return (RET_SPECIAL);
    432        1.7       cgd 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
    433        1.1       cgd 			return (RET_ERROR);
    434        1.7       cgd 		ep->index = 0;
    435        1.7       cgd 		ep->page = h;
    436        1.1       cgd 	}
    437        1.7       cgd 	*erval = *ep;
    438        1.1       cgd 	return (RET_SUCCESS);
    439        1.1       cgd }
    440        1.1       cgd 
    441        1.1       cgd /*
    442        1.7       cgd  * __bt_setcur --
    443        1.7       cgd  *	Set the cursor to an entry in the tree.
    444        1.1       cgd  *
    445        1.1       cgd  * Parameters:
    446        1.7       cgd  *	t:	the tree
    447        1.7       cgd  *   pgno:	page number
    448  1.11.12.1   nathanw  *    idx:	page index
    449        1.1       cgd  */
    450        1.7       cgd void
    451  1.11.12.1   nathanw __bt_setcur(t, pgno, idx)
    452        1.1       cgd 	BTREE *t;
    453        1.7       cgd 	pgno_t pgno;
    454  1.11.12.1   nathanw 	u_int idx;
    455        1.1       cgd {
    456        1.7       cgd 	/* Lose any already deleted key. */
    457        1.7       cgd 	if (t->bt_cursor.key.data != NULL) {
    458        1.7       cgd 		free(t->bt_cursor.key.data);
    459        1.7       cgd 		t->bt_cursor.key.size = 0;
    460        1.7       cgd 		t->bt_cursor.key.data = NULL;
    461        1.7       cgd 	}
    462        1.7       cgd 	F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
    463        1.1       cgd 
    464        1.7       cgd 	/* Update the cursor. */
    465        1.7       cgd 	t->bt_cursor.pg.pgno = pgno;
    466  1.11.12.1   nathanw 	t->bt_cursor.pg.index = idx;
    467        1.7       cgd 	F_SET(&t->bt_cursor, CURS_INIT);
    468        1.1       cgd }
    469