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*64488Sbostic static char sccsid[] = "@(#)bt_put.c 8.3 (Berkeley) 09/16/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
__bt_put(dbp,key,data,flags)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
5964456Sbostic /* Toss any page pinned across calls. */
6064456Sbostic if (t->bt_pinned != NULL) {
6164456Sbostic mpool_put(t->bt_mp, t->bt_pinned, 0);
6264456Sbostic t->bt_pinned = NULL;
6364456Sbostic }
6464456Sbostic
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 *
bt_fast(t,key,data,exactp)23850989Sbostic bt_fast(t, key, data, exactp)
23950989Sbostic BTREE *t;
24050989Sbostic const DBT *key, *data;
24150989Sbostic int *exactp;
24246131Smao {
24350989Sbostic PAGE *h;
24450989Sbostic size_t nbytes;
24550989Sbostic int cmp;
24646131Smao
24750989Sbostic if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
24850989Sbostic t->bt_order = NOT;
24950989Sbostic return (NULL);
25050989Sbostic }
251*64488Sbostic t->bt_cur.page = h;
252*64488Sbostic t->bt_cur.index = t->bt_last.index;
25346131Smao
25446131Smao /*
25550989Sbostic * If won't fit in this page or have too many keys in this page, have
25650989Sbostic * to search to get split stack.
25746131Smao */
25851099Sbostic nbytes = NBLEAFDBT(key->size, data->size);
25957989Sbostic if (h->upper - h->lower < nbytes + sizeof(indx_t))
26050989Sbostic goto miss;
26146131Smao
26250989Sbostic if (t->bt_order == FORWARD) {
263*64488Sbostic if (t->bt_cur.page->nextpg != P_INVALID)
26450989Sbostic goto miss;
265*64488Sbostic if (t->bt_cur.index != NEXTINDEX(h) - 1)
26650989Sbostic goto miss;
267*64488Sbostic if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
26850989Sbostic goto miss;
269*64488Sbostic t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
27046131Smao } else {
271*64488Sbostic if (t->bt_cur.page->prevpg != P_INVALID)
27250989Sbostic goto miss;
273*64488Sbostic if (t->bt_cur.index != 0)
27450989Sbostic goto miss;
275*64488Sbostic if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
27650989Sbostic goto miss;
27750989Sbostic t->bt_last.index = 0;
27846131Smao }
27950989Sbostic *exactp = cmp == 0;
28050989Sbostic #ifdef STATISTICS
28150989Sbostic ++bt_cache_hit;
28250989Sbostic #endif
283*64488Sbostic return (&t->bt_cur);
28446131Smao
28551099Sbostic miss:
28650989Sbostic #ifdef STATISTICS
28750989Sbostic ++bt_cache_miss;
28850989Sbostic #endif
28950989Sbostic t->bt_order = NOT;
29050989Sbostic mpool_put(t->bt_mp, h, 0);
29150989Sbostic return (NULL);
29246131Smao }
293