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*51099Sbostic static char sccsid[] = "@(#)bt_put.c 5.5 (Berkeley) 09/12/91"; 1346131Smao #endif /* LIBC_SCCS and not lint */ 1446131Smao 1546131Smao #include <sys/types.h> 1650989Sbostic #include <errno.h> 1746131Smao #include <db.h> 1850989Sbostic #include <stdio.h> 1946561Sbostic #include <stdlib.h> 2046561Sbostic #include <string.h> 2146131Smao #include "btree.h" 2246131Smao 2350989Sbostic static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *)); 2450989Sbostic 2546131Smao /* 2650989Sbostic * __BT_PUT -- Add a btree item to the tree. 2746131Smao * 2850989Sbostic * Parameters: 2950989Sbostic * dbp: pointer to access method 3050989Sbostic * key: key 3150989Sbostic * data: data 3250989Sbostic * flag: R_NOOVERWRITE 3346131Smao * 3450989Sbostic * Returns: 3550989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 3650989Sbostic * tree and R_NOOVERWRITE specified. 3746131Smao */ 3846131Smao int 3950989Sbostic __bt_put(dbp, key, data, flags) 4050989Sbostic const DB *dbp; 4150989Sbostic const DBT *key, *data; 4250989Sbostic u_int flags; 4346131Smao { 4450989Sbostic BTREE *t; 4550989Sbostic DBT tkey, tdata; 4650989Sbostic EPG *e; 4750989Sbostic PAGE *h; 4850989Sbostic index_t index, nxtindex; 4950989Sbostic pgno_t pg; 5050989Sbostic size_t nbytes; 51*51099Sbostic int dflags, exact, status; 5250989Sbostic char *dest, db[NOVFLSIZE], kb[NOVFLSIZE]; 5346131Smao 54*51099Sbostic switch (flags) { 55*51099Sbostic case R_CURSOR: 56*51099Sbostic if (ISSET(t, BTF_DELCRSR)) { 57*51099Sbostic errno = EINVAL; 58*51099Sbostic return (RET_ERROR); 59*51099Sbostic } 60*51099Sbostic break; 61*51099Sbostic case 0: 62*51099Sbostic case R_NOOVERWRITE: 63*51099Sbostic break; 64*51099Sbostic default: 6550989Sbostic errno = EINVAL; 6646131Smao return (RET_ERROR); 6746131Smao } 68*51099Sbostic 6950989Sbostic t = dbp->internal; 7050989Sbostic if (ISSET(t, BTF_RDONLY)) { 7150989Sbostic errno = EPERM; 7250989Sbostic return (RET_ERROR); 7346131Smao } 74*51099Sbostic 7550989Sbostic /* 7650989Sbostic * If the key/data won't fit on a page, store it on indirect pages. 77*51099Sbostic * Only store the key on the overflow page if it's too big after the 78*51099Sbostic * data is on an overflow page. 7950989Sbostic * 8050989Sbostic * XXX 8150989Sbostic * If the insert fails later on, these pages aren't recovered. 8250989Sbostic */ 8350989Sbostic dflags = 0; 84*51099Sbostic if (key->size + data->size > t->bt_ovflsize) { 85*51099Sbostic if (key->size > t->bt_ovflsize) { 86*51099Sbostic storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR) 87*51099Sbostic return (RET_ERROR); 88*51099Sbostic tkey.data = kb; 89*51099Sbostic tkey.size = NOVFLSIZE; 90*51099Sbostic *(pgno_t *)kb = pg; 91*51099Sbostic *(size_t *)(kb + sizeof(pgno_t)) = key->size; 92*51099Sbostic dflags |= P_BIGKEY; 93*51099Sbostic key = &tkey; 94*51099Sbostic } 95*51099Sbostic if (key->size + data->size > t->bt_ovflsize) { 96*51099Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 97*51099Sbostic return (RET_ERROR); 98*51099Sbostic tdata.data = db; 99*51099Sbostic tdata.size = NOVFLSIZE; 100*51099Sbostic *(pgno_t *)db = pg; 101*51099Sbostic *(size_t *)(db + sizeof(pgno_t)) = data->size; 102*51099Sbostic dflags |= P_BIGDATA; 103*51099Sbostic data = &tdata; 104*51099Sbostic } 105*51099Sbostic if (key->size + data->size > t->bt_ovflsize) 106*51099Sbostic goto storekey; 10746131Smao } 108*51099Sbostic 109*51099Sbostic /* Replace the cursor. */ 110*51099Sbostic if (flags == R_CURSOR) { 111*51099Sbostic if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL) 11250989Sbostic return (RET_ERROR); 113*51099Sbostic index = t->bt_bcursor.index; 114*51099Sbostic goto delete; 11550989Sbostic } 11646131Smao 117*51099Sbostic /* 118*51099Sbostic * Find the key to delete, or, the location at which to insert. Bt_fast 119*51099Sbostic * and __bt_search pin the returned page. 120*51099Sbostic */ 12150989Sbostic if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 12250989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 12350989Sbostic return (RET_ERROR); 12450989Sbostic h = e->page; 12550989Sbostic index = e->index; 12646131Smao 12750989Sbostic /* 12850989Sbostic * Add the specified key/data pair to the tree. If an identical key 12950989Sbostic * is already in the tree, and R_NOOVERWRITE is set, an error is 13050989Sbostic * returned. If R_NOOVERWRITE is not set, the key is either added (if 13150989Sbostic * duplicates are permitted) or an error is returned. 13250989Sbostic * 13350989Sbostic * Pages are split as required. 13450989Sbostic */ 13550989Sbostic switch (flags) { 13650989Sbostic case R_NOOVERWRITE: 13750989Sbostic if (!exact) 13850989Sbostic break; 13950989Sbostic /* 14050989Sbostic * One special case is if the cursor references the record and 141*51099Sbostic * it's been flagged for deletion. Then, we delete the record, 142*51099Sbostic * leaving the cursor there -- this means that the inserted 143*51099Sbostic * record will not be seen in a cursor scan. 14450989Sbostic */ 14550989Sbostic if (ISSET(t, BTF_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 14650989Sbostic t->bt_bcursor.index == index) { 14750989Sbostic UNSET(t, BTF_DELCRSR); 14850989Sbostic goto delete; 14946131Smao } 15050989Sbostic BT_CLR(t); 15150989Sbostic mpool_put(t->bt_mp, h, 0); 15250989Sbostic return (RET_SPECIAL); 15350989Sbostic default: 15450989Sbostic if (!exact || NOTSET(t, BTF_NODUPS)) 15550989Sbostic break; 15650989Sbostic delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 15750989Sbostic BT_CLR(t); 15850989Sbostic mpool_put(t->bt_mp, h, 0); 15946131Smao return (RET_ERROR); 16046131Smao } 16150989Sbostic break; 16246131Smao } 16346131Smao 16450989Sbostic /* 16550989Sbostic * If not enough room, or the user has put a ceiling on the number of 16650989Sbostic * keys permitted in the page, split the page. The split code will 16750989Sbostic * insert the key and data and unpin the current page. If inserting 16850989Sbostic * into the offset array, shift the pointers up. 16950989Sbostic */ 17050989Sbostic nbytes = NBLEAFDBT(key->size, data->size); 171*51099Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t)) { 172*51099Sbostic status = __bt_split(t, h, key, data, dflags, nbytes, index); 173*51099Sbostic if (status == RET_SUCCESS) 174*51099Sbostic SET(t, BTF_MODIFIED); 175*51099Sbostic return (status); 176*51099Sbostic } 17746131Smao 17850989Sbostic if (index < (nxtindex = NEXTINDEX(h))) 17950989Sbostic bcopy(h->linp + index, h->linp + index + 1, 18050989Sbostic (nxtindex - index) * sizeof(index_t)); 18150989Sbostic h->lower += sizeof(index_t); 18246131Smao 18350989Sbostic h->linp[index] = h->upper -= nbytes; 18450989Sbostic dest = (char *)h + h->upper; 18550989Sbostic WR_BLEAF(dest, key, data, dflags); 18646131Smao 18750989Sbostic if (t->bt_order == NOT) 18850989Sbostic if (h->nextpg == P_INVALID) { 18950989Sbostic if (index == NEXTINDEX(h) - 1) { 19050989Sbostic t->bt_order = FORWARD; 19150989Sbostic t->bt_last.index = index; 19250989Sbostic t->bt_last.pgno = h->pgno; 19350989Sbostic } 19450989Sbostic } else if (h->prevpg == P_INVALID) { 19550989Sbostic if (index == 0) { 19650989Sbostic t->bt_order = BACK; 19750989Sbostic t->bt_last.index = 0; 19850989Sbostic t->bt_last.pgno = h->pgno; 19950989Sbostic } 20046131Smao } 20146131Smao 202*51099Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 20350989Sbostic BT_CLR(t); 20450989Sbostic SET(t, BTF_MODIFIED); 20550989Sbostic return (RET_SUCCESS); 20646131Smao } 20746131Smao 20850989Sbostic #ifdef STATISTICS 20950989Sbostic u_long bt_cache_hit, bt_cache_miss; 21050989Sbostic #endif 21150989Sbostic 21246131Smao /* 21350989Sbostic * BT_FAST -- Do a quick check for sorted data. 21446131Smao * 21550989Sbostic * Parameters: 21650989Sbostic * t: tree 21750989Sbostic * key: key to insert 21846131Smao * 21950989Sbostic * Returns: 22050989Sbostic * EPG for new record or NULL if not found. 22146131Smao */ 22250989Sbostic static EPG * 22350989Sbostic bt_fast(t, key, data, exactp) 22450989Sbostic BTREE *t; 22550989Sbostic const DBT *key, *data; 22650989Sbostic int *exactp; 22746131Smao { 22850989Sbostic EPG e; 22950989Sbostic PAGE *h; 23050989Sbostic size_t nbytes; 23150989Sbostic int cmp; 23246131Smao 23350989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 23450989Sbostic t->bt_order = NOT; 23550989Sbostic return (NULL); 23650989Sbostic } 23750989Sbostic e.page = h; 23850989Sbostic e.index = t->bt_last.index; 23946131Smao 24046131Smao /* 24150989Sbostic * If won't fit in this page or have too many keys in this page, have 24250989Sbostic * to search to get split stack. 24346131Smao */ 244*51099Sbostic nbytes = NBLEAFDBT(key->size, data->size); 245*51099Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t)) 24650989Sbostic goto miss; 24746131Smao 24850989Sbostic if (t->bt_order == FORWARD) { 24950989Sbostic if (e.page->nextpg != P_INVALID) 25050989Sbostic goto miss; 25150989Sbostic if (e.index != NEXTINDEX(h) - 1) 25250989Sbostic goto miss; 25350989Sbostic if ((cmp = __bt_cmp(t, key, &e)) < 0) 25450989Sbostic goto miss; 25550989Sbostic t->bt_last.index = ++e.index; 25646131Smao } else { 25750989Sbostic if (e.page->prevpg != P_INVALID) 25850989Sbostic goto miss; 25950989Sbostic if (e.index != 0) 26050989Sbostic goto miss; 26150989Sbostic if ((cmp = __bt_cmp(t, key, &e)) > 0) 26250989Sbostic goto miss; 26350989Sbostic t->bt_last.index = 0; 26446131Smao } 26550989Sbostic *exactp = cmp == 0; 26650989Sbostic #ifdef STATISTICS 26750989Sbostic ++bt_cache_hit; 26850989Sbostic #endif 26950989Sbostic return (&e); 27046131Smao 271*51099Sbostic miss: 27250989Sbostic #ifdef STATISTICS 27350989Sbostic ++bt_cache_miss; 27450989Sbostic #endif 27550989Sbostic t->bt_order = NOT; 27650989Sbostic mpool_put(t->bt_mp, h, 0); 27750989Sbostic return (NULL); 27846131Smao } 279