📄 hash_dup.c
字号:
__ham_check_move(dbc, add_len) DBC *dbc; u_int32_t add_len;{ DB *dbp; DBT k, d; DB_LSN new_lsn; DB_MPOOLFILE *mpf; HASH_CURSOR *hcp; PAGE *next_pagep; db_pgno_t next_pgno; u_int32_t new_datalen, old_len, rectype; u_int8_t *hk; int ret; dbp = dbc->dbp; mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; hk = H_PAIRDATA(dbp, hcp->page, hcp->indx); /* * If the item is already off page duplicates or an offpage item, * then we know we can do whatever we need to do in-place */ if (HPAGE_PTYPE(hk) == H_OFFDUP || HPAGE_PTYPE(hk) == H_OFFPAGE) return (0); old_len = LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)); new_datalen = old_len - HKEYDATA_SIZE(0) + add_len; if (HPAGE_PTYPE(hk) != H_DUPLICATE) new_datalen += DUP_SIZE(0); /* * We need to add a new page under two conditions: * 1. The addition makes the total data length cross the BIG * threshold and the OFFDUP structure won't fit on this page. * 2. The addition does not make the total data cross the * threshold, but the new data won't fit on the page. * If neither of these is true, then we can return. */ if (ISBIG(hcp, new_datalen) && (old_len > HOFFDUP_SIZE || HOFFDUP_SIZE - old_len <= P_FREESPACE(dbp, hcp->page))) return (0); if (!ISBIG(hcp, new_datalen) && add_len <= P_FREESPACE(dbp, hcp->page)) return (0); /* * If we get here, then we need to move the item to a new page. * Check if there are more pages in the chain. We now need to * update new_datalen to include the size of both the key and * the data that we need to move. */ new_datalen = ISBIG(hcp, new_datalen) ? HOFFDUP_SIZE : HKEYDATA_SIZE(new_datalen); new_datalen += LEN_HITEM(dbp, hcp->page, dbp->pgsize, H_KEYINDEX(hcp->indx)); next_pagep = NULL; for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID; next_pgno = NEXT_PGNO(next_pagep)) { if (next_pagep != NULL && (ret = mpf->put(mpf, next_pagep, 0)) != 0) return (ret); if ((ret = mpf->get(mpf, &next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0) return (ret); if (P_FREESPACE(dbp, next_pagep) >= new_datalen) break; } /* No more pages, add one. */ if (next_pagep == NULL && (ret = __ham_add_ovflpage(dbc, hcp->page, 0, &next_pagep)) != 0) return (ret); /* Add new page at the end of the chain. */ if (P_FREESPACE(dbp, next_pagep) < new_datalen && (ret = __ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) { (void)mpf->put(mpf, next_pagep, 0); return (ret); } /* Copy the item to the new page. */ if (DBC_LOGGING(dbc)) { rectype = PUTPAIR; k.flags = 0; d.flags = 0; if (HPAGE_PTYPE( H_PAIRKEY(dbp, hcp->page, hcp->indx)) == H_OFFPAGE) { rectype |= PAIR_KEYMASK; k.data = H_PAIRKEY(dbp, hcp->page, hcp->indx); k.size = HOFFPAGE_SIZE; } else { k.data = HKEYDATA_DATA(H_PAIRKEY(dbp, hcp->page, hcp->indx)); k.size = LEN_HKEY(dbp, hcp->page, dbp->pgsize, hcp->indx); } if (HPAGE_PTYPE(hk) == H_OFFPAGE) { rectype |= PAIR_DATAMASK; d.data = H_PAIRDATA(dbp, hcp->page, hcp->indx); d.size = HOFFPAGE_SIZE; } else { if (HPAGE_PTYPE(H_PAIRDATA(dbp, hcp->page, hcp->indx)) == H_DUPLICATE) rectype |= PAIR_DUPMASK; d.data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)); d.size = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx); } if ((ret = __ham_insdel_log(dbp, dbc->txn, &new_lsn, 0, rectype, PGNO(next_pagep), (u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep), &k, &d)) != 0) { (void)mpf->put(mpf, next_pagep, 0); return (ret); } } else LSN_NOT_LOGGED(new_lsn); /* Move lsn onto page. */ LSN(next_pagep) = new_lsn; /* Structure assignment. */ __ham_copy_item(dbp, hcp->page, H_KEYINDEX(hcp->indx), next_pagep); __ham_copy_item(dbp, hcp->page, H_DATAINDEX(hcp->indx), next_pagep); /* * We've just manually inserted a key and set of data onto * next_pagep; however, it's possible that our caller will * return without further modifying the new page, for instance * if DB_NODUPDATA is set and our new item is a duplicate duplicate. * Thus, to be on the safe side, we need to mark the page dirty * here. [#2996] * * Note that __ham_del_pair should dirty the page we're moving * the items from, so we need only dirty the new page ourselves. */ if ((ret = mpf->set(mpf, next_pagep, DB_MPOOL_DIRTY)) != 0) goto out; /* Update all cursors that used to point to this item. */ if ((ret = __ham_c_chgpg(dbc, PGNO(hcp->page), H_KEYINDEX(hcp->indx), PGNO(next_pagep), NUM_ENT(next_pagep) - 2)) != 0) goto out; /* Now delete the pair from the current page. */ ret = __ham_del_pair(dbc, 0); /* * __ham_del_pair decremented nelem. This is incorrect; we * manually copied the element elsewhere, so the total number * of elements hasn't changed. Increment it again. * * !!! * Note that we still have the metadata page pinned, and * __ham_del_pair dirtied it, so we don't need to set the dirty * flag again. */ if (!STD_LOCKING(dbc)) hcp->hdr->nelem++;out: (void)mpf->put(mpf, hcp->page, DB_MPOOL_DIRTY); hcp->page = next_pagep; hcp->pgno = PGNO(hcp->page); hcp->indx = NUM_ENT(hcp->page) - 2; F_SET(hcp, H_EXPAND); F_CLR(hcp, H_DELETED); return (ret);}/* * __ham_move_offpage -- * Replace an onpage set of duplicates with the OFFDUP structure * that references the duplicate page. * * XXX * This is really just a special case of __onpage_replace; we should * probably combine them. * */static int__ham_move_offpage(dbc, pagep, ndx, pgno) DBC *dbc; PAGE *pagep; u_int32_t ndx; db_pgno_t pgno;{ DB *dbp; DBT new_dbt; DBT old_dbt; HOFFDUP od; db_indx_t i, *inp; int32_t shrink; u_int8_t *src; int ret; dbp = dbc->dbp; od.type = H_OFFDUP; UMRW_SET(od.unused[0]); UMRW_SET(od.unused[1]); UMRW_SET(od.unused[2]); od.pgno = pgno; ret = 0; if (DBC_LOGGING(dbc)) { new_dbt.data = &od; new_dbt.size = HOFFDUP_SIZE; old_dbt.data = P_ENTRY(dbp, pagep, ndx); old_dbt.size = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx); if ((ret = __ham_replace_log(dbp, dbc->txn, &LSN(pagep), 0, PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1, &old_dbt, &new_dbt, 0)) != 0) return (ret); } else LSN_NOT_LOGGED(LSN(pagep)); shrink = LEN_HITEM(dbp, pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE; inp = P_INP(dbp, pagep); if (shrink != 0) { /* Copy data. */ src = (u_int8_t *)(pagep) + HOFFSET(pagep); memmove(src + shrink, src, inp[ndx] - HOFFSET(pagep)); HOFFSET(pagep) += shrink; /* Update index table. */ for (i = ndx; i < NUM_ENT(pagep); i++) inp[i] += shrink; } /* Now copy the offdup entry onto the page. */ memcpy(P_ENTRY(dbp, pagep, ndx), &od, HOFFDUP_SIZE); return (ret);}/* * __ham_dsearch: * Locate a particular duplicate in a duplicate set. Make sure that * we exit with the cursor set appropriately. * * PUBLIC: void __ham_dsearch * PUBLIC: __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t)); */void__ham_dsearch(dbc, dbt, offp, cmpp, flags) DBC *dbc; DBT *dbt; u_int32_t *offp, flags; int *cmpp;{ DB *dbp; HASH_CURSOR *hcp; DBT cur; db_indx_t i, len; int (*func) __P((DB *, const DBT *, const DBT *)); u_int8_t *data; dbp = dbc->dbp; hcp = (HASH_CURSOR *)dbc->internal; func = dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare; i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0; data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)) + i; hcp->dup_tlen = LEN_HDATA(dbp, hcp->page, dbp->pgsize, hcp->indx); while (i < hcp->dup_tlen) { memcpy(&len, data, sizeof(db_indx_t)); data += sizeof(db_indx_t); cur.data = data; cur.size = (u_int32_t)len; /* * If we find an exact match, we're done. If in a sorted * duplicate set and the item is larger than our test item, * we're done. In the latter case, if permitting partial * matches, it's not a failure. */ *cmpp = func(dbp, dbt, &cur); if (*cmpp == 0) break; if (*cmpp < 0 && dbp->dup_compare != NULL) { if (flags == DB_GET_BOTH_RANGE) *cmpp = 0; break; } i += len + 2 * sizeof(db_indx_t); data += len + sizeof(db_indx_t); } *offp = i; hcp->dup_off = i; hcp->dup_len = len; F_SET(hcp, H_ISDUP);}#ifdef DEBUG/* * __ham_cprint -- * Display the current cursor list. * * PUBLIC: void __ham_cprint __P((DBC *)); */void__ham_cprint(dbc) DBC *dbc;{ HASH_CURSOR *cp; cp = (HASH_CURSOR *)dbc->internal; fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu", P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno, (u_long)cp->indx); if (F_ISSET(cp, H_DELETED)) fprintf(stderr, " (deleted)"); fprintf(stderr, "\n");}#endif /* DEBUG *//* * __ham_dcursor -- * * Create an off page duplicate cursor for this cursor. */static int__ham_dcursor(dbc, pgno, indx) DBC *dbc; db_pgno_t pgno; u_int32_t indx;{ DB *dbp; HASH_CURSOR *hcp; BTREE_CURSOR *dcp; int ret; dbp = dbc->dbp; hcp = (HASH_CURSOR *)dbc->internal; if ((ret = __db_c_newopd(dbc, pgno, hcp->opd, &hcp->opd)) != 0) return (ret); dcp = (BTREE_CURSOR *)hcp->opd->internal; dcp->pgno = pgno; dcp->indx = indx; if (dbp->dup_compare == NULL) { /* * Converting to off-page Recno trees is tricky. The * record number for the cursor is the index + 1 (to * convert to 1-based record numbers). */ dcp->recno = indx + 1; } /* * Transfer the deleted flag from the top-level cursor to the * created one. */ if (F_ISSET(hcp, H_DELETED)) { F_SET(dcp, C_DELETED); F_CLR(hcp, H_DELETED); } return (0);}/* * __ham_c_chgpg -- * Adjust the cursors after moving an item to a new page. We only * move cursors that are pointing at this one item and are not * deleted; since we only touch non-deleted cursors, and since * (by definition) no item existed at the pgno/indx we're moving the * item to, we're guaranteed that all the cursors we affect here or * on abort really do refer to this one item. */static int__ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index) DBC *dbc; db_pgno_t old_pgno, new_pgno; u_int32_t old_index, new_index;{ DB *dbp, *ldbp; DB_ENV *dbenv; DB_LSN lsn; DB_TXN *my_txn; DBC *cp; HASH_CURSOR *hcp; int found, ret; dbp = dbc->dbp; dbenv = dbp->dbenv; my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; found = 0; MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; ldbp = LIST_NEXT(ldbp, dblistlinks)) { MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; cp = TAILQ_NEXT(cp, links)) { if (cp == dbc || cp->dbtype != DB_HASH) continue; hcp = (HASH_CURSOR *)cp->internal; /* * If a cursor is deleted, it doesn't refer to this * item--it just happens to have the same indx, but * it points to a former neighbor. Don't move it. */ if (F_ISSET(hcp, H_DELETED)) continue; if (hcp->pgno == old_pgno) { if (hcp->indx == old_index) { hcp->pgno = new_pgno; hcp->indx = new_index; } else continue; if (my_txn != NULL && cp->txn != my_txn) found = 1; } } MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); } MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); if (found != 0 && DBC_LOGGING(dbc)) { if ((ret = __ham_chgpg_log(dbp, my_txn, &lsn, 0, DB_HAM_CHGPG, old_pgno, new_pgno, old_index, new_index)) != 0) return (ret); } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -