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_put.c 5.4 (Berkeley) 09/04/91"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <sys/types.h> 16 #include <errno.h> 17 #include <db.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include "btree.h" 22 23 static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *)); 24 25 /* 26 * __BT_PUT -- Add a btree item to the tree. 27 * 28 * Parameters: 29 * dbp: pointer to access method 30 * key: key 31 * data: data 32 * flag: R_NOOVERWRITE 33 * 34 * Returns: 35 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 36 * tree and R_NOOVERWRITE specified. 37 */ 38 int 39 __bt_put(dbp, key, data, flags) 40 const DB *dbp; 41 const DBT *key, *data; 42 u_int flags; 43 { 44 BTREE *t; 45 DBT tkey, tdata; 46 EPG *e; 47 PAGE *h; 48 index_t index, nxtindex; 49 pgno_t pg; 50 size_t nbytes; 51 int dflags, exact; 52 char *dest, db[NOVFLSIZE], kb[NOVFLSIZE]; 53 54 if (flags && flags != R_NOOVERWRITE) { 55 errno = EINVAL; 56 return (RET_ERROR); 57 } 58 t = dbp->internal; 59 if (ISSET(t, BTF_RDONLY)) { 60 errno = EPERM; 61 return (RET_ERROR); 62 } 63 64 /* 65 * If the key/data won't fit on a page, store it on indirect pages. 66 * 67 * XXX 68 * If the insert fails later on, these pages aren't recovered. 69 */ 70 dflags = 0; 71 if (key->size >= t->bt_minkeypage) { 72 if (__ovfl_put(t, key, &pg) == RET_ERROR) 73 return (RET_ERROR); 74 tkey.data = kb; 75 tkey.size = NOVFLSIZE; 76 *(pgno_t *)kb = pg; 77 *(size_t *)(kb + sizeof(pgno_t)) = key->size; 78 dflags |= P_BIGKEY; 79 key = &tkey; 80 } 81 if (data->size >= t->bt_minkeypage) { 82 if (__ovfl_put(t, data, &pg) == RET_ERROR) 83 return (RET_ERROR); 84 tdata.data = db; 85 tdata.size = NOVFLSIZE; 86 *(pgno_t *)db = pg; 87 *(size_t *)(db + sizeof(pgno_t)) = data->size; 88 dflags |= P_BIGDATA; 89 data = &tdata; 90 } 91 92 /* bt_fast and __bt_search pin the returned page. */ 93 if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 94 if ((e = __bt_search(t, key, &exact)) == NULL) 95 return (RET_ERROR); 96 97 h = e->page; 98 index = e->index; 99 100 /* 101 * Add the specified key/data pair to the tree. If an identical key 102 * is already in the tree, and R_NOOVERWRITE is set, an error is 103 * returned. If R_NOOVERWRITE is not set, the key is either added (if 104 * duplicates are permitted) or an error is returned. 105 * 106 * Pages are split as required. 107 */ 108 switch (flags) { 109 case R_NOOVERWRITE: 110 if (!exact) 111 break; 112 /* 113 * One special case is if the cursor references the record and 114 * it's been flagged for deletion. If so, we delete it and 115 * pretend it was never there. Since the cursor will move to 116 * the next record the inserted record won't be seen. 117 */ 118 if (ISSET(t, BTF_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 119 t->bt_bcursor.index == index) { 120 UNSET(t, BTF_DELCRSR); 121 goto delete; 122 } 123 BT_CLR(t); 124 mpool_put(t->bt_mp, h, 0); 125 return (RET_SPECIAL); 126 default: 127 if (!exact || NOTSET(t, BTF_NODUPS)) 128 break; 129 delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 130 BT_CLR(t); 131 mpool_put(t->bt_mp, h, 0); 132 return (RET_ERROR); 133 } 134 break; 135 } 136 137 /* 138 * If not enough room, or the user has put a ceiling on the number of 139 * keys permitted in the page, split the page. The split code will 140 * insert the key and data and unpin the current page. If inserting 141 * into the offset array, shift the pointers up. 142 */ 143 nbytes = NBLEAFDBT(key->size, data->size); 144 if (h->upper - h->lower < nbytes + sizeof(index_t) || 145 t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h)) 146 return (__bt_split(t, h, key, data, dflags, nbytes, index)); 147 148 if (index < (nxtindex = NEXTINDEX(h))) 149 bcopy(h->linp + index, h->linp + index + 1, 150 (nxtindex - index) * sizeof(index_t)); 151 h->lower += sizeof(index_t); 152 153 h->linp[index] = h->upper -= nbytes; 154 dest = (char *)h + h->upper; 155 WR_BLEAF(dest, key, data, dflags); 156 157 if (t->bt_order == NOT) 158 if (h->nextpg == P_INVALID) { 159 if (index == NEXTINDEX(h) - 1) { 160 t->bt_order = FORWARD; 161 t->bt_last.index = index; 162 t->bt_last.pgno = h->pgno; 163 } 164 } else if (h->prevpg == P_INVALID) { 165 if (index == 0) { 166 t->bt_order = BACK; 167 t->bt_last.index = 0; 168 t->bt_last.pgno = h->pgno; 169 } 170 } 171 172 BT_CLR(t); 173 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 174 SET(t, BTF_MODIFIED); 175 return (RET_SUCCESS); 176 } 177 178 #ifdef STATISTICS 179 u_long bt_cache_hit, bt_cache_miss; 180 #endif 181 182 /* 183 * BT_FAST -- Do a quick check for sorted data. 184 * 185 * Parameters: 186 * t: tree 187 * key: key to insert 188 * 189 * Returns: 190 * EPG for new record or NULL if not found. 191 */ 192 static EPG * 193 bt_fast(t, key, data, exactp) 194 BTREE *t; 195 const DBT *key, *data; 196 int *exactp; 197 { 198 EPG e; 199 PAGE *h; 200 size_t nbytes; 201 int cmp; 202 203 if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 204 t->bt_order = NOT; 205 return (NULL); 206 } 207 e.page = h; 208 e.index = t->bt_last.index; 209 210 /* 211 * If won't fit in this page or have too many keys in this page, have 212 * to search to get split stack. 213 */ 214 nbytes = 215 NBLEAFDBT(key->size >= t->bt_minkeypage ? NOVFLSIZE : key->size, 216 data->size >= t->bt_minkeypage ? NOVFLSIZE : data->size); 217 if (h->upper - h->lower < nbytes + sizeof(index_t) || 218 t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h)) 219 goto miss; 220 221 if (t->bt_order == FORWARD) { 222 if (e.page->nextpg != P_INVALID) 223 goto miss; 224 if (e.index != NEXTINDEX(h) - 1) 225 goto miss; 226 if ((cmp = __bt_cmp(t, key, &e)) < 0) 227 goto miss; 228 t->bt_last.index = ++e.index; 229 } else { 230 if (e.page->prevpg != P_INVALID) 231 goto miss; 232 if (e.index != 0) 233 goto miss; 234 if ((cmp = __bt_cmp(t, key, &e)) > 0) 235 goto miss; 236 t->bt_last.index = 0; 237 } 238 *exactp = cmp == 0; 239 #ifdef STATISTICS 240 ++bt_cache_hit; 241 #endif 242 return (&e); 243 244 miss: 245 #ifdef STATISTICS 246 ++bt_cache_miss; 247 #endif 248 t->bt_order = NOT; 249 mpool_put(t->bt_mp, h, 0); 250 return (NULL); 251 } 252