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*56995Sbostic static char sccsid[] = "@(#)bt_put.c 5.9 (Berkeley) 12/04/92"; 1346131Smao #endif /* LIBC_SCCS and not lint */ 1446131Smao 1546131Smao #include <sys/types.h> 1656751Sbostic 1756751Sbostic #include <db.h> 1850989Sbostic #include <errno.h> 1950989Sbostic #include <stdio.h> 2046561Sbostic #include <stdlib.h> 2146561Sbostic #include <string.h> 2256751Sbostic 2346131Smao #include "btree.h" 2446131Smao 2550989Sbostic static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *)); 2650989Sbostic 2746131Smao /* 2850989Sbostic * __BT_PUT -- Add a btree item to the tree. 2946131Smao * 3050989Sbostic * Parameters: 3150989Sbostic * dbp: pointer to access method 3250989Sbostic * key: key 3350989Sbostic * data: data 3450989Sbostic * flag: R_NOOVERWRITE 3546131Smao * 3650989Sbostic * Returns: 3750989Sbostic * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the 3850989Sbostic * tree and R_NOOVERWRITE specified. 3946131Smao */ 4046131Smao int 4150989Sbostic __bt_put(dbp, key, data, flags) 4250989Sbostic const DB *dbp; 4356751Sbostic DBT *key; 4456751Sbostic const DBT *data; 4550989Sbostic u_int flags; 4646131Smao { 4750989Sbostic BTREE *t; 4850989Sbostic DBT tkey, tdata; 4950989Sbostic EPG *e; 5050989Sbostic PAGE *h; 5150989Sbostic index_t index, nxtindex; 5250989Sbostic pgno_t pg; 5350989Sbostic size_t nbytes; 5451099Sbostic int dflags, exact, status; 5550989Sbostic char *dest, db[NOVFLSIZE], kb[NOVFLSIZE]; 5646131Smao 5756751Sbostic t = dbp->internal; 5856751Sbostic 5951099Sbostic switch (flags) { 6051099Sbostic case R_CURSOR: 61*56995Sbostic if (!ISSET(t, BTF_SEQINIT)) 62*56995Sbostic goto einval; 63*56995Sbostic if (ISSET(t, BTF_DELCRSR)) 64*56995Sbostic goto einval; 6551099Sbostic break; 6651099Sbostic case 0: 6751099Sbostic case R_NOOVERWRITE: 6851099Sbostic break; 6951099Sbostic default: 70*56995Sbostic einval: errno = EINVAL; 7146131Smao return (RET_ERROR); 7246131Smao } 7351099Sbostic 7450989Sbostic if (ISSET(t, BTF_RDONLY)) { 7550989Sbostic errno = EPERM; 7650989Sbostic return (RET_ERROR); 7746131Smao } 7851099Sbostic 7950989Sbostic /* 8050989Sbostic * If the key/data won't fit on a page, store it on indirect pages. 8151099Sbostic * Only store the key on the overflow page if it's too big after the 8251099Sbostic * data is on an overflow page. 8350989Sbostic * 8450989Sbostic * XXX 8550989Sbostic * If the insert fails later on, these pages aren't recovered. 8650989Sbostic */ 8750989Sbostic dflags = 0; 8851099Sbostic if (key->size + data->size > t->bt_ovflsize) { 8951099Sbostic if (key->size > t->bt_ovflsize) { 9051099Sbostic storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR) 9151099Sbostic return (RET_ERROR); 9251099Sbostic tkey.data = kb; 9351099Sbostic tkey.size = NOVFLSIZE; 9456558Sbostic bcopy(&pg, kb, sizeof(pgno_t)); 9556558Sbostic bcopy(&key->size, kb + sizeof(pgno_t), sizeof(size_t)); 9651099Sbostic dflags |= P_BIGKEY; 9751099Sbostic key = &tkey; 9851099Sbostic } 9951099Sbostic if (key->size + data->size > t->bt_ovflsize) { 10051099Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 10151099Sbostic return (RET_ERROR); 10251099Sbostic tdata.data = db; 10351099Sbostic tdata.size = NOVFLSIZE; 10456558Sbostic bcopy(&pg, db, sizeof(pgno_t)); 10556558Sbostic bcopy(&data->size, db + sizeof(pgno_t), sizeof(size_t)); 10651099Sbostic dflags |= P_BIGDATA; 10751099Sbostic data = &tdata; 10851099Sbostic } 10951099Sbostic if (key->size + data->size > t->bt_ovflsize) 11051099Sbostic goto storekey; 11146131Smao } 11251099Sbostic 11351099Sbostic /* Replace the cursor. */ 11451099Sbostic if (flags == R_CURSOR) { 11551099Sbostic if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL) 11650989Sbostic return (RET_ERROR); 11751099Sbostic index = t->bt_bcursor.index; 11851099Sbostic goto delete; 11950989Sbostic } 12046131Smao 12151099Sbostic /* 12251099Sbostic * Find the key to delete, or, the location at which to insert. Bt_fast 12351099Sbostic * and __bt_search pin the returned page. 12451099Sbostic */ 12550989Sbostic if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 12650989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 12750989Sbostic return (RET_ERROR); 12850989Sbostic h = e->page; 12950989Sbostic index = e->index; 13046131Smao 13150989Sbostic /* 13250989Sbostic * Add the specified key/data pair to the tree. If an identical key 13350989Sbostic * is already in the tree, and R_NOOVERWRITE is set, an error is 13450989Sbostic * returned. If R_NOOVERWRITE is not set, the key is either added (if 13550989Sbostic * duplicates are permitted) or an error is returned. 13650989Sbostic * 13750989Sbostic * Pages are split as required. 13850989Sbostic */ 13950989Sbostic switch (flags) { 14050989Sbostic case R_NOOVERWRITE: 14150989Sbostic if (!exact) 14250989Sbostic break; 14350989Sbostic /* 14450989Sbostic * One special case is if the cursor references the record and 14551099Sbostic * it's been flagged for deletion. Then, we delete the record, 14651099Sbostic * leaving the cursor there -- this means that the inserted 14751099Sbostic * record will not be seen in a cursor scan. 14850989Sbostic */ 14950989Sbostic if (ISSET(t, BTF_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 15050989Sbostic t->bt_bcursor.index == index) { 15156751Sbostic CLR(t, BTF_DELCRSR); 15250989Sbostic goto delete; 15346131Smao } 15450989Sbostic BT_CLR(t); 15550989Sbostic mpool_put(t->bt_mp, h, 0); 15650989Sbostic return (RET_SPECIAL); 15750989Sbostic default: 15856751Sbostic if (!exact || !ISSET(t, BTF_NODUPS)) 15950989Sbostic break; 16050989Sbostic delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 16150989Sbostic BT_CLR(t); 16250989Sbostic mpool_put(t->bt_mp, h, 0); 16346131Smao return (RET_ERROR); 16446131Smao } 16550989Sbostic break; 16646131Smao } 16746131Smao 16850989Sbostic /* 16950989Sbostic * If not enough room, or the user has put a ceiling on the number of 17050989Sbostic * keys permitted in the page, split the page. The split code will 17150989Sbostic * insert the key and data and unpin the current page. If inserting 17250989Sbostic * into the offset array, shift the pointers up. 17350989Sbostic */ 17450989Sbostic nbytes = NBLEAFDBT(key->size, data->size); 17551099Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t)) { 17656751Sbostic if ((status = __bt_split(t, h, key, 17756751Sbostic data, dflags, nbytes, index)) != RET_SUCCESS) 17856751Sbostic return (status); 17956751Sbostic goto success; 18051099Sbostic } 18146131Smao 18250989Sbostic if (index < (nxtindex = NEXTINDEX(h))) 18350989Sbostic bcopy(h->linp + index, h->linp + index + 1, 18450989Sbostic (nxtindex - index) * sizeof(index_t)); 18550989Sbostic h->lower += sizeof(index_t); 18646131Smao 18750989Sbostic h->linp[index] = h->upper -= nbytes; 18850989Sbostic dest = (char *)h + h->upper; 18950989Sbostic WR_BLEAF(dest, key, data, dflags); 19046131Smao 19150989Sbostic if (t->bt_order == NOT) 19250989Sbostic if (h->nextpg == P_INVALID) { 19350989Sbostic if (index == NEXTINDEX(h) - 1) { 19450989Sbostic t->bt_order = FORWARD; 19550989Sbostic t->bt_last.index = index; 19650989Sbostic t->bt_last.pgno = h->pgno; 19750989Sbostic } 19850989Sbostic } else if (h->prevpg == P_INVALID) { 19950989Sbostic if (index == 0) { 20050989Sbostic t->bt_order = BACK; 20150989Sbostic t->bt_last.index = 0; 20250989Sbostic t->bt_last.pgno = h->pgno; 20350989Sbostic } 20446131Smao } 20546131Smao 20651099Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 20750989Sbostic BT_CLR(t); 20856751Sbostic 20956751Sbostic success: 21056751Sbostic if (flags == R_SETCURSOR) { 21156751Sbostic t->bt_bcursor.pgno = e->page->pgno; 21256751Sbostic t->bt_bcursor.index = e->index; 21356751Sbostic } 21450989Sbostic SET(t, BTF_MODIFIED); 21550989Sbostic return (RET_SUCCESS); 21646131Smao } 21746131Smao 21850989Sbostic #ifdef STATISTICS 21950989Sbostic u_long bt_cache_hit, bt_cache_miss; 22050989Sbostic #endif 22150989Sbostic 22246131Smao /* 22350989Sbostic * BT_FAST -- Do a quick check for sorted data. 22446131Smao * 22550989Sbostic * Parameters: 22650989Sbostic * t: tree 22750989Sbostic * key: key to insert 22846131Smao * 22950989Sbostic * Returns: 23050989Sbostic * EPG for new record or NULL if not found. 23146131Smao */ 23250989Sbostic static EPG * 23350989Sbostic bt_fast(t, key, data, exactp) 23450989Sbostic BTREE *t; 23550989Sbostic const DBT *key, *data; 23650989Sbostic int *exactp; 23746131Smao { 23850989Sbostic EPG e; 23950989Sbostic PAGE *h; 24050989Sbostic size_t nbytes; 24150989Sbostic int cmp; 24246131Smao 24350989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 24450989Sbostic t->bt_order = NOT; 24550989Sbostic return (NULL); 24650989Sbostic } 24750989Sbostic e.page = h; 24850989Sbostic e.index = t->bt_last.index; 24946131Smao 25046131Smao /* 25150989Sbostic * If won't fit in this page or have too many keys in this page, have 25250989Sbostic * to search to get split stack. 25346131Smao */ 25451099Sbostic nbytes = NBLEAFDBT(key->size, data->size); 25551099Sbostic if (h->upper - h->lower < nbytes + sizeof(index_t)) 25650989Sbostic goto miss; 25746131Smao 25850989Sbostic if (t->bt_order == FORWARD) { 25950989Sbostic if (e.page->nextpg != P_INVALID) 26050989Sbostic goto miss; 26150989Sbostic if (e.index != NEXTINDEX(h) - 1) 26250989Sbostic goto miss; 26350989Sbostic if ((cmp = __bt_cmp(t, key, &e)) < 0) 26450989Sbostic goto miss; 26551880Sbostic t->bt_last.index = cmp ? ++e.index : e.index; 26646131Smao } else { 26750989Sbostic if (e.page->prevpg != P_INVALID) 26850989Sbostic goto miss; 26950989Sbostic if (e.index != 0) 27050989Sbostic goto miss; 27150989Sbostic if ((cmp = __bt_cmp(t, key, &e)) > 0) 27250989Sbostic goto miss; 27350989Sbostic t->bt_last.index = 0; 27446131Smao } 27550989Sbostic *exactp = cmp == 0; 27650989Sbostic #ifdef STATISTICS 27750989Sbostic ++bt_cache_hit; 27850989Sbostic #endif 27950989Sbostic return (&e); 28046131Smao 28151099Sbostic miss: 28250989Sbostic #ifdef STATISTICS 28350989Sbostic ++bt_cache_miss; 28450989Sbostic #endif 28550989Sbostic t->bt_order = NOT; 28650989Sbostic mpool_put(t->bt_mp, h, 0); 28750989Sbostic return (NULL); 28846131Smao } 289