xref: /csrg-svn/lib/libc/db/btree/bt_put.c (revision 50989)
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*50989Sbostic static char sccsid[] = "@(#)bt_put.c	5.4 (Berkeley) 09/04/91";
1346131Smao #endif /* LIBC_SCCS and not lint */
1446131Smao 
1546131Smao #include <sys/types.h>
16*50989Sbostic #include <errno.h>
1746131Smao #include <db.h>
18*50989Sbostic #include <stdio.h>
1946561Sbostic #include <stdlib.h>
2046561Sbostic #include <string.h>
2146131Smao #include "btree.h"
2246131Smao 
23*50989Sbostic static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
24*50989Sbostic 
2546131Smao /*
26*50989Sbostic  * __BT_PUT -- Add a btree item to the tree.
2746131Smao  *
28*50989Sbostic  * Parameters:
29*50989Sbostic  *	dbp:	pointer to access method
30*50989Sbostic  *	key:	key
31*50989Sbostic  *	data:	data
32*50989Sbostic  *	flag:	R_NOOVERWRITE
3346131Smao  *
34*50989Sbostic  * Returns:
35*50989Sbostic  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
36*50989Sbostic  *	tree and R_NOOVERWRITE specified.
3746131Smao  */
3846131Smao int
39*50989Sbostic __bt_put(dbp, key, data, flags)
40*50989Sbostic 	const DB *dbp;
41*50989Sbostic 	const DBT *key, *data;
42*50989Sbostic 	u_int flags;
4346131Smao {
44*50989Sbostic 	BTREE *t;
45*50989Sbostic 	DBT tkey, tdata;
46*50989Sbostic 	EPG *e;
47*50989Sbostic 	PAGE *h;
48*50989Sbostic 	index_t index, nxtindex;
49*50989Sbostic 	pgno_t pg;
50*50989Sbostic 	size_t nbytes;
51*50989Sbostic 	int dflags, exact;
52*50989Sbostic 	char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
5346131Smao 
54*50989Sbostic 	if (flags && flags != R_NOOVERWRITE) {
55*50989Sbostic 		errno = EINVAL;
5646131Smao 		return (RET_ERROR);
5746131Smao 	}
58*50989Sbostic 	t = dbp->internal;
59*50989Sbostic 	if (ISSET(t, BTF_RDONLY)) {
60*50989Sbostic 		errno = EPERM;
61*50989Sbostic 		return (RET_ERROR);
6246131Smao 	}
63*50989Sbostic 
64*50989Sbostic 	/*
65*50989Sbostic 	 * If the key/data won't fit on a page, store it on indirect pages.
66*50989Sbostic 	 *
67*50989Sbostic 	 * XXX
68*50989Sbostic 	 * If the insert fails later on, these pages aren't recovered.
69*50989Sbostic 	 */
70*50989Sbostic 	dflags = 0;
71*50989Sbostic 	if (key->size >= t->bt_minkeypage) {
72*50989Sbostic 		if (__ovfl_put(t, key, &pg) == RET_ERROR)
7346131Smao 			return (RET_ERROR);
74*50989Sbostic 		tkey.data = kb;
75*50989Sbostic 		tkey.size = NOVFLSIZE;
76*50989Sbostic 		*(pgno_t *)kb = pg;
77*50989Sbostic 		*(size_t *)(kb + sizeof(pgno_t)) = key->size;
78*50989Sbostic 		dflags |= P_BIGKEY;
79*50989Sbostic 		key = &tkey;
8046131Smao 	}
81*50989Sbostic 	if (data->size >= t->bt_minkeypage) {
82*50989Sbostic 		if (__ovfl_put(t, data, &pg) == RET_ERROR)
83*50989Sbostic 			return (RET_ERROR);
84*50989Sbostic 		tdata.data = db;
85*50989Sbostic 		tdata.size = NOVFLSIZE;
86*50989Sbostic 		*(pgno_t *)db = pg;
87*50989Sbostic 		*(size_t *)(db + sizeof(pgno_t)) = data->size;
88*50989Sbostic 		dflags |= P_BIGDATA;
89*50989Sbostic 		data = &tdata;
90*50989Sbostic 	}
9146131Smao 
92*50989Sbostic 	/* bt_fast and __bt_search pin the returned page. */
93*50989Sbostic 	if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
94*50989Sbostic 		if ((e = __bt_search(t, key, &exact)) == NULL)
95*50989Sbostic 			return (RET_ERROR);
9646131Smao 
97*50989Sbostic 	h = e->page;
98*50989Sbostic 	index = e->index;
9946131Smao 
100*50989Sbostic 	/*
101*50989Sbostic 	 * Add the specified key/data pair to the tree.  If an identical key
102*50989Sbostic 	 * is already in the tree, and R_NOOVERWRITE is set, an error is
103*50989Sbostic 	 * returned.  If R_NOOVERWRITE is not set, the key is either added (if
104*50989Sbostic 	 * duplicates are permitted) or an error is returned.
105*50989Sbostic 	 *
106*50989Sbostic 	 * Pages are split as required.
107*50989Sbostic 	 */
108*50989Sbostic 	switch (flags) {
109*50989Sbostic 	case R_NOOVERWRITE:
110*50989Sbostic 		if (!exact)
111*50989Sbostic 			break;
112*50989Sbostic 		/*
113*50989Sbostic 		 * One special case is if the cursor references the record and
114*50989Sbostic 		 * it's been flagged for deletion.  If so, we delete it and
115*50989Sbostic 		 * pretend it was never there.  Since the cursor will move to
116*50989Sbostic 		 * the next record the inserted record won't be seen.
117*50989Sbostic 		 */
118*50989Sbostic 		if (ISSET(t, BTF_DELCRSR) && t->bt_bcursor.pgno == h->pgno &&
119*50989Sbostic 		    t->bt_bcursor.index == index) {
120*50989Sbostic 			UNSET(t, BTF_DELCRSR);
121*50989Sbostic 			goto delete;
12246131Smao 		}
123*50989Sbostic 		BT_CLR(t);
124*50989Sbostic 		mpool_put(t->bt_mp, h, 0);
125*50989Sbostic 		return (RET_SPECIAL);
126*50989Sbostic 	default:
127*50989Sbostic 		if (!exact || NOTSET(t, BTF_NODUPS))
128*50989Sbostic 			break;
129*50989Sbostic delete:		if (__bt_dleaf(t, h, index) == RET_ERROR) {
130*50989Sbostic 			BT_CLR(t);
131*50989Sbostic 			mpool_put(t->bt_mp, h, 0);
13246131Smao 			return (RET_ERROR);
13346131Smao 		}
134*50989Sbostic 		break;
13546131Smao 	}
13646131Smao 
137*50989Sbostic 	/*
138*50989Sbostic 	 * If not enough room, or the user has put a ceiling on the number of
139*50989Sbostic 	 * keys permitted in the page, split the page.  The split code will
140*50989Sbostic 	 * insert the key and data and unpin the current page.  If inserting
141*50989Sbostic 	 * into the offset array, shift the pointers up.
142*50989Sbostic 	 */
143*50989Sbostic 	nbytes = NBLEAFDBT(key->size, data->size);
144*50989Sbostic 	if (h->upper - h->lower < nbytes + sizeof(index_t) ||
145*50989Sbostic 	    t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h))
146*50989Sbostic 		return (__bt_split(t, h, key, data, dflags, nbytes, index));
14746131Smao 
148*50989Sbostic 	if (index < (nxtindex = NEXTINDEX(h)))
149*50989Sbostic 		bcopy(h->linp + index, h->linp + index + 1,
150*50989Sbostic 		    (nxtindex - index) * sizeof(index_t));
151*50989Sbostic 	h->lower += sizeof(index_t);
15246131Smao 
153*50989Sbostic 	h->linp[index] = h->upper -= nbytes;
154*50989Sbostic 	dest = (char *)h + h->upper;
155*50989Sbostic 	WR_BLEAF(dest, key, data, dflags);
15646131Smao 
157*50989Sbostic 	if (t->bt_order == NOT)
158*50989Sbostic 		if (h->nextpg == P_INVALID) {
159*50989Sbostic 			if (index == NEXTINDEX(h) - 1) {
160*50989Sbostic 				t->bt_order = FORWARD;
161*50989Sbostic 				t->bt_last.index = index;
162*50989Sbostic 				t->bt_last.pgno = h->pgno;
163*50989Sbostic 			}
164*50989Sbostic 		} else if (h->prevpg == P_INVALID) {
165*50989Sbostic 			if (index == 0) {
166*50989Sbostic 				t->bt_order = BACK;
167*50989Sbostic 				t->bt_last.index = 0;
168*50989Sbostic 				t->bt_last.pgno = h->pgno;
169*50989Sbostic 			}
17046131Smao 		}
17146131Smao 
172*50989Sbostic 	BT_CLR(t);
173*50989Sbostic 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
174*50989Sbostic 	SET(t, BTF_MODIFIED);
175*50989Sbostic 	return (RET_SUCCESS);
17646131Smao }
17746131Smao 
178*50989Sbostic #ifdef STATISTICS
179*50989Sbostic u_long bt_cache_hit, bt_cache_miss;
180*50989Sbostic #endif
181*50989Sbostic 
18246131Smao /*
183*50989Sbostic  * BT_FAST -- Do a quick check for sorted data.
18446131Smao  *
185*50989Sbostic  * Parameters:
186*50989Sbostic  *	t:	tree
187*50989Sbostic  *	key:	key to insert
18846131Smao  *
189*50989Sbostic  * Returns:
190*50989Sbostic  * 	EPG for new record or NULL if not found.
19146131Smao  */
192*50989Sbostic static EPG *
193*50989Sbostic bt_fast(t, key, data, exactp)
194*50989Sbostic 	BTREE *t;
195*50989Sbostic 	const DBT *key, *data;
196*50989Sbostic 	int *exactp;
19746131Smao {
198*50989Sbostic 	EPG e;
199*50989Sbostic 	PAGE *h;
200*50989Sbostic 	size_t nbytes;
201*50989Sbostic 	int cmp;
20246131Smao 
203*50989Sbostic 	if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
204*50989Sbostic 		t->bt_order = NOT;
205*50989Sbostic 		return (NULL);
206*50989Sbostic 	}
207*50989Sbostic 	e.page = h;
208*50989Sbostic 	e.index = t->bt_last.index;
20946131Smao 
21046131Smao 	/*
211*50989Sbostic 	 * If won't fit in this page or have too many keys in this page, have
212*50989Sbostic 	 * to search to get split stack.
21346131Smao 	 */
214*50989Sbostic 	nbytes =
215*50989Sbostic 	    NBLEAFDBT(key->size >= t->bt_minkeypage ? NOVFLSIZE : key->size,
216*50989Sbostic 	    data->size >= t->bt_minkeypage ? NOVFLSIZE : data->size);
217*50989Sbostic 	if (h->upper - h->lower < nbytes + sizeof(index_t) ||
218*50989Sbostic 	    t->bt_maxkeypage && t->bt_maxkeypage < NEXTINDEX(h))
219*50989Sbostic 		goto miss;
22046131Smao 
221*50989Sbostic 	if (t->bt_order == FORWARD) {
222*50989Sbostic 		if (e.page->nextpg != P_INVALID)
223*50989Sbostic 			goto miss;
224*50989Sbostic 		if (e.index != NEXTINDEX(h) - 1)
225*50989Sbostic 			goto miss;
226*50989Sbostic 		if ((cmp = __bt_cmp(t, key, &e)) < 0)
227*50989Sbostic 			goto miss;
228*50989Sbostic 		t->bt_last.index = ++e.index;
22946131Smao 	} else {
230*50989Sbostic 		if (e.page->prevpg != P_INVALID)
231*50989Sbostic 			goto miss;
232*50989Sbostic 		if (e.index != 0)
233*50989Sbostic 			goto miss;
234*50989Sbostic 		if ((cmp = __bt_cmp(t, key, &e)) > 0)
235*50989Sbostic 			goto miss;
236*50989Sbostic 		t->bt_last.index = 0;
23746131Smao 	}
238*50989Sbostic 	*exactp = cmp == 0;
239*50989Sbostic #ifdef STATISTICS
240*50989Sbostic 	++bt_cache_hit;
241*50989Sbostic #endif
242*50989Sbostic 	return (&e);
24346131Smao 
244*50989Sbostic miss:
245*50989Sbostic #ifdef STATISTICS
246*50989Sbostic 	++bt_cache_miss;
247*50989Sbostic #endif
248*50989Sbostic 	t->bt_order = NOT;
249*50989Sbostic 	mpool_put(t->bt_mp, h, 0);
250*50989Sbostic 	return (NULL);
25146131Smao }
252