bt_put.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

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