xref: /csrg-svn/lib/libc/db/btree/bt_overflow.c (revision 50989)
146129Smao /*-
246129Smao  * Copyright (c) 1990 The Regents of the University of California.
346129Smao  * All rights reserved.
446129Smao  *
546129Smao  * This code is derived from software contributed to Berkeley by
646129Smao  * Mike Olson.
746129Smao  *
846129Smao  * %sccs.include.redist.c%
946129Smao  */
1046129Smao 
1146129Smao #if defined(LIBC_SCCS) && !defined(lint)
12*50989Sbostic static char sccsid[] = "@(#)bt_overflow.c	5.3 (Berkeley) 09/04/91";
1346129Smao #endif /* LIBC_SCCS and not lint */
1446129Smao 
15*50989Sbostic #include <sys/param.h>
1646129Smao #include <db.h>
17*50989Sbostic #include <stdio.h>
1846561Sbostic #include <stdlib.h>
1946561Sbostic #include <string.h>
2046129Smao #include "btree.h"
2146129Smao 
2246129Smao /*
23*50989Sbostic  * Big key/data code.
2446129Smao  *
25*50989Sbostic  * Big key and data entries are stored on linked lists of pages.  The initial
26*50989Sbostic  * reference is byte string stored with the key or data and is the page number
27*50989Sbostic  * and size.  The actual record is stored in a chain of pages linked by the
28*50989Sbostic  * nextpg field of the PAGE header.
2946129Smao  *
30*50989Sbostic  * The first page of the chain has a special property.  If the record is used
31*50989Sbostic  * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
32*50989Sbostic  * in the header.
3346129Smao  *
34*50989Sbostic  * XXX
35*50989Sbostic  * A single DBT is written to each chain, so a lot of space on the last page
36*50989Sbostic  * is wasted.  This is a fairly major bug for some data sets.
3746129Smao  */
3846129Smao 
3946129Smao /*
40*50989Sbostic  * __OVFL_GET -- Get an overflow key/data item.
4146129Smao  *
42*50989Sbostic  * Parameters:
43*50989Sbostic  *	t:	tree
44*50989Sbostic  *	p:	pointer to { pgno_t, size_t }
45*50989Sbostic  *	buf:	storage address
46*50989Sbostic  *	bufsz:	storage size
4746129Smao  *
48*50989Sbostic  * Returns:
49*50989Sbostic  *	RET_ERROR, RET_SUCCESS
5046129Smao  */
5146129Smao int
52*50989Sbostic __ovfl_get(t, p, ssz, buf, bufsz)
53*50989Sbostic 	BTREE *t;
54*50989Sbostic 	void *p;
55*50989Sbostic 	size_t *ssz;
56*50989Sbostic 	char **buf;
57*50989Sbostic 	size_t *bufsz;
5846129Smao {
59*50989Sbostic 	PAGE *h;
60*50989Sbostic 	pgno_t pg;
61*50989Sbostic 	size_t nb, plen, sz;
6246129Smao 
63*50989Sbostic 	pg = *(pgno_t *)p;
64*50989Sbostic 	*ssz = sz = *(size_t *)((char *)p + sizeof(pgno_t));
6546129Smao 
66*50989Sbostic #ifdef DEBUG
67*50989Sbostic 	if (pg == P_INVALID || sz == 0)
68*50989Sbostic 		abort();
69*50989Sbostic #endif
70*50989Sbostic 	/* Make the buffer bigger as necessary. */
71*50989Sbostic 	if (*bufsz < sz) {
72*50989Sbostic 		if ((*buf = realloc(*buf, sz)) == NULL)
73*50989Sbostic 			return (RET_ERROR);
74*50989Sbostic 		*bufsz = sz;
75*50989Sbostic 	}
76*50989Sbostic 
7746129Smao 	/*
78*50989Sbostic 	 * Step through the linked list of pages, copying the data on each one
79*50989Sbostic 	 * into the buffer.  Never copy more than the data's length.
8046129Smao 	 */
81*50989Sbostic 	plen = t->bt_psize - BTDATAOFF;
82*50989Sbostic 	for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
83*50989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
8446129Smao 			return (RET_ERROR);
8546129Smao 
86*50989Sbostic 		nb = MIN(sz, plen);
87*50989Sbostic 		bcopy((char *)h + BTDATAOFF, p, nb);
88*50989Sbostic 		mpool_put(t->bt_mp, h, 0);
8946129Smao 
90*50989Sbostic 		if ((sz -= nb) == 0)
91*50989Sbostic 			break;
9246129Smao 	}
9346129Smao 	return (RET_SUCCESS);
9446129Smao }
9546129Smao 
9646129Smao /*
97*50989Sbostic  * __OVFL_PUT -- Store an overflow key/data item.
9846129Smao  *
99*50989Sbostic  * Parameters:
100*50989Sbostic  *	t:	tree
101*50989Sbostic  *	data:	DBT to store
102*50989Sbostic  *	pgno:	storage page number
10346129Smao  *
104*50989Sbostic  * Returns:
105*50989Sbostic  *	RET_ERROR, RET_SUCCESS
10646129Smao  */
10746129Smao int
108*50989Sbostic __ovfl_put(t, dbt, pg)
109*50989Sbostic 	BTREE *t;
110*50989Sbostic 	const DBT *dbt;
111*50989Sbostic 	pgno_t *pg;
11246129Smao {
113*50989Sbostic 	PAGE *h, *last;
114*50989Sbostic 	void *p;
115*50989Sbostic 	pgno_t npg;
116*50989Sbostic 	size_t nb, plen, sz;
11746129Smao 
118*50989Sbostic 	/*
119*50989Sbostic 	 * Allocate pages and copy the key/data record into them.  Store the
120*50989Sbostic 	 * number of the first page in the chain.
121*50989Sbostic 	 */
122*50989Sbostic 	plen = t->bt_psize - BTDATAOFF;
123*50989Sbostic 	for (last = NULL, p = dbt->data, sz = dbt->size;;
124*50989Sbostic 	    p = (char *)p + plen, last = h) {
125*50989Sbostic 		if ((h = mpool_new(t->bt_mp, &npg)) == NULL)
12646129Smao 			return (RET_ERROR);
12746129Smao 
128*50989Sbostic 		h->pgno = npg;
129*50989Sbostic 		h->nextpg = h->prevpg = P_INVALID;
130*50989Sbostic 		h->lower = h->upper = 0;
13146129Smao 
132*50989Sbostic 		nb = MIN(sz, plen);
133*50989Sbostic 		bcopy(p, (char *)h + BTDATAOFF, nb);
13446129Smao 
135*50989Sbostic 		if (last) {
136*50989Sbostic 			last->nextpg = h->pgno;
137*50989Sbostic 			last->flags |= P_OVERFLOW;
138*50989Sbostic 			mpool_put(t->bt_mp, last, MPOOL_DIRTY);
139*50989Sbostic 		} else
140*50989Sbostic 			*pg = h->pgno;
14146129Smao 
142*50989Sbostic 		if ((sz -= nb) == 0) {
143*50989Sbostic 			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
14446129Smao 			break;
14546129Smao 		}
14646129Smao 	}
14746129Smao 	return (RET_SUCCESS);
14846129Smao }
14946129Smao 
15046129Smao /*
151*50989Sbostic  * __OVFL_DELETE -- Delete an overflow chain.
15246129Smao  *
153*50989Sbostic  * Parameters:
154*50989Sbostic  *	t:	tree
155*50989Sbostic  *	p:	pointer to { pgno_t, size_t }
15646129Smao  *
157*50989Sbostic  * Returns:
158*50989Sbostic  *	RET_ERROR, RET_SUCCESS
15946129Smao  */
16046129Smao int
161*50989Sbostic __ovfl_delete(t, p)
162*50989Sbostic 	BTREE *t;
163*50989Sbostic 	void *p;
16446129Smao {
165*50989Sbostic 	PAGE *h;
166*50989Sbostic 	pgno_t pg;
167*50989Sbostic 	size_t plen, sz;
16846129Smao 
169*50989Sbostic 	pg = *(pgno_t *)p;
170*50989Sbostic 	sz = *(size_t *)((char *)p + sizeof(pgno_t));
17146129Smao 
172*50989Sbostic #ifdef DEBUG
173*50989Sbostic 	if (pg == P_INVALID || sz == 0)
174*50989Sbostic 		abort();
175*50989Sbostic #endif
176*50989Sbostic 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
17746129Smao 		return (RET_ERROR);
17846129Smao 
179*50989Sbostic 	/* Don't delete chains used by internal pages. */
180*50989Sbostic 	if (h->flags & P_PRESERVE) {
181*50989Sbostic 		mpool_put(t->bt_mp, h, 0);
182*50989Sbostic 		return (RET_SUCCESS);
183*50989Sbostic 	}
18446129Smao 
185*50989Sbostic 	/* Step through the chain, calling the free routine for each page. */
186*50989Sbostic 	plen = t->bt_psize - BTDATAOFF;
187*50989Sbostic 	for (;; sz -= plen) {
188*50989Sbostic 		if (sz >= plen)
189*50989Sbostic 			break;
190*50989Sbostic 		pg = h->nextpg;
191*50989Sbostic 		/* XXX mpool_free(t->bt_mp, h->pgno); */
192*50989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
193*50989Sbostic 			return (RET_ERROR);
194*50989Sbostic 	}
19546129Smao 	return (RET_SUCCESS);
19646129Smao }
197