2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1996-2002
5
* Sleepycat Software. All rights reserved.
8
* Copyright (c) 1990, 1993, 1994
9
* The Regents of the University of California. All rights reserved.
11
* This code is derived from software contributed to Berkeley by
14
* Redistribution and use in source and binary forms, with or without
15
* modification, are permitted provided that the following conditions
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.
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
38
#include "db_config.h"
41
static const char revid[] = "$Id$";
48
* Manipulation of duplicates for the hash package.
51
#ifndef NO_SYSTEM_INCLUDES
52
#include <sys/types.h>
58
#include "dbinc/db_page.h"
59
#include "dbinc/hash.h"
60
#include "dbinc/btree.h"
62
static int __ham_c_chgpg __P((DBC *,
63
db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
64
static int __ham_check_move __P((DBC *, u_int32_t));
65
static int __ham_dcursor __P((DBC *, db_pgno_t, u_int32_t));
66
static int __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
69
* Called from hash_access to add a duplicate key. nval is the new
70
* value that we want to add. The flags correspond to the flag values
71
* to cursor_put indicating where to add the new element.
73
* Case 1: The existing duplicate set already resides on a separate page.
74
* We return and let the common code handle this.
75
* Case 2: The element is small enough to just be added to the existing set.
76
* Case 3: The element is large enough to be a big item, so we're going to
77
* have to push the set onto a new page.
78
* Case 4: The element is large enough to push the duplicate set onto a
81
* PUBLIC: int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *));
84
__ham_add_dup(dbc, nval, flags, pgnop)
94
u_int32_t add_bytes, new_size;
100
hcp = (HASH_CURSOR *)dbc->internal;
102
DB_ASSERT(flags != DB_CURRENT);
104
add_bytes = nval->size +
105
(F_ISSET(nval, DB_DBT_PARTIAL) ? nval->doff : 0);
106
add_bytes = DUP_SIZE(add_bytes);
108
if ((ret = __ham_check_move(dbc, add_bytes)) != 0)
112
* Check if resulting duplicate set is going to need to go
113
* onto a separate duplicate page. If so, convert the
114
* duplicate set and add the new one. After conversion,
115
* hcp->dndx is the first free ndx or the index of the
116
* current pointer into the duplicate set.
118
hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
119
/* Add the len bytes to the current singleton. */
120
if (HPAGE_PTYPE(hk) != H_DUPLICATE)
121
add_bytes += DUP_SIZE(0);
123
LEN_HKEYDATA(dbp, hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)) +
127
* We convert to off-page duplicates if the item is a big item,
128
* the addition of the new item will make the set large, or
129
* if there isn't enough room on this page to add the next item.
131
if (HPAGE_PTYPE(hk) != H_OFFDUP &&
132
(HPAGE_PTYPE(hk) == H_OFFPAGE || ISBIG(hcp, new_size) ||
133
add_bytes > P_FREESPACE(dbp, hcp->page))) {
135
if ((ret = __ham_dup_convert(dbc)) != 0)
137
return (hcp->opd->c_am_put(hcp->opd,
138
NULL, nval, flags, NULL));
141
/* There are two separate cases here: on page and off page. */
142
if (HPAGE_PTYPE(hk) != H_OFFDUP) {
143
if (HPAGE_PTYPE(hk) != H_DUPLICATE) {
145
pval.data = HKEYDATA_DATA(hk);
146
pval.size = LEN_HDATA(dbp, hcp->page, dbp->pgsize,
148
if ((ret = __ham_make_dup(dbp->dbenv,
149
&pval, &tmp_val, &dbc->my_rdata.data,
150
&dbc->my_rdata.ulen)) != 0 || (ret =
151
__ham_replpair(dbc, &tmp_val, 1)) != 0)
153
hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
154
HPAGE_PTYPE(hk) = H_DUPLICATE;
157
* Update the cursor position since we now are in
162
hcp->dup_len = pval.size;
163
hcp->dup_tlen = DUP_SIZE(hcp->dup_len);
166
/* Now make the new entry a duplicate. */
167
if ((ret = __ham_make_dup(dbp->dbenv, nval,
168
&tmp_val, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) != 0)
172
switch (flags) { /* On page. */
176
if (dbp->dup_compare != NULL) {
178
nval, &tmp_val.doff, &cmp, flags);
180
/* dup dups are not supported w/ sorted dups */
182
return (__db_duperr(dbp, flags));
184
hcp->dup_tlen = LEN_HDATA(dbp, hcp->page,
185
dbp->pgsize, hcp->indx);
186
hcp->dup_len = nval->size;
188
if (flags == DB_KEYFIRST)
189
hcp->dup_off = tmp_val.doff = 0;
192
tmp_val.doff = hcp->dup_tlen;
196
tmp_val.doff = hcp->dup_off;
199
tmp_val.doff = hcp->dup_off + DUP_SIZE(hcp->dup_len);
202
/* Add the duplicate. */
203
ret = __ham_replpair(dbc, &tmp_val, 0);
205
ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
209
/* Now, update the cursor if necessary. */
212
hcp->dup_off += DUP_SIZE(hcp->dup_len);
213
hcp->dup_len = nval->size;
214
hcp->dup_tlen += (db_indx_t)DUP_SIZE(nval->size);
219
hcp->dup_tlen += (db_indx_t)DUP_SIZE(nval->size);
220
hcp->dup_len = nval->size;
223
ret = __ham_c_update(dbc, tmp_val.size, 1, 1);
228
* If we get here, then we're on duplicate pages; set pgnop and
229
* return so the common code can handle it.
231
memcpy(pgnop, HOFFDUP_PGNO(H_PAIRDATA(dbp, hcp->page, hcp->indx)),
238
* Convert an on-page set of duplicates to an offpage set of duplicates.
240
* PUBLIC: int __ham_dup_convert __P((DBC *));
243
__ham_dup_convert(dbc)
255
db_indx_t i, len, off;
261
hcp = (HASH_CURSOR *)dbc->internal;
264
* Create a new page for the duplicates.
266
if ((ret = __db_new(dbc,
267
dbp->dup_compare == NULL ? P_LRECNO : P_LDUP, &dp)) != 0)
269
P_INIT(dp, dbp->pgsize,
270
dp->pgno, PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp));
273
* Get the list of cursors that may need to be updated.
275
if ((ret = __ham_get_clist(dbp,
276
PGNO(hcp->page), (u_int32_t)hcp->indx, &hcs)) != 0)
280
* Now put the duplicates onto the new page.
283
switch (HPAGE_PTYPE(H_PAIRDATA(dbp, hcp->page, hcp->indx))) {
285
/* Simple case, one key on page; move it to dup page. */
286
dbt.size = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
287
dbt.data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
288
ret = __db_pitem(dbc,
289
dp, 0, BKEYDATA_SIZE(dbt.size), NULL, &dbt);
292
/* Simple case, one key on page; move it to dup page. */
293
memcpy(&ho, P_ENTRY(dbp, hcp->page, H_DATAINDEX(hcp->indx)),
295
UMRW_SET(bo.unused1);
296
B_TSET(bo.type, ho.type, 0);
297
UMRW_SET(bo.unused2);
300
dbt.size = BOVERFLOW_SIZE;
303
ret = __db_pitem(dbc, dp, 0, dbt.size, &dbt, NULL);
304
finish: if (ret == 0) {
305
if ((ret = mpf->set(mpf, dp, DB_MPOOL_DIRTY)) != 0)
308
/* Update any other cursors. */
309
if (hcs != NULL && DBC_LOGGING(dbc) &&
310
IS_SUBTRANSACTION(dbc->txn)) {
311
if ((ret = __ham_chgpg_log(dbp, dbc->txn,
312
&lsn, 0, DB_HAM_DUP, PGNO(hcp->page),
313
PGNO(dp), hcp->indx, 0)) != 0)
316
for (c = 0; hcs != NULL && hcs[c] != NULL; c++)
317
if ((ret = __ham_dcursor(hcs[c],
323
p = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
325
LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
328
* We need to maintain the duplicate cursor position.
329
* Keep track of where we are in the duplicate set via
330
* the offset, and when it matches the one in the cursor,
331
* set the off-page duplicate cursor index to the current
334
for (off = 0, i = 0; p < pend; i++) {
335
memcpy(&len, p, sizeof(db_indx_t));
337
p += sizeof(db_indx_t);
339
p += len + sizeof(db_indx_t);
340
if ((ret = __db_pitem(dbc, dp,
341
i, BKEYDATA_SIZE(dbt.size), NULL, &dbt)) != 0)
344
/* Update any other cursors */
345
if (hcs != NULL && DBC_LOGGING(dbc) &&
346
IS_SUBTRANSACTION(dbc->txn)) {
347
if ((ret = __ham_chgpg_log(dbp, dbc->txn,
348
&lsn, 0, DB_HAM_DUP, PGNO(hcp->page),
349
PGNO(dp), hcp->indx, i)) != 0)
352
for (c = 0; hcs != NULL && hcs[c] != NULL; c++)
353
if (((HASH_CURSOR *)(hcs[c]->internal))->dup_off
354
== off && (ret = __ham_dcursor(hcs[c],
357
off += len + 2 * sizeof(db_indx_t);
361
ret = __db_pgfmt(dbp->dbenv, (u_long)hcp->pgno);
366
* Now attach this to the source page in place of the old duplicate
370
ret = __ham_move_offpage(dbc, hcp->page,
371
(u_int32_t)H_DATAINDEX(hcp->indx), PGNO(dp));
374
ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
377
mpf->put(mpf, dp, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0)
381
hcp->dup_tlen = hcp->dup_off = hcp->dup_len = 0;
384
__os_free(dbp->dbenv, hcs);
392
* Take a regular dbt and make it into a duplicate item with all the partial
393
* information set appropriately. If the incoming dbt is a partial, assume
394
* we are creating a new entry and make sure that we do any initial padding.
396
* PUBLIC: int __ham_make_dup __P((DB_ENV *,
397
* PUBLIC: const DBT *, DBT *d, void **, u_int32_t *));
400
__ham_make_dup(dbenv, notdup, duplicate, bufp, sizep)
407
db_indx_t tsize, item_size;
411
item_size = (db_indx_t)notdup->size;
412
if (F_ISSET(notdup, DB_DBT_PARTIAL))
413
item_size += notdup->doff;
415
tsize = DUP_SIZE(item_size);
416
if ((ret = __ham_init_dbt(dbenv, duplicate, tsize, bufp, sizep)) != 0)
420
duplicate->flags = notdup->flags;
421
F_SET(duplicate, DB_DBT_PARTIAL);
424
memcpy(p, &item_size, sizeof(db_indx_t));
425
p += sizeof(db_indx_t);
426
if (F_ISSET(notdup, DB_DBT_PARTIAL)) {
427
memset(p, 0, notdup->doff);
430
memcpy(p, notdup->data, notdup->size);
432
memcpy(p, &item_size, sizeof(db_indx_t));
435
duplicate->dlen = notdup->size;
441
* __ham_check_move --
443
* Check if we can do whatever we need to on this page. If not,
444
* then we'll have to move the current element to a new page.
447
__ham_check_move(dbc, add_len)
458
u_int32_t new_datalen, old_len, rectype;
464
hcp = (HASH_CURSOR *)dbc->internal;
466
hk = H_PAIRDATA(dbp, hcp->page, hcp->indx);
469
* If the item is already off page duplicates or an offpage item,
470
* then we know we can do whatever we need to do in-place
472
if (HPAGE_PTYPE(hk) == H_OFFDUP || HPAGE_PTYPE(hk) == H_OFFPAGE)
475
old_len = LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx));
476
new_datalen = old_len - HKEYDATA_SIZE(0) + add_len;
477
if (HPAGE_PTYPE(hk) != H_DUPLICATE)
478
new_datalen += DUP_SIZE(0);
481
* We need to add a new page under two conditions:
482
* 1. The addition makes the total data length cross the BIG
483
* threshold and the OFFDUP structure won't fit on this page.
484
* 2. The addition does not make the total data cross the
485
* threshold, but the new data won't fit on the page.
486
* If neither of these is true, then we can return.
488
if (ISBIG(hcp, new_datalen) && (old_len > HOFFDUP_SIZE ||
489
HOFFDUP_SIZE - old_len <= P_FREESPACE(dbp, hcp->page)))
492
if (!ISBIG(hcp, new_datalen) && add_len <= P_FREESPACE(dbp, hcp->page))
496
* If we get here, then we need to move the item to a new page.
497
* Check if there are more pages in the chain. We now need to
498
* update new_datalen to include the size of both the key and
499
* the data that we need to move.
502
new_datalen = ISBIG(hcp, new_datalen) ?
503
HOFFDUP_SIZE : HKEYDATA_SIZE(new_datalen);
504
new_datalen += LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_KEYINDEX(hcp->indx));
507
for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID;
508
next_pgno = NEXT_PGNO(next_pagep)) {
509
if (next_pagep != NULL &&
510
(ret = mpf->put(mpf, next_pagep, 0)) != 0)
513
if ((ret = mpf->get(mpf,
514
&next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0)
517
if (P_FREESPACE(dbp, next_pagep) >= new_datalen)
521
/* No more pages, add one. */
522
if (next_pagep == NULL && (ret = __ham_add_ovflpage(dbc,
523
hcp->page, 0, &next_pagep)) != 0)
526
/* Add new page at the end of the chain. */
527
if (P_FREESPACE(dbp, next_pagep) < new_datalen && (ret =
528
__ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) {
529
(void)mpf->put(mpf, next_pagep, 0);
533
/* Copy the item to the new page. */
534
if (DBC_LOGGING(dbc)) {
539
H_PAIRKEY(dbp, hcp->page, hcp->indx)) == H_OFFPAGE) {
540
rectype |= PAIR_KEYMASK;
541
k.data = H_PAIRKEY(dbp, hcp->page, hcp->indx);
542
k.size = HOFFPAGE_SIZE;
545
HKEYDATA_DATA(H_PAIRKEY(dbp, hcp->page, hcp->indx));
547
LEN_HKEY(dbp, hcp->page, dbp->pgsize, hcp->indx);
550
if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
551
rectype |= PAIR_DATAMASK;
552
d.data = H_PAIRDATA(dbp, hcp->page, hcp->indx);
553
d.size = HOFFPAGE_SIZE;
555
if (HPAGE_PTYPE(H_PAIRDATA(dbp, hcp->page, hcp->indx))
557
rectype |= PAIR_DUPMASK;
559
HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx));
560
d.size = LEN_HDATA(dbp, hcp->page,
561
dbp->pgsize, hcp->indx);
564
if ((ret = __ham_insdel_log(dbp,
565
dbc->txn, &new_lsn, 0, rectype, PGNO(next_pagep),
566
(u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep),
568
(void)mpf->put(mpf, next_pagep, 0);
572
LSN_NOT_LOGGED(new_lsn);
574
/* Move lsn onto page. */
575
LSN(next_pagep) = new_lsn; /* Structure assignment. */
577
__ham_copy_item(dbp, hcp->page, H_KEYINDEX(hcp->indx), next_pagep);
578
__ham_copy_item(dbp, hcp->page, H_DATAINDEX(hcp->indx), next_pagep);
581
* We've just manually inserted a key and set of data onto
582
* next_pagep; however, it's possible that our caller will
583
* return without further modifying the new page, for instance
584
* if DB_NODUPDATA is set and our new item is a duplicate duplicate.
585
* Thus, to be on the safe side, we need to mark the page dirty
588
* Note that __ham_del_pair should dirty the page we're moving
589
* the items from, so we need only dirty the new page ourselves.
591
if ((ret = mpf->set(mpf, next_pagep, DB_MPOOL_DIRTY)) != 0)
594
/* Update all cursors that used to point to this item. */
595
if ((ret = __ham_c_chgpg(dbc, PGNO(hcp->page), H_KEYINDEX(hcp->indx),
596
PGNO(next_pagep), NUM_ENT(next_pagep) - 2)) != 0)
599
/* Now delete the pair from the current page. */
600
ret = __ham_del_pair(dbc, 0);
603
* __ham_del_pair decremented nelem. This is incorrect; we
604
* manually copied the element elsewhere, so the total number
605
* of elements hasn't changed. Increment it again.
608
* Note that we still have the metadata page pinned, and
609
* __ham_del_pair dirtied it, so we don't need to set the dirty
612
if (!STD_LOCKING(dbc))
616
(void)mpf->put(mpf, hcp->page, DB_MPOOL_DIRTY);
617
hcp->page = next_pagep;
618
hcp->pgno = PGNO(hcp->page);
619
hcp->indx = NUM_ENT(hcp->page) - 2;
620
F_SET(hcp, H_EXPAND);
621
F_CLR(hcp, H_DELETED);
627
* __ham_move_offpage --
628
* Replace an onpage set of duplicates with the OFFDUP structure
629
* that references the duplicate page.
632
* This is really just a special case of __onpage_replace; we should
633
* probably combine them.
637
__ham_move_offpage(dbc, pagep, ndx, pgno)
654
UMRW_SET(od.unused[0]);
655
UMRW_SET(od.unused[1]);
656
UMRW_SET(od.unused[2]);
660
if (DBC_LOGGING(dbc)) {
662
new_dbt.size = HOFFDUP_SIZE;
663
old_dbt.data = P_ENTRY(dbp, pagep, ndx);
664
old_dbt.size = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx);
665
if ((ret = __ham_replace_log(dbp, dbc->txn, &LSN(pagep), 0,
666
PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1,
667
&old_dbt, &new_dbt, 0)) != 0)
670
LSN_NOT_LOGGED(LSN(pagep));
672
shrink = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE;
673
inp = P_INP(dbp, pagep);
677
src = (u_int8_t *)(pagep) + HOFFSET(pagep);
678
memmove(src + shrink, src, inp[ndx] - HOFFSET(pagep));
679
HOFFSET(pagep) += shrink;
681
/* Update index table. */
682
for (i = ndx; i < NUM_ENT(pagep); i++)
686
/* Now copy the offdup entry onto the page. */
687
memcpy(P_ENTRY(dbp, pagep, ndx), &od, HOFFDUP_SIZE);
693
* Locate a particular duplicate in a duplicate set. Make sure that
694
* we exit with the cursor set appropriately.
696
* PUBLIC: void __ham_dsearch
697
* PUBLIC: __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t));
700
__ham_dsearch(dbc, dbt, offp, cmpp, flags)
703
u_int32_t *offp, flags;
710
int (*func) __P((DB *, const DBT *, const DBT *));
714
hcp = (HASH_CURSOR *)dbc->internal;
715
func = dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare;
717
i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0;
718
data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)) + i;
719
hcp->dup_tlen = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx);
720
while (i < hcp->dup_tlen) {
721
memcpy(&len, data, sizeof(db_indx_t));
722
data += sizeof(db_indx_t);
724
cur.size = (u_int32_t)len;
727
* If we find an exact match, we're done. If in a sorted
728
* duplicate set and the item is larger than our test item,
729
* we're done. In the latter case, if permitting partial
730
* matches, it's not a failure.
732
*cmpp = func(dbp, dbt, &cur);
735
if (*cmpp < 0 && dbp->dup_compare != NULL) {
736
if (flags == DB_GET_BOTH_RANGE)
741
i += len + 2 * sizeof(db_indx_t);
742
data += len + sizeof(db_indx_t);
754
* Display the current cursor list.
756
* PUBLIC: void __ham_cprint __P((DBC *));
764
cp = (HASH_CURSOR *)dbc->internal;
766
fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu",
767
P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno,
769
if (F_ISSET(cp, H_DELETED))
770
fprintf(stderr, " (deleted)");
771
fprintf(stderr, "\n");
778
* Create an off page duplicate cursor for this cursor.
781
__ham_dcursor(dbc, pgno, indx)
792
hcp = (HASH_CURSOR *)dbc->internal;
794
if ((ret = __db_c_newopd(dbc, pgno, hcp->opd, &hcp->opd)) != 0)
797
dcp = (BTREE_CURSOR *)hcp->opd->internal;
801
if (dbp->dup_compare == NULL) {
803
* Converting to off-page Recno trees is tricky. The
804
* record number for the cursor is the index + 1 (to
805
* convert to 1-based record numbers).
807
dcp->recno = indx + 1;
811
* Transfer the deleted flag from the top-level cursor to the
814
if (F_ISSET(hcp, H_DELETED)) {
815
F_SET(dcp, C_DELETED);
816
F_CLR(hcp, H_DELETED);
824
* Adjust the cursors after moving an item to a new page. We only
825
* move cursors that are pointing at this one item and are not
826
* deleted; since we only touch non-deleted cursors, and since
827
* (by definition) no item existed at the pgno/indx we're moving the
828
* item to, we're guaranteed that all the cursors we affect here or
829
* on abort really do refer to this one item.
832
__ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index)
834
db_pgno_t old_pgno, new_pgno;
835
u_int32_t old_index, new_index;
848
my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL;
851
MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
852
for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
853
ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
854
ldbp = LIST_NEXT(ldbp, dblistlinks)) {
855
MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
856
for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
857
cp = TAILQ_NEXT(cp, links)) {
858
if (cp == dbc || cp->dbtype != DB_HASH)
861
hcp = (HASH_CURSOR *)cp->internal;
864
* If a cursor is deleted, it doesn't refer to this
865
* item--it just happens to have the same indx, but
866
* it points to a former neighbor. Don't move it.
868
if (F_ISSET(hcp, H_DELETED))
871
if (hcp->pgno == old_pgno) {
872
if (hcp->indx == old_index) {
873
hcp->pgno = new_pgno;
874
hcp->indx = new_index;
877
if (my_txn != NULL && cp->txn != my_txn)
881
MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
883
MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
885
if (found != 0 && DBC_LOGGING(dbc)) {
886
if ((ret = __ham_chgpg_log(dbp, my_txn, &lsn, 0, DB_HAM_CHGPG,
887
old_pgno, new_pgno, old_index, new_index)) != 0)