📄 hash_page.c
字号:
end = (u_int8_t *)tdata.data + tdata.size; src = (u_int8_t *)tdata.data + dbt->doff + dbt->dlen; if (src < end && tdata.size > dbt->doff + dbt->dlen) { len = tdata.size - dbt->doff - dbt->dlen; dest = src + change; memmove(dest, src, len); } memcpy((u_int8_t *)tdata.data + dbt->doff, dbt->data, dbt->size); tdata.size += change; /* Now add the pair. */ ret = __ham_add_el(dbc, &tmp, &tdata, type); __os_free(dbenv, memp); } F_SET(hcp, dup_flag);err: return (ret); } /* * Set up pointer into existing data. Do it before the log * message so we can use it inside of the log setup. */ beg = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)); beg += dbt->doff; /* * If we are going to have to move bytes at all, figure out * all the parameters here. Then log the call before moving * anything around. */ if (DBC_LOGGING(dbc)) { old_dbt.data = beg; old_dbt.size = dbt->dlen; if ((ret = __ham_replace_log(dbp, dbc->txn, &new_lsn, 0, PGNO(hcp->page), (u_int32_t)H_DATAINDEX(hcp->indx), &LSN(hcp->page), (u_int32_t)dbt->doff, &old_dbt, dbt, make_dup)) != 0) return (ret); } else LSN_NOT_LOGGED(new_lsn); LSN(hcp->page) = new_lsn; /* Structure assignment. */ __ham_onpage_replace(dbp, hcp->page, (u_int32_t)H_DATAINDEX(hcp->indx), (int32_t)dbt->doff, change, dbt); return (0);}/* * Replace data on a page with new data, possibly growing or shrinking what's * there. This is called on two different occasions. On one (from replpair) * we are interested in changing only the data. On the other (from recovery) * we are replacing the entire data (header and all) with a new element. In * the latter case, the off argument is negative. * pagep: the page that we're changing * ndx: page index of the element that is growing/shrinking. * off: Offset at which we are beginning the replacement. * change: the number of bytes (+ or -) that the element is growing/shrinking. * dbt: the new data that gets written at beg. * * PUBLIC: void __ham_onpage_replace __P((DB *, PAGE *, u_int32_t, * PUBLIC: int32_t, int32_t, DBT *)); */void__ham_onpage_replace(dbp, pagep, ndx, off, change, dbt) DB *dbp; PAGE *pagep; u_int32_t ndx; int32_t off; int32_t change; DBT *dbt;{ db_indx_t i, *inp; int32_t len; size_t pgsize; u_int8_t *src, *dest; int zero_me; pgsize = dbp->pgsize; inp = P_INP(dbp, pagep); if (change != 0) { zero_me = 0; src = (u_int8_t *)(pagep) + HOFFSET(pagep); if (off < 0) len = inp[ndx] - HOFFSET(pagep); else if ((u_int32_t)off >= LEN_HKEYDATA(dbp, pagep, pgsize, ndx)) { len = (int32_t)(HKEYDATA_DATA(P_ENTRY(dbp, pagep, ndx)) + LEN_HKEYDATA(dbp, pagep, pgsize, ndx) - src); zero_me = 1; } else len = (int32_t)( (HKEYDATA_DATA(P_ENTRY(dbp, pagep, ndx)) + off) - src); dest = src - change; memmove(dest, src, len); if (zero_me) memset(dest + len, 0, change); /* Now update the indices. */ for (i = ndx; i < NUM_ENT(pagep); i++) inp[i] -= change; HOFFSET(pagep) -= change; } if (off >= 0) memcpy(HKEYDATA_DATA(P_ENTRY(dbp, pagep, ndx)) + off, dbt->data, dbt->size); else memcpy(P_ENTRY(dbp, pagep, ndx), dbt->data, dbt->size);}/* * PUBLIC: int __ham_split_page __P((DBC *, u_int32_t, u_int32_t)); */int__ham_split_page(dbc, obucket, nbucket) DBC *dbc; u_int32_t obucket, nbucket;{ DB *dbp; DBC **carray; DBT key, page_dbt; DB_ENV *dbenv; DB_LOCK block; DB_LSN new_lsn; DB_MPOOLFILE *mpf; HASH_CURSOR *hcp, *cp; PAGE **pp, *old_pagep, *temp_pagep, *new_pagep; db_indx_t n; db_pgno_t bucket_pgno, npgno, next_pgno; u_int32_t big_len, len; int found, i, ret, t_ret; void *big_buf; dbp = dbc->dbp; dbenv = dbp->dbenv; mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; temp_pagep = old_pagep = new_pagep = NULL; carray = NULL; LOCK_INIT(block); bucket_pgno = BUCKET_TO_PAGE(hcp, obucket); if ((ret = __db_lget(dbc, 0, bucket_pgno, DB_LOCK_WRITE, 0, &block)) != 0) goto err; if ((ret = mpf->get(mpf, &bucket_pgno, DB_MPOOL_CREATE, &old_pagep)) != 0) goto err; /* Properly initialize the new bucket page. */ npgno = BUCKET_TO_PAGE(hcp, nbucket); if ((ret = mpf->get(mpf, &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0) goto err; P_INIT(new_pagep, dbp->pgsize, npgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH); temp_pagep = hcp->split_buf; memcpy(temp_pagep, old_pagep, dbp->pgsize); if (DBC_LOGGING(dbc)) { page_dbt.size = dbp->pgsize; page_dbt.data = old_pagep; if ((ret = __ham_splitdata_log(dbp, dbc->txn, &new_lsn, 0, SPLITOLD, PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0) goto err; } else LSN_NOT_LOGGED(new_lsn); LSN(old_pagep) = new_lsn; /* Structure assignment. */ P_INIT(old_pagep, dbp->pgsize, PGNO(old_pagep), PGNO_INVALID, PGNO_INVALID, 0, P_HASH); big_len = 0; big_buf = NULL; key.flags = 0; while (temp_pagep != NULL) { if ((ret = __ham_get_clist(dbp, PGNO(temp_pagep), NDX_INVALID, &carray)) != 0) goto err; for (n = 0; n < (db_indx_t)NUM_ENT(temp_pagep); n += 2) { if ((ret = __db_ret(dbp, temp_pagep, H_KEYINDEX(n), &key, &big_buf, &big_len)) != 0) goto err; if (__ham_call_hash(dbc, key.data, key.size) == obucket) pp = &old_pagep; else pp = &new_pagep; /* * Figure out how many bytes we need on the new * page to store the key/data pair. */ len = LEN_HITEM(dbp, temp_pagep, dbp->pgsize, H_DATAINDEX(n)) + LEN_HITEM(dbp, temp_pagep, dbp->pgsize, H_KEYINDEX(n)) + 2 * sizeof(db_indx_t); if (P_FREESPACE(dbp, *pp) < len) { if (DBC_LOGGING(dbc)) { page_dbt.size = dbp->pgsize; page_dbt.data = *pp; if ((ret = __ham_splitdata_log(dbp, dbc->txn, &new_lsn, 0, SPLITNEW, PGNO(*pp), &page_dbt, &LSN(*pp))) != 0) goto err; } else LSN_NOT_LOGGED(new_lsn); LSN(*pp) = new_lsn; if ((ret = __ham_add_ovflpage(dbc, *pp, 1, pp)) != 0) goto err; } /* Check if we need to update a cursor. */ if (carray != NULL) { found = 0; for (i = 0; carray[i] != NULL; i++) { cp = (HASH_CURSOR *)carray[i]->internal; if (cp->pgno == PGNO(temp_pagep) && cp->indx == n) { cp->pgno = PGNO(*pp); cp->indx = NUM_ENT(*pp); found = 1; } } if (found && DBC_LOGGING(dbc) && IS_SUBTRANSACTION(dbc->txn)) { if ((ret = __ham_chgpg_log(dbp, dbc->txn, &new_lsn, 0, DB_HAM_SPLIT, PGNO(temp_pagep), PGNO(*pp), n, NUM_ENT(*pp))) != 0) goto err; } } __ham_copy_item(dbp, temp_pagep, H_KEYINDEX(n), *pp); __ham_copy_item(dbp, temp_pagep, H_DATAINDEX(n), *pp); } next_pgno = NEXT_PGNO(temp_pagep); /* Clear temp_page; if it's a link overflow page, free it. */ if (PGNO(temp_pagep) != bucket_pgno && (ret = __db_free(dbc, temp_pagep)) != 0) { temp_pagep = NULL; goto err; } if (next_pgno == PGNO_INVALID) temp_pagep = NULL; else if ((ret = mpf->get( mpf, &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0) goto err; if (temp_pagep != NULL) { if (DBC_LOGGING(dbc)) { page_dbt.size = dbp->pgsize; page_dbt.data = temp_pagep; if ((ret = __ham_splitdata_log(dbp, dbc->txn, &new_lsn, 0, SPLITOLD, PGNO(temp_pagep), &page_dbt, &LSN(temp_pagep))) != 0) goto err; } else LSN_NOT_LOGGED(new_lsn); LSN(temp_pagep) = new_lsn; } if (carray != NULL) /* We never knew its size. */ __os_free(dbenv, carray); carray = NULL; } if (big_buf != NULL) __os_free(dbenv, big_buf); /* * If the original bucket spanned multiple pages, then we've got * a pointer to a page that used to be on the bucket chain. It * should be deleted. */ if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno && (ret = __db_free(dbc, temp_pagep)) != 0) { temp_pagep = NULL; goto err; } /* * Write new buckets out. */ if (DBC_LOGGING(dbc)) { page_dbt.size = dbp->pgsize; page_dbt.data = old_pagep; if ((ret = __ham_splitdata_log(dbp, dbc->txn, &new_lsn, 0, SPLITNEW, PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0) goto err; LSN(old_pagep) = new_lsn; page_dbt.data = new_pagep; if ((ret = __ham_splitdata_log(dbp, dbc->txn, &new_lsn, 0, SPLITNEW, PGNO(new_pagep), &page_dbt, &LSN(new_pagep))) != 0) goto err; LSN(new_pagep) = new_lsn; } else { LSN_NOT_LOGGED(LSN(old_pagep)); LSN_NOT_LOGGED(LSN(new_pagep)); } ret = mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY); if ((t_ret = mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) ret = t_ret; if (0) {err: if (old_pagep != NULL) (void)mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY); if (new_pagep != NULL) (void)mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY); if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno) (void)mpf->put(mpf, temp_pagep, DB_MPOOL_DIRTY); } if (LOCK_ISSET(block)) __TLPUT(dbc, block); if (carray != NULL) /* We never knew its size. */ __os_free(dbenv, carray); return (ret);}/* * Add the given pair to the page. The page in question may already be * held (i.e. it was already gotten). If it is, then the page is passed * in via the pagep parameter. On return, pagep will contain the page * to which we just added something. This allows us to link overflow * pages and return the new page having correctly put the last page. * * PUBLIC: int __ham_add_el __P((DBC *, const DBT *, const DBT *, int)); */int__ham_add_el(dbc, key, val, type) DBC *dbc; const DBT *key, *val; int type;{ const DBT *pkey, *pdata; DB *dbp; DBT key_dbt, data_dbt; DB_LSN new_lsn; DB_MPOOLFILE *mpf; HASH_CURSOR *hcp; HOFFPAGE doff, koff; db_pgno_t next_pgno, pgno; u_int32_t data_size, key_size, pairsize, rectype; int do_expand, is_keybig, is_databig, ret; int key_type, data_type; dbp = dbc->dbp; mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; do_expand = 0; pgno = hcp->seek_found_page != PGNO_INVALID ? hcp->seek_found_page : hcp->pgno; if (hcp->page == NULL && (ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) return (ret); key_size = HKEYDATA_PSIZE(key->size); data_size = HKEYDATA_PSIZE(val->size); is_keybig = ISBIG(hcp, key->size); is_databig = ISBIG(hcp, val->size); if (is_keybig) key_size = HOFFPAGE_PSIZE; if (is_databig) data_size = HOFFPAGE_PSIZE; pairsize = key_size + data_size; /* Advance to first page in chain with room for item. */ while (H_NUMPAIRS(hcp->page) && NEXT_PGNO(hcp->page) != PGNO_INVALID) { /* * This may not be the end of the chain, but the pair may fit * anyway. Check if it's a bigpair that fits or a regular * pair that fits. */ if (P_FREESPACE(dbp, hcp->page) >= pairsize) break; next_pgno = NEXT_PGNO(hcp->page); if ((ret = __ham_next_cpage(dbc, next_pgno, 0)) != 0) return (ret); } /* * Check if we need to allocate a new page. */ if (P_FREESPACE(dbp, hcp->page) < pairsize) { do_expand = 1; if ((ret = __ham_add_ovflpage(dbc, (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) != 0) return (ret); hcp->pgno = PGNO(hcp->page); } /* * Update cursor. */ hcp->indx = NUM_ENT(hcp->page); F_CLR(hcp, H_DELETED); if (is_keybig) { koff.type = H_OFFPAGE; UMRW_SET(koff.unused[0]); UMRW_SET(koff.unused[1]); UMRW_SET(koff.unused[2]); if ((ret = __db_poff(dbc, key, &koff.pgno)) != 0) return (ret); koff.tlen = key->size; key_dbt.data = &koff; key_dbt.size = sizeof(koff); pkey = &key_dbt; key_type = H_OFFPAGE; } else { pkey = key; key_type = H_KEYDATA; } if (is_databig) { doff.type = H_OFFPAGE; UMRW_SET(doff.unused[0]); UMRW_SET(doff.unused[1]); UMRW_SET(doff.unused[2]); if ((ret = __db_poff(dbc, val, &doff.pgno)) != 0) return (ret); doff.tlen = val->size; data_dbt.data = &doff; data_dbt.size = sizeof(doff); pdata = &data_dbt; data_type = H_OFFPAGE; } else { pdata = val; data_type = type; } if (DBC_LOGGING(dbc)) { rectype = PUTPAIR; if (is_databig) rectype |= PAIR_DATAMASK; if (is_keybig) rectype |= PAIR_KEYMASK; if (type == H_DUPLICATE) rectype |= PAIR_DUPMASK; if ((ret = __ham_insdel_log(dbp, dbc->txn, &new_lsn, 0, rectype, PGNO(hcp->page), (u_int32_t)NUM_ENT(hcp->page), &LSN(hcp->page), pkey, pdata)) != 0) return (ret);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -