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*50989Sbostic static char sccsid[] = "@(#)bt_overflow.c 5.3 (Berkeley) 09/04/91"; 1346129Smao #endif /* LIBC_SCCS and not lint */ 1446129Smao 15*50989Sbostic #include <sys/param.h> 1646129Smao #include <db.h> 17*50989Sbostic #include <stdio.h> 1846561Sbostic #include <stdlib.h> 1946561Sbostic #include <string.h> 2046129Smao #include "btree.h" 2146129Smao 2246129Smao /* 23*50989Sbostic * Big key/data code. 2446129Smao * 25*50989Sbostic * Big key and data entries are stored on linked lists of pages. The initial 26*50989Sbostic * reference is byte string stored with the key or data and is the page number 27*50989Sbostic * and size. The actual record is stored in a chain of pages linked by the 28*50989Sbostic * nextpg field of the PAGE header. 2946129Smao * 30*50989Sbostic * The first page of the chain has a special property. If the record is used 31*50989Sbostic * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set 32*50989Sbostic * in the header. 3346129Smao * 34*50989Sbostic * XXX 35*50989Sbostic * A single DBT is written to each chain, so a lot of space on the last page 36*50989Sbostic * is wasted. This is a fairly major bug for some data sets. 3746129Smao */ 3846129Smao 3946129Smao /* 40*50989Sbostic * __OVFL_GET -- Get an overflow key/data item. 4146129Smao * 42*50989Sbostic * Parameters: 43*50989Sbostic * t: tree 44*50989Sbostic * p: pointer to { pgno_t, size_t } 45*50989Sbostic * buf: storage address 46*50989Sbostic * bufsz: storage size 4746129Smao * 48*50989Sbostic * Returns: 49*50989Sbostic * RET_ERROR, RET_SUCCESS 5046129Smao */ 5146129Smao int 52*50989Sbostic __ovfl_get(t, p, ssz, buf, bufsz) 53*50989Sbostic BTREE *t; 54*50989Sbostic void *p; 55*50989Sbostic size_t *ssz; 56*50989Sbostic char **buf; 57*50989Sbostic size_t *bufsz; 5846129Smao { 59*50989Sbostic PAGE *h; 60*50989Sbostic pgno_t pg; 61*50989Sbostic size_t nb, plen, sz; 6246129Smao 63*50989Sbostic pg = *(pgno_t *)p; 64*50989Sbostic *ssz = sz = *(size_t *)((char *)p + sizeof(pgno_t)); 6546129Smao 66*50989Sbostic #ifdef DEBUG 67*50989Sbostic if (pg == P_INVALID || sz == 0) 68*50989Sbostic abort(); 69*50989Sbostic #endif 70*50989Sbostic /* Make the buffer bigger as necessary. */ 71*50989Sbostic if (*bufsz < sz) { 72*50989Sbostic if ((*buf = realloc(*buf, sz)) == NULL) 73*50989Sbostic return (RET_ERROR); 74*50989Sbostic *bufsz = sz; 75*50989Sbostic } 76*50989Sbostic 7746129Smao /* 78*50989Sbostic * Step through the linked list of pages, copying the data on each one 79*50989Sbostic * into the buffer. Never copy more than the data's length. 8046129Smao */ 81*50989Sbostic plen = t->bt_psize - BTDATAOFF; 82*50989Sbostic for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) { 83*50989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 8446129Smao return (RET_ERROR); 8546129Smao 86*50989Sbostic nb = MIN(sz, plen); 87*50989Sbostic bcopy((char *)h + BTDATAOFF, p, nb); 88*50989Sbostic mpool_put(t->bt_mp, h, 0); 8946129Smao 90*50989Sbostic if ((sz -= nb) == 0) 91*50989Sbostic break; 9246129Smao } 9346129Smao return (RET_SUCCESS); 9446129Smao } 9546129Smao 9646129Smao /* 97*50989Sbostic * __OVFL_PUT -- Store an overflow key/data item. 9846129Smao * 99*50989Sbostic * Parameters: 100*50989Sbostic * t: tree 101*50989Sbostic * data: DBT to store 102*50989Sbostic * pgno: storage page number 10346129Smao * 104*50989Sbostic * Returns: 105*50989Sbostic * RET_ERROR, RET_SUCCESS 10646129Smao */ 10746129Smao int 108*50989Sbostic __ovfl_put(t, dbt, pg) 109*50989Sbostic BTREE *t; 110*50989Sbostic const DBT *dbt; 111*50989Sbostic pgno_t *pg; 11246129Smao { 113*50989Sbostic PAGE *h, *last; 114*50989Sbostic void *p; 115*50989Sbostic pgno_t npg; 116*50989Sbostic size_t nb, plen, sz; 11746129Smao 118*50989Sbostic /* 119*50989Sbostic * Allocate pages and copy the key/data record into them. Store the 120*50989Sbostic * number of the first page in the chain. 121*50989Sbostic */ 122*50989Sbostic plen = t->bt_psize - BTDATAOFF; 123*50989Sbostic for (last = NULL, p = dbt->data, sz = dbt->size;; 124*50989Sbostic p = (char *)p + plen, last = h) { 125*50989Sbostic if ((h = mpool_new(t->bt_mp, &npg)) == NULL) 12646129Smao return (RET_ERROR); 12746129Smao 128*50989Sbostic h->pgno = npg; 129*50989Sbostic h->nextpg = h->prevpg = P_INVALID; 130*50989Sbostic h->lower = h->upper = 0; 13146129Smao 132*50989Sbostic nb = MIN(sz, plen); 133*50989Sbostic bcopy(p, (char *)h + BTDATAOFF, nb); 13446129Smao 135*50989Sbostic if (last) { 136*50989Sbostic last->nextpg = h->pgno; 137*50989Sbostic last->flags |= P_OVERFLOW; 138*50989Sbostic mpool_put(t->bt_mp, last, MPOOL_DIRTY); 139*50989Sbostic } else 140*50989Sbostic *pg = h->pgno; 14146129Smao 142*50989Sbostic if ((sz -= nb) == 0) { 143*50989Sbostic mpool_put(t->bt_mp, h, MPOOL_DIRTY); 14446129Smao break; 14546129Smao } 14646129Smao } 14746129Smao return (RET_SUCCESS); 14846129Smao } 14946129Smao 15046129Smao /* 151*50989Sbostic * __OVFL_DELETE -- Delete an overflow chain. 15246129Smao * 153*50989Sbostic * Parameters: 154*50989Sbostic * t: tree 155*50989Sbostic * p: pointer to { pgno_t, size_t } 15646129Smao * 157*50989Sbostic * Returns: 158*50989Sbostic * RET_ERROR, RET_SUCCESS 15946129Smao */ 16046129Smao int 161*50989Sbostic __ovfl_delete(t, p) 162*50989Sbostic BTREE *t; 163*50989Sbostic void *p; 16446129Smao { 165*50989Sbostic PAGE *h; 166*50989Sbostic pgno_t pg; 167*50989Sbostic size_t plen, sz; 16846129Smao 169*50989Sbostic pg = *(pgno_t *)p; 170*50989Sbostic sz = *(size_t *)((char *)p + sizeof(pgno_t)); 17146129Smao 172*50989Sbostic #ifdef DEBUG 173*50989Sbostic if (pg == P_INVALID || sz == 0) 174*50989Sbostic abort(); 175*50989Sbostic #endif 176*50989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 17746129Smao return (RET_ERROR); 17846129Smao 179*50989Sbostic /* Don't delete chains used by internal pages. */ 180*50989Sbostic if (h->flags & P_PRESERVE) { 181*50989Sbostic mpool_put(t->bt_mp, h, 0); 182*50989Sbostic return (RET_SUCCESS); 183*50989Sbostic } 18446129Smao 185*50989Sbostic /* Step through the chain, calling the free routine for each page. */ 186*50989Sbostic plen = t->bt_psize - BTDATAOFF; 187*50989Sbostic for (;; sz -= plen) { 188*50989Sbostic if (sz >= plen) 189*50989Sbostic break; 190*50989Sbostic pg = h->nextpg; 191*50989Sbostic /* XXX mpool_free(t->bt_mp, h->pgno); */ 192*50989Sbostic if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 193*50989Sbostic return (RET_ERROR); 194*50989Sbostic } 19546129Smao return (RET_SUCCESS); 19646129Smao } 197