xref: /csrg-svn/lib/libc/db/btree/bt_overflow.c (revision 57932)
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*57932Sbostic static char sccsid[] = "@(#)bt_overflow.c	5.7 (Berkeley) 02/11/93";
1346129Smao #endif /* LIBC_SCCS and not lint */
1446129Smao 
1550989Sbostic #include <sys/param.h>
1656739Sbostic 
1750989Sbostic #include <stdio.h>
1846561Sbostic #include <stdlib.h>
1946561Sbostic #include <string.h>
2056739Sbostic 
21*57932Sbostic #include <db.h>
2246129Smao #include "btree.h"
2346129Smao 
2446129Smao /*
2550989Sbostic  * Big key/data code.
2646129Smao  *
2750989Sbostic  * Big key and data entries are stored on linked lists of pages.  The initial
2850989Sbostic  * reference is byte string stored with the key or data and is the page number
2950989Sbostic  * and size.  The actual record is stored in a chain of pages linked by the
3050989Sbostic  * nextpg field of the PAGE header.
3146129Smao  *
3250989Sbostic  * The first page of the chain has a special property.  If the record is used
3350989Sbostic  * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
3450989Sbostic  * in the header.
3546129Smao  *
3650989Sbostic  * XXX
3750989Sbostic  * A single DBT is written to each chain, so a lot of space on the last page
3850989Sbostic  * is wasted.  This is a fairly major bug for some data sets.
3946129Smao  */
4046129Smao 
4146129Smao /*
4250989Sbostic  * __OVFL_GET -- Get an overflow key/data item.
4346129Smao  *
4450989Sbostic  * Parameters:
4550989Sbostic  *	t:	tree
4650989Sbostic  *	p:	pointer to { pgno_t, size_t }
4750989Sbostic  *	buf:	storage address
4850989Sbostic  *	bufsz:	storage size
4946129Smao  *
5050989Sbostic  * Returns:
5150989Sbostic  *	RET_ERROR, RET_SUCCESS
5246129Smao  */
5346129Smao int
5450989Sbostic __ovfl_get(t, p, ssz, buf, bufsz)
5550989Sbostic 	BTREE *t;
5650989Sbostic 	void *p;
5750989Sbostic 	size_t *ssz;
5850989Sbostic 	char **buf;
5950989Sbostic 	size_t *bufsz;
6046129Smao {
6150989Sbostic 	PAGE *h;
6250989Sbostic 	pgno_t pg;
6350989Sbostic 	size_t nb, plen, sz;
6446129Smao 
6556558Sbostic 	bcopy(p, &pg, sizeof(pgno_t));
6656558Sbostic 	bcopy((char *)p + sizeof(pgno_t), &sz, sizeof(size_t));
6756558Sbostic 	*ssz = sz;
6846129Smao 
6950989Sbostic #ifdef DEBUG
7050989Sbostic 	if (pg == P_INVALID || sz == 0)
7150989Sbostic 		abort();
7250989Sbostic #endif
7350989Sbostic 	/* Make the buffer bigger as necessary. */
7450989Sbostic 	if (*bufsz < sz) {
7550989Sbostic 		if ((*buf = realloc(*buf, sz)) == NULL)
7650989Sbostic 			return (RET_ERROR);
7750989Sbostic 		*bufsz = sz;
7850989Sbostic 	}
7950989Sbostic 
8046129Smao 	/*
8150989Sbostic 	 * Step through the linked list of pages, copying the data on each one
8250989Sbostic 	 * into the buffer.  Never copy more than the data's length.
8346129Smao 	 */
8450989Sbostic 	plen = t->bt_psize - BTDATAOFF;
8550989Sbostic 	for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
8650989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
8746129Smao 			return (RET_ERROR);
8846129Smao 
8950989Sbostic 		nb = MIN(sz, plen);
9050989Sbostic 		bcopy((char *)h + BTDATAOFF, p, nb);
9150989Sbostic 		mpool_put(t->bt_mp, h, 0);
9246129Smao 
9350989Sbostic 		if ((sz -= nb) == 0)
9450989Sbostic 			break;
9546129Smao 	}
9646129Smao 	return (RET_SUCCESS);
9746129Smao }
9846129Smao 
9946129Smao /*
10050989Sbostic  * __OVFL_PUT -- Store an overflow key/data item.
10146129Smao  *
10250989Sbostic  * Parameters:
10350989Sbostic  *	t:	tree
10450989Sbostic  *	data:	DBT to store
10550989Sbostic  *	pgno:	storage page number
10646129Smao  *
10750989Sbostic  * Returns:
10850989Sbostic  *	RET_ERROR, RET_SUCCESS
10946129Smao  */
11046129Smao int
11150989Sbostic __ovfl_put(t, dbt, pg)
11250989Sbostic 	BTREE *t;
11350989Sbostic 	const DBT *dbt;
11450989Sbostic 	pgno_t *pg;
11546129Smao {
11650989Sbostic 	PAGE *h, *last;
11750989Sbostic 	void *p;
11850989Sbostic 	pgno_t npg;
11950989Sbostic 	size_t nb, plen, sz;
12046129Smao 
12150989Sbostic 	/*
12250989Sbostic 	 * Allocate pages and copy the key/data record into them.  Store the
12350989Sbostic 	 * number of the first page in the chain.
12450989Sbostic 	 */
12550989Sbostic 	plen = t->bt_psize - BTDATAOFF;
12650989Sbostic 	for (last = NULL, p = dbt->data, sz = dbt->size;;
12750989Sbostic 	    p = (char *)p + plen, last = h) {
12856493Sbostic 		if ((h = __bt_new(t, &npg)) == NULL)
12946129Smao 			return (RET_ERROR);
13046129Smao 
13150989Sbostic 		h->pgno = npg;
13250989Sbostic 		h->nextpg = h->prevpg = P_INVALID;
13356558Sbostic 		h->flags = P_OVERFLOW;
13450989Sbostic 		h->lower = h->upper = 0;
13546129Smao 
13650989Sbostic 		nb = MIN(sz, plen);
13750989Sbostic 		bcopy(p, (char *)h + BTDATAOFF, nb);
13846129Smao 
13950989Sbostic 		if (last) {
14050989Sbostic 			last->nextpg = h->pgno;
14150989Sbostic 			mpool_put(t->bt_mp, last, MPOOL_DIRTY);
14250989Sbostic 		} else
14350989Sbostic 			*pg = h->pgno;
14446129Smao 
14550989Sbostic 		if ((sz -= nb) == 0) {
14650989Sbostic 			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
14746129Smao 			break;
14846129Smao 		}
14946129Smao 	}
15046129Smao 	return (RET_SUCCESS);
15146129Smao }
15246129Smao 
15346129Smao /*
15450989Sbostic  * __OVFL_DELETE -- Delete an overflow chain.
15546129Smao  *
15650989Sbostic  * Parameters:
15750989Sbostic  *	t:	tree
15850989Sbostic  *	p:	pointer to { pgno_t, size_t }
15946129Smao  *
16050989Sbostic  * Returns:
16150989Sbostic  *	RET_ERROR, RET_SUCCESS
16246129Smao  */
16346129Smao int
16450989Sbostic __ovfl_delete(t, p)
16550989Sbostic 	BTREE *t;
16650989Sbostic 	void *p;
16746129Smao {
16850989Sbostic 	PAGE *h;
16950989Sbostic 	pgno_t pg;
17050989Sbostic 	size_t plen, sz;
17146129Smao 
17256558Sbostic 	bcopy(p, &pg, sizeof(pgno_t));
17356558Sbostic 	bcopy((char *)p + sizeof(pgno_t), &sz, sizeof(size_t));
17446129Smao 
17550989Sbostic #ifdef DEBUG
17650989Sbostic 	if (pg == P_INVALID || sz == 0)
17750989Sbostic 		abort();
17850989Sbostic #endif
17950989Sbostic 	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
18046129Smao 		return (RET_ERROR);
18146129Smao 
18250989Sbostic 	/* Don't delete chains used by internal pages. */
18350989Sbostic 	if (h->flags & P_PRESERVE) {
18450989Sbostic 		mpool_put(t->bt_mp, h, 0);
18550989Sbostic 		return (RET_SUCCESS);
18650989Sbostic 	}
18746129Smao 
18850989Sbostic 	/* Step through the chain, calling the free routine for each page. */
18956493Sbostic 	for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
19056493Sbostic 		pg = h->nextpg;
19156493Sbostic 		__bt_free(t, h);
19256493Sbostic 		if (sz <= plen)
19350989Sbostic 			break;
19450989Sbostic 		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
19550989Sbostic 			return (RET_ERROR);
19650989Sbostic 	}
19746129Smao 	return (RET_SUCCESS);
19846129Smao }
199