xref: /csrg-svn/lib/libc/db/btree/bt_overflow.c (revision 56493)
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*56493Sbostic static char sccsid[] = "@(#)bt_overflow.c	5.4 (Berkeley) 10/09/92";
1346129Smao #endif /* LIBC_SCCS and not lint */
1446129Smao 
1550989Sbostic #include <sys/param.h>
1646129Smao #include <db.h>
1750989Sbostic #include <stdio.h>
1846561Sbostic #include <stdlib.h>
1946561Sbostic #include <string.h>
2046129Smao #include "btree.h"
2146129Smao 
2246129Smao /*
2350989Sbostic  * Big key/data code.
2446129Smao  *
2550989Sbostic  * Big key and data entries are stored on linked lists of pages.  The initial
2650989Sbostic  * reference is byte string stored with the key or data and is the page number
2750989Sbostic  * and size.  The actual record is stored in a chain of pages linked by the
2850989Sbostic  * nextpg field of the PAGE header.
2946129Smao  *
3050989Sbostic  * The first page of the chain has a special property.  If the record is used
3150989Sbostic  * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
3250989Sbostic  * in the header.
3346129Smao  *
3450989Sbostic  * XXX
3550989Sbostic  * A single DBT is written to each chain, so a lot of space on the last page
3650989Sbostic  * is wasted.  This is a fairly major bug for some data sets.
3746129Smao  */
3846129Smao 
3946129Smao /*
4050989Sbostic  * __OVFL_GET -- Get an overflow key/data item.
4146129Smao  *
4250989Sbostic  * Parameters:
4350989Sbostic  *	t:	tree
4450989Sbostic  *	p:	pointer to { pgno_t, size_t }
4550989Sbostic  *	buf:	storage address
4650989Sbostic  *	bufsz:	storage size
4746129Smao  *
4850989Sbostic  * Returns:
4950989Sbostic  *	RET_ERROR, RET_SUCCESS
5046129Smao  */
5146129Smao int
5250989Sbostic __ovfl_get(t, p, ssz, buf, bufsz)
5350989Sbostic 	BTREE *t;
5450989Sbostic 	void *p;
5550989Sbostic 	size_t *ssz;
5650989Sbostic 	char **buf;
5750989Sbostic 	size_t *bufsz;
5846129Smao {
5950989Sbostic 	PAGE *h;
6050989Sbostic 	pgno_t pg;
6150989Sbostic 	size_t nb, plen, sz;
6246129Smao 
6350989Sbostic 	pg = *(pgno_t *)p;
6450989Sbostic 	*ssz = sz = *(size_t *)((char *)p + sizeof(pgno_t));
6546129Smao 
6650989Sbostic #ifdef DEBUG
6750989Sbostic 	if (pg == P_INVALID || sz == 0)
6850989Sbostic 		abort();
6950989Sbostic #endif
7050989Sbostic 	/* Make the buffer bigger as necessary. */
7150989Sbostic 	if (*bufsz < sz) {
7250989Sbostic 		if ((*buf = realloc(*buf, sz)) == NULL)
7350989Sbostic 			return (RET_ERROR);
7450989Sbostic 		*bufsz = sz;
7550989Sbostic 	}
7650989Sbostic 
7746129Smao 	/*
7850989Sbostic 	 * Step through the linked list of pages, copying the data on each one
7950989Sbostic 	 * into the buffer.  Never copy more than the data's length.
8046129Smao 	 */
8150989Sbostic 	plen = t->bt_psize - BTDATAOFF;
8250989Sbostic 	for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
8350989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
8446129Smao 			return (RET_ERROR);
8546129Smao 
8650989Sbostic 		nb = MIN(sz, plen);
8750989Sbostic 		bcopy((char *)h + BTDATAOFF, p, nb);
8850989Sbostic 		mpool_put(t->bt_mp, h, 0);
8946129Smao 
9050989Sbostic 		if ((sz -= nb) == 0)
9150989Sbostic 			break;
9246129Smao 	}
9346129Smao 	return (RET_SUCCESS);
9446129Smao }
9546129Smao 
9646129Smao /*
9750989Sbostic  * __OVFL_PUT -- Store an overflow key/data item.
9846129Smao  *
9950989Sbostic  * Parameters:
10050989Sbostic  *	t:	tree
10150989Sbostic  *	data:	DBT to store
10250989Sbostic  *	pgno:	storage page number
10346129Smao  *
10450989Sbostic  * Returns:
10550989Sbostic  *	RET_ERROR, RET_SUCCESS
10646129Smao  */
10746129Smao int
10850989Sbostic __ovfl_put(t, dbt, pg)
10950989Sbostic 	BTREE *t;
11050989Sbostic 	const DBT *dbt;
11150989Sbostic 	pgno_t *pg;
11246129Smao {
11350989Sbostic 	PAGE *h, *last;
11450989Sbostic 	void *p;
11550989Sbostic 	pgno_t npg;
11650989Sbostic 	size_t nb, plen, sz;
11746129Smao 
11850989Sbostic 	/*
11950989Sbostic 	 * Allocate pages and copy the key/data record into them.  Store the
12050989Sbostic 	 * number of the first page in the chain.
12150989Sbostic 	 */
12250989Sbostic 	plen = t->bt_psize - BTDATAOFF;
12350989Sbostic 	for (last = NULL, p = dbt->data, sz = dbt->size;;
12450989Sbostic 	    p = (char *)p + plen, last = h) {
125*56493Sbostic 		if ((h = __bt_new(t, &npg)) == NULL)
12646129Smao 			return (RET_ERROR);
12746129Smao 
12850989Sbostic 		h->pgno = npg;
12950989Sbostic 		h->nextpg = h->prevpg = P_INVALID;
13050989Sbostic 		h->lower = h->upper = 0;
13146129Smao 
13250989Sbostic 		nb = MIN(sz, plen);
13350989Sbostic 		bcopy(p, (char *)h + BTDATAOFF, nb);
13446129Smao 
13550989Sbostic 		if (last) {
13650989Sbostic 			last->nextpg = h->pgno;
13750989Sbostic 			last->flags |= P_OVERFLOW;
13850989Sbostic 			mpool_put(t->bt_mp, last, MPOOL_DIRTY);
13950989Sbostic 		} else
14050989Sbostic 			*pg = h->pgno;
14146129Smao 
14250989Sbostic 		if ((sz -= nb) == 0) {
14350989Sbostic 			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
14446129Smao 			break;
14546129Smao 		}
14646129Smao 	}
14746129Smao 	return (RET_SUCCESS);
14846129Smao }
14946129Smao 
15046129Smao /*
15150989Sbostic  * __OVFL_DELETE -- Delete an overflow chain.
15246129Smao  *
15350989Sbostic  * Parameters:
15450989Sbostic  *	t:	tree
15550989Sbostic  *	p:	pointer to { pgno_t, size_t }
15646129Smao  *
15750989Sbostic  * Returns:
15850989Sbostic  *	RET_ERROR, RET_SUCCESS
15946129Smao  */
16046129Smao int
16150989Sbostic __ovfl_delete(t, p)
16250989Sbostic 	BTREE *t;
16350989Sbostic 	void *p;
16446129Smao {
16550989Sbostic 	PAGE *h;
16650989Sbostic 	pgno_t pg;
16750989Sbostic 	size_t plen, sz;
16846129Smao 
16950989Sbostic 	pg = *(pgno_t *)p;
17050989Sbostic 	sz = *(size_t *)((char *)p + sizeof(pgno_t));
17146129Smao 
17250989Sbostic #ifdef DEBUG
17350989Sbostic 	if (pg == P_INVALID || sz == 0)
17450989Sbostic 		abort();
17550989Sbostic #endif
17650989Sbostic 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
17746129Smao 		return (RET_ERROR);
17846129Smao 
17950989Sbostic 	/* Don't delete chains used by internal pages. */
18050989Sbostic 	if (h->flags & P_PRESERVE) {
18150989Sbostic 		mpool_put(t->bt_mp, h, 0);
18250989Sbostic 		return (RET_SUCCESS);
18350989Sbostic 	}
18446129Smao 
18550989Sbostic 	/* Step through the chain, calling the free routine for each page. */
186*56493Sbostic 	for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
187*56493Sbostic 		pg = h->nextpg;
188*56493Sbostic 		__bt_free(t, h);
189*56493Sbostic 		if (sz <= plen)
19050989Sbostic 			break;
19150989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
19250989Sbostic 			return (RET_ERROR);
19350989Sbostic 	}
19446129Smao 	return (RET_SUCCESS);
19546129Smao }
196