xref: /csrg-svn/lib/libc/db/btree/bt_overflow.c (revision 56558)
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*56558Sbostic static char sccsid[] = "@(#)bt_overflow.c	5.5 (Berkeley) 10/13/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 
63*56558Sbostic 	bcopy(p, &pg, sizeof(pgno_t));
64*56558Sbostic 	bcopy((char *)p + sizeof(pgno_t), &sz, sizeof(size_t));
65*56558Sbostic 	*ssz = sz;
6646129Smao 
6750989Sbostic #ifdef DEBUG
6850989Sbostic 	if (pg == P_INVALID || sz == 0)
6950989Sbostic 		abort();
7050989Sbostic #endif
7150989Sbostic 	/* Make the buffer bigger as necessary. */
7250989Sbostic 	if (*bufsz < sz) {
7350989Sbostic 		if ((*buf = realloc(*buf, sz)) == NULL)
7450989Sbostic 			return (RET_ERROR);
7550989Sbostic 		*bufsz = sz;
7650989Sbostic 	}
7750989Sbostic 
7846129Smao 	/*
7950989Sbostic 	 * Step through the linked list of pages, copying the data on each one
8050989Sbostic 	 * into the buffer.  Never copy more than the data's length.
8146129Smao 	 */
8250989Sbostic 	plen = t->bt_psize - BTDATAOFF;
8350989Sbostic 	for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
8450989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
8546129Smao 			return (RET_ERROR);
8646129Smao 
8750989Sbostic 		nb = MIN(sz, plen);
8850989Sbostic 		bcopy((char *)h + BTDATAOFF, p, nb);
8950989Sbostic 		mpool_put(t->bt_mp, h, 0);
9046129Smao 
9150989Sbostic 		if ((sz -= nb) == 0)
9250989Sbostic 			break;
9346129Smao 	}
9446129Smao 	return (RET_SUCCESS);
9546129Smao }
9646129Smao 
9746129Smao /*
9850989Sbostic  * __OVFL_PUT -- Store an overflow key/data item.
9946129Smao  *
10050989Sbostic  * Parameters:
10150989Sbostic  *	t:	tree
10250989Sbostic  *	data:	DBT to store
10350989Sbostic  *	pgno:	storage page number
10446129Smao  *
10550989Sbostic  * Returns:
10650989Sbostic  *	RET_ERROR, RET_SUCCESS
10746129Smao  */
10846129Smao int
10950989Sbostic __ovfl_put(t, dbt, pg)
11050989Sbostic 	BTREE *t;
11150989Sbostic 	const DBT *dbt;
11250989Sbostic 	pgno_t *pg;
11346129Smao {
11450989Sbostic 	PAGE *h, *last;
11550989Sbostic 	void *p;
11650989Sbostic 	pgno_t npg;
11750989Sbostic 	size_t nb, plen, sz;
11846129Smao 
11950989Sbostic 	/*
12050989Sbostic 	 * Allocate pages and copy the key/data record into them.  Store the
12150989Sbostic 	 * number of the first page in the chain.
12250989Sbostic 	 */
12350989Sbostic 	plen = t->bt_psize - BTDATAOFF;
12450989Sbostic 	for (last = NULL, p = dbt->data, sz = dbt->size;;
12550989Sbostic 	    p = (char *)p + plen, last = h) {
12656493Sbostic 		if ((h = __bt_new(t, &npg)) == NULL)
12746129Smao 			return (RET_ERROR);
12846129Smao 
12950989Sbostic 		h->pgno = npg;
13050989Sbostic 		h->nextpg = h->prevpg = P_INVALID;
131*56558Sbostic 		h->flags = P_OVERFLOW;
13250989Sbostic 		h->lower = h->upper = 0;
13346129Smao 
13450989Sbostic 		nb = MIN(sz, plen);
13550989Sbostic 		bcopy(p, (char *)h + BTDATAOFF, nb);
13646129Smao 
13750989Sbostic 		if (last) {
13850989Sbostic 			last->nextpg = h->pgno;
13950989Sbostic 			mpool_put(t->bt_mp, last, MPOOL_DIRTY);
14050989Sbostic 		} else
14150989Sbostic 			*pg = h->pgno;
14246129Smao 
14350989Sbostic 		if ((sz -= nb) == 0) {
14450989Sbostic 			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
14546129Smao 			break;
14646129Smao 		}
14746129Smao 	}
14846129Smao 	return (RET_SUCCESS);
14946129Smao }
15046129Smao 
15146129Smao /*
15250989Sbostic  * __OVFL_DELETE -- Delete an overflow chain.
15346129Smao  *
15450989Sbostic  * Parameters:
15550989Sbostic  *	t:	tree
15650989Sbostic  *	p:	pointer to { pgno_t, size_t }
15746129Smao  *
15850989Sbostic  * Returns:
15950989Sbostic  *	RET_ERROR, RET_SUCCESS
16046129Smao  */
16146129Smao int
16250989Sbostic __ovfl_delete(t, p)
16350989Sbostic 	BTREE *t;
16450989Sbostic 	void *p;
16546129Smao {
16650989Sbostic 	PAGE *h;
16750989Sbostic 	pgno_t pg;
16850989Sbostic 	size_t plen, sz;
16946129Smao 
170*56558Sbostic 	bcopy(p, &pg, sizeof(pgno_t));
171*56558Sbostic 	bcopy((char *)p + sizeof(pgno_t), &sz, sizeof(size_t));
17246129Smao 
17350989Sbostic #ifdef DEBUG
17450989Sbostic 	if (pg == P_INVALID || sz == 0)
17550989Sbostic 		abort();
17650989Sbostic #endif
17750989Sbostic 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
17846129Smao 		return (RET_ERROR);
17946129Smao 
18050989Sbostic 	/* Don't delete chains used by internal pages. */
18150989Sbostic 	if (h->flags & P_PRESERVE) {
18250989Sbostic 		mpool_put(t->bt_mp, h, 0);
18350989Sbostic 		return (RET_SUCCESS);
18450989Sbostic 	}
18546129Smao 
18650989Sbostic 	/* Step through the chain, calling the free routine for each page. */
18756493Sbostic 	for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
18856493Sbostic 		pg = h->nextpg;
18956493Sbostic 		__bt_free(t, h);
19056493Sbostic 		if (sz <= plen)
19150989Sbostic 			break;
19250989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
19350989Sbostic 			return (RET_ERROR);
19450989Sbostic 	}
19546129Smao 	return (RET_SUCCESS);
19646129Smao }
197