diff options
Diffstat (limited to 'db2/btree/bt_put.c')
-rw-r--r-- | db2/btree/bt_put.c | 831 |
1 files changed, 0 insertions, 831 deletions
diff --git a/db2/btree/bt_put.c b/db2/btree/bt_put.c deleted file mode 100644 index 0d7a69889a..0000000000 --- a/db2/btree/bt_put.c +++ /dev/null @@ -1,831 +0,0 @@ -/*- - * See the file LICENSE for redistribution information. - * - * Copyright (c) 1996, 1997, 1998 - * Sleepycat Software. All rights reserved. - */ -/* - * Copyright (c) 1990, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - */ -/* - * Copyright (c) 1990, 1993, 1994, 1995 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Olson. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)bt_put.c 10.54 (Sleepycat) 12/6/98"; -#endif /* not lint */ - -#ifndef NO_SYSTEM_INCLUDES -#include <sys/types.h> - -#include <errno.h> -#include <string.h> -#endif - -#include "db_int.h" -#include "db_page.h" -#include "btree.h" - -static int __bam_fixed __P((DBC *, DBT *)); -static int __bam_ndup __P((DBC *, PAGE *, u_int32_t)); -static int __bam_ovput __P((DBC *, PAGE *, u_int32_t, DBT *)); -static int __bam_partial __P((DBC *, - DBT *, PAGE *, u_int32_t, u_int32_t, u_int32_t)); -static u_int32_t __bam_partsize __P((DBT *, PAGE *, u_int32_t)); - -/* - * __bam_iitem -- - * Insert an item into the tree. - * - * PUBLIC: int __bam_iitem __P((DBC *, - * PUBLIC: PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t)); - */ -int -__bam_iitem(dbc, hp, indxp, key, data, op, flags) - DBC *dbc; - PAGE **hp; - db_indx_t *indxp; - DBT *key, *data; - u_int32_t op, flags; -{ - BTREE *t; - BKEYDATA *bk; - DB *dbp; - DBT tdbt; - PAGE *h; - db_indx_t indx, nbytes; - u_int32_t data_size, have_bytes, need_bytes, needed; - int bigkey, bigdata, dupadjust, replace, ret; - - COMPQUIET(bk, NULL); - - dbp = dbc->dbp; - t = dbp->internal; - h = *hp; - indx = *indxp; - dupadjust = replace = 0; - - /* - * If it's a page of duplicates, call the common code to do the work. - * - * !!! - * Here's where the hp and indxp are important. The duplicate code - * may decide to rework/rearrange the pages and indices we're using, - * so the caller must understand that the page stack may change. - */ - if (TYPE(h) == P_DUPLICATE) { - /* Adjust the index for the new item if it's a DB_AFTER op. */ - if (op == DB_AFTER) - ++*indxp; - - /* Remove the current item if it's a DB_CURRENT op. */ - if (op == DB_CURRENT) { - bk = GET_BKEYDATA(*hp, *indxp); - switch (B_TYPE(bk->type)) { - case B_KEYDATA: - nbytes = BKEYDATA_SIZE(bk->len); - break; - case B_OVERFLOW: - nbytes = BOVERFLOW_SIZE; - break; - default: - return (__db_pgfmt(dbp, h->pgno)); - } - if ((ret = __db_ditem(dbc, *hp, *indxp, nbytes)) != 0) - return (ret); - } - - /* Put the new/replacement item onto the page. */ - if ((ret = __db_dput(dbc, data, hp, indxp, __bam_new)) != 0) - return (ret); - - goto done; - } - - /* Handle fixed-length records: build the real record. */ - if (F_ISSET(dbp, DB_RE_FIXEDLEN) && data->size != t->recno->re_len) { - tdbt = *data; - if ((ret = __bam_fixed(dbc, &tdbt)) != 0) - return (ret); - data = &tdbt; - } - - /* - * Figure out how much space the data will take, including if it's a - * partial record. If either of the key or data items won't fit on - * a page, we'll have to store them on overflow pages. - */ - bigkey = LF_ISSET(BI_NEWKEY) && key->size > t->bt_ovflsize; - data_size = F_ISSET(data, DB_DBT_PARTIAL) ? - __bam_partsize(data, h, indx) : data->size; - bigdata = data_size > t->bt_ovflsize; - - needed = 0; - if (LF_ISSET(BI_NEWKEY)) { - /* If BI_NEWKEY is set we're adding a new key and data pair. */ - if (bigkey) - needed += BOVERFLOW_PSIZE; - else - needed += BKEYDATA_PSIZE(key->size); - if (bigdata) - needed += BOVERFLOW_PSIZE; - else - needed += BKEYDATA_PSIZE(data_size); - } else { - /* - * We're either overwriting the data item of a key/data pair - * or we're adding the data item only, i.e. a new duplicate. - */ - if (op == DB_CURRENT) { - bk = GET_BKEYDATA(h, - indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); - if (B_TYPE(bk->type) == B_KEYDATA) - have_bytes = BKEYDATA_PSIZE(bk->len); - else - have_bytes = BOVERFLOW_PSIZE; - need_bytes = 0; - } else { - have_bytes = 0; - need_bytes = sizeof(db_indx_t); - } - if (bigdata) - need_bytes += BOVERFLOW_PSIZE; - else - need_bytes += BKEYDATA_PSIZE(data_size); - - if (have_bytes < need_bytes) - needed += need_bytes - have_bytes; - } - - /* - * If there's not enough room, or the user has put a ceiling on the - * number of keys permitted in the page, split the page. - * - * XXX - * The t->bt_maxkey test here may be insufficient -- do we have to - * check in the btree split code, so we don't undo it there!?!? - */ - if (P_FREESPACE(h) < needed || - (t->bt_maxkey != 0 && NUM_ENT(h) > t->bt_maxkey)) - return (DB_NEEDSPLIT); - - /* Handle partial puts: build the real record. */ - if (F_ISSET(data, DB_DBT_PARTIAL)) { - tdbt = *data; - if ((ret = __bam_partial(dbc, - &tdbt, h, indx, data_size, flags)) != 0) - return (ret); - data = &tdbt; - } - - /* - * The code breaks it up into six cases: - * - * 1. Append a new key/data pair. - * 2. Insert a new key/data pair. - * 3. Append a new data item (a new duplicate). - * 4. Insert a new data item (a new duplicate). - * 5. Overflow item: delete and re-add the data item. - * 6. Replace the data item. - */ - if (LF_ISSET(BI_NEWKEY)) { - switch (op) { - case DB_AFTER: /* 1. Append a new key/data pair. */ - indx += 2; - *indxp += 2; - break; - case DB_BEFORE: /* 2. Insert a new key/data pair. */ - break; - default: - return (EINVAL); - } - - /* Add the key. */ - if (bigkey) { - if ((ret = __bam_ovput(dbc, h, indx, key)) != 0) - return (ret); - } else - if ((ret = __db_pitem(dbc, h, indx, - BKEYDATA_SIZE(key->size), NULL, key)) != 0) - return (ret); - ++indx; - } else { - switch (op) { - case DB_AFTER: /* 3. Append a new data item. */ - if (TYPE(h) == P_LBTREE) { - /* - * Adjust the cursor and copy in the key for - * the duplicate. - */ - if ((ret = __bam_adjindx(dbc, - h, indx + P_INDX, indx, 1)) != 0) - return (ret); - - indx += 3; - dupadjust = 1; - - *indxp += 2; - } else { - ++indx; - __bam_ca_di(dbp, h->pgno, indx, 1); - - *indxp += 1; - } - break; - case DB_BEFORE: /* 4. Insert a new data item. */ - if (TYPE(h) == P_LBTREE) { - /* - * Adjust the cursor and copy in the key for - * the duplicate. - */ - if ((ret = - __bam_adjindx(dbc, h, indx, indx, 1)) != 0) - return (ret); - - ++indx; - dupadjust = 1; - } else - __bam_ca_di(dbp, h->pgno, indx, 1); - break; - case DB_CURRENT: - if (TYPE(h) == P_LBTREE) - ++indx; - - /* - * 5. Delete/re-add the data item. - * - * If we're dealing with offpage items, we have to - * delete and then re-add the item. - */ - if (bigdata || B_TYPE(bk->type) != B_KEYDATA) { - if ((ret = __bam_ditem(dbc, h, indx)) != 0) - return (ret); - break; - } - - /* 6. Replace the data item. */ - replace = 1; - break; - default: - return (EINVAL); - } - } - - /* Add the data. */ - if (bigdata) { - if ((ret = __bam_ovput(dbc, h, indx, data)) != 0) - return (ret); - } else { - BKEYDATA __bk; - DBT __hdr; - - if (LF_ISSET(BI_DELETED)) { - B_TSET(__bk.type, B_KEYDATA, 1); - __bk.len = data->size; - __hdr.data = &__bk; - __hdr.size = SSZA(BKEYDATA, data); - ret = __db_pitem(dbc, h, indx, - BKEYDATA_SIZE(data->size), &__hdr, data); - } else if (replace) - ret = __bam_ritem(dbc, h, indx, data); - else - ret = __db_pitem(dbc, h, indx, - BKEYDATA_SIZE(data->size), NULL, data); - if (ret != 0) - return (ret); - } - - if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) - return (ret); - - /* - * If the page is at least 50% full, and we added a duplicate, see if - * that set of duplicates takes up at least 25% of the space. If it - * does, move it off onto its own page. - */ - if (dupadjust && P_FREESPACE(h) <= dbp->pgsize / 2) { - --indx; - if ((ret = __bam_ndup(dbc, h, indx)) != 0) - return (ret); - } - - /* - * If we've changed the record count, update the tree. Record counts - * need to be updated in recno databases and in btree databases where - * we are supporting records. In both cases, adjust the count if the - * operation wasn't performed on the current record or when the caller - * overrides and wants the adjustment made regardless. - */ -done: if (LF_ISSET(BI_DOINCR) || - (op != DB_CURRENT && - (F_ISSET(dbp, DB_BT_RECNUM) || dbp->type == DB_RECNO))) - if ((ret = __bam_adjust(dbc, 1)) != 0) - return (ret); - - /* If we've modified a recno file, set the flag */ - if (t->recno != NULL) - F_SET(t->recno, RECNO_MODIFIED); - - return (ret); -} - -/* - * __bam_partsize -- - * Figure out how much space a partial data item is in total. - */ -static u_int32_t -__bam_partsize(data, h, indx) - DBT *data; - PAGE *h; - u_int32_t indx; -{ - BKEYDATA *bk; - u_int32_t nbytes; - - /* - * Figure out how much total space we'll need. If the record doesn't - * already exist, it's simply the data we're provided. - */ - if (indx >= NUM_ENT(h)) - return (data->doff + data->size); - - /* - * Otherwise, it's the data provided plus any already existing data - * that we're not replacing. - */ - bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); - nbytes = - B_TYPE(bk->type) == B_OVERFLOW ? ((BOVERFLOW *)bk)->tlen : bk->len; - - /* - * There are really two cases here: - * - * Case 1: We are replacing some bytes that do not exist (i.e., they - * are past the end of the record). In this case the number of bytes - * we are replacing is irrelevant and all we care about is how many - * bytes we are going to add from offset. So, the new record length - * is going to be the size of the new bytes (size) plus wherever those - * new bytes begin (doff). - * - * Case 2: All the bytes we are replacing exist. Therefore, the new - * size is the oldsize (nbytes) minus the bytes we are replacing (dlen) - * plus the bytes we are adding (size). - */ - if (nbytes < data->doff + data->dlen) /* Case 1 */ - return (data->doff + data->size); - - return (nbytes + data->size - data->dlen); /* Case 2 */ -} - -/* - * OVPUT -- - * Copy an overflow item onto a page. - */ -#undef OVPUT -#define OVPUT(h, indx, bo) do { \ - DBT __hdr; \ - memset(&__hdr, 0, sizeof(__hdr)); \ - __hdr.data = &bo; \ - __hdr.size = BOVERFLOW_SIZE; \ - if ((ret = __db_pitem(dbc, \ - h, indx, BOVERFLOW_SIZE, &__hdr, NULL)) != 0) \ - return (ret); \ -} while (0) - -/* - * __bam_ovput -- - * Build an overflow item and put it on the page. - */ -static int -__bam_ovput(dbc, h, indx, item) - DBC *dbc; - PAGE *h; - u_int32_t indx; - DBT *item; -{ - BOVERFLOW bo; - int ret; - - UMRW(bo.unused1); - B_TSET(bo.type, B_OVERFLOW, 0); - UMRW(bo.unused2); - if ((ret = __db_poff(dbc, item, &bo.pgno, __bam_new)) != 0) - return (ret); - bo.tlen = item->size; - - OVPUT(h, indx, bo); - - return (0); -} - -/* - * __bam_ritem -- - * Replace an item on a page. - * - * PUBLIC: int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *)); - */ -int -__bam_ritem(dbc, h, indx, data) - DBC *dbc; - PAGE *h; - u_int32_t indx; - DBT *data; -{ - BKEYDATA *bk; - DB *dbp; - DBT orig, repl; - db_indx_t cnt, lo, ln, min, off, prefix, suffix; - int32_t nbytes; - int ret; - u_int8_t *p, *t; - - dbp = dbc->dbp; - - /* - * Replace a single item onto a page. The logic figuring out where - * to insert and whether it fits is handled in the caller. All we do - * here is manage the page shuffling. - */ - bk = GET_BKEYDATA(h, indx); - - /* Log the change. */ - if (DB_LOGGING(dbc)) { - /* - * We might as well check to see if the two data items share - * a common prefix and suffix -- it can save us a lot of log - * message if they're large. - */ - min = data->size < bk->len ? data->size : bk->len; - for (prefix = 0, - p = bk->data, t = data->data; - prefix < min && *p == *t; ++prefix, ++p, ++t) - ; - - min -= prefix; - for (suffix = 0, - p = (u_int8_t *)bk->data + bk->len - 1, - t = (u_int8_t *)data->data + data->size - 1; - suffix < min && *p == *t; ++suffix, --p, --t) - ; - - /* We only log the parts of the keys that have changed. */ - orig.data = (u_int8_t *)bk->data + prefix; - orig.size = bk->len - (prefix + suffix); - repl.data = (u_int8_t *)data->data + prefix; - repl.size = data->size - (prefix + suffix); - if ((ret = __bam_repl_log(dbp->dbenv->lg_info, dbc->txn, - &LSN(h), 0, dbp->log_fileid, PGNO(h), &LSN(h), - (u_int32_t)indx, (u_int32_t)B_DISSET(bk->type), - &orig, &repl, (u_int32_t)prefix, (u_int32_t)suffix)) != 0) - return (ret); - } - - /* - * Set references to the first in-use byte on the page and the - * first byte of the item being replaced. - */ - p = (u_int8_t *)h + HOFFSET(h); - t = (u_int8_t *)bk; - - /* - * If the entry is growing in size, shift the beginning of the data - * part of the page down. If the entry is shrinking in size, shift - * the beginning of the data part of the page up. Use memmove(3), - * the regions overlap. - */ - lo = BKEYDATA_SIZE(bk->len); - ln = BKEYDATA_SIZE(data->size); - if (lo != ln) { - nbytes = lo - ln; /* Signed difference. */ - if (p == t) /* First index is fast. */ - h->inp[indx] += nbytes; - else { /* Else, shift the page. */ - memmove(p + nbytes, p, t - p); - - /* Adjust the indices' offsets. */ - off = h->inp[indx]; - for (cnt = 0; cnt < NUM_ENT(h); ++cnt) - if (h->inp[cnt] <= off) - h->inp[cnt] += nbytes; - } - - /* Clean up the page and adjust the item's reference. */ - HOFFSET(h) += nbytes; - t += nbytes; - } - - /* Copy the new item onto the page. */ - bk = (BKEYDATA *)t; - B_TSET(bk->type, B_KEYDATA, 0); - bk->len = data->size; - memcpy(bk->data, data->data, data->size); - - return (0); -} - -/* - * __bam_ndup -- - * Check to see if the duplicate set at indx should have its own page. - * If it should, create it. - */ -static int -__bam_ndup(dbc, h, indx) - DBC *dbc; - PAGE *h; - u_int32_t indx; -{ - BKEYDATA *bk; - BOVERFLOW bo; - DB *dbp; - DBT hdr; - PAGE *cp; - db_indx_t cnt, cpindx, first, sz; - int ret; - - dbp = dbc->dbp; - - while (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX]) - indx -= P_INDX; - for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) { - if (indx >= NUM_ENT(h) || h->inp[first] != h->inp[indx]) - break; - bk = GET_BKEYDATA(h, indx); - sz += B_TYPE(bk->type) == B_KEYDATA ? - BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE; - bk = GET_BKEYDATA(h, indx + O_INDX); - sz += B_TYPE(bk->type) == B_KEYDATA ? - BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE; - } - - /* - * If this set of duplicates is using more than 25% of the page, move - * them off. The choice of 25% is a WAG, but it has to be small enough - * that we can always split regardless of the presence of duplicates. - */ - if (sz < dbp->pgsize / 4) - return (0); - - /* Get a new page. */ - if ((ret = __bam_new(dbc, P_DUPLICATE, &cp)) != 0) - return (ret); - - /* - * Move this set of duplicates off the page. First points to the first - * key of the first duplicate key/data pair, cnt is the number of pairs - * we're dealing with. - */ - memset(&hdr, 0, sizeof(hdr)); - for (indx = first + O_INDX, cpindx = 0;; ++cpindx) { - /* Copy the entry to the new page. */ - bk = GET_BKEYDATA(h, indx); - hdr.data = bk; - hdr.size = B_TYPE(bk->type) == B_KEYDATA ? - BKEYDATA_SIZE(bk->len) : BOVERFLOW_SIZE; - if ((ret = - __db_pitem(dbc, cp, cpindx, hdr.size, &hdr, NULL)) != 0) - goto err; - - /* - * Move cursors referencing the old entry to the new entry. - * Done after the page put because __db_pitem() adjusts - * cursors on the new page, and before the delete because - * __db_ditem adjusts cursors on the old page. - */ - __bam_ca_dup(dbp, - PGNO(h), first, indx - O_INDX, PGNO(cp), cpindx); - - /* Delete the data item. */ - if ((ret = __db_ditem(dbc, h, indx, hdr.size)) != 0) - goto err; - - /* Delete all but the first reference to the key. */ - if (--cnt == 0) - break; - if ((ret = __bam_adjindx(dbc, h, indx, first, 0)) != 0) - goto err; - } - - /* Put in a new data item that points to the duplicates page. */ - UMRW(bo.unused1); - B_TSET(bo.type, B_DUPLICATE, 0); - UMRW(bo.unused2); - bo.pgno = cp->pgno; - bo.tlen = 0; - - OVPUT(h, indx, bo); - - return (memp_fput(dbp->mpf, cp, DB_MPOOL_DIRTY)); - -err: (void)__bam_free(dbc, cp); - return (ret); -} - -/* - * __bam_fixed -- - * Build the real record for a fixed length put. - */ -static int -__bam_fixed(dbc, dbt) - DBC *dbc; - DBT *dbt; -{ - DB *dbp; - RECNO *rp; - int ret; - - dbp = dbc->dbp; - rp = ((BTREE *)dbp->internal)->recno; - - /* - * If database contains fixed-length records, and the record is long, - * return EINVAL. - */ - if (dbt->size > rp->re_len) - return (EINVAL); - - /* - * The caller checked to see if it was just right, so we know it's - * short. Pad it out. We use the record data return memory, it's - * only a short-term use. - */ - if (dbc->rdata.ulen < rp->re_len) { - if ((ret = __os_realloc(&dbc->rdata.data, rp->re_len)) != 0) { - dbc->rdata.ulen = 0; - dbc->rdata.data = NULL; - return (ret); - } - dbc->rdata.ulen = rp->re_len; - } - memcpy(dbc->rdata.data, dbt->data, dbt->size); - memset((u_int8_t *)dbc->rdata.data + dbt->size, - rp->re_pad, rp->re_len - dbt->size); - - /* - * Clean up our flags and other information just in case, and - * change the caller's DBT to reference our created record. - */ - dbc->rdata.size = rp->re_len; - dbc->rdata.dlen = 0; - dbc->rdata.doff = 0; - dbc->rdata.flags = 0; - *dbt = dbc->rdata; - - return (0); -} - -/* - * __bam_partial -- - * Build the real record for a partial put. - */ -static int -__bam_partial(dbc, dbt, h, indx, nbytes, flags) - DBC *dbc; - DBT *dbt; - PAGE *h; - u_int32_t indx, nbytes, flags; -{ - BKEYDATA *bk, tbk; - BOVERFLOW *bo; - DB *dbp; - DBT copy; - u_int32_t len, tlen; - u_int8_t *p; - int ret; - - COMPQUIET(bo, NULL); - - dbp = dbc->dbp; - - /* We use the record data return memory, it's only a short-term use. */ - if (dbc->rdata.ulen < nbytes) { - if ((ret = __os_realloc(&dbc->rdata.data, nbytes)) != 0) { - dbc->rdata.ulen = 0; - dbc->rdata.data = NULL; - return (ret); - } - dbc->rdata.ulen = nbytes; - } - - /* - * We use nul bytes for any part of the record that isn't specified; - * get it over with. - */ - memset(dbc->rdata.data, 0, nbytes); - - /* - * In the next clauses, we need to do three things: a) set p to point - * to the place at which to copy the user's data, b) set tlen to the - * total length of the record, not including the bytes contributed by - * the user, and c) copy any valid data from an existing record. - */ - if (LF_ISSET(BI_NEWKEY)) { - tlen = dbt->doff; - p = (u_int8_t *)dbc->rdata.data + dbt->doff; - goto ucopy; - } - - /* Find the current record. */ - if (indx < NUM_ENT(h)) { - bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); - bo = (BOVERFLOW *)bk; - } else { - bk = &tbk; - B_TSET(bk->type, B_KEYDATA, 0); - bk->len = 0; - } - if (B_TYPE(bk->type) == B_OVERFLOW) { - /* - * In the case of an overflow record, we shift things around - * in the current record rather than allocate a separate copy. - */ - memset(©, 0, sizeof(copy)); - if ((ret = __db_goff(dbp, ©, bo->tlen, - bo->pgno, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) - return (ret); - - /* Skip any leading data from the original record. */ - tlen = dbt->doff; - p = (u_int8_t *)dbc->rdata.data + dbt->doff; - - /* - * Copy in any trailing data from the original record. - * - * If the original record was larger than the original offset - * plus the bytes being deleted, there is trailing data in the - * original record we need to preserve. If we aren't deleting - * the same number of bytes as we're inserting, copy it up or - * down, into place. - * - * Use memmove(), the regions may overlap. - */ - if (bo->tlen > dbt->doff + dbt->dlen) { - len = bo->tlen - (dbt->doff + dbt->dlen); - if (dbt->dlen != dbt->size) - memmove(p + dbt->size, p + dbt->dlen, len); - tlen += len; - } - } else { - /* Copy in any leading data from the original record. */ - memcpy(dbc->rdata.data, - bk->data, dbt->doff > bk->len ? bk->len : dbt->doff); - tlen = dbt->doff; - p = (u_int8_t *)dbc->rdata.data + dbt->doff; - - /* Copy in any trailing data from the original record. */ - len = dbt->doff + dbt->dlen; - if (bk->len > len) { - memcpy(p + dbt->size, bk->data + len, bk->len - len); - tlen += bk->len - len; - } - } - -ucopy: /* - * Copy in the application provided data -- p and tlen must have been - * initialized above. - */ - memcpy(p, dbt->data, dbt->size); - tlen += dbt->size; - - /* Set the DBT to reference our new record. */ - dbc->rdata.size = tlen; - dbc->rdata.dlen = 0; - dbc->rdata.doff = 0; - dbc->rdata.flags = 0; - *dbt = dbc->rdata; - return (0); -} |