bt_put.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:23k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. /*
  8.  * Copyright (c) 1990, 1993, 1994, 1995, 1996
  9.  * Keith Bostic.  All rights reserved.
  10.  */
  11. /*
  12.  * Copyright (c) 1990, 1993, 1994, 1995
  13.  * The Regents of the University of California.  All rights reserved.
  14.  *
  15.  * This code is derived from software contributed to Berkeley by
  16.  * Mike Olson.
  17.  *
  18.  * Redistribution and use in source and binary forms, with or without
  19.  * modification, are permitted provided that the following conditions
  20.  * are met:
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42. #include "db_config.h"
  43. #ifndef lint
  44. static const char revid[] = "$Id: bt_put.c,v 11.69 2002/08/06 06:11:12 bostic Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <string.h>
  49. #endif
  50. #include "db_int.h"
  51. #include "dbinc/db_page.h"
  52. #include "dbinc/btree.h"
  53. static int __bam_build
  54.        __P((DBC *, u_int32_t, DBT *, PAGE *, u_int32_t, u_int32_t));
  55. static int __bam_dup_convert __P((DBC *, PAGE *, u_int32_t));
  56. static int __bam_ovput
  57.        __P((DBC *, u_int32_t, db_pgno_t, PAGE *, u_int32_t, DBT *));
  58. static u_int32_t
  59.    __bam_partsize __P((DB *, u_int32_t, DBT *, PAGE *, u_int32_t));
  60. /*
  61.  * __bam_iitem --
  62.  * Insert an item into the tree.
  63.  *
  64.  * PUBLIC: int __bam_iitem __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t));
  65.  */
  66. int
  67. __bam_iitem(dbc, key, data, op, flags)
  68. DBC *dbc;
  69. DBT *key, *data;
  70. u_int32_t op, flags;
  71. {
  72. BKEYDATA *bk, bk_tmp;
  73. BTREE *t;
  74. BTREE_CURSOR *cp;
  75. DB *dbp;
  76. DBT bk_hdr, tdbt;
  77. DB_MPOOLFILE *mpf;
  78. PAGE *h;
  79. db_indx_t indx;
  80. u_int32_t data_size, have_bytes, need_bytes, needed;
  81. int cmp, bigkey, bigdata, dupadjust, padrec, replace, ret, was_deleted;
  82. COMPQUIET(bk, NULL);
  83. dbp = dbc->dbp;
  84. mpf = dbp->mpf;
  85. cp = (BTREE_CURSOR *)dbc->internal;
  86. t = dbp->bt_internal;
  87. h = cp->page;
  88. indx = cp->indx;
  89. dupadjust = replace = was_deleted = 0;
  90. /*
  91.  * Fixed-length records with partial puts: it's an error to specify
  92.  * anything other simple overwrite.
  93.  */
  94. if (F_ISSET(dbp, DB_AM_FIXEDLEN) &&
  95.     F_ISSET(data, DB_DBT_PARTIAL) && data->dlen != data->size) {
  96. data_size = data->size;
  97. goto len_err;
  98. }
  99. /*
  100.  * Figure out how much space the data will take, including if it's a
  101.  * partial record.
  102.  *
  103.  * Fixed-length records: it's an error to specify a record that's
  104.  * longer than the fixed-length, and we never require less than
  105.  * the fixed-length record size.
  106.  */
  107. data_size = F_ISSET(data, DB_DBT_PARTIAL) ?
  108.     __bam_partsize(dbp, op, data, h, indx) : data->size;
  109. padrec = 0;
  110. if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
  111. if (data_size > t->re_len) {
  112. len_err: __db_err(dbp->dbenv,
  113.     "Length improper for fixed length record %lu",
  114.     (u_long)data_size);
  115. return (EINVAL);
  116. }
  117. /* Records that are deleted anyway needn't be padded out. */
  118. if (!LF_ISSET(BI_DELETED) && data_size < t->re_len) {
  119. padrec = 1;
  120. data_size = t->re_len;
  121. }
  122. }
  123. /*
  124.  * Handle partial puts or short fixed-length records: build the
  125.  * real record.
  126.  */
  127. if (padrec || F_ISSET(data, DB_DBT_PARTIAL)) {
  128. tdbt = *data;
  129. if ((ret =
  130.     __bam_build(dbc, op, &tdbt, h, indx, data_size)) != 0)
  131. return (ret);
  132. data = &tdbt;
  133. }
  134. /*
  135.  * If the user has specified a duplicate comparison function, return
  136.  * an error if DB_CURRENT was specified and the replacement data
  137.  * doesn't compare equal to the current data.  This stops apps from
  138.  * screwing up the duplicate sort order.  We have to do this after
  139.  * we build the real record so that we're comparing the real items.
  140.  */
  141. if (op == DB_CURRENT && dbp->dup_compare != NULL) {
  142. if ((ret = __bam_cmp(dbp, data, h,
  143.     indx + (TYPE(h) == P_LBTREE ? O_INDX : 0),
  144.     dbp->dup_compare, &cmp)) != 0)
  145. return (ret);
  146. if (cmp != 0) {
  147. __db_err(dbp->dbenv,
  148.     "Current data differs from put data");
  149. return (EINVAL);
  150. }
  151. }
  152. /*
  153.  * If the key or data item won't fit on a page, we'll have to store
  154.  * them on overflow pages.
  155.  */
  156. needed = 0;
  157. bigdata = data_size > cp->ovflsize;
  158. switch (op) {
  159. case DB_KEYFIRST:
  160. /* We're adding a new key and data pair. */
  161. bigkey = key->size > cp->ovflsize;
  162. if (bigkey)
  163. needed += BOVERFLOW_PSIZE;
  164. else
  165. needed += BKEYDATA_PSIZE(key->size);
  166. if (bigdata)
  167. needed += BOVERFLOW_PSIZE;
  168. else
  169. needed += BKEYDATA_PSIZE(data_size);
  170. break;
  171. case DB_AFTER:
  172. case DB_BEFORE:
  173. case DB_CURRENT:
  174. /*
  175.  * We're either overwriting the data item of a key/data pair
  176.  * or we're creating a new on-page duplicate and only adding
  177.  * a data item.
  178.  *
  179.  * !!!
  180.  * We're not currently correcting for space reclaimed from
  181.  * already deleted items, but I don't think it's worth the
  182.  * complexity.
  183.  */
  184. bigkey = 0;
  185. if (op == DB_CURRENT) {
  186. bk = GET_BKEYDATA(dbp, h,
  187.     indx + (TYPE(h) == P_LBTREE ? O_INDX : 0));
  188. if (B_TYPE(bk->type) == B_KEYDATA)
  189. have_bytes = BKEYDATA_PSIZE(bk->len);
  190. else
  191. have_bytes = BOVERFLOW_PSIZE;
  192. need_bytes = 0;
  193. } else {
  194. have_bytes = 0;
  195. need_bytes = sizeof(db_indx_t);
  196. }
  197. if (bigdata)
  198. need_bytes += BOVERFLOW_PSIZE;
  199. else
  200. need_bytes += BKEYDATA_PSIZE(data_size);
  201. if (have_bytes < need_bytes)
  202. needed += need_bytes - have_bytes;
  203. break;
  204. default:
  205. return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op));
  206. }
  207. /*
  208.  * If there's not enough room, or the user has put a ceiling on the
  209.  * number of keys permitted in the page, split the page.
  210.  *
  211.  * XXX
  212.  * The t->bt_maxkey test here may be insufficient -- do we have to
  213.  * check in the btree split code, so we don't undo it there!?!?
  214.  */
  215. if (P_FREESPACE(dbp, h) < needed ||
  216.     (t->bt_maxkey != 0 && NUM_ENT(h) > t->bt_maxkey))
  217. return (DB_NEEDSPLIT);
  218. /*
  219.  * The code breaks it up into five cases:
  220.  *
  221.  * 1. Insert a new key/data pair.
  222.  * 2. Append a new data item (a new duplicate).
  223.  * 3. Insert a new data item (a new duplicate).
  224.  * 4. Delete and re-add the data item (overflow item).
  225.  * 5. Overwrite the data item.
  226.  */
  227. switch (op) {
  228. case DB_KEYFIRST: /* 1. Insert a new key/data pair. */
  229. if (bigkey) {
  230. if ((ret = __bam_ovput(dbc,
  231.     B_OVERFLOW, PGNO_INVALID, h, indx, key)) != 0)
  232. return (ret);
  233. } else
  234. if ((ret = __db_pitem(dbc, h, indx,
  235.     BKEYDATA_SIZE(key->size), NULL, key)) != 0)
  236. return (ret);
  237. if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0)
  238. return (ret);
  239. ++indx;
  240. break;
  241. case DB_AFTER: /* 2. Append a new data item. */
  242. if (TYPE(h) == P_LBTREE) {
  243. /* Copy the key for the duplicate and adjust cursors. */
  244. if ((ret =
  245.     __bam_adjindx(dbc, h, indx + P_INDX, indx, 1)) != 0)
  246. return (ret);
  247. if ((ret =
  248.     __bam_ca_di(dbc, PGNO(h), indx + P_INDX, 1)) != 0)
  249. return (ret);
  250. indx += 3;
  251. dupadjust = 1;
  252. cp->indx += 2;
  253. } else {
  254. ++indx;
  255. cp->indx += 1;
  256. }
  257. break;
  258. case DB_BEFORE: /* 3. Insert a new data item. */
  259. if (TYPE(h) == P_LBTREE) {
  260. /* Copy the key for the duplicate and adjust cursors. */
  261. if ((ret = __bam_adjindx(dbc, h, indx, indx, 1)) != 0)
  262. return (ret);
  263. if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0)
  264. return (ret);
  265. ++indx;
  266. dupadjust = 1;
  267. }
  268. break;
  269. case DB_CURRENT:
  270.  /*
  271.   * Clear the cursor's deleted flag.  The problem is that if
  272.   * we deadlock or fail while deleting the overflow item or
  273.   * replacing the non-overflow item, a subsequent cursor close
  274.   * will try and remove the item because the cursor's delete
  275.   * flag is set
  276.   */
  277. (void)__bam_ca_delete(dbp, PGNO(h), indx, 0);
  278. if (TYPE(h) == P_LBTREE) {
  279. ++indx;
  280. dupadjust = 1;
  281. /*
  282.  * In a Btree deleted records aren't counted (deleted
  283.  * records are counted in a Recno because all accesses
  284.  * are based on record number).  If it's a Btree and
  285.  * it's a DB_CURRENT operation overwriting a previously
  286.  * deleted record, increment the record count.
  287.  */
  288. was_deleted = B_DISSET(bk->type);
  289. }
  290. /*
  291.  * 4. Delete and re-add the data item.
  292.  *
  293.  * If we're changing the type of the on-page structure, or we
  294.  * are referencing offpage items, we have to delete and then
  295.  * re-add the item.  We do not do any cursor adjustments here
  296.  * because we're going to immediately re-add the item into the
  297.  * same slot.
  298.  */
  299. if (bigdata || B_TYPE(bk->type) != B_KEYDATA) {
  300. if ((ret = __bam_ditem(dbc, h, indx)) != 0)
  301. return (ret);
  302. break;
  303. }
  304. /* 5. Overwrite the data item. */
  305. replace = 1;
  306. break;
  307. default:
  308. return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op));
  309. }
  310. /* Add the data. */
  311. if (bigdata) {
  312. /*
  313.  * We do not have to handle deleted (BI_DELETED) records
  314.  * in this case; the actual records should never be created.
  315.  */
  316. DB_ASSERT(!LF_ISSET(BI_DELETED));
  317. if ((ret = __bam_ovput(dbc,
  318.     B_OVERFLOW, PGNO_INVALID, h, indx, data)) != 0)
  319. return (ret);
  320. } else {
  321. if (LF_ISSET(BI_DELETED)) {
  322. B_TSET(bk_tmp.type, B_KEYDATA, 1);
  323. bk_tmp.len = data->size;
  324. bk_hdr.data = &bk_tmp;
  325. bk_hdr.size = SSZA(BKEYDATA, data);
  326. ret = __db_pitem(dbc, h, indx,
  327.     BKEYDATA_SIZE(data->size), &bk_hdr, data);
  328. } else if (replace)
  329. ret = __bam_ritem(dbc, h, indx, data);
  330. else
  331. ret = __db_pitem(dbc, h, indx,
  332.     BKEYDATA_SIZE(data->size), NULL, data);
  333. if (ret != 0)
  334. return (ret);
  335. }
  336. if ((ret = mpf->set(mpf, h, DB_MPOOL_DIRTY)) != 0)
  337. return (ret);
  338. /*
  339.  * Re-position the cursors if necessary and reset the current cursor
  340.  * to point to the new item.
  341.  */
  342. if (op != DB_CURRENT) {
  343. if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0)
  344. return (ret);
  345. cp->indx = TYPE(h) == P_LBTREE ? indx - O_INDX : indx;
  346. }
  347. /*
  348.  * If we've changed the record count, update the tree.  There's no
  349.  * need to adjust the count if the operation not performed on the
  350.  * current record or when the current record was previously deleted.
  351.  */
  352. if (F_ISSET(cp, C_RECNUM) && (op != DB_CURRENT || was_deleted))
  353. if ((ret = __bam_adjust(dbc, 1)) != 0)
  354. return (ret);
  355. /*
  356.  * If a Btree leaf page is at least 50% full and we may have added or
  357.  * modified a duplicate data item, see if the set of duplicates takes
  358.  * up at least 25% of the space on the page.  If it does, move it onto
  359.  * its own page.
  360.  */
  361. if (dupadjust && P_FREESPACE(dbp, h) <= dbp->pgsize / 2) {
  362. if ((ret = __bam_dup_convert(dbc, h, indx - O_INDX)) != 0)
  363. return (ret);
  364. }
  365. /* If we've modified a recno file, set the flag. */
  366. if (dbc->dbtype == DB_RECNO)
  367. t->re_modified = 1;
  368. return (ret);
  369. }
  370. /*
  371.  * __bam_partsize --
  372.  * Figure out how much space a partial data item is in total.
  373.  */
  374. static u_int32_t
  375. __bam_partsize(dbp, op, data, h, indx)
  376. DB *dbp;
  377. u_int32_t op, indx;
  378. DBT *data;
  379. PAGE *h;
  380. {
  381. BKEYDATA *bk;
  382. u_int32_t nbytes;
  383. /*
  384.  * If the record doesn't already exist, it's simply the data we're
  385.  * provided.
  386.  */
  387. if (op != DB_CURRENT)
  388. return (data->doff + data->size);
  389. /*
  390.  * Otherwise, it's the data provided plus any already existing data
  391.  * that we're not replacing.
  392.  */
  393. bk = GET_BKEYDATA(dbp, h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0));
  394. nbytes =
  395.     B_TYPE(bk->type) == B_OVERFLOW ? ((BOVERFLOW *)bk)->tlen : bk->len;
  396. return (__db_partsize(nbytes, data));
  397. }
  398. /*
  399.  * __bam_build --
  400.  * Build the real record for a partial put, or short fixed-length record.
  401.  */
  402. static int
  403. __bam_build(dbc, op, dbt, h, indx, nbytes)
  404. DBC *dbc;
  405. u_int32_t op, indx, nbytes;
  406. DBT *dbt;
  407. PAGE *h;
  408. {
  409. BKEYDATA *bk, tbk;
  410. BOVERFLOW *bo;
  411. BTREE *t;
  412. DB *dbp;
  413. DBT copy, *rdata;
  414. u_int32_t len, tlen;
  415. u_int8_t *p;
  416. int ret;
  417. COMPQUIET(bo, NULL);
  418. dbp = dbc->dbp;
  419. t = dbp->bt_internal;
  420. /* We use the record data return memory, it's only a short-term use. */
  421. rdata = &dbc->my_rdata;
  422. if (rdata->ulen < nbytes) {
  423. if ((ret = __os_realloc(dbp->dbenv,
  424.     nbytes, &rdata->data)) != 0) {
  425. rdata->ulen = 0;
  426. rdata->data = NULL;
  427. return (ret);
  428. }
  429. rdata->ulen = nbytes;
  430. }
  431. /*
  432.  * We use nul or pad bytes for any part of the record that isn't
  433.  * specified; get it over with.
  434.  */
  435. memset(rdata->data,
  436.    F_ISSET(dbp, DB_AM_FIXEDLEN) ? t->re_pad : 0, nbytes);
  437. /*
  438.  * In the next clauses, we need to do three things: a) set p to point
  439.  * to the place at which to copy the user's data, b) set tlen to the
  440.  * total length of the record, not including the bytes contributed by
  441.  * the user, and c) copy any valid data from an existing record.  If
  442.  * it's not a partial put (this code is called for both partial puts
  443.  * and fixed-length record padding) or it's a new key, we can cut to
  444.  * the chase.
  445.  */
  446. if (!F_ISSET(dbt, DB_DBT_PARTIAL) || op != DB_CURRENT) {
  447. p = (u_int8_t *)rdata->data + dbt->doff;
  448. tlen = dbt->doff;
  449. goto user_copy;
  450. }
  451. /* Find the current record. */
  452. if (indx < NUM_ENT(h)) {
  453. bk = GET_BKEYDATA(dbp, h, indx + (TYPE(h) == P_LBTREE ?
  454.     O_INDX : 0));
  455. bo = (BOVERFLOW *)bk;
  456. } else {
  457. bk = &tbk;
  458. B_TSET(bk->type, B_KEYDATA, 0);
  459. bk->len = 0;
  460. }
  461. if (B_TYPE(bk->type) == B_OVERFLOW) {
  462. /*
  463.  * In the case of an overflow record, we shift things around
  464.  * in the current record rather than allocate a separate copy.
  465.  */
  466. memset(&copy, 0, sizeof(copy));
  467. if ((ret = __db_goff(dbp, &copy, bo->tlen,
  468.     bo->pgno, &rdata->data, &rdata->ulen)) != 0)
  469. return (ret);
  470. /* Skip any leading data from the original record. */
  471. tlen = dbt->doff;
  472. p = (u_int8_t *)rdata->data + dbt->doff;
  473. /*
  474.  * Copy in any trailing data from the original record.
  475.  *
  476.  * If the original record was larger than the original offset
  477.  * plus the bytes being deleted, there is trailing data in the
  478.  * original record we need to preserve.  If we aren't deleting
  479.  * the same number of bytes as we're inserting, copy it up or
  480.  * down, into place.
  481.  *
  482.  * Use memmove(), the regions may overlap.
  483.  */
  484. if (bo->tlen > dbt->doff + dbt->dlen) {
  485. len = bo->tlen - (dbt->doff + dbt->dlen);
  486. if (dbt->dlen != dbt->size)
  487. memmove(p + dbt->size, p + dbt->dlen, len);
  488. tlen += len;
  489. }
  490. } else {
  491. /* Copy in any leading data from the original record. */
  492. memcpy(rdata->data,
  493.     bk->data, dbt->doff > bk->len ? bk->len : dbt->doff);
  494. tlen = dbt->doff;
  495. p = (u_int8_t *)rdata->data + dbt->doff;
  496. /* Copy in any trailing data from the original record. */
  497. len = dbt->doff + dbt->dlen;
  498. if (bk->len > len) {
  499. memcpy(p + dbt->size, bk->data + len, bk->len - len);
  500. tlen += bk->len - len;
  501. }
  502. }
  503. user_copy:
  504. /*
  505.  * Copy in the application provided data -- p and tlen must have been
  506.  * initialized above.
  507.  */
  508. memcpy(p, dbt->data, dbt->size);
  509. tlen += dbt->size;
  510. /* Set the DBT to reference our new record. */
  511. rdata->size = F_ISSET(dbp, DB_AM_FIXEDLEN) ? t->re_len : tlen;
  512. rdata->dlen = 0;
  513. rdata->doff = 0;
  514. rdata->flags = 0;
  515. *dbt = *rdata;
  516. return (0);
  517. }
  518. /*
  519.  * __bam_ritem --
  520.  * Replace an item on a page.
  521.  *
  522.  * PUBLIC: int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *));
  523.  */
  524. int
  525. __bam_ritem(dbc, h, indx, data)
  526. DBC *dbc;
  527. PAGE *h;
  528. u_int32_t indx;
  529. DBT *data;
  530. {
  531. BKEYDATA *bk;
  532. DB *dbp;
  533. DBT orig, repl;
  534. db_indx_t cnt, lo, ln, min, off, prefix, suffix;
  535. int32_t nbytes;
  536. int ret;
  537. db_indx_t *inp;
  538. u_int8_t *p, *t;
  539. dbp = dbc->dbp;
  540. /*
  541.  * Replace a single item onto a page.  The logic figuring out where
  542.  * to insert and whether it fits is handled in the caller.  All we do
  543.  * here is manage the page shuffling.
  544.  */
  545. bk = GET_BKEYDATA(dbp, h, indx);
  546. /* Log the change. */
  547. if (DBC_LOGGING(dbc)) {
  548. /*
  549.  * We might as well check to see if the two data items share
  550.  * a common prefix and suffix -- it can save us a lot of log
  551.  * message if they're large.
  552.  */
  553. min = data->size < bk->len ? data->size : bk->len;
  554. for (prefix = 0,
  555.     p = bk->data, t = data->data;
  556.     prefix < min && *p == *t; ++prefix, ++p, ++t)
  557. ;
  558. min -= prefix;
  559. for (suffix = 0,
  560.     p = (u_int8_t *)bk->data + bk->len - 1,
  561.     t = (u_int8_t *)data->data + data->size - 1;
  562.     suffix < min && *p == *t; ++suffix, --p, --t)
  563. ;
  564. /* We only log the parts of the keys that have changed. */
  565. orig.data = (u_int8_t *)bk->data + prefix;
  566. orig.size = bk->len - (prefix + suffix);
  567. repl.data = (u_int8_t *)data->data + prefix;
  568. repl.size = data->size - (prefix + suffix);
  569. if ((ret = __bam_repl_log(dbp, dbc->txn, &LSN(h), 0, PGNO(h),
  570.     &LSN(h), (u_int32_t)indx, (u_int32_t)B_DISSET(bk->type),
  571.     &orig, &repl, (u_int32_t)prefix, (u_int32_t)suffix)) != 0)
  572. return (ret);
  573. } else
  574. LSN_NOT_LOGGED(LSN(h));
  575. /*
  576.  * Set references to the first in-use byte on the page and the
  577.  * first byte of the item being replaced.
  578.  */
  579. inp = P_INP(dbp, h);
  580. p = (u_int8_t *)h + HOFFSET(h);
  581. t = (u_int8_t *)bk;
  582. /*
  583.  * If the entry is growing in size, shift the beginning of the data
  584.  * part of the page down.  If the entry is shrinking in size, shift
  585.  * the beginning of the data part of the page up.  Use memmove(3),
  586.  * the regions overlap.
  587.  */
  588. lo = BKEYDATA_SIZE(bk->len);
  589. ln = (db_indx_t)BKEYDATA_SIZE(data->size);
  590. if (lo != ln) {
  591. nbytes = lo - ln; /* Signed difference. */
  592. if (p == t) /* First index is fast. */
  593. inp[indx] += nbytes;
  594. else { /* Else, shift the page. */
  595. memmove(p + nbytes, p, t - p);
  596. /* Adjust the indices' offsets. */
  597. off = inp[indx];
  598. for (cnt = 0; cnt < NUM_ENT(h); ++cnt)
  599. if (inp[cnt] <= off)
  600. inp[cnt] += nbytes;
  601. }
  602. /* Clean up the page and adjust the item's reference. */
  603. HOFFSET(h) += nbytes;
  604. t += nbytes;
  605. }
  606. /* Copy the new item onto the page. */
  607. bk = (BKEYDATA *)t;
  608. B_TSET(bk->type, B_KEYDATA, 0);
  609. bk->len = data->size;
  610. memcpy(bk->data, data->data, data->size);
  611. return (0);
  612. }
  613. /*
  614.  * __bam_dup_convert --
  615.  * Check to see if the duplicate set at indx should have its own page.
  616.  * If it should, create it.
  617.  */
  618. static int
  619. __bam_dup_convert(dbc, h, indx)
  620. DBC *dbc;
  621. PAGE *h;
  622. u_int32_t indx;
  623. {
  624. BKEYDATA *bk;
  625. DB *dbp;
  626. DBT hdr;
  627. DB_MPOOLFILE *mpf;
  628. PAGE *dp;
  629. db_indx_t cnt, cpindx, dindx, first, *inp, sz;
  630. int ret;
  631. dbp = dbc->dbp;
  632. mpf = dbp->mpf;
  633. inp = P_INP(dbp, h);
  634. /*
  635.  * Count the duplicate records and calculate how much room they're
  636.  * using on the page.
  637.  */
  638. while (indx > 0 && inp[indx] == inp[indx - P_INDX])
  639. indx -= P_INDX;
  640. for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) {
  641. if (indx >= NUM_ENT(h) || inp[first] != inp[indx])
  642. break;
  643. bk = GET_BKEYDATA(dbp, h, indx);
  644. sz += B_TYPE(bk->type) == B_KEYDATA ?
  645.     BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
  646. bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
  647. sz += B_TYPE(bk->type) == B_KEYDATA ?
  648.     BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
  649. }
  650. /*
  651.  * We have to do these checks when the user is replacing the cursor's
  652.  * data item -- if the application replaces a duplicate item with a
  653.  * larger data item, it can increase the amount of space used by the
  654.  * duplicates, requiring this check.  But that means we may have done
  655.  * this check when it wasn't a duplicate item after all.
  656.  */
  657. if (cnt == 1)
  658. return (0);
  659. /*
  660.  * If this set of duplicates is using more than 25% of the page, move
  661.  * them off.  The choice of 25% is a WAG, but the value must be small
  662.  * enough that we can always split a page without putting duplicates
  663.  * on two different pages.
  664.  */
  665. if (sz < dbp->pgsize / 4)
  666. return (0);
  667. /* Get a new page. */
  668. if ((ret = __db_new(dbc,
  669.     dbp->dup_compare == NULL ? P_LRECNO : P_LDUP, &dp)) != 0)
  670. return (ret);
  671. P_INIT(dp, dbp->pgsize, dp->pgno,
  672.     PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp));
  673. /*
  674.  * Move this set of duplicates off the page.  First points to the first
  675.  * key of the first duplicate key/data pair, cnt is the number of pairs
  676.  * we're dealing with.
  677.  */
  678. memset(&hdr, 0, sizeof(hdr));
  679. dindx = first;
  680. indx = first;
  681. cpindx = 0;
  682. do {
  683. /* Move cursors referencing the old entry to the new entry. */
  684. if ((ret = __bam_ca_dup(dbc, first,
  685.     PGNO(h), indx, PGNO(dp), cpindx)) != 0)
  686. goto err;
  687. /*
  688.  * Copy the entry to the new page.  If the off-duplicate page
  689.  * If the off-duplicate page is a Btree page (i.e. dup_compare
  690.  * will be non-NULL, we use Btree pages for sorted dups,
  691.  * and Recno pages for unsorted dups), move all entries
  692.  * normally, even deleted ones.  If it's a Recno page,
  693.  * deleted entries are discarded (if the deleted entry is
  694.  * overflow, then free up those pages).
  695.  */
  696. bk = GET_BKEYDATA(dbp, h, dindx + 1);
  697. hdr.data = bk;
  698. hdr.size = B_TYPE(bk->type) == B_KEYDATA ?
  699.     BKEYDATA_SIZE(bk->len) : BOVERFLOW_SIZE;
  700. if (dbp->dup_compare == NULL && B_DISSET(bk->type)) {
  701. /*
  702.  * Unsorted dups, i.e. recno page, and we have
  703.  * a deleted entry, don't move it, but if it was
  704.  * an overflow entry, we need to free those pages.
  705.  */
  706. if (B_TYPE(bk->type) == B_OVERFLOW &&
  707.     (ret = __db_doff(dbc,
  708.     (GET_BOVERFLOW(dbp, h, dindx + 1))->pgno)) != 0)
  709. goto err;
  710. } else {
  711. if ((ret = __db_pitem(
  712.     dbc, dp, cpindx, hdr.size, &hdr, NULL)) != 0)
  713. goto err;
  714. ++cpindx;
  715. }
  716. /* Delete all but the last reference to the key. */
  717. if (cnt != 1) {
  718. if ((ret = __bam_adjindx(dbc,
  719.     h, dindx, first + 1, 0)) != 0)
  720. goto err;
  721. } else
  722. dindx++;
  723. /* Delete the data item. */
  724. if ((ret = __db_ditem(dbc, h, dindx, hdr.size)) != 0)
  725. goto err;
  726. indx += P_INDX;
  727. } while (--cnt);
  728. /* Put in a new data item that points to the duplicates page. */
  729. if ((ret = __bam_ovput(dbc,
  730.     B_DUPLICATE, dp->pgno, h, first + 1, NULL)) != 0)
  731. goto err;
  732. /* Adjust cursors for all the above movments. */
  733. if ((ret = __bam_ca_di(dbc,
  734.     PGNO(h), first + P_INDX, first + P_INDX - indx)) != 0)
  735. goto err;
  736. return (mpf->put(mpf, dp, DB_MPOOL_DIRTY));
  737. err: (void)mpf->put(mpf, dp, 0);
  738. return (ret);
  739. }
  740. /*
  741.  * __bam_ovput --
  742.  * Build an item for an off-page duplicates page or overflow page and
  743.  * insert it on the page.
  744.  */
  745. static int
  746. __bam_ovput(dbc, type, pgno, h, indx, item)
  747. DBC *dbc;
  748. u_int32_t type, indx;
  749. db_pgno_t pgno;
  750. PAGE *h;
  751. DBT *item;
  752. {
  753. BOVERFLOW bo;
  754. DBT hdr;
  755. int ret;
  756. UMRW_SET(bo.unused1);
  757. B_TSET(bo.type, type, 0);
  758. UMRW_SET(bo.unused2);
  759. /*
  760.  * If we're creating an overflow item, do so and acquire the page
  761.  * number for it.  If we're creating an off-page duplicates tree,
  762.  * we are giving the page number as an argument.
  763.  */
  764. if (type == B_OVERFLOW) {
  765. if ((ret = __db_poff(dbc, item, &bo.pgno)) != 0)
  766. return (ret);
  767. bo.tlen = item->size;
  768. } else {
  769. bo.pgno = pgno;
  770. bo.tlen = 0;
  771. }
  772. /* Store the new record on the page. */
  773. memset(&hdr, 0, sizeof(hdr));
  774. hdr.data = &bo;
  775. hdr.size = BOVERFLOW_SIZE;
  776. return (__db_pitem(dbc, h, indx, BOVERFLOW_SIZE, &hdr, NULL));
  777. }