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*56493Sbostic static char sccsid[] = "@(#)bt_overflow.c 5.4 (Berkeley) 10/09/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 6350989Sbostic pg = *(pgno_t *)p; 6450989Sbostic *ssz = sz = *(size_t *)((char *)p + sizeof(pgno_t)); 6546129Smao 6650989Sbostic #ifdef DEBUG 6750989Sbostic if (pg == P_INVALID || sz == 0) 6850989Sbostic abort(); 6950989Sbostic #endif 7050989Sbostic /* Make the buffer bigger as necessary. */ 7150989Sbostic if (*bufsz < sz) { 7250989Sbostic if ((*buf = realloc(*buf, sz)) == NULL) 7350989Sbostic return (RET_ERROR); 7450989Sbostic *bufsz = sz; 7550989Sbostic } 7650989Sbostic 7746129Smao /* 7850989Sbostic * Step through the linked list of pages, copying the data on each one 7950989Sbostic * into the buffer. Never copy more than the data's length. 8046129Smao */ 8150989Sbostic plen = t->bt_psize - BTDATAOFF; 8250989Sbostic for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) { 8350989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 8446129Smao return (RET_ERROR); 8546129Smao 8650989Sbostic nb = MIN(sz, plen); 8750989Sbostic bcopy((char *)h + BTDATAOFF, p, nb); 8850989Sbostic mpool_put(t->bt_mp, h, 0); 8946129Smao 9050989Sbostic if ((sz -= nb) == 0) 9150989Sbostic break; 9246129Smao } 9346129Smao return (RET_SUCCESS); 9446129Smao } 9546129Smao 9646129Smao /* 9750989Sbostic * __OVFL_PUT -- Store an overflow key/data item. 9846129Smao * 9950989Sbostic * Parameters: 10050989Sbostic * t: tree 10150989Sbostic * data: DBT to store 10250989Sbostic * pgno: storage page number 10346129Smao * 10450989Sbostic * Returns: 10550989Sbostic * RET_ERROR, RET_SUCCESS 10646129Smao */ 10746129Smao int 10850989Sbostic __ovfl_put(t, dbt, pg) 10950989Sbostic BTREE *t; 11050989Sbostic const DBT *dbt; 11150989Sbostic pgno_t *pg; 11246129Smao { 11350989Sbostic PAGE *h, *last; 11450989Sbostic void *p; 11550989Sbostic pgno_t npg; 11650989Sbostic size_t nb, plen, sz; 11746129Smao 11850989Sbostic /* 11950989Sbostic * Allocate pages and copy the key/data record into them. Store the 12050989Sbostic * number of the first page in the chain. 12150989Sbostic */ 12250989Sbostic plen = t->bt_psize - BTDATAOFF; 12350989Sbostic for (last = NULL, p = dbt->data, sz = dbt->size;; 12450989Sbostic p = (char *)p + plen, last = h) { 125*56493Sbostic if ((h = __bt_new(t, &npg)) == NULL) 12646129Smao return (RET_ERROR); 12746129Smao 12850989Sbostic h->pgno = npg; 12950989Sbostic h->nextpg = h->prevpg = P_INVALID; 13050989Sbostic h->lower = h->upper = 0; 13146129Smao 13250989Sbostic nb = MIN(sz, plen); 13350989Sbostic bcopy(p, (char *)h + BTDATAOFF, nb); 13446129Smao 13550989Sbostic if (last) { 13650989Sbostic last->nextpg = h->pgno; 13750989Sbostic last->flags |= P_OVERFLOW; 13850989Sbostic mpool_put(t->bt_mp, last, MPOOL_DIRTY); 13950989Sbostic } else 14050989Sbostic *pg = h->pgno; 14146129Smao 14250989Sbostic if ((sz -= nb) == 0) { 14350989Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 14446129Smao break; 14546129Smao } 14646129Smao } 14746129Smao return (RET_SUCCESS); 14846129Smao } 14946129Smao 15046129Smao /* 15150989Sbostic * __OVFL_DELETE -- Delete an overflow chain. 15246129Smao * 15350989Sbostic * Parameters: 15450989Sbostic * t: tree 15550989Sbostic * p: pointer to { pgno_t, size_t } 15646129Smao * 15750989Sbostic * Returns: 15850989Sbostic * RET_ERROR, RET_SUCCESS 15946129Smao */ 16046129Smao int 16150989Sbostic __ovfl_delete(t, p) 16250989Sbostic BTREE *t; 16350989Sbostic void *p; 16446129Smao { 16550989Sbostic PAGE *h; 16650989Sbostic pgno_t pg; 16750989Sbostic size_t plen, sz; 16846129Smao 16950989Sbostic pg = *(pgno_t *)p; 17050989Sbostic sz = *(size_t *)((char *)p + sizeof(pgno_t)); 17146129Smao 17250989Sbostic #ifdef DEBUG 17350989Sbostic if (pg == P_INVALID || sz == 0) 17450989Sbostic abort(); 17550989Sbostic #endif 17650989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 17746129Smao return (RET_ERROR); 17846129Smao 17950989Sbostic /* Don't delete chains used by internal pages. */ 18050989Sbostic if (h->flags & P_PRESERVE) { 18150989Sbostic mpool_put(t->bt_mp, h, 0); 18250989Sbostic return (RET_SUCCESS); 18350989Sbostic } 18446129Smao 18550989Sbostic /* Step through the chain, calling the free routine for each page. */ 186*56493Sbostic for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) { 187*56493Sbostic pg = h->nextpg; 188*56493Sbostic __bt_free(t, h); 189*56493Sbostic if (sz <= plen) 19050989Sbostic break; 19150989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 19250989Sbostic return (RET_ERROR); 19350989Sbostic } 19446129Smao return (RET_SUCCESS); 19546129Smao } 196