1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Olson. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)bt_get.c 5.8 (Berkeley) 02/14/93"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/types.h> 16 17 #include <errno.h> 18 #include <stddef.h> 19 #include <stdio.h> 20 21 #include <db.h> 22 #include "btree.h" 23 24 /* 25 * __BT_GET -- Get a record from the btree. 26 * 27 * Parameters: 28 * dbp: pointer to access method 29 * key: key to find 30 * data: data to return 31 * flag: currently unused 32 * 33 * Returns: 34 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found. 35 */ 36 int 37 __bt_get(dbp, key, data, flags) 38 const DB *dbp; 39 const DBT *key; 40 DBT *data; 41 u_int flags; 42 { 43 BTREE *t; 44 EPG *e; 45 int exact, status; 46 47 if (flags) { 48 errno = EINVAL; 49 return (RET_ERROR); 50 } 51 t = dbp->internal; 52 if ((e = __bt_search(t, key, &exact)) == NULL) 53 return (RET_ERROR); 54 if (!exact) { 55 mpool_put(t->bt_mp, e->page, 0); 56 return (RET_SPECIAL); 57 } 58 59 /* 60 * A special case is if we found the record but it's flagged for 61 * deletion. In this case, we want to find another record with the 62 * same key, if it exists. Rather than look around the tree we call 63 * __bt_first and have it redo the search, as __bt_first will not 64 * return keys marked for deletion. Slow, but should never happen. 65 */ 66 if (ISSET(t, BTF_DELCRSR) && e->page->pgno == t->bt_bcursor.pgno && 67 e->index == t->bt_bcursor.index) { 68 mpool_put(t->bt_mp, e->page, 0); 69 if ((e = __bt_first(t, key, &exact)) == NULL) 70 return (RET_ERROR); 71 if (!exact) 72 return (RET_SPECIAL); 73 } 74 75 status = __bt_ret(t, e, NULL, data); 76 mpool_put(t->bt_mp, e->page, 0); 77 return (status); 78 } 79 80 /* 81 * __BT_FIRST -- Find the first entry. 82 * 83 * Parameters: 84 * t: the tree 85 * key: the key 86 * 87 * Returns: 88 * The first entry in the tree greater than or equal to key. 89 */ 90 EPG * 91 __bt_first(t, key, exactp) 92 BTREE *t; 93 const DBT *key; 94 int *exactp; 95 { 96 register PAGE *h; 97 register EPG *e; 98 EPG save; 99 pgno_t cpgno, pg; 100 indx_t cindex; 101 int found; 102 103 /* 104 * Find any matching record; __bt_search pins the page. Only exact 105 * matches are tricky, otherwise just return the location of the key 106 * if it were to be inserted into the tree. 107 */ 108 if ((e = __bt_search(t, key, exactp)) == NULL) 109 return (NULL); 110 if (!*exactp) 111 return (e); 112 113 if (ISSET(t, BTF_DELCRSR)) { 114 cpgno = t->bt_bcursor.pgno; 115 cindex = t->bt_bcursor.index; 116 } else { 117 cpgno = P_INVALID; 118 cindex = 0; /* GCC thinks it's uninitialized. */ 119 } 120 121 /* 122 * Walk backwards, skipping empty pages, as long as the entry matches 123 * and there are keys left in the tree. Save a copy of each match in 124 * case we go too far. A special case is that we don't return a match 125 * on records that the cursor references that have already been flagged 126 * for deletion. 127 */ 128 save = *e; 129 h = e->page; 130 found = 0; 131 do { 132 if (cpgno != h->pgno || cindex != e->index) { 133 if (save.page->pgno != e->page->pgno) { 134 mpool_put(t->bt_mp, save.page, 0); 135 save = *e; 136 } else 137 save.index = e->index; 138 found = 1; 139 } 140 /* 141 * Make a special effort not to unpin the page the last (or 142 * original) match was on, but also make sure it's unpinned 143 * if an error occurs. 144 */ 145 while (e->index == 0) { 146 if (h->prevpg == P_INVALID) 147 goto done1; 148 if (h->pgno != save.page->pgno) 149 mpool_put(t->bt_mp, h, 0); 150 if ((h = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL) { 151 if (h->pgno == save.page->pgno) 152 mpool_put(t->bt_mp, save.page, 0); 153 return (NULL); 154 } 155 e->page = h; 156 e->index = NEXTINDEX(h); 157 } 158 --e->index; 159 } while (__bt_cmp(t, key, e) == 0); 160 161 /* 162 * Reach here with the last page that was looked at pinned, which may 163 * or may not be the same as the last (or original) match page. If 164 * it's not useful, release it. 165 */ 166 done1: if (h->pgno != save.page->pgno) 167 mpool_put(t->bt_mp, h, 0); 168 169 /* 170 * If still haven't found a record, the only possibility left is the 171 * next one. Move forward one slot, skipping empty pages and check. 172 */ 173 if (!found) { 174 h = save.page; 175 if (++save.index == NEXTINDEX(h)) { 176 do { 177 pg = h->nextpg; 178 mpool_put(t->bt_mp, h, 0); 179 if (pg == P_INVALID) { 180 *exactp = 0; 181 return (e); 182 } 183 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 184 return (NULL); 185 } while ((save.index = NEXTINDEX(h)) == 0); 186 save.page = h; 187 } 188 if (__bt_cmp(t, key, &save) != 0) { 189 *exactp = 0; 190 return (e); 191 } 192 } 193 *e = save; 194 *exactp = 1; 195 return (e); 196 } 197