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

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
  9.  * The Regents of the University of California.  All rights reserved.
  10.  *
  11.  * This code is derived from software contributed to Berkeley by
  12.  * Margo Seltzer.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38. #include "db_config.h"
  39. #ifndef lint
  40. static const char revid[] = "$Id: hash_dup.c,v 11.76 2002/08/06 05:34:40 bostic Exp $";
  41. #endif /* not lint */
  42. /*
  43.  * PACKAGE:  hashing
  44.  *
  45.  * DESCRIPTION:
  46.  * Manipulation of duplicates for the hash package.
  47.  */
  48. #ifndef NO_SYSTEM_INCLUDES
  49. #include <sys/types.h>
  50. #include <string.h>
  51. #endif
  52. #include "db_int.h"
  53. #include "dbinc/db_page.h"
  54. #include "dbinc/hash.h"
  55. #include "dbinc/btree.h"
  56. static int __ham_c_chgpg __P((DBC *,
  57.     db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
  58. static int __ham_check_move __P((DBC *, u_int32_t));
  59. static int __ham_dcursor __P((DBC *, db_pgno_t, u_int32_t));
  60. static int __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
  61. /*
  62.  * Called from hash_access to add a duplicate key. nval is the new
  63.  * value that we want to add.  The flags correspond to the flag values
  64.  * to cursor_put indicating where to add the new element.
  65.  * There are 4 cases.
  66.  * Case 1: The existing duplicate set already resides on a separate page.
  67.  *    We return and let the common code handle this.
  68.  * Case 2: The element is small enough to just be added to the existing set.
  69.  * Case 3: The element is large enough to be a big item, so we're going to
  70.  *    have to push the set onto a new page.
  71.  * Case 4: The element is large enough to push the duplicate set onto a
  72.  *    separate page.
  73.  *
  74.  * PUBLIC: int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *));
  75.  */
  76. int
  77. __ham_add_dup(dbc, nval, flags, pgnop)
  78. DBC *dbc;
  79. DBT *nval;
  80. u_int32_t flags;
  81. db_pgno_t *pgnop;
  82. {
  83. DB *dbp;
  84. DBT pval, tmp_val;
  85. DB_MPOOLFILE *mpf;
  86. HASH_CURSOR *hcp;
  87. u_int32_t add_bytes, new_size;
  88. int cmp, ret;
  89. u_int8_t *hk;
  90. dbp = dbc->dbp;
  91. mpf = dbp->mpf;
  92. hcp = (HASH_CURSOR *)dbc->internal;
  93. DB_ASSERT(flags != DB_CURRENT);
  94. add_bytes = nval->size +
  95.     (F_ISSET(nval, DB_DBT_PARTIAL) ? nval->doff : 0);
  96. add_bytes = DUP_SIZE(add_bytes);
  97. if ((ret = __ham_check_move(dbc, add_bytes)) != 0)
  98. return (ret);
  99. /*
  100.  * Check if resulting duplicate set is going to need to go
  101.  * onto a separate duplicate page.  If so, convert the
  102.  * duplicate set and add the new one.  After conversion,
  103.  * hcp->dndx is the first free ndx or the index of the
  104.  * current pointer into the duplicate set.
  105.  */
  106. hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
  107. /* Add the len bytes to the current singleton. */
  108. if (HPAGE_PTYPE(hk) != H_DUPLICATE)
  109. add_bytes += DUP_SIZE(0);
  110. new_size =
  111.     LEN_HKEYDATA(dbp, hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)) +
  112.     add_bytes;
  113. /*
  114.  * We convert to off-page duplicates if the item is a big item,
  115.  * the addition of the new item will make the set large, or
  116.  * if there isn't enough room on this page to add the next item.
  117.  */
  118. if (HPAGE_PTYPE(hk) != H_OFFDUP &&
  119.     (HPAGE_PTYPE(hk) == H_OFFPAGE || ISBIG(hcp, new_size) ||
  120.     add_bytes > P_FREESPACE(dbp, hcp->page))) {
  121. if ((ret = __ham_dup_convert(dbc)) != 0)
  122. return (ret);
  123. return (hcp->opd->c_am_put(hcp->opd,
  124.     NULL, nval, flags, NULL));
  125. }
  126. /* There are two separate cases here: on page and off page. */
  127. if (HPAGE_PTYPE(hk) != H_OFFDUP) {
  128. if (HPAGE_PTYPE(hk) != H_DUPLICATE) {
  129. pval.flags = 0;
  130. pval.data = HKEYDATA_DATA(hk);
  131. pval.size = LEN_HDATA(dbp, hcp->page, dbp->pgsize,
  132.     hcp->indx);
  133. if ((ret = __ham_make_dup(dbp->dbenv,
  134.     &pval, &tmp_val, &dbc->my_rdata.data,
  135.     &dbc->my_rdata.ulen)) != 0 || (ret =
  136.     __ham_replpair(dbc, &tmp_val, 1)) != 0)
  137. return (ret);
  138. hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
  139. HPAGE_PTYPE(hk) = H_DUPLICATE;
  140. /*
  141.  * Update the cursor position since we now are in
  142.  * duplicates.
  143.  */
  144. F_SET(hcp, H_ISDUP);
  145. hcp->dup_off = 0;
  146. hcp->dup_len = pval.size;
  147. hcp->dup_tlen = DUP_SIZE(hcp->dup_len);
  148. }
  149. /* Now make the new entry a duplicate. */
  150. if ((ret = __ham_make_dup(dbp->dbenv, nval,
  151.     &tmp_val, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) != 0)
  152. return (ret);
  153. tmp_val.dlen = 0;
  154. switch (flags) { /* On page. */
  155. case DB_KEYFIRST:
  156. case DB_KEYLAST:
  157. case DB_NODUPDATA:
  158. if (dbp->dup_compare != NULL) {
  159. __ham_dsearch(dbc,
  160.     nval, &tmp_val.doff, &cmp, flags);
  161. /* dup dups are not supported w/ sorted dups */
  162. if (cmp == 0)
  163. return (__db_duperr(dbp, flags));
  164. } else {
  165. hcp->dup_tlen = LEN_HDATA(dbp, hcp->page,
  166.     dbp->pgsize, hcp->indx);
  167. hcp->dup_len = nval->size;
  168. F_SET(hcp, H_ISDUP);
  169. if (flags == DB_KEYFIRST)
  170. hcp->dup_off = tmp_val.doff = 0;
  171. else
  172. hcp->dup_off =
  173.     tmp_val.doff = hcp->dup_tlen;
  174. }
  175. break;
  176. case DB_BEFORE:
  177. tmp_val.doff = hcp->dup_off;
  178. break;
  179. case DB_AFTER:
  180. tmp_val.doff = hcp->dup_off + DUP_SIZE(hcp->dup_len);
  181. break;
  182. }
  183. /* Add the duplicate. */
  184. ret = __ham_replpair(dbc, &tmp_val, 0);
  185. if (ret == 0)
  186. ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
  187. if (ret != 0)
  188. return (ret);
  189. /* Now, update the cursor if necessary. */
  190. switch (flags) {
  191. case DB_AFTER:
  192. hcp->dup_off += DUP_SIZE(hcp->dup_len);
  193. hcp->dup_len = nval->size;
  194. hcp->dup_tlen += (db_indx_t)DUP_SIZE(nval->size);
  195. break;
  196. case DB_KEYFIRST:
  197. case DB_KEYLAST:
  198. case DB_BEFORE:
  199. hcp->dup_tlen += (db_indx_t)DUP_SIZE(nval->size);
  200. hcp->dup_len = nval->size;
  201. break;
  202. }
  203. ret = __ham_c_update(dbc, tmp_val.size, 1, 1);
  204. return (ret);
  205. }
  206. /*
  207.  * If we get here, then we're on duplicate pages; set pgnop and
  208.  * return so the common code can handle it.
  209.  */
  210. memcpy(pgnop, HOFFDUP_PGNO(H_PAIRDATA(dbp, hcp->page, hcp->indx)),
  211.     sizeof(db_pgno_t));
  212. return (ret);
  213. }
  214. /*
  215.  * Convert an on-page set of duplicates to an offpage set of duplicates.
  216.  *
  217.  * PUBLIC: int __ham_dup_convert __P((DBC *));
  218.  */
  219. int
  220. __ham_dup_convert(dbc)
  221. DBC *dbc;
  222. {
  223. BOVERFLOW bo;
  224. DB *dbp;
  225. DBC **hcs;
  226. DBT dbt;
  227. DB_LSN lsn;
  228. DB_MPOOLFILE *mpf;
  229. HASH_CURSOR *hcp;
  230. HOFFPAGE ho;
  231. PAGE *dp;
  232. db_indx_t i, len, off;
  233. int c, ret, t_ret;
  234. u_int8_t *p, *pend;
  235. dbp = dbc->dbp;
  236. mpf = dbp->mpf;
  237. hcp = (HASH_CURSOR *)dbc->internal;
  238. /*
  239.  * Create a new page for the duplicates.
  240.  */
  241. if ((ret = __db_new(dbc,
  242.     dbp->dup_compare == NULL ? P_LRECNO : P_LDUP, &dp)) != 0)
  243. return (ret);
  244. P_INIT(dp, dbp->pgsize,
  245.     dp->pgno, PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp));
  246. /*
  247.  * Get the list of cursors that may need to be updated.
  248.  */
  249. if ((ret = __ham_get_clist(dbp,
  250.     PGNO(hcp->page), (u_int32_t)hcp->indx, &hcs)) != 0)
  251. goto err;
  252. /*
  253.  * Now put the duplicates onto the new page.
  254.  */
  255. dbt.flags = 0;
  256. switch (HPAGE_PTYPE(H_PAIRDATA(dbp, hcp->page, hcp->indx))) {
  257. case H_KEYDATA:
  258. /* Simple case, one key on page; move it to dup page. */
  259. dbt.size = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
  260. dbt.data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
  261. ret = __db_pitem(dbc,
  262.     dp, 0, BKEYDATA_SIZE(dbt.size), NULL, &dbt);
  263. goto finish;
  264. case H_OFFPAGE:
  265. /* Simple case, one key on page; move it to dup page. */
  266. memcpy(&ho, P_ENTRY(dbp, hcp->page, H_DATAINDEX(hcp->indx)),
  267.     HOFFPAGE_SIZE);
  268. UMRW_SET(bo.unused1);
  269. B_TSET(bo.type, ho.type, 0);
  270. UMRW_SET(bo.unused2);
  271. bo.pgno = ho.pgno;
  272. bo.tlen = ho.tlen;
  273. dbt.size = BOVERFLOW_SIZE;
  274. dbt.data = &bo;
  275. ret = __db_pitem(dbc, dp, 0, dbt.size, &dbt, NULL);
  276. finish: if (ret == 0) {
  277. if ((ret = mpf->set(mpf, dp, DB_MPOOL_DIRTY)) != 0)
  278. break;
  279. /* Update any other cursors. */
  280. if (hcs != NULL && DBC_LOGGING(dbc) &&
  281.     IS_SUBTRANSACTION(dbc->txn)) {
  282. if ((ret = __ham_chgpg_log(dbp, dbc->txn,
  283.     &lsn, 0, DB_HAM_DUP, PGNO(hcp->page),
  284.     PGNO(dp), hcp->indx, 0)) != 0)
  285. break;
  286. }
  287. for (c = 0; hcs != NULL && hcs[c] != NULL; c++)
  288. if ((ret = __ham_dcursor(hcs[c],
  289.     PGNO(dp), 0)) != 0)
  290. break;
  291. }
  292. break;
  293. case H_DUPLICATE:
  294. p = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
  295. pend = p +
  296.     LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
  297. /*
  298.  * We need to maintain the duplicate cursor position.
  299.  * Keep track of where we are in the duplicate set via
  300.  * the offset, and when it matches the one in the cursor,
  301.  * set the off-page duplicate cursor index to the current
  302.  * index.
  303.  */
  304. for (off = 0, i = 0; p < pend; i++) {
  305. memcpy(&len, p, sizeof(db_indx_t));
  306. dbt.size = len;
  307. p += sizeof(db_indx_t);
  308. dbt.data = p;
  309. p += len + sizeof(db_indx_t);
  310. if ((ret = __db_pitem(dbc, dp,
  311.     i, BKEYDATA_SIZE(dbt.size), NULL, &dbt)) != 0)
  312. break;
  313. /* Update any other cursors */
  314. if (hcs != NULL && DBC_LOGGING(dbc) &&
  315.     IS_SUBTRANSACTION(dbc->txn)) {
  316. if ((ret = __ham_chgpg_log(dbp, dbc->txn,
  317.     &lsn, 0, DB_HAM_DUP, PGNO(hcp->page),
  318.     PGNO(dp), hcp->indx, i)) != 0)
  319. break;
  320. }
  321. for (c = 0; hcs != NULL && hcs[c] != NULL; c++)
  322. if (((HASH_CURSOR *)(hcs[c]->internal))->dup_off
  323.     == off && (ret = __ham_dcursor(hcs[c],
  324.     PGNO(dp), i)) != 0)
  325. goto err;
  326. off += len + 2 * sizeof(db_indx_t);
  327. }
  328. break;
  329. default:
  330. ret = __db_pgfmt(dbp->dbenv, (u_long)hcp->pgno);
  331. break;
  332. }
  333. /*
  334.  * Now attach this to the source page in place of the old duplicate
  335.  * item.
  336.  */
  337. if (ret == 0)
  338. ret = __ham_move_offpage(dbc, hcp->page,
  339.     (u_int32_t)H_DATAINDEX(hcp->indx), PGNO(dp));
  340. err: if (ret == 0)
  341. ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
  342. if ((t_ret =
  343.     mpf->put(mpf, dp, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0)
  344. ret = t_ret;
  345. if (ret == 0)
  346. hcp->dup_tlen = hcp->dup_off = hcp->dup_len = 0;
  347. if (hcs != NULL)
  348. __os_free(dbp->dbenv, hcs);
  349. return (ret);
  350. }
  351. /*
  352.  * __ham_make_dup
  353.  *
  354.  * Take a regular dbt and make it into a duplicate item with all the partial
  355.  * information set appropriately. If the incoming dbt is a partial, assume
  356.  * we are creating a new entry and make sure that we do any initial padding.
  357.  *
  358.  * PUBLIC: int __ham_make_dup __P((DB_ENV *,
  359.  * PUBLIC:     const DBT *, DBT *d, void **, u_int32_t *));
  360.  */
  361. int
  362. __ham_make_dup(dbenv, notdup, duplicate, bufp, sizep)
  363. DB_ENV *dbenv;
  364. const DBT *notdup;
  365. DBT *duplicate;
  366. void **bufp;
  367. u_int32_t *sizep;
  368. {
  369. db_indx_t tsize, item_size;
  370. int ret;
  371. u_int8_t *p;
  372. item_size = (db_indx_t)notdup->size;
  373. if (F_ISSET(notdup, DB_DBT_PARTIAL))
  374. item_size += notdup->doff;
  375. tsize = DUP_SIZE(item_size);
  376. if ((ret = __ham_init_dbt(dbenv, duplicate, tsize, bufp, sizep)) != 0)
  377. return (ret);
  378. duplicate->dlen = 0;
  379. duplicate->flags = notdup->flags;
  380. F_SET(duplicate, DB_DBT_PARTIAL);
  381. p = duplicate->data;
  382. memcpy(p, &item_size, sizeof(db_indx_t));
  383. p += sizeof(db_indx_t);
  384. if (F_ISSET(notdup, DB_DBT_PARTIAL)) {
  385. memset(p, 0, notdup->doff);
  386. p += notdup->doff;
  387. }
  388. memcpy(p, notdup->data, notdup->size);
  389. p += notdup->size;
  390. memcpy(p, &item_size, sizeof(db_indx_t));
  391. duplicate->doff = 0;
  392. duplicate->dlen = notdup->size;
  393. return (0);
  394. }
  395. /*
  396.  * __ham_check_move --
  397.  *
  398.  * Check if we can do whatever we need to on this page.  If not,
  399.  * then we'll have to move the current element to a new page.
  400.  */
  401. static int
  402. __ham_check_move(dbc, add_len)
  403. DBC *dbc;
  404. u_int32_t add_len;
  405. {
  406. DB *dbp;
  407. DBT k, d;
  408. DB_LSN new_lsn;
  409. DB_MPOOLFILE *mpf;
  410. HASH_CURSOR *hcp;
  411. PAGE *next_pagep;
  412. db_pgno_t next_pgno;
  413. u_int32_t new_datalen, old_len, rectype;
  414. u_int8_t *hk;
  415. int ret;
  416. dbp = dbc->dbp;
  417. mpf = dbp->mpf;
  418. hcp = (HASH_CURSOR *)dbc->internal;
  419. hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
  420. /*
  421.  * If the item is already off page duplicates or an offpage item,
  422.  * then we know we can do whatever we need to do in-place
  423.  */
  424. if (HPAGE_PTYPE(hk) == H_OFFDUP || HPAGE_PTYPE(hk) == H_OFFPAGE)
  425. return (0);
  426. old_len = LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx));
  427. new_datalen = old_len - HKEYDATA_SIZE(0) + add_len;
  428. if (HPAGE_PTYPE(hk) != H_DUPLICATE)
  429. new_datalen += DUP_SIZE(0);
  430. /*
  431.  * We need to add a new page under two conditions:
  432.  * 1. The addition makes the total data length cross the BIG
  433.  *    threshold and the OFFDUP structure won't fit on this page.
  434.  * 2. The addition does not make the total data cross the
  435.  *    threshold, but the new data won't fit on the page.
  436.  * If neither of these is true, then we can return.
  437.  */
  438. if (ISBIG(hcp, new_datalen) && (old_len > HOFFDUP_SIZE ||
  439.     HOFFDUP_SIZE - old_len <= P_FREESPACE(dbp, hcp->page)))
  440. return (0);
  441. if (!ISBIG(hcp, new_datalen) && add_len <= P_FREESPACE(dbp, hcp->page))
  442. return (0);
  443. /*
  444.  * If we get here, then we need to move the item to a new page.
  445.  * Check if there are more pages in the chain.  We now need to
  446.  * update new_datalen to include the size of both the key and
  447.  * the data that we need to move.
  448.  */
  449. new_datalen = ISBIG(hcp, new_datalen) ?
  450.     HOFFDUP_SIZE : HKEYDATA_SIZE(new_datalen);
  451. new_datalen += LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_KEYINDEX(hcp->indx));
  452. next_pagep = NULL;
  453. for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID;
  454.     next_pgno = NEXT_PGNO(next_pagep)) {
  455. if (next_pagep != NULL &&
  456.     (ret = mpf->put(mpf, next_pagep, 0)) != 0)
  457. return (ret);
  458. if ((ret = mpf->get(mpf,
  459.     &next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0)
  460. return (ret);
  461. if (P_FREESPACE(dbp, next_pagep) >= new_datalen)
  462. break;
  463. }
  464. /* No more pages, add one. */
  465. if (next_pagep == NULL && (ret = __ham_add_ovflpage(dbc,
  466.     hcp->page, 0, &next_pagep)) != 0)
  467. return (ret);
  468. /* Add new page at the end of the chain. */
  469. if (P_FREESPACE(dbp, next_pagep) < new_datalen && (ret =
  470.     __ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) {
  471. (void)mpf->put(mpf, next_pagep, 0);
  472. return (ret);
  473. }
  474. /* Copy the item to the new page. */
  475. if (DBC_LOGGING(dbc)) {
  476. rectype = PUTPAIR;
  477. k.flags = 0;
  478. d.flags = 0;
  479. if (HPAGE_PTYPE(
  480.     H_PAIRKEY(dbp, hcp->page, hcp->indx)) == H_OFFPAGE) {
  481. rectype |= PAIR_KEYMASK;
  482. k.data = H_PAIRKEY(dbp, hcp->page, hcp->indx);
  483. k.size = HOFFPAGE_SIZE;
  484. } else {
  485. k.data =
  486.     HKEYDATA_DATA(H_PAIRKEY(dbp, hcp->page, hcp->indx));
  487. k.size =
  488.     LEN_HKEY(dbp, hcp->page, dbp->pgsize, hcp->indx);
  489. }
  490. if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
  491. rectype |= PAIR_DATAMASK;
  492. d.data = H_PAIRDATA(dbp, hcp->page, hcp->indx);
  493. d.size = HOFFPAGE_SIZE;
  494. } else {
  495. if (HPAGE_PTYPE(H_PAIRDATA(dbp, hcp->page, hcp->indx))
  496.     == H_DUPLICATE)
  497. rectype |= PAIR_DUPMASK;
  498. d.data =
  499.     HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
  500. d.size = LEN_HDATA(dbp, hcp->page,
  501.     dbp->pgsize, hcp->indx);
  502. }
  503. if ((ret = __ham_insdel_log(dbp,
  504.     dbc->txn, &new_lsn, 0, rectype, PGNO(next_pagep),
  505.     (u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep),
  506.     &k, &d)) != 0) {
  507. (void)mpf->put(mpf, next_pagep, 0);
  508. return (ret);
  509. }
  510. } else
  511. LSN_NOT_LOGGED(new_lsn);
  512. /* Move lsn onto page. */
  513. LSN(next_pagep) = new_lsn; /* Structure assignment. */
  514. __ham_copy_item(dbp, hcp->page, H_KEYINDEX(hcp->indx), next_pagep);
  515. __ham_copy_item(dbp, hcp->page, H_DATAINDEX(hcp->indx), next_pagep);
  516. /*
  517.  * We've just manually inserted a key and set of data onto
  518.  * next_pagep;  however, it's possible that our caller will
  519.  * return without further modifying the new page, for instance
  520.  * if DB_NODUPDATA is set and our new item is a duplicate duplicate.
  521.  * Thus, to be on the safe side, we need to mark the page dirty
  522.  * here. [#2996]
  523.  *
  524.  * Note that __ham_del_pair should dirty the page we're moving
  525.  * the items from, so we need only dirty the new page ourselves.
  526.  */
  527. if ((ret = mpf->set(mpf, next_pagep, DB_MPOOL_DIRTY)) != 0)
  528. goto out;
  529. /* Update all cursors that used to point to this item. */
  530. if ((ret = __ham_c_chgpg(dbc, PGNO(hcp->page), H_KEYINDEX(hcp->indx),
  531.     PGNO(next_pagep), NUM_ENT(next_pagep) - 2)) != 0)
  532. goto out;
  533. /* Now delete the pair from the current page. */
  534. ret = __ham_del_pair(dbc, 0);
  535. /*
  536.  * __ham_del_pair decremented nelem.  This is incorrect;  we
  537.  * manually copied the element elsewhere, so the total number
  538.  * of elements hasn't changed.  Increment it again.
  539.  *
  540.  * !!!
  541.  * Note that we still have the metadata page pinned, and
  542.  * __ham_del_pair dirtied it, so we don't need to set the dirty
  543.  * flag again.
  544.  */
  545. if (!STD_LOCKING(dbc))
  546. hcp->hdr->nelem++;
  547. out:
  548. (void)mpf->put(mpf, hcp->page, DB_MPOOL_DIRTY);
  549. hcp->page = next_pagep;
  550. hcp->pgno = PGNO(hcp->page);
  551. hcp->indx = NUM_ENT(hcp->page) - 2;
  552. F_SET(hcp, H_EXPAND);
  553. F_CLR(hcp, H_DELETED);
  554. return (ret);
  555. }
  556. /*
  557.  * __ham_move_offpage --
  558.  * Replace an onpage set of duplicates with the OFFDUP structure
  559.  * that references the duplicate page.
  560.  *
  561.  * XXX
  562.  * This is really just a special case of __onpage_replace; we should
  563.  * probably combine them.
  564.  *
  565.  */
  566. static int
  567. __ham_move_offpage(dbc, pagep, ndx, pgno)
  568. DBC *dbc;
  569. PAGE *pagep;
  570. u_int32_t ndx;
  571. db_pgno_t pgno;
  572. {
  573. DB *dbp;
  574. DBT new_dbt;
  575. DBT old_dbt;
  576. HOFFDUP od;
  577. db_indx_t i, *inp;
  578. int32_t shrink;
  579. u_int8_t *src;
  580. int ret;
  581. dbp = dbc->dbp;
  582. od.type = H_OFFDUP;
  583. UMRW_SET(od.unused[0]);
  584. UMRW_SET(od.unused[1]);
  585. UMRW_SET(od.unused[2]);
  586. od.pgno = pgno;
  587. ret = 0;
  588. if (DBC_LOGGING(dbc)) {
  589. new_dbt.data = &od;
  590. new_dbt.size = HOFFDUP_SIZE;
  591. old_dbt.data = P_ENTRY(dbp, pagep, ndx);
  592. old_dbt.size = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx);
  593. if ((ret = __ham_replace_log(dbp, dbc->txn, &LSN(pagep), 0,
  594.     PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1,
  595.     &old_dbt, &new_dbt, 0)) != 0)
  596. return (ret);
  597. } else
  598. LSN_NOT_LOGGED(LSN(pagep));
  599. shrink = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE;
  600. inp = P_INP(dbp, pagep);
  601. if (shrink != 0) {
  602. /* Copy data. */
  603. src = (u_int8_t *)(pagep) + HOFFSET(pagep);
  604. memmove(src + shrink, src, inp[ndx] - HOFFSET(pagep));
  605. HOFFSET(pagep) += shrink;
  606. /* Update index table. */
  607. for (i = ndx; i < NUM_ENT(pagep); i++)
  608. inp[i] += shrink;
  609. }
  610. /* Now copy the offdup entry onto the page. */
  611. memcpy(P_ENTRY(dbp, pagep, ndx), &od, HOFFDUP_SIZE);
  612. return (ret);
  613. }
  614. /*
  615.  * __ham_dsearch:
  616.  * Locate a particular duplicate in a duplicate set.  Make sure that
  617.  * we exit with the cursor set appropriately.
  618.  *
  619.  * PUBLIC: void __ham_dsearch
  620.  * PUBLIC:     __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t));
  621.  */
  622. void
  623. __ham_dsearch(dbc, dbt, offp, cmpp, flags)
  624. DBC *dbc;
  625. DBT *dbt;
  626. u_int32_t *offp, flags;
  627. int *cmpp;
  628. {
  629. DB *dbp;
  630. HASH_CURSOR *hcp;
  631. DBT cur;
  632. db_indx_t i, len;
  633. int (*func) __P((DB *, const DBT *, const DBT *));
  634. u_int8_t *data;
  635. dbp = dbc->dbp;
  636. hcp = (HASH_CURSOR *)dbc->internal;
  637. func = dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare;
  638. i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0;
  639. data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)) + i;
  640. hcp->dup_tlen = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
  641. while (i < hcp->dup_tlen) {
  642. memcpy(&len, data, sizeof(db_indx_t));
  643. data += sizeof(db_indx_t);
  644. cur.data = data;
  645. cur.size = (u_int32_t)len;
  646. /*
  647.  * If we find an exact match, we're done.  If in a sorted
  648.  * duplicate set and the item is larger than our test item,
  649.  * we're done.  In the latter case, if permitting partial
  650.  * matches, it's not a failure.
  651.  */
  652. *cmpp = func(dbp, dbt, &cur);
  653. if (*cmpp == 0)
  654. break;
  655. if (*cmpp < 0 && dbp->dup_compare != NULL) {
  656. if (flags == DB_GET_BOTH_RANGE)
  657. *cmpp = 0;
  658. break;
  659. }
  660. i += len + 2 * sizeof(db_indx_t);
  661. data += len + sizeof(db_indx_t);
  662. }
  663. *offp = i;
  664. hcp->dup_off = i;
  665. hcp->dup_len = len;
  666. F_SET(hcp, H_ISDUP);
  667. }
  668. #ifdef DEBUG
  669. /*
  670.  * __ham_cprint --
  671.  * Display the current cursor list.
  672.  *
  673.  * PUBLIC: void __ham_cprint __P((DBC *));
  674.  */
  675. void
  676. __ham_cprint(dbc)
  677. DBC *dbc;
  678. {
  679. HASH_CURSOR *cp;
  680. cp = (HASH_CURSOR *)dbc->internal;
  681. fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu",
  682.     P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno,
  683.     (u_long)cp->indx);
  684. if (F_ISSET(cp, H_DELETED))
  685. fprintf(stderr, " (deleted)");
  686. fprintf(stderr, "n");
  687. }
  688. #endif /* DEBUG */
  689. /*
  690.  * __ham_dcursor --
  691.  *
  692.  * Create an off page duplicate cursor for this cursor.
  693.  */
  694. static int
  695. __ham_dcursor(dbc, pgno, indx)
  696. DBC *dbc;
  697. db_pgno_t pgno;
  698. u_int32_t indx;
  699. {
  700. DB *dbp;
  701. HASH_CURSOR *hcp;
  702. BTREE_CURSOR *dcp;
  703. int ret;
  704. dbp = dbc->dbp;
  705. hcp = (HASH_CURSOR *)dbc->internal;
  706. if ((ret = __db_c_newopd(dbc, pgno, hcp->opd, &hcp->opd)) != 0)
  707. return (ret);
  708. dcp = (BTREE_CURSOR *)hcp->opd->internal;
  709. dcp->pgno = pgno;
  710. dcp->indx = indx;
  711. if (dbp->dup_compare == NULL) {
  712. /*
  713.  * Converting to off-page Recno trees is tricky.  The
  714.  * record number for the cursor is the index + 1 (to
  715.  * convert to 1-based record numbers).
  716.  */
  717. dcp->recno = indx + 1;
  718. }
  719. /*
  720.  * Transfer the deleted flag from the top-level cursor to the
  721.  * created one.
  722.  */
  723. if (F_ISSET(hcp, H_DELETED)) {
  724. F_SET(dcp, C_DELETED);
  725. F_CLR(hcp, H_DELETED);
  726. }
  727. return (0);
  728. }
  729. /*
  730.  * __ham_c_chgpg --
  731.  * Adjust the cursors after moving an item to a new page.  We only
  732.  * move cursors that are pointing at this one item and are not
  733.  * deleted;  since we only touch non-deleted cursors, and since
  734.  * (by definition) no item existed at the pgno/indx we're moving the
  735.  * item to, we're guaranteed that all the cursors we affect here or
  736.  * on abort really do refer to this one item.
  737.  */
  738. static int
  739. __ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index)
  740. DBC *dbc;
  741. db_pgno_t old_pgno, new_pgno;
  742. u_int32_t old_index, new_index;
  743. {
  744. DB *dbp, *ldbp;
  745. DB_ENV *dbenv;
  746. DB_LSN lsn;
  747. DB_TXN *my_txn;
  748. DBC *cp;
  749. HASH_CURSOR *hcp;
  750. int found, ret;
  751. dbp = dbc->dbp;
  752. dbenv = dbp->dbenv;
  753. my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL;
  754. found = 0;
  755. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  756. for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
  757.     ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
  758.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  759. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  760. for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
  761.     cp = TAILQ_NEXT(cp, links)) {
  762. if (cp == dbc || cp->dbtype != DB_HASH)
  763. continue;
  764. hcp = (HASH_CURSOR *)cp->internal;
  765. /*
  766.  * If a cursor is deleted, it doesn't refer to this
  767.  * item--it just happens to have the same indx, but
  768.  * it points to a former neighbor.  Don't move it.
  769.  */
  770. if (F_ISSET(hcp, H_DELETED))
  771. continue;
  772. if (hcp->pgno == old_pgno) {
  773. if (hcp->indx == old_index) {
  774. hcp->pgno = new_pgno;
  775. hcp->indx = new_index;
  776. } else
  777. continue;
  778. if (my_txn != NULL && cp->txn != my_txn)
  779. found = 1;
  780. }
  781. }
  782. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  783. }
  784. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  785. if (found != 0 && DBC_LOGGING(dbc)) {
  786. if ((ret = __ham_chgpg_log(dbp, my_txn, &lsn, 0, DB_HAM_CHGPG,
  787.     old_pgno, new_pgno, old_index, new_index)) != 0)
  788. return (ret);
  789. }
  790. return (0);
  791. }