158f0484fSRodney W. Grimes /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 4ef5d438eSPaul Traina * Copyright (c) 1990, 1993, 1994 558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 658f0484fSRodney W. Grimes * 758f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by 858f0484fSRodney W. Grimes * Mike Olson. 958f0484fSRodney W. Grimes * 1058f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 1158f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1258f0484fSRodney W. Grimes * are met: 1358f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1558f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1658f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1758f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 1958f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 2058f0484fSRodney W. Grimes * without specific prior written permission. 2158f0484fSRodney W. Grimes * 2258f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2358f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2458f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2558f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2658f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2758f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2858f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2958f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3058f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3158f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3258f0484fSRodney W. Grimes * SUCH DAMAGE. 3358f0484fSRodney W. Grimes */ 3458f0484fSRodney W. Grimes 3558f0484fSRodney W. Grimes #include <sys/types.h> 3658f0484fSRodney W. Grimes 3758f0484fSRodney W. Grimes #include <errno.h> 3858f0484fSRodney W. Grimes #include <stddef.h> 3958f0484fSRodney W. Grimes #include <stdio.h> 4058f0484fSRodney W. Grimes #include <stdlib.h> 4158f0484fSRodney W. Grimes 4258f0484fSRodney W. Grimes #include <db.h> 4358f0484fSRodney W. Grimes #include "btree.h" 4458f0484fSRodney W. Grimes 45c05ac53bSDavid E. O'Brien static int __bt_first(BTREE *, const DBT *, EPG *, int *); 46c05ac53bSDavid E. O'Brien static int __bt_seqadv(BTREE *, EPG *, int); 47c05ac53bSDavid E. O'Brien static int __bt_seqset(BTREE *, EPG *, DBT *, int); 4858f0484fSRodney W. Grimes 4958f0484fSRodney W. Grimes /* 5058f0484fSRodney W. Grimes * Sequential scan support. 5158f0484fSRodney W. Grimes * 52ef5d438eSPaul Traina * The tree can be scanned sequentially, starting from either end of the 53ef5d438eSPaul Traina * tree or from any specific key. A scan request before any scanning is 54ef5d438eSPaul Traina * done is initialized as starting from the least node. 5558f0484fSRodney W. Grimes */ 5658f0484fSRodney W. Grimes 5758f0484fSRodney W. Grimes /* 58ef5d438eSPaul Traina * __bt_seq -- 59ef5d438eSPaul Traina * Btree sequential scan interface. 6058f0484fSRodney W. Grimes * 6158f0484fSRodney W. Grimes * Parameters: 6258f0484fSRodney W. Grimes * dbp: pointer to access method 6358f0484fSRodney W. Grimes * key: key for positioning and return value 6458f0484fSRodney W. Grimes * data: data return value 6558f0484fSRodney W. Grimes * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV. 6658f0484fSRodney W. Grimes * 6758f0484fSRodney W. Grimes * Returns: 6858f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key. 6958f0484fSRodney W. Grimes */ 7058f0484fSRodney W. Grimes int 710ac22237SXin LI __bt_seq(const DB *dbp, DBT *key, DBT *data, u_int flags) 7258f0484fSRodney W. Grimes { 7358f0484fSRodney W. Grimes BTREE *t; 7458f0484fSRodney W. Grimes EPG e; 7558f0484fSRodney W. Grimes int status; 7658f0484fSRodney W. Grimes 7758f0484fSRodney W. Grimes t = dbp->internal; 7858f0484fSRodney W. Grimes 7958f0484fSRodney W. Grimes /* Toss any page pinned across calls. */ 8058f0484fSRodney W. Grimes if (t->bt_pinned != NULL) { 8158f0484fSRodney W. Grimes mpool_put(t->bt_mp, t->bt_pinned, 0); 8258f0484fSRodney W. Grimes t->bt_pinned = NULL; 8358f0484fSRodney W. Grimes } 8458f0484fSRodney W. Grimes 8558f0484fSRodney W. Grimes /* 86*0fc1fb14Srilysh * If scan uninitialized as yet, or starting at a specific record, set 87ef5d438eSPaul Traina * the scan to a specific key. Both __bt_seqset and __bt_seqadv pin 88ef5d438eSPaul Traina * the page the cursor references if they're successful. 8958f0484fSRodney W. Grimes */ 9058f0484fSRodney W. Grimes switch (flags) { 9158f0484fSRodney W. Grimes case R_NEXT: 9258f0484fSRodney W. Grimes case R_PREV: 93ef5d438eSPaul Traina if (F_ISSET(&t->bt_cursor, CURS_INIT)) { 94ef5d438eSPaul Traina status = __bt_seqadv(t, &e, flags); 9558f0484fSRodney W. Grimes break; 9658f0484fSRodney W. Grimes } 9758f0484fSRodney W. Grimes /* FALLTHROUGH */ 9858f0484fSRodney W. Grimes case R_FIRST: 9958f0484fSRodney W. Grimes case R_LAST: 100ef5d438eSPaul Traina case R_CURSOR: 101ef5d438eSPaul Traina status = __bt_seqset(t, &e, key, flags); 10258f0484fSRodney W. Grimes break; 10358f0484fSRodney W. Grimes default: 10458f0484fSRodney W. Grimes errno = EINVAL; 10558f0484fSRodney W. Grimes return (RET_ERROR); 10658f0484fSRodney W. Grimes } 10758f0484fSRodney W. Grimes 10858f0484fSRodney W. Grimes if (status == RET_SUCCESS) { 109ef5d438eSPaul Traina __bt_setcur(t, e.page->pgno, e.index); 11058f0484fSRodney W. Grimes 111ef5d438eSPaul Traina status = 112ef5d438eSPaul Traina __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0); 11358f0484fSRodney W. Grimes 11458f0484fSRodney W. Grimes /* 11558f0484fSRodney W. Grimes * If the user is doing concurrent access, we copied the 11658f0484fSRodney W. Grimes * key/data, toss the page. 11758f0484fSRodney W. Grimes */ 118ef5d438eSPaul Traina if (F_ISSET(t, B_DB_LOCK)) 11958f0484fSRodney W. Grimes mpool_put(t->bt_mp, e.page, 0); 12058f0484fSRodney W. Grimes else 12158f0484fSRodney W. Grimes t->bt_pinned = e.page; 12258f0484fSRodney W. Grimes } 12358f0484fSRodney W. Grimes return (status); 12458f0484fSRodney W. Grimes } 12558f0484fSRodney W. Grimes 12658f0484fSRodney W. Grimes /* 127ef5d438eSPaul Traina * __bt_seqset -- 128ef5d438eSPaul Traina * Set the sequential scan to a specific key. 12958f0484fSRodney W. Grimes * 13058f0484fSRodney W. Grimes * Parameters: 13158f0484fSRodney W. Grimes * t: tree 13258f0484fSRodney W. Grimes * ep: storage for returned key 13358f0484fSRodney W. Grimes * key: key for initial scan position 13458f0484fSRodney W. Grimes * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV 13558f0484fSRodney W. Grimes * 13658f0484fSRodney W. Grimes * Side effects: 13758f0484fSRodney W. Grimes * Pins the page the cursor references. 13858f0484fSRodney W. Grimes * 13958f0484fSRodney W. Grimes * Returns: 14058f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key. 14158f0484fSRodney W. Grimes */ 14258f0484fSRodney W. Grimes static int 1430ac22237SXin LI __bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags) 14458f0484fSRodney W. Grimes { 14558f0484fSRodney W. Grimes PAGE *h; 14658f0484fSRodney W. Grimes pgno_t pg; 14758f0484fSRodney W. Grimes int exact; 14858f0484fSRodney W. Grimes 14958f0484fSRodney W. Grimes /* 150ef5d438eSPaul Traina * Find the first, last or specific key in the tree and point the 151ef5d438eSPaul Traina * cursor at it. The cursor may not be moved until a new key has 152ef5d438eSPaul Traina * been found. 15358f0484fSRodney W. Grimes */ 15458f0484fSRodney W. Grimes switch (flags) { 15558f0484fSRodney W. Grimes case R_CURSOR: /* Keyed scan. */ 15658f0484fSRodney W. Grimes /* 157ef5d438eSPaul Traina * Find the first instance of the key or the smallest key 158ef5d438eSPaul Traina * which is greater than or equal to the specified key. 15958f0484fSRodney W. Grimes */ 16058f0484fSRodney W. Grimes if (key->data == NULL || key->size == 0) { 16158f0484fSRodney W. Grimes errno = EINVAL; 16258f0484fSRodney W. Grimes return (RET_ERROR); 16358f0484fSRodney W. Grimes } 164ef5d438eSPaul Traina return (__bt_first(t, key, ep, &exact)); 16558f0484fSRodney W. Grimes case R_FIRST: /* First record. */ 16658f0484fSRodney W. Grimes case R_NEXT: 16758f0484fSRodney W. Grimes /* Walk down the left-hand side of the tree. */ 16858f0484fSRodney W. Grimes for (pg = P_ROOT;;) { 16958f0484fSRodney W. Grimes if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 17058f0484fSRodney W. Grimes return (RET_ERROR); 17158f0484fSRodney W. Grimes 172ef5d438eSPaul Traina /* Check for an empty tree. */ 17358f0484fSRodney W. Grimes if (NEXTINDEX(h) == 0) { 17458f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 17558f0484fSRodney W. Grimes return (RET_SPECIAL); 17658f0484fSRodney W. Grimes } 17758f0484fSRodney W. Grimes 178ef5d438eSPaul Traina if (h->flags & (P_BLEAF | P_RLEAF)) 179ef5d438eSPaul Traina break; 180ef5d438eSPaul Traina pg = GETBINTERNAL(h, 0)->pgno; 181ef5d438eSPaul Traina mpool_put(t->bt_mp, h, 0); 182ef5d438eSPaul Traina } 18358f0484fSRodney W. Grimes ep->page = h; 18458f0484fSRodney W. Grimes ep->index = 0; 18558f0484fSRodney W. Grimes break; 18658f0484fSRodney W. Grimes case R_LAST: /* Last record. */ 18758f0484fSRodney W. Grimes case R_PREV: 18858f0484fSRodney W. Grimes /* Walk down the right-hand side of the tree. */ 18958f0484fSRodney W. Grimes for (pg = P_ROOT;;) { 19058f0484fSRodney W. Grimes if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 19158f0484fSRodney W. Grimes return (RET_ERROR); 192ef5d438eSPaul Traina 193ef5d438eSPaul Traina /* Check for an empty tree. */ 194ef5d438eSPaul Traina if (NEXTINDEX(h) == 0) { 195ef5d438eSPaul Traina mpool_put(t->bt_mp, h, 0); 196ef5d438eSPaul Traina return (RET_SPECIAL); 197ef5d438eSPaul Traina } 198ef5d438eSPaul Traina 19958f0484fSRodney W. Grimes if (h->flags & (P_BLEAF | P_RLEAF)) 20058f0484fSRodney W. Grimes break; 20158f0484fSRodney W. Grimes pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno; 20258f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 20358f0484fSRodney W. Grimes } 20458f0484fSRodney W. Grimes 20558f0484fSRodney W. Grimes ep->page = h; 20658f0484fSRodney W. Grimes ep->index = NEXTINDEX(h) - 1; 20758f0484fSRodney W. Grimes break; 20858f0484fSRodney W. Grimes } 20958f0484fSRodney W. Grimes return (RET_SUCCESS); 21058f0484fSRodney W. Grimes } 21158f0484fSRodney W. Grimes 21258f0484fSRodney W. Grimes /* 213ef5d438eSPaul Traina * __bt_seqadvance -- 214ef5d438eSPaul Traina * Advance the sequential scan. 21558f0484fSRodney W. Grimes * 21658f0484fSRodney W. Grimes * Parameters: 21758f0484fSRodney W. Grimes * t: tree 21858f0484fSRodney W. Grimes * flags: R_NEXT, R_PREV 21958f0484fSRodney W. Grimes * 22058f0484fSRodney W. Grimes * Side effects: 22158f0484fSRodney W. Grimes * Pins the page the new key/data record is on. 22258f0484fSRodney W. Grimes * 22358f0484fSRodney W. Grimes * Returns: 22458f0484fSRodney W. Grimes * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key. 22558f0484fSRodney W. Grimes */ 22658f0484fSRodney W. Grimes static int 2270ac22237SXin LI __bt_seqadv(BTREE *t, EPG *ep, int flags) 22858f0484fSRodney W. Grimes { 229ef5d438eSPaul Traina CURSOR *c; 23058f0484fSRodney W. Grimes PAGE *h; 2314c66e4b6SXin LI indx_t idx; 23258f0484fSRodney W. Grimes pgno_t pg; 233ef5d438eSPaul Traina int exact; 23458f0484fSRodney W. Grimes 235ef5d438eSPaul Traina /* 236ef5d438eSPaul Traina * There are a couple of states that we can be in. The cursor has 237ef5d438eSPaul Traina * been initialized by the time we get here, but that's all we know. 238ef5d438eSPaul Traina */ 239ef5d438eSPaul Traina c = &t->bt_cursor; 24058f0484fSRodney W. Grimes 241ef5d438eSPaul Traina /* 242ef5d438eSPaul Traina * The cursor was deleted where there weren't any duplicate records, 243ef5d438eSPaul Traina * so the key was saved. Find out where that key would go in the 244ef5d438eSPaul Traina * current tree. It doesn't matter if the returned key is an exact 245ef5d438eSPaul Traina * match or not -- if it's an exact match, the record was added after 246ef5d438eSPaul Traina * the delete so we can just return it. If not, as long as there's 247ef5d438eSPaul Traina * a record there, return it. 248ef5d438eSPaul Traina */ 249ef5d438eSPaul Traina if (F_ISSET(c, CURS_ACQUIRE)) 250ef5d438eSPaul Traina return (__bt_first(t, &c->key, ep, &exact)); 251ef5d438eSPaul Traina 252ef5d438eSPaul Traina /* Get the page referenced by the cursor. */ 253ef5d438eSPaul Traina if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL) 25458f0484fSRodney W. Grimes return (RET_ERROR); 25558f0484fSRodney W. Grimes 25658f0484fSRodney W. Grimes /* 257ef5d438eSPaul Traina * Find the next/previous record in the tree and point the cursor at 258ef5d438eSPaul Traina * it. The cursor may not be moved until a new key has been found. 25958f0484fSRodney W. Grimes */ 26058f0484fSRodney W. Grimes switch (flags) { 26158f0484fSRodney W. Grimes case R_NEXT: /* Next record. */ 262ef5d438eSPaul Traina /* 263ef5d438eSPaul Traina * The cursor was deleted in duplicate records, and moved 264ef5d438eSPaul Traina * forward to a record that has yet to be returned. Clear 265ef5d438eSPaul Traina * that flag, and return the record. 266ef5d438eSPaul Traina */ 267ef5d438eSPaul Traina if (F_ISSET(c, CURS_AFTER)) 268ef5d438eSPaul Traina goto usecurrent; 2694c66e4b6SXin LI idx = c->pg.index; 2704c66e4b6SXin LI if (++idx == NEXTINDEX(h)) { 27158f0484fSRodney W. Grimes pg = h->nextpg; 27258f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 27358f0484fSRodney W. Grimes if (pg == P_INVALID) 27458f0484fSRodney W. Grimes return (RET_SPECIAL); 27558f0484fSRodney W. Grimes if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 27658f0484fSRodney W. Grimes return (RET_ERROR); 2774c66e4b6SXin LI idx = 0; 27858f0484fSRodney W. Grimes } 27958f0484fSRodney W. Grimes break; 28058f0484fSRodney W. Grimes case R_PREV: /* Previous record. */ 281ef5d438eSPaul Traina /* 282ef5d438eSPaul Traina * The cursor was deleted in duplicate records, and moved 283ef5d438eSPaul Traina * backward to a record that has yet to be returned. Clear 284ef5d438eSPaul Traina * that flag, and return the record. 285ef5d438eSPaul Traina */ 286ef5d438eSPaul Traina if (F_ISSET(c, CURS_BEFORE)) { 287ef5d438eSPaul Traina usecurrent: F_CLR(c, CURS_AFTER | CURS_BEFORE); 288ef5d438eSPaul Traina ep->page = h; 289ef5d438eSPaul Traina ep->index = c->pg.index; 290ef5d438eSPaul Traina return (RET_SUCCESS); 291ef5d438eSPaul Traina } 2924c66e4b6SXin LI idx = c->pg.index; 2934c66e4b6SXin LI if (idx == 0) { 29458f0484fSRodney W. Grimes pg = h->prevpg; 29558f0484fSRodney W. Grimes mpool_put(t->bt_mp, h, 0); 29658f0484fSRodney W. Grimes if (pg == P_INVALID) 29758f0484fSRodney W. Grimes return (RET_SPECIAL); 29858f0484fSRodney W. Grimes if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 29958f0484fSRodney W. Grimes return (RET_ERROR); 3004c66e4b6SXin LI idx = NEXTINDEX(h) - 1; 301ef5d438eSPaul Traina } else 3024c66e4b6SXin LI --idx; 30358f0484fSRodney W. Grimes break; 30458f0484fSRodney W. Grimes } 30558f0484fSRodney W. Grimes 306ef5d438eSPaul Traina ep->page = h; 3074c66e4b6SXin LI ep->index = idx; 30858f0484fSRodney W. Grimes return (RET_SUCCESS); 30958f0484fSRodney W. Grimes } 31058f0484fSRodney W. Grimes 31158f0484fSRodney W. Grimes /* 312ef5d438eSPaul Traina * __bt_first -- 313ef5d438eSPaul Traina * Find the first entry. 31458f0484fSRodney W. Grimes * 31558f0484fSRodney W. Grimes * Parameters: 316ef5d438eSPaul Traina * t: the tree 317ef5d438eSPaul Traina * key: the key 318ef5d438eSPaul Traina * erval: return EPG 319ef5d438eSPaul Traina * exactp: pointer to exact match flag 32058f0484fSRodney W. Grimes * 32158f0484fSRodney W. Grimes * Returns: 322ef5d438eSPaul Traina * The first entry in the tree greater than or equal to key, 323ef5d438eSPaul Traina * or RET_SPECIAL if no such key exists. 32458f0484fSRodney W. Grimes */ 325ef5d438eSPaul Traina static int 3260ac22237SXin LI __bt_first(BTREE *t, const DBT *key, EPG *erval, int *exactp) 32758f0484fSRodney W. Grimes { 32858f0484fSRodney W. Grimes PAGE *h; 329ef5d438eSPaul Traina EPG *ep, save; 330ef5d438eSPaul Traina pgno_t pg; 33158f0484fSRodney W. Grimes 332ef5d438eSPaul Traina /* 333ef5d438eSPaul Traina * Find any matching record; __bt_search pins the page. 334ef5d438eSPaul Traina * 335ef5d438eSPaul Traina * If it's an exact match and duplicates are possible, walk backwards 336ef5d438eSPaul Traina * in the tree until we find the first one. Otherwise, make sure it's 337ef5d438eSPaul Traina * a valid key (__bt_search may return an index just past the end of a 338ef5d438eSPaul Traina * page) and return it. 339ef5d438eSPaul Traina */ 340ef5d438eSPaul Traina if ((ep = __bt_search(t, key, exactp)) == NULL) 341d030d2d2SPoul-Henning Kamp return (0); 342ef5d438eSPaul Traina if (*exactp) { 343ef5d438eSPaul Traina if (F_ISSET(t, B_NODUPS)) { 344ef5d438eSPaul Traina *erval = *ep; 345ef5d438eSPaul Traina return (RET_SUCCESS); 346ef5d438eSPaul Traina } 347ef5d438eSPaul Traina 348ef5d438eSPaul Traina /* 349ef5d438eSPaul Traina * Walk backwards, as long as the entry matches and there are 350ef5d438eSPaul Traina * keys left in the tree. Save a copy of each match in case 351ef5d438eSPaul Traina * we go too far. 352ef5d438eSPaul Traina */ 353ef5d438eSPaul Traina save = *ep; 354ef5d438eSPaul Traina h = ep->page; 355ef5d438eSPaul Traina do { 356ef5d438eSPaul Traina if (save.page->pgno != ep->page->pgno) { 357ef5d438eSPaul Traina mpool_put(t->bt_mp, save.page, 0); 358ef5d438eSPaul Traina save = *ep; 359ef5d438eSPaul Traina } else 360ef5d438eSPaul Traina save.index = ep->index; 361ef5d438eSPaul Traina 362ef5d438eSPaul Traina /* 363ef5d438eSPaul Traina * Don't unpin the page the last (or original) match 364ef5d438eSPaul Traina * was on, but make sure it's unpinned if an error 365ef5d438eSPaul Traina * occurs. 366ef5d438eSPaul Traina */ 367ef5d438eSPaul Traina if (ep->index == 0) { 368ef5d438eSPaul Traina if (h->prevpg == P_INVALID) 369ef5d438eSPaul Traina break; 370ef5d438eSPaul Traina if (h->pgno != save.page->pgno) 371ef5d438eSPaul Traina mpool_put(t->bt_mp, h, 0); 372ef5d438eSPaul Traina if ((h = mpool_get(t->bt_mp, 373ef5d438eSPaul Traina h->prevpg, 0)) == NULL) { 374ef5d438eSPaul Traina if (h->pgno == save.page->pgno) 375ef5d438eSPaul Traina mpool_put(t->bt_mp, 376ef5d438eSPaul Traina save.page, 0); 37758f0484fSRodney W. Grimes return (RET_ERROR); 378ef5d438eSPaul Traina } 379ef5d438eSPaul Traina ep->page = h; 380ef5d438eSPaul Traina ep->index = NEXTINDEX(h); 381ef5d438eSPaul Traina } 382ef5d438eSPaul Traina --ep->index; 383ef5d438eSPaul Traina } while (__bt_cmp(t, key, ep) == 0); 384ef5d438eSPaul Traina 385ef5d438eSPaul Traina /* 386ef5d438eSPaul Traina * Reach here with the last page that was looked at pinned, 387ef5d438eSPaul Traina * which may or may not be the same as the last (or original) 388ef5d438eSPaul Traina * match page. If it's not useful, release it. 389ef5d438eSPaul Traina */ 390ef5d438eSPaul Traina if (h->pgno != save.page->pgno) 391ef5d438eSPaul Traina mpool_put(t->bt_mp, h, 0); 392ef5d438eSPaul Traina 393ef5d438eSPaul Traina *erval = save; 394ef5d438eSPaul Traina return (RET_SUCCESS); 395ef5d438eSPaul Traina } 396ef5d438eSPaul Traina 397ef5d438eSPaul Traina /* If at the end of a page, find the next entry. */ 398ef5d438eSPaul Traina if (ep->index == NEXTINDEX(ep->page)) { 399ef5d438eSPaul Traina h = ep->page; 400ef5d438eSPaul Traina pg = h->nextpg; 401ef5d438eSPaul Traina mpool_put(t->bt_mp, h, 0); 402ef5d438eSPaul Traina if (pg == P_INVALID) 403ef5d438eSPaul Traina return (RET_SPECIAL); 404ef5d438eSPaul Traina if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 405ef5d438eSPaul Traina return (RET_ERROR); 406ef5d438eSPaul Traina ep->index = 0; 407ef5d438eSPaul Traina ep->page = h; 408ef5d438eSPaul Traina } 409ef5d438eSPaul Traina *erval = *ep; 410ef5d438eSPaul Traina return (RET_SUCCESS); 411ef5d438eSPaul Traina } 412ef5d438eSPaul Traina 413ef5d438eSPaul Traina /* 414ef5d438eSPaul Traina * __bt_setcur -- 415ef5d438eSPaul Traina * Set the cursor to an entry in the tree. 416ef5d438eSPaul Traina * 417ef5d438eSPaul Traina * Parameters: 418ef5d438eSPaul Traina * t: the tree 419ef5d438eSPaul Traina * pgno: page number 4204c66e4b6SXin LI * idx: page index 421ef5d438eSPaul Traina */ 422ef5d438eSPaul Traina void 4234c66e4b6SXin LI __bt_setcur(BTREE *t, pgno_t pgno, u_int idx) 424ef5d438eSPaul Traina { 425ef5d438eSPaul Traina /* Lose any already deleted key. */ 426ef5d438eSPaul Traina if (t->bt_cursor.key.data != NULL) { 427ef5d438eSPaul Traina free(t->bt_cursor.key.data); 428ef5d438eSPaul Traina t->bt_cursor.key.size = 0; 429ef5d438eSPaul Traina t->bt_cursor.key.data = NULL; 430ef5d438eSPaul Traina } 431ef5d438eSPaul Traina F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE); 432ef5d438eSPaul Traina 433ef5d438eSPaul Traina /* Update the cursor. */ 434ef5d438eSPaul Traina t->bt_cursor.pg.pgno = pgno; 4354c66e4b6SXin LI t->bt_cursor.pg.index = idx; 436ef5d438eSPaul Traina F_SET(&t->bt_cursor, CURS_INIT); 43758f0484fSRodney W. Grimes } 438