146129Smao /*-
261196Sbostic * Copyright (c) 1990, 1993
361196Sbostic * The Regents of the University of California. 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*66214Sbostic static char sccsid[] = "@(#)bt_overflow.c 8.2 (Berkeley) 02/21/94";
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
2157932Sbostic #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
__ovfl_get(t,p,ssz,buf,bufsz)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
6558017Sbostic memmove(&pg, p, sizeof(pgno_t));
6658017Sbostic memmove(&sz, (char *)p + sizeof(pgno_t), 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) {
75*66214Sbostic if ((*buf = (char *)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);
9058017Sbostic memmove(p, (char *)h + BTDATAOFF, 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
__ovfl_put(t,dbt,pg)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);
13758017Sbostic memmove((char *)h + BTDATAOFF, p, 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
__ovfl_delete(t,p)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
17258017Sbostic memmove(&pg, p, sizeof(pgno_t));
17358017Sbostic memmove(&sz, (char *)p + sizeof(pgno_t), 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