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