1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_dup.c,v 12.14 2008/01/08 20:58:10 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/mp.h" 14#include "dbinc/db_am.h" 15 16/* 17 * __db_ditem -- 18 * Remove an item from a page. 19 * 20 * PUBLIC: int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t)); 21 */ 22int 23__db_ditem(dbc, pagep, indx, nbytes) 24 DBC *dbc; 25 PAGE *pagep; 26 u_int32_t indx, nbytes; 27{ 28 DB *dbp; 29 DBT ldbt; 30 db_indx_t cnt, *inp, offset; 31 int ret; 32 u_int8_t *from; 33 34 dbp = dbc->dbp; 35 DB_ASSERT(dbp->env, IS_DIRTY(pagep)); 36 DB_ASSERT(dbp->env, indx < NUM_ENT(pagep)); 37 38 if (DBC_LOGGING(dbc)) { 39 ldbt.data = P_ENTRY(dbp, pagep, indx); 40 ldbt.size = nbytes; 41 if ((ret = __db_addrem_log(dbp, dbc->txn, 42 &LSN(pagep), 0, DB_REM_DUP, PGNO(pagep), 43 (u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0) 44 return (ret); 45 } else 46 LSN_NOT_LOGGED(LSN(pagep)); 47 48 /* 49 * If there's only a single item on the page, we don't have to 50 * work hard. 51 */ 52 if (NUM_ENT(pagep) == 1) { 53 NUM_ENT(pagep) = 0; 54 HOFFSET(pagep) = dbp->pgsize; 55 return (0); 56 } 57 58 inp = P_INP(dbp, pagep); 59 /* 60 * Pack the remaining key/data items at the end of the page. Use 61 * memmove(3), the regions may overlap. 62 */ 63 from = (u_int8_t *)pagep + HOFFSET(pagep); 64 DB_ASSERT(dbp->env, inp[indx] >= HOFFSET(pagep)); 65 memmove(from + nbytes, from, inp[indx] - HOFFSET(pagep)); 66 HOFFSET(pagep) += nbytes; 67 68 /* Adjust the indices' offsets. */ 69 offset = inp[indx]; 70 for (cnt = 0; cnt < NUM_ENT(pagep); ++cnt) 71 if (inp[cnt] < offset) 72 inp[cnt] += nbytes; 73 74 /* Shift the indices down. */ 75 --NUM_ENT(pagep); 76 if (indx != NUM_ENT(pagep)) 77 memmove(&inp[indx], &inp[indx + 1], 78 sizeof(db_indx_t) * (NUM_ENT(pagep) - indx)); 79 80 return (0); 81} 82 83/* 84 * __db_pitem -- 85 * Put an item on a page. 86 * 87 * PUBLIC: int __db_pitem 88 * PUBLIC: __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *)); 89 */ 90int 91__db_pitem(dbc, pagep, indx, nbytes, hdr, data) 92 DBC *dbc; 93 PAGE *pagep; 94 u_int32_t indx; 95 u_int32_t nbytes; 96 DBT *hdr, *data; 97{ 98 BKEYDATA bk; 99 DB *dbp; 100 DBT thdr; 101 db_indx_t *inp; 102 int ret; 103 u_int8_t *p; 104 105 dbp = dbc->dbp; 106 DB_ASSERT(dbp->env, IS_DIRTY(pagep)); 107 108 if (nbytes > P_FREESPACE(dbp, pagep)) { 109 DB_ASSERT(dbp->env, nbytes <= P_FREESPACE(dbp, pagep)); 110 return (EINVAL); 111 } 112 /* 113 * Put a single item onto a page. The logic figuring out where to 114 * insert and whether it fits is handled in the caller. All we do 115 * here is manage the page shuffling. We cheat a little bit in that 116 * we don't want to copy the dbt on a normal put twice. If hdr is 117 * NULL, we create a BKEYDATA structure on the page, otherwise, just 118 * copy the caller's information onto the page. 119 * 120 * This routine is also used to put entries onto the page where the 121 * entry is pre-built, e.g., during recovery. In this case, the hdr 122 * will point to the entry, and the data argument will be NULL. 123 * 124 * !!! 125 * There's a tremendous potential for off-by-one errors here, since 126 * the passed in header sizes must be adjusted for the structure's 127 * placeholder for the trailing variable-length data field. 128 */ 129 if (DBC_LOGGING(dbc)) { 130 if ((ret = __db_addrem_log(dbp, dbc->txn, 131 &LSN(pagep), 0, DB_ADD_DUP, PGNO(pagep), 132 (u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0) 133 return (ret); 134 } else 135 LSN_NOT_LOGGED(LSN(pagep)); 136 137 if (hdr == NULL) { 138 B_TSET(bk.type, B_KEYDATA); 139 bk.len = data == NULL ? 0 : data->size; 140 141 thdr.data = &bk; 142 thdr.size = SSZA(BKEYDATA, data); 143 hdr = &thdr; 144 } 145 inp = P_INP(dbp, pagep); 146 147 /* Adjust the index table, then put the item on the page. */ 148 if (indx != NUM_ENT(pagep)) 149 memmove(&inp[indx + 1], &inp[indx], 150 sizeof(db_indx_t) * (NUM_ENT(pagep) - indx)); 151 HOFFSET(pagep) -= nbytes; 152 inp[indx] = HOFFSET(pagep); 153 ++NUM_ENT(pagep); 154 155 p = P_ENTRY(dbp, pagep, indx); 156 memcpy(p, hdr->data, hdr->size); 157 if (data != NULL) 158 memcpy(p + hdr->size, data->data, data->size); 159 160 return (0); 161} 162