146131Smao /*- 246131Smao * Copyright (c) 1990 The Regents of the University of California. 346131Smao * All rights reserved. 446131Smao * 546131Smao * This code is derived from software contributed to Berkeley by 646131Smao * Mike Olson. 746131Smao * 846131Smao * %sccs.include.redist.c% 946131Smao */ 1046131Smao 1146131Smao #if defined(LIBC_SCCS) && !defined(lint) 12*50989Sbostic static char sccsid[] = "@(#)bt_put.c 5.4 (Berkeley) 09/04/91"; 1346131Smao #endif /* LIBC_SCCS and not lint */ 1446131Smao 1546131Smao #include <sys/types.h> 16*50989Sbostic #include <errno.h> 1746131Smao #include <db.h> 18*50989Sbostic #include <stdio.h> 1946561Sbostic #include <stdlib.h> 2046561Sbostic #include <string.h> 2146131Smao #include "btree.h" 2246131Smao 23*50989Sbostic static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *)); 24*50989Sbostic 2546131Smao /* 26*50989Sbostic * __BT_PUT -- Add a btree item to the tree. 2746131Smao * 28*50989Sbostic * Parameters: 29*50989Sbostic * dbp: pointer to access method 30*50989Sbostic * key: key 31*50989Sbostic * data: data 32*50989Sbostic * flag: R_NOOVERWRITE 3346131Smao * 34*50989Sbostic * Returns: 35*50989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 36*50989Sbostic * tree and R_NOOVERWRITE specified. 3746131Smao */ 3846131Smao int 39*50989Sbostic __bt_put(dbp, key, data, flags) 40*50989Sbostic const DB *dbp; 41*50989Sbostic const DBT *key, *data; 42*50989Sbostic u_int flags; 4346131Smao { 44*50989Sbostic BTREE *t; 45*50989Sbostic DBT tkey, tdata; 46*50989Sbostic EPG *e; 47*50989Sbostic PAGE *h; 48*50989Sbostic index_t index, nxtindex; 49*50989Sbostic pgno_t pg; 50*50989Sbostic size_t nbytes; 51*50989Sbostic int dflags, exact; 52*50989Sbostic char *dest, db[NOVFLSIZE], kb[NOVFLSIZE]; 5346131Smao 54*50989Sbostic if (flags && flags != R_NOOVERWRITE) { 55*50989Sbostic errno = EINVAL; 5646131Smao return (RET_ERROR); 5746131Smao } 58*50989Sbostic t = dbp->internal; 59*50989Sbostic if (ISSET(t, BTF_RDONLY)) { 60*50989Sbostic errno = EPERM; 61*50989Sbostic return (RET_ERROR); 6246131Smao } 63*50989Sbostic 64*50989Sbostic /* 65*50989Sbostic * If the key/data won't fit on a page, store it on indirect pages. 66*50989Sbostic * 67*50989Sbostic * XXX 68*50989Sbostic * If the insert fails later on, these pages aren't recovered. 69*50989Sbostic */ 70*50989Sbostic dflags = 0; 71*50989Sbostic if (key->size >= t->bt_minkeypage) { 72*50989Sbostic if (__ovfl_put(t, key, &pg) == RET_ERROR) 7346131Smao return (RET_ERROR); 74*50989Sbostic tkey.data = kb; 75*50989Sbostic tkey.size = NOVFLSIZE; 76*50989Sbostic *(pgno_t *)kb = pg; 77*50989Sbostic *(size_t *)(kb + sizeof(pgno_t)) = key->size; 78*50989Sbostic dflags |= P_BIGKEY; 79*50989Sbostic key = &tkey; 8046131Smao } 81*50989Sbostic if (data->size >= t->bt_minkeypage) { 82*50989Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 83*50989Sbostic return (RET_ERROR); 84*50989Sbostic tdata.data = db; 85*50989Sbostic tdata.size = NOVFLSIZE; 86*50989Sbostic *(pgno_t *)db = pg; 87*50989Sbostic *(size_t *)(db + sizeof(pgno_t)) = data->size; 88*50989Sbostic dflags |= P_BIGDATA; 89*50989Sbostic data = &tdata; 90*50989Sbostic } 9146131Smao 92*50989Sbostic /* bt_fast and __bt_search pin the returned page. */ 93*50989Sbostic if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 94*50989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 95*50989Sbostic return (RET_ERROR); 9646131Smao 97*50989Sbostic h = e->page; 98*50989Sbostic index = e->index; 9946131Smao 100*50989Sbostic /* 101*50989Sbostic * Add the specified key/data pair to the tree. If an identical key 102*50989Sbostic * is already in the tree, and R_NOOVERWRITE is set, an error is 103*50989Sbostic * returned. If R_NOOVERWRITE is not set, the key is either added (if 104*50989Sbostic * duplicates are permitted) or an error is returned. 105*50989Sbostic * 106*50989Sbostic * Pages are split as required. 107*50989Sbostic */ 108*50989Sbostic switch (flags) { 109*50989Sbostic case R_NOOVERWRITE: 110*50989Sbostic if (!exact) 111*50989Sbostic break; 112*50989Sbostic /* 113*50989Sbostic * One special case is if the cursor references the record and 114*50989Sbostic * it's been flagged for deletion. If so, we delete it and 115*50989Sbostic * pretend it was never there. Since the cursor will move to 116*50989Sbostic * the next record the inserted record won't be seen. 117*50989Sbostic */ 118*50989Sbostic if (ISSET(t, BTF_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 119*50989Sbostic t->bt_bcursor.index == index) { 120*50989Sbostic UNSET(t, BTF_DELCRSR); 121*50989Sbostic goto delete; 12246131Smao } 123*50989Sbostic BT_CLR(t); 124*50989Sbostic mpool_put(t->bt_mp, h, 0); 125*50989Sbostic return (RET_SPECIAL); 126*50989Sbostic default: 127*50989Sbostic if (!exact || NOTSET(t, BTF_NODUPS)) 128*50989Sbostic break; 129*50989Sbostic delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 130*50989Sbostic BT_CLR(t); 131*50989Sbostic mpool_put(t->bt_mp, h, 0); 13246131Smao return (RET_ERROR); 13346131Smao } 134*50989Sbostic break; 13546131Smao } 13646131Smao 137*50989Sbostic /* 138*50989Sbostic * If not enough room, or the user has put a ceiling on the number of 139*50989Sbostic * keys permitted in the page, split the page. The split code will 140*50989Sbostic * insert the key and data and unpin the current page. If inserting 141*50989Sbostic * into the offset array, shift the pointers up. 142*50989Sbostic */ 143*50989Sbostic nbytes = NBLEAFDBT(key->size, data->size); 144*50989Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t) || 145*50989Sbostic t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h)) 146*50989Sbostic return (__bt_split(t, h, key, data, dflags, nbytes, index)); 14746131Smao 148*50989Sbostic if (index < (nxtindex = NEXTINDEX(h))) 149*50989Sbostic bcopy(h->linp + index, h->linp + index + 1, 150*50989Sbostic (nxtindex - index) * sizeof(index_t)); 151*50989Sbostic h->lower += sizeof(index_t); 15246131Smao 153*50989Sbostic h->linp[index] = h->upper -= nbytes; 154*50989Sbostic dest = (char *)h + h->upper; 155*50989Sbostic WR_BLEAF(dest, key, data, dflags); 15646131Smao 157*50989Sbostic if (t->bt_order == NOT) 158*50989Sbostic if (h->nextpg == P_INVALID) { 159*50989Sbostic if (index == NEXTINDEX(h) - 1) { 160*50989Sbostic t->bt_order = FORWARD; 161*50989Sbostic t->bt_last.index = index; 162*50989Sbostic t->bt_last.pgno = h->pgno; 163*50989Sbostic } 164*50989Sbostic } else if (h->prevpg == P_INVALID) { 165*50989Sbostic if (index == 0) { 166*50989Sbostic t->bt_order = BACK; 167*50989Sbostic t->bt_last.index = 0; 168*50989Sbostic t->bt_last.pgno = h->pgno; 169*50989Sbostic } 17046131Smao } 17146131Smao 172*50989Sbostic BT_CLR(t); 173*50989Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 174*50989Sbostic SET(t, BTF_MODIFIED); 175*50989Sbostic return (RET_SUCCESS); 17646131Smao } 17746131Smao 178*50989Sbostic #ifdef STATISTICS 179*50989Sbostic u_long bt_cache_hit, bt_cache_miss; 180*50989Sbostic #endif 181*50989Sbostic 18246131Smao /* 183*50989Sbostic * BT_FAST -- Do a quick check for sorted data. 18446131Smao * 185*50989Sbostic * Parameters: 186*50989Sbostic * t: tree 187*50989Sbostic * key: key to insert 18846131Smao * 189*50989Sbostic * Returns: 190*50989Sbostic * EPG for new record or NULL if not found. 19146131Smao */ 192*50989Sbostic static EPG * 193*50989Sbostic bt_fast(t, key, data, exactp) 194*50989Sbostic BTREE *t; 195*50989Sbostic const DBT *key, *data; 196*50989Sbostic int *exactp; 19746131Smao { 198*50989Sbostic EPG e; 199*50989Sbostic PAGE *h; 200*50989Sbostic size_t nbytes; 201*50989Sbostic int cmp; 20246131Smao 203*50989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 204*50989Sbostic t->bt_order = NOT; 205*50989Sbostic return (NULL); 206*50989Sbostic } 207*50989Sbostic e.page = h; 208*50989Sbostic e.index = t->bt_last.index; 20946131Smao 21046131Smao /* 211*50989Sbostic * If won't fit in this page or have too many keys in this page, have 212*50989Sbostic * to search to get split stack. 21346131Smao */ 214*50989Sbostic nbytes = 215*50989Sbostic NBLEAFDBT(key->size >= t->bt_minkeypage ? NOVFLSIZE : key->size, 216*50989Sbostic data->size >= t->bt_minkeypage ? NOVFLSIZE : data->size); 217*50989Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t) || 218*50989Sbostic t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h)) 219*50989Sbostic goto miss; 22046131Smao 221*50989Sbostic if (t->bt_order == FORWARD) { 222*50989Sbostic if (e.page->nextpg != P_INVALID) 223*50989Sbostic goto miss; 224*50989Sbostic if (e.index != NEXTINDEX(h) - 1) 225*50989Sbostic goto miss; 226*50989Sbostic if ((cmp = __bt_cmp(t, key, &e)) < 0) 227*50989Sbostic goto miss; 228*50989Sbostic t->bt_last.index = ++e.index; 22946131Smao } else { 230*50989Sbostic if (e.page->prevpg != P_INVALID) 231*50989Sbostic goto miss; 232*50989Sbostic if (e.index != 0) 233*50989Sbostic goto miss; 234*50989Sbostic if ((cmp = __bt_cmp(t, key, &e)) > 0) 235*50989Sbostic goto miss; 236*50989Sbostic t->bt_last.index = 0; 23746131Smao } 238*50989Sbostic *exactp = cmp == 0; 239*50989Sbostic #ifdef STATISTICS 240*50989Sbostic ++bt_cache_hit; 241*50989Sbostic #endif 242*50989Sbostic return (&e); 24346131Smao 244*50989Sbostic miss: 245*50989Sbostic #ifdef STATISTICS 246*50989Sbostic ++bt_cache_miss; 247*50989Sbostic #endif 248*50989Sbostic t->bt_order = NOT; 249*50989Sbostic mpool_put(t->bt_mp, h, 0); 250*50989Sbostic return (NULL); 25146131Smao } 252