146131Smao /*- 261196Sbostic * Copyright (c) 1990, 1993 361196Sbostic * 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*64456Sbostic static char sccsid[] = "@(#)bt_put.c 8.2 (Berkeley) 09/07/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 59*64456Sbostic /* Toss any page pinned across calls. */ 60*64456Sbostic if (t->bt_pinned != NULL) { 61*64456Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0); 62*64456Sbostic t->bt_pinned = NULL; 63*64456Sbostic } 64*64456Sbostic 6551099Sbostic switch (flags) { 6651099Sbostic case R_CURSOR: 6760041Sbostic if (!ISSET(t, B_SEQINIT)) 6856995Sbostic goto einval; 6960041Sbostic if (ISSET(t, B_DELCRSR)) 7056995Sbostic goto einval; 7151099Sbostic break; 7251099Sbostic case 0: 7351099Sbostic case R_NOOVERWRITE: 7451099Sbostic break; 7551099Sbostic default: 7656995Sbostic einval: errno = EINVAL; 7746131Smao return (RET_ERROR); 7846131Smao } 7951099Sbostic 8060041Sbostic if (ISSET(t, B_RDONLY)) { 8150989Sbostic errno = EPERM; 8250989Sbostic return (RET_ERROR); 8346131Smao } 8451099Sbostic 8550989Sbostic /* 8650989Sbostic * If the key/data won't fit on a page, store it on indirect pages. 8751099Sbostic * Only store the key on the overflow page if it's too big after the 8851099Sbostic * data is on an overflow page. 8950989Sbostic * 9050989Sbostic * XXX 9150989Sbostic * If the insert fails later on, these pages aren't recovered. 9250989Sbostic */ 9350989Sbostic dflags = 0; 9451099Sbostic if (key->size + data->size > t->bt_ovflsize) { 9551099Sbostic if (key->size > t->bt_ovflsize) { 9651099Sbostic storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR) 9751099Sbostic return (RET_ERROR); 9851099Sbostic tkey.data = kb; 9951099Sbostic tkey.size = NOVFLSIZE; 10058017Sbostic memmove(kb, &pg, sizeof(pgno_t)); 10158017Sbostic memmove(kb + sizeof(pgno_t), 10258017Sbostic &key->size, sizeof(size_t)); 10351099Sbostic dflags |= P_BIGKEY; 10451099Sbostic key = &tkey; 10551099Sbostic } 10651099Sbostic if (key->size + data->size > t->bt_ovflsize) { 10751099Sbostic if (__ovfl_put(t, data, &pg) == RET_ERROR) 10851099Sbostic return (RET_ERROR); 10951099Sbostic tdata.data = db; 11051099Sbostic tdata.size = NOVFLSIZE; 11158017Sbostic memmove(db, &pg, sizeof(pgno_t)); 11258017Sbostic memmove(db + sizeof(pgno_t), 11358017Sbostic &data->size, sizeof(size_t)); 11451099Sbostic dflags |= P_BIGDATA; 11551099Sbostic data = &tdata; 11651099Sbostic } 11751099Sbostic if (key->size + data->size > t->bt_ovflsize) 11851099Sbostic goto storekey; 11946131Smao } 12051099Sbostic 12151099Sbostic /* Replace the cursor. */ 12251099Sbostic if (flags == R_CURSOR) { 12351099Sbostic if ((h = mpool_get(t->bt_mp, t->bt_bcursor.pgno, 0)) == NULL) 12450989Sbostic return (RET_ERROR); 12551099Sbostic index = t->bt_bcursor.index; 12651099Sbostic goto delete; 12750989Sbostic } 12846131Smao 12951099Sbostic /* 13051099Sbostic * Find the key to delete, or, the location at which to insert. Bt_fast 13151099Sbostic * and __bt_search pin the returned page. 13251099Sbostic */ 13350989Sbostic if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL) 13450989Sbostic if ((e = __bt_search(t, key, &exact)) == NULL) 13550989Sbostic return (RET_ERROR); 13650989Sbostic h = e->page; 13750989Sbostic index = e->index; 13846131Smao 13950989Sbostic /* 14050989Sbostic * Add the specified key/data pair to the tree. If an identical key 14150989Sbostic * is already in the tree, and R_NOOVERWRITE is set, an error is 14250989Sbostic * returned. If R_NOOVERWRITE is not set, the key is either added (if 14350989Sbostic * duplicates are permitted) or an error is returned. 14450989Sbostic * 14550989Sbostic * Pages are split as required. 14650989Sbostic */ 14750989Sbostic switch (flags) { 14850989Sbostic case R_NOOVERWRITE: 14950989Sbostic if (!exact) 15050989Sbostic break; 15150989Sbostic /* 15250989Sbostic * One special case is if the cursor references the record and 15351099Sbostic * it's been flagged for deletion. Then, we delete the record, 15451099Sbostic * leaving the cursor there -- this means that the inserted 15551099Sbostic * record will not be seen in a cursor scan. 15650989Sbostic */ 15760041Sbostic if (ISSET(t, B_DELCRSR) && t->bt_bcursor.pgno == h->pgno && 15850989Sbostic t->bt_bcursor.index == index) { 15960041Sbostic CLR(t, B_DELCRSR); 16050989Sbostic goto delete; 16146131Smao } 16250989Sbostic mpool_put(t->bt_mp, h, 0); 16350989Sbostic return (RET_SPECIAL); 16450989Sbostic default: 16560041Sbostic if (!exact || !ISSET(t, B_NODUPS)) 16650989Sbostic break; 16750989Sbostic delete: if (__bt_dleaf(t, h, index) == RET_ERROR) { 16850989Sbostic mpool_put(t->bt_mp, h, 0); 16946131Smao return (RET_ERROR); 17046131Smao } 17150989Sbostic break; 17246131Smao } 17346131Smao 17450989Sbostic /* 17550989Sbostic * If not enough room, or the user has put a ceiling on the number of 17650989Sbostic * keys permitted in the page, split the page. The split code will 17750989Sbostic * insert the key and data and unpin the current page. If inserting 17850989Sbostic * into the offset array, shift the pointers up. 17950989Sbostic */ 18050989Sbostic nbytes = NBLEAFDBT(key->size, data->size); 18157989Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t)) { 18256751Sbostic if ((status = __bt_split(t, h, key, 18356751Sbostic data, dflags, nbytes, index)) != RET_SUCCESS) 18456751Sbostic return (status); 18556751Sbostic goto success; 18651099Sbostic } 18746131Smao 18850989Sbostic if (index < (nxtindex = NEXTINDEX(h))) 18958017Sbostic memmove(h->linp + index + 1, h->linp + index, 19057989Sbostic (nxtindex - index) * sizeof(indx_t)); 19157989Sbostic h->lower += sizeof(indx_t); 19246131Smao 19350989Sbostic h->linp[index] = h->upper -= nbytes; 19450989Sbostic dest = (char *)h + h->upper; 19550989Sbostic WR_BLEAF(dest, key, data, dflags); 19646131Smao 19750989Sbostic if (t->bt_order == NOT) 19850989Sbostic if (h->nextpg == P_INVALID) { 19950989Sbostic if (index == NEXTINDEX(h) - 1) { 20050989Sbostic t->bt_order = FORWARD; 20150989Sbostic t->bt_last.index = index; 20250989Sbostic t->bt_last.pgno = h->pgno; 20350989Sbostic } 20450989Sbostic } else if (h->prevpg == P_INVALID) { 20550989Sbostic if (index == 0) { 20650989Sbostic t->bt_order = BACK; 20750989Sbostic t->bt_last.index = 0; 20850989Sbostic t->bt_last.pgno = h->pgno; 20950989Sbostic } 21046131Smao } 21146131Smao 21251099Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 21356751Sbostic 21456751Sbostic success: 21556751Sbostic if (flags == R_SETCURSOR) { 21656751Sbostic t->bt_bcursor.pgno = e->page->pgno; 21756751Sbostic t->bt_bcursor.index = e->index; 21856751Sbostic } 21960041Sbostic SET(t, B_MODIFIED); 22050989Sbostic return (RET_SUCCESS); 22146131Smao } 22246131Smao 22350989Sbostic #ifdef STATISTICS 22450989Sbostic u_long bt_cache_hit, bt_cache_miss; 22550989Sbostic #endif 22650989Sbostic 22746131Smao /* 22850989Sbostic * BT_FAST -- Do a quick check for sorted data. 22946131Smao * 23050989Sbostic * Parameters: 23150989Sbostic * t: tree 23250989Sbostic * key: key to insert 23346131Smao * 23450989Sbostic * Returns: 23550989Sbostic * EPG for new record or NULL if not found. 23646131Smao */ 23750989Sbostic static EPG * 23850989Sbostic bt_fast(t, key, data, exactp) 23950989Sbostic BTREE *t; 24050989Sbostic const DBT *key, *data; 24150989Sbostic int *exactp; 24246131Smao { 24350989Sbostic EPG e; 24450989Sbostic PAGE *h; 24550989Sbostic size_t nbytes; 24650989Sbostic int cmp; 24746131Smao 24850989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) { 24950989Sbostic t->bt_order = NOT; 25050989Sbostic return (NULL); 25150989Sbostic } 25250989Sbostic e.page = h; 25350989Sbostic e.index = t->bt_last.index; 25446131Smao 25546131Smao /* 25650989Sbostic * If won't fit in this page or have too many keys in this page, have 25750989Sbostic * to search to get split stack. 25846131Smao */ 25951099Sbostic nbytes = NBLEAFDBT(key->size, data->size); 26057989Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t)) 26150989Sbostic goto miss; 26246131Smao 26350989Sbostic if (t->bt_order == FORWARD) { 26450989Sbostic if (e.page->nextpg != P_INVALID) 26550989Sbostic goto miss; 26650989Sbostic if (e.index != NEXTINDEX(h) - 1) 26750989Sbostic goto miss; 26850989Sbostic if ((cmp = __bt_cmp(t, key, &e)) < 0) 26950989Sbostic goto miss; 27051880Sbostic t->bt_last.index = cmp ? ++e.index : e.index; 27146131Smao } else { 27250989Sbostic if (e.page->prevpg != P_INVALID) 27350989Sbostic goto miss; 27450989Sbostic if (e.index != 0) 27550989Sbostic goto miss; 27650989Sbostic if ((cmp = __bt_cmp(t, key, &e)) > 0) 27750989Sbostic goto miss; 27850989Sbostic t->bt_last.index = 0; 27946131Smao } 28050989Sbostic *exactp = cmp == 0; 28150989Sbostic #ifdef STATISTICS 28250989Sbostic ++bt_cache_hit; 28350989Sbostic #endif 28450989Sbostic return (&e); 28546131Smao 28651099Sbostic miss: 28750989Sbostic #ifdef STATISTICS 28850989Sbostic ++bt_cache_miss; 28950989Sbostic #endif 29050989Sbostic t->bt_order = NOT; 29150989Sbostic mpool_put(t->bt_mp, h, 0); 29250989Sbostic return (NULL); 29346131Smao } 294