📄 hash.c
字号:
nval->doff + nval->dlen, len); p += len; } /* Final size. */ memcpy(p, &newsize, sizeof(db_indx_t)); /* * Make sure that the caller isn't corrupting * the sort order. */ if (dbp->dup_compare != NULL) { tmp_val2.data = (u_int8_t *)newrec + sizeof(db_indx_t); tmp_val2.size = newsize; if (dbp->dup_compare( dbp, &tmp_val, &tmp_val2) != 0) { (void)__os_free(dbenv, newrec); return (__db_duperr(dbp, flags)); } } tmp_val2.data = newrec; tmp_val2.size = DUP_SIZE(newsize); tmp_val2.doff = hcp->dup_off; tmp_val2.dlen = DUP_SIZE(hcp->dup_len); ret = __ham_replpair(dbc, &tmp_val2, 0); (void)__os_free(dbenv, newrec); /* Update cursor */ if (ret != 0) return (ret); if (newsize > nondup_size) hcp->dup_tlen += (newsize - nondup_size); else hcp->dup_tlen -= (nondup_size - newsize); hcp->dup_len = DUP_SIZE(newsize); return (0); } else { /* Check whether we need to convert to off page. */ if (ISBIG(hcp, hcp->dup_tlen - hcp->dup_len + nval->size)) { if ((ret = __ham_dup_convert(dbc)) != 0) return (ret); return (hcp->opd->c_am_put(hcp->opd, NULL, nval, flags, NULL)); } /* Make sure we maintain sort order. */ if (dbp->dup_compare != NULL) { tmp_val2.data = HKEYDATA_DATA(H_PAIRDATA(dbp, hcp->page, hcp->indx)) + hcp->dup_off + sizeof(db_indx_t); tmp_val2.size = hcp->dup_len; if (dbp->dup_compare(dbp, nval, &tmp_val2) != 0) return (EINVAL); } /* Overwriting a complete duplicate. */ if ((ret = __ham_make_dup(dbp->dbenv, nval, &tmp_val, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) != 0) return (ret); /* Now fix what we are replacing. */ tmp_val.doff = hcp->dup_off; tmp_val.dlen = DUP_SIZE(hcp->dup_len); /* Update cursor */ if (nval->size > hcp->dup_len) hcp->dup_tlen += (nval->size - hcp->dup_len); else hcp->dup_tlen -= (hcp->dup_len - nval->size); hcp->dup_len = (db_indx_t)DUP_SIZE(nval->size); } myval = &tmp_val; } else if (!F_ISSET(nval, DB_DBT_PARTIAL)) { /* Put/overwrite */ memcpy(&tmp_val, nval, sizeof(*nval)); F_SET(&tmp_val, DB_DBT_PARTIAL); tmp_val.doff = 0; hk = H_PAIRDATA(dbp, hcp->page, hcp->indx); if (HPAGE_PTYPE(hk) == H_OFFPAGE) memcpy(&tmp_val.dlen, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); else tmp_val.dlen = LEN_HDATA(dbp, hcp->page, hcp->hdr->dbmeta.pagesize, hcp->indx); myval = &tmp_val; } else /* Regular partial put */ myval = nval; return (__ham_replpair(dbc, myval, 0));}/* * Given a key and a cursor, sets the cursor to the page/ndx on which * the key resides. If the key is found, the cursor H_OK flag is set * and the pagep, bndx, pgno (dpagep, dndx, dpgno) fields are set. * If the key is not found, the H_OK flag is not set. If the sought * field is non-0, the pagep, bndx, pgno (dpagep, dndx, dpgno) fields * are set indicating where an add might take place. If it is 0, * non of the cursor pointer field are valid. */static int__ham_lookup(dbc, key, sought, mode, pgnop) DBC *dbc; const DBT *key; u_int32_t sought; db_lockmode_t mode; db_pgno_t *pgnop;{ DB *dbp; HASH_CURSOR *hcp; db_pgno_t pgno; u_int32_t tlen; int match, ret; u_int8_t *hk, *dk; dbp = dbc->dbp; hcp = (HASH_CURSOR *)dbc->internal; /* * Set up cursor so that we're looking for space to add an item * as we cycle through the pages looking for the key. */ if ((ret = __ham_item_reset(dbc)) != 0) return (ret); hcp->seek_size = sought; hcp->bucket = __ham_call_hash(dbc, (u_int8_t *)key->data, key->size); hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); for (;;) { *pgnop = PGNO_INVALID; if ((ret = __ham_item_next(dbc, mode, pgnop)) != 0) return (ret); if (F_ISSET(hcp, H_NOMORE)) break; hk = H_PAIRKEY(dbp, hcp->page, hcp->indx); switch (HPAGE_PTYPE(hk)) { case H_OFFPAGE: memcpy(&tlen, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); if (tlen == key->size) { memcpy(&pgno, HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); if ((ret = __db_moff(dbp, key, pgno, tlen, NULL, &match)) != 0) return (ret); if (match == 0) goto found_key; } break; case H_KEYDATA: if (key->size == LEN_HKEY(dbp, hcp->page, dbp->pgsize, hcp->indx) && memcmp(key->data, HKEYDATA_DATA(hk), key->size) == 0) { /* Found the key, check for data type. */found_key: F_SET(hcp, H_OK); dk = H_PAIRDATA(dbp, hcp->page, hcp->indx); if (HPAGE_PTYPE(dk) == H_OFFDUP) memcpy(pgnop, HOFFDUP_PGNO(dk), sizeof(db_pgno_t)); return (0); } break; case H_DUPLICATE: case H_OFFDUP: /* * These are errors because keys are never * duplicated, only data items are. */ return (__db_pgfmt(dbp->dbenv, PGNO(hcp->page))); } } /* * Item was not found. */ if (sought != 0) return (ret); return (ret);}/* * __ham_init_dbt -- * Initialize a dbt using some possibly already allocated storage * for items. * * PUBLIC: int __ham_init_dbt __P((DB_ENV *, * PUBLIC: DBT *, u_int32_t, void **, u_int32_t *)); */int__ham_init_dbt(dbenv, dbt, size, bufp, sizep) DB_ENV *dbenv; DBT *dbt; u_int32_t size; void **bufp; u_int32_t *sizep;{ int ret; memset(dbt, 0, sizeof(*dbt)); if (*sizep < size) { if ((ret = __os_realloc(dbenv, size, bufp)) != 0) { *sizep = 0; return (ret); } *sizep = size; } dbt->data = *bufp; dbt->size = size; return (0);}/* * Adjust the cursor after an insert or delete. The cursor passed is * the one that was operated upon; we just need to check any of the * others. * * len indicates the length of the item added/deleted * add indicates if the item indicated by the cursor has just been * added (add == 1) or deleted (add == 0). * dup indicates if the addition occurred into a duplicate set. * * PUBLIC: int __ham_c_update * PUBLIC: __P((DBC *, u_int32_t, int, int)); */int__ham_c_update(dbc, len, add, is_dup) DBC *dbc; u_int32_t len; int add, is_dup;{ DB *dbp, *ldbp; DBC *cp; DB_ENV *dbenv; DB_LSN lsn; DB_TXN *my_txn; HASH_CURSOR *hcp, *lcp; int found, ret; u_int32_t order; dbp = dbc->dbp; dbenv = dbp->dbenv; hcp = (HASH_CURSOR *)dbc->internal; /* * Adjustment will only be logged if this is a subtransaction. * Only subtransactions can abort and effect their parent * transactions cursors. */ my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; found = 0; MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); /* * Calculate the order of this deleted record. * This will be one greater than any cursor that is pointing * at this record and already marked as deleted. */ order = 0; if (!add) { order = 1; 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; lcp = (HASH_CURSOR *)cp->internal; if (F_ISSET(lcp, H_DELETED) && hcp->pgno == lcp->pgno && hcp->indx == lcp->indx && order <= lcp->order && (!is_dup || hcp->dup_off == lcp->dup_off)) order = lcp->order + 1; } MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); } hcp->order = order; } 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; lcp = (HASH_CURSOR *)cp->internal; if (lcp->pgno != hcp->pgno || lcp->indx == NDX_INVALID) continue; if (my_txn != NULL && cp->txn != my_txn) found = 1; if (!is_dup) { if (add) { /* * This routine is not called to add * non-dup records which are always put * at the end. It is only called from * recovery in this case and the * cursor will be marked deleted. * We are "undeleting" so unmark all * cursors with the same order. */ if (lcp->indx == hcp->indx && F_ISSET(lcp, H_DELETED)) { if (lcp->order == hcp->order) F_CLR(lcp, H_DELETED); else if (lcp->order > hcp->order) { /* * If we've moved this cursor's * index, split its order * number--i.e., decrement it by * enough so that the lowest * cursor moved has order 1. * cp_arg->order is the split * point, so decrement by one * less than that. */ lcp->order -= (hcp->order - 1); lcp->indx += 2; } } else if (lcp->indx >= hcp->indx) lcp->indx += 2; } else { if (lcp->indx > hcp->indx) { lcp->indx -= 2; if (lcp->indx == hcp->indx && F_ISSET(lcp, H_DELETED)) lcp->order += order; } else if (lcp->indx == hcp->indx && !F_ISSET(lcp, H_DELETED)) { F_SET(lcp, H_DELETED); F_CLR(lcp, H_ISDUP); lcp->order = order; } } } else if (lcp->indx == hcp->indx) { /* * Handle duplicates. This routine is * only called for on page dups. * Off page dups are handled by btree/rtree * code. */ if (add) { lcp->dup_tlen += len; if (lcp->dup_off == hcp->dup_off && F_ISSET(hcp, H_DELETED) && F_ISSET(lcp, H_DELETED)) { /* Abort of a delete. */ if (lcp->order == hcp->order) F_CLR(lcp, H_DELETED); else if (lcp->order > hcp->order) { lcp->order -= (hcp->order -1); lcp->dup_off += len; } } else if (lcp->dup_off >= hcp->dup_off) lcp->dup_off += len; } else { lcp->dup_tlen -= len; if (lcp->dup_off > hcp->dup_off) { lcp->dup_off -= len; if (lcp->dup_off == hcp->dup_off && F_ISSET(lcp, H_DELETED)) lcp->order += order; } else if (lcp->dup_off == hcp->dup_off && !F_ISSET(lcp, H_DELETED)) { F_SET(lcp, H_DELETED); lcp->order = order; } } } } MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); } MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); if (found != 0 && DBC_LOGGING(dbc)) { if ((ret = __ham_curadj_log(dbp, my_txn, &lsn, 0, hcp->pgno, hcp->indx, len, hcp->dup_off, add, is_dup, order)) != 0) return (ret); } return (0);}/* * __ham_get_clist -- * * Get a list of cursors either on a particular bucket or on a particular * page and index combination. The former is so that we can update * cursors on a split. The latter is so we can update cursors when we * move items off page. * * PUBLIC: int __ham_get_clist __P((DB *, db_pgno_t, u_int32_t, DBC ***)); */int__ham_get_clist(dbp, pgno, indx, listp) DB *dbp; db_pgno_t pgno; u_int32_t indx; DBC ***listp;{ DB *ldbp; DBC *cp; DB_ENV *dbenv; int nalloc, nused, ret; /* * Assume that finding anything is the exception, so optimize for * the case where there aren't any. */ nalloc = nused = 0; *listp = NULL; dbenv = dbp->dbenv; 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)) /* * We match if cp->pgno matches the specified * pgno, and if either the cp->indx matches * or we weren't given an index. */ if (cp->internal->pgno == pgno && (indx == NDX_INVALID || cp->internal->indx == indx)) { if (nused >= nalloc) { nalloc += 10; if ((ret = __os_realloc(dbp->dbenv, nalloc * sizeof(HASH_CURSOR *), listp)) != 0) goto err; } (*listp)[nused++] = cp; } MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); } MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); if (listp != NULL) { if (nused >= nalloc) { nalloc++; if ((ret = __os_realloc(dbp->dbenv, nalloc * sizeof(HASH_CURSOR *), listp)) != 0) return (ret); } (*listp)[nused] = NULL; } return (0);err: MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); return (ret);}static int__ham_c_writelock(dbc) DBC *dbc;{ DB_ENV *dbenv; DB_LOCK tmp_lock; HASH_CURSOR *hcp; int ret; /* * All we need do is acquire the lock and let the off-page * dup tree do its thing. */ if (!STD_LOCKING(dbc)) return (0); hcp = (HASH_CURSOR *)dbc->internal; if ((!LOCK_ISSET(hcp->lock) || hcp->lock_mode == DB_LOCK_READ)) { tmp_lock = hcp->lock; if ((ret = __ham_lock_bucket(dbc, DB_LOCK_WRITE)) != 0) return (ret); dbenv = dbc->dbp->dbenv; if (LOCK_ISSET(tmp_lock) && (ret = dbenv->lock_put(dbenv, &tmp_lock)) != 0) return (ret); } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -