146129Smao /*- 2*61196Sbostic * Copyright (c) 1990, 1993 3*61196Sbostic * 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*61196Sbostic static char sccsid[] = "@(#)bt_overflow.c 8.1 (Berkeley) 06/04/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 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 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) { 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); 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 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 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