146131Smao /*- 2*61196Sbostic * Copyright (c) 1990, 1993 3*61196Sbostic * The Regents of the University of California. 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*61196Sbostic static char sccsid[] = "@(#)bt_put.c 8.1 (Berkeley) 06/04/93"; 1346131Smao #endif /* LIBC_SCCS and not lint */ 1446131Smao 1546131Smao #include <sys/types.h> 1656751Sbostic 1750989Sbostic #include <errno.h> 1850989Sbostic #include <stdio.h> 1946561Sbostic #include <stdlib.h> 2046561Sbostic #include <string.h> 2156751Sbostic 2257932Sbostic #include <db.h> 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; 5157989Sbostic indx_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: 6160041Sbostic if (!ISSET(t, B_SEQINIT)) 6256995Sbostic goto einval; 6360041Sbostic if (ISSET(t, B_DELCRSR)) 6456995Sbostic goto einval; 6551099Sbostic break; 6651099Sbostic case 0: 6751099Sbostic case R_NOOVERWRITE: 6851099Sbostic break; 6951099Sbostic default: 7056995Sbostic einval: errno = EINVAL; 7146131Smao return (RET_ERROR); 7246131Smao } 7351099Sbostic 7460041Sbostic if (ISSET(t, B_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; 9458017Sbostic memmove(kb, &pg, sizeof(pgno_t)); 9558017Sbostic memmove(kb + sizeof(pgno_t), 9658017Sbostic &key->size, sizeof(size_t)); 9751099Sbostic dflags |= P_BIGKEY; 9851099Sbostic key = &tkey; 9951099Sbostic } 10051099Sbostic if (key->size + data->size > t->bt_ovflsize) { 10151099Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 10251099Sbostic return (RET_ERROR); 10351099Sbostic tdata.data = db; 10451099Sbostic tdata.size = NOVFLSIZE; 10558017Sbostic memmove(db, &pg, sizeof(pgno_t)); 10658017Sbostic memmove(db + sizeof(pgno_t), 10758017Sbostic &data->size, sizeof(size_t)); 10851099Sbostic dflags |= P_BIGDATA; 10951099Sbostic data = &tdata; 11051099Sbostic } 11151099Sbostic if (key->size + data->size > t->bt_ovflsize) 11251099Sbostic goto storekey; 11346131Smao } 11451099Sbostic 11551099Sbostic /* Replace the cursor. */ 11651099Sbostic if (flags == R_CURSOR) { 11751099Sbostic if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL) 11850989Sbostic return (RET_ERROR); 11951099Sbostic index = t->bt_bcursor.index; 12051099Sbostic goto delete; 12150989Sbostic } 12246131Smao 12351099Sbostic /* 12451099Sbostic * Find the key to delete, or, the location at which to insert. Bt_fast 12551099Sbostic * and __bt_search pin the returned page. 12651099Sbostic */ 12750989Sbostic if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 12850989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 12950989Sbostic return (RET_ERROR); 13050989Sbostic h = e->page; 13150989Sbostic index = e->index; 13246131Smao 13350989Sbostic /* 13450989Sbostic * Add the specified key/data pair to the tree. If an identical key 13550989Sbostic * is already in the tree, and R_NOOVERWRITE is set, an error is 13650989Sbostic * returned. If R_NOOVERWRITE is not set, the key is either added (if 13750989Sbostic * duplicates are permitted) or an error is returned. 13850989Sbostic * 13950989Sbostic * Pages are split as required. 14050989Sbostic */ 14150989Sbostic switch (flags) { 14250989Sbostic case R_NOOVERWRITE: 14350989Sbostic if (!exact) 14450989Sbostic break; 14550989Sbostic /* 14650989Sbostic * One special case is if the cursor references the record and 14751099Sbostic * it's been flagged for deletion. Then, we delete the record, 14851099Sbostic * leaving the cursor there -- this means that the inserted 14951099Sbostic * record will not be seen in a cursor scan. 15050989Sbostic */ 15160041Sbostic if (ISSET(t, B_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 15250989Sbostic t->bt_bcursor.index == index) { 15360041Sbostic CLR(t, B_DELCRSR); 15450989Sbostic goto delete; 15546131Smao } 15650989Sbostic mpool_put(t->bt_mp, h, 0); 15750989Sbostic return (RET_SPECIAL); 15850989Sbostic default: 15960041Sbostic if (!exact || !ISSET(t, B_NODUPS)) 16050989Sbostic break; 16150989Sbostic delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 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); 17557989Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_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))) 18358017Sbostic memmove(h->linp + index + 1, h->linp + index, 18457989Sbostic (nxtindex - index) * sizeof(indx_t)); 18557989Sbostic h->lower += sizeof(indx_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); 20756751Sbostic 20856751Sbostic success: 20956751Sbostic if (flags == R_SETCURSOR) { 21056751Sbostic t->bt_bcursor.pgno = e->page->pgno; 21156751Sbostic t->bt_bcursor.index = e->index; 21256751Sbostic } 21360041Sbostic SET(t, B_MODIFIED); 21450989Sbostic return (RET_SUCCESS); 21546131Smao } 21646131Smao 21750989Sbostic #ifdef STATISTICS 21850989Sbostic u_long bt_cache_hit, bt_cache_miss; 21950989Sbostic #endif 22050989Sbostic 22146131Smao /* 22250989Sbostic * BT_FAST -- Do a quick check for sorted data. 22346131Smao * 22450989Sbostic * Parameters: 22550989Sbostic * t: tree 22650989Sbostic * key: key to insert 22746131Smao * 22850989Sbostic * Returns: 22950989Sbostic * EPG for new record or NULL if not found. 23046131Smao */ 23150989Sbostic static EPG * 23250989Sbostic bt_fast(t, key, data, exactp) 23350989Sbostic BTREE *t; 23450989Sbostic const DBT *key, *data; 23550989Sbostic int *exactp; 23646131Smao { 23750989Sbostic EPG e; 23850989Sbostic PAGE *h; 23950989Sbostic size_t nbytes; 24050989Sbostic int cmp; 24146131Smao 24250989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 24350989Sbostic t->bt_order = NOT; 24450989Sbostic return (NULL); 24550989Sbostic } 24650989Sbostic e.page = h; 24750989Sbostic e.index = t->bt_last.index; 24846131Smao 24946131Smao /* 25050989Sbostic * If won't fit in this page or have too many keys in this page, have 25150989Sbostic * to search to get split stack. 25246131Smao */ 25351099Sbostic nbytes = NBLEAFDBT(key->size, data->size); 25457989Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t)) 25550989Sbostic goto miss; 25646131Smao 25750989Sbostic if (t->bt_order == FORWARD) { 25850989Sbostic if (e.page->nextpg != P_INVALID) 25950989Sbostic goto miss; 26050989Sbostic if (e.index != NEXTINDEX(h) - 1) 26150989Sbostic goto miss; 26250989Sbostic if ((cmp = __bt_cmp(t, key, &e)) < 0) 26350989Sbostic goto miss; 26451880Sbostic t->bt_last.index = cmp ? ++e.index : e.index; 26546131Smao } else { 26650989Sbostic if (e.page->prevpg != P_INVALID) 26750989Sbostic goto miss; 26850989Sbostic if (e.index != 0) 26950989Sbostic goto miss; 27050989Sbostic if ((cmp = __bt_cmp(t, key, &e)) > 0) 27150989Sbostic goto miss; 27250989Sbostic t->bt_last.index = 0; 27346131Smao } 27450989Sbostic *exactp = cmp == 0; 27550989Sbostic #ifdef STATISTICS 27650989Sbostic ++bt_cache_hit; 27750989Sbostic #endif 27850989Sbostic return (&e); 27946131Smao 28051099Sbostic miss: 28150989Sbostic #ifdef STATISTICS 28250989Sbostic ++bt_cache_miss; 28350989Sbostic #endif 28450989Sbostic t->bt_order = NOT; 28550989Sbostic mpool_put(t->bt_mp, h, 0); 28650989Sbostic return (NULL); 28746131Smao } 288