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