📄 hash.c
字号:
case DB_PREV_NODUP: ret = mpf->put(mpf, hcp->page, 0); hcp->page = NULL; if (hcp->bucket == 0) { ret = DB_NOTFOUND; hcp->pgno = PGNO_INVALID; goto err; } F_CLR(hcp, H_ISDUP); hcp->bucket--; hcp->indx = NDX_INVALID; hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); if (ret == 0) ret = __ham_item_prev(dbc, lock_type, pgnop); break; case DB_FIRST: case DB_NEXT: case DB_NEXT_NODUP: ret = mpf->put(mpf, hcp->page, 0); hcp->page = NULL; hcp->indx = NDX_INVALID; hcp->bucket++; F_CLR(hcp, H_ISDUP); hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); if (hcp->bucket > hcp->hdr->max_bucket) { ret = DB_NOTFOUND; hcp->pgno = PGNO_INVALID; goto err; } if (ret == 0) ret = __ham_item_next(dbc, lock_type, pgnop); break; case DB_GET_BOTH: case DB_GET_BOTHC: case DB_GET_BOTH_RANGE: case DB_NEXT_DUP: case DB_SET: case DB_SET_RANGE: /* Key not found. */ ret = DB_NOTFOUND; goto err; case DB_CURRENT: /* * This should only happen if you are doing * deletes and reading with concurrent threads * and not doing proper locking. We return * the same error code as we would if the * cursor were deleted. */ ret = DB_KEYEMPTY; goto err; default: DB_ASSERT(0); } } if (get_key == 0) F_SET(key, DB_DBT_ISSET);err: if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) ret = t_ret; F_CLR(hcp, H_DUPONLY); F_CLR(hcp, H_NEXT_NODUP); return (ret);}/* * __ham_bulk -- Return bulk data from a hash table. */static int__ham_bulk(dbc, data, flags) DBC *dbc; DBT *data; u_int32_t flags;{ DB *dbp; DB_MPOOLFILE *mpf; HASH_CURSOR *cp; PAGE *pg; db_indx_t dup_len, dup_off, dup_tlen, indx, *inp; db_lockmode_t lock_mode; db_pgno_t pgno; int32_t *endp, key_off, *offp, *saveoff; u_int32_t key_size, size, space; u_int8_t *dbuf, *dp, *hk, *np, *tmp; int is_dup, is_key; int need_pg, next_key, no_dup, pagesize, ret, t_ret; ret = 0; key_off = 0; dup_len = dup_off = dup_tlen = 0; size = 0; dbp = dbc->dbp; pagesize = dbp->pgsize; mpf = dbp->mpf; cp = (HASH_CURSOR *)dbc->internal; is_key = LF_ISSET(DB_MULTIPLE_KEY) ? 1 : 0; next_key = is_key && LF_ISSET(DB_OPFLAGS_MASK) != DB_NEXT_DUP; no_dup = LF_ISSET(DB_OPFLAGS_MASK) == DB_NEXT_NODUP; dbuf = data->data; np = dp = dbuf; /* Keep track of space that is left. There is an termination entry */ space = data->ulen; space -= sizeof(*offp); /* Build the offset/size table from the end up. */ endp = (int32_t *) ((u_int8_t *)dbuf + data->ulen); endp--; offp = endp; key_size = 0; lock_mode = F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE: DB_LOCK_READ;next_pg: need_pg = 1; indx = cp->indx; pg = cp->page; inp = P_INP(dbp, pg); do { if (is_key) { hk = H_PAIRKEY(dbp, pg, indx); if (HPAGE_PTYPE(hk) == H_OFFPAGE) { memcpy(&key_size, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); memcpy(&pgno, HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); size = key_size; if (key_size > space) goto get_key_space; if ((ret = __bam_bulk_overflow( dbc, key_size, pgno, np)) != 0) return (ret); space -= key_size; key_off = (int32_t)(np - dbuf); np += key_size; } else { if (need_pg) { dp = np; size = pagesize - HOFFSET(pg); if (space < size) {get_key_space: if (offp == endp) { data->size = ALIGN(size + pagesize, sizeof(u_int32_t)); return (ENOMEM); } goto back_up; } memcpy(dp, (u_int8_t *)pg + HOFFSET(pg), size); need_pg = 0; space -= size; np += size; } key_size = LEN_HKEY(dbp, pg, pagesize, indx); key_off = (int32_t)(inp[indx] - HOFFSET(pg) + dp - dbuf + SSZA(HKEYDATA, data)); } } hk = H_PAIRDATA(dbp, pg, indx); switch (HPAGE_PTYPE(hk)) { case H_DUPLICATE: case H_KEYDATA: if (need_pg) { dp = np; size = pagesize - HOFFSET(pg); if (space < size) {back_up: if (indx != 0) { indx -= 2; /* XXX * It's not clear that this is * the right way to fix this, * but here goes. * If we are backing up onto a * duplicate, then we need to * position ourselves at the * end of the duplicate set. * We probably need to make * this work for H_OFFDUP too. * It might be worth making a * dummy cursor and calling * __ham_item_prev. */ tmp = H_PAIRDATA(dbp, pg, indx); if (HPAGE_PTYPE(tmp) == H_DUPLICATE) { dup_off = dup_tlen = LEN_HDATA(dbp, pg, pagesize, indx + 1); memcpy(&dup_len, HKEYDATA_DATA(tmp), sizeof(db_indx_t)); } goto get_space; } /* indx == 0 */ if ((ret = __ham_item_prev(dbc, lock_mode, &pgno)) != 0) { if (ret != DB_NOTFOUND) return (ret); if ((ret = mpf->put(mpf, cp->page, 0)) != 0) return (ret); cp->page = NULL; if (cp->bucket == 0) { cp->indx = indx = NDX_INVALID; goto get_space; } if ((ret = __ham_get_meta(dbc)) != 0) return (ret); cp->bucket--; cp->pgno = BUCKET_TO_PAGE(cp, cp->bucket); cp->indx = NDX_INVALID; if ((ret = __ham_release_meta( dbc)) != 0) return (ret); if ((ret = __ham_item_prev(dbc, lock_mode, &pgno)) != 0) return (ret); } indx = cp->indx;get_space: /* * See if we put any data in the buffer. */ if (offp >= endp || F_ISSET(dbc, DBC_TRANSIENT)) { data->size = ALIGN(size + data->ulen - space, sizeof(u_int32_t)); return (ENOMEM); } /* * Don't continue; we're all out * of space, even though we're * returning success. */ next_key = 0; break; } memcpy(dp, (u_int8_t *)pg + HOFFSET(pg), size); need_pg = 0; space -= size; np += size; } /* * We're about to crack the offset(s) and length(s) * out of an H_KEYDATA or H_DUPLICATE item. * There are three cases: * 1. We were moved into a duplicate set by * the standard hash cursor code. Respect * the dup_off and dup_tlen we were given. * 2. We stumbled upon a duplicate set while * walking the page on our own. We need to * recognize it as a dup and set dup_off and * dup_tlen. * 3. The current item is not a dup. */ if (F_ISSET(cp, H_ISDUP)) { /* Case 1 */ is_dup = 1; dup_len = cp->dup_len; dup_off = cp->dup_off; dup_tlen = cp->dup_tlen; } else if (HPAGE_PTYPE(hk) == H_DUPLICATE) { /* Case 2 */ is_dup = 1; /* * If we run out of memory and bail, * make sure the fact we're in a dup set * isn't ignored later. */ F_SET(cp, H_ISDUP); dup_off = 0; memcpy(&dup_len, HKEYDATA_DATA(hk), sizeof(db_indx_t)); dup_tlen = LEN_HDATA(dbp, pg, pagesize, indx); } else /* Case 3 */ is_dup = dup_len = dup_off = dup_tlen = 0; do { space -= (is_key ? 4 : 2) * sizeof(*offp); size += (is_key ? 4 : 2) * sizeof(*offp); /* * Since space is an unsigned, if we happen * to wrap, then this comparison will turn out * to be true. XXX Wouldn't it be better to * simply check above that space is greater than * the value we're about to subtract??? */ if (space > data->ulen) { if (!is_dup || dup_off == 0) goto back_up; dup_off -= (db_indx_t)DUP_SIZE(offp[1]); goto get_space; } if (is_key) { *offp-- = key_off; *offp-- = key_size; } if (is_dup) { *offp-- = (int32_t)( inp[indx + 1] - HOFFSET(pg) + dp - dbuf + SSZA(HKEYDATA, data) + dup_off + sizeof(db_indx_t)); memcpy(&dup_len, HKEYDATA_DATA(hk) + dup_off, sizeof(db_indx_t)); dup_off += DUP_SIZE(dup_len); *offp-- = dup_len; } else { *offp-- = (int32_t)( inp[indx + 1] - HOFFSET(pg) + dp - dbuf + SSZA(HKEYDATA, data)); *offp-- = LEN_HDATA(dbp, pg, pagesize, indx); } } while (is_dup && dup_off < dup_tlen && no_dup == 0); F_CLR(cp, H_ISDUP); break; case H_OFFDUP: memcpy(&pgno, HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); space -= 2 * sizeof(*offp); if (space > data->ulen) goto back_up; if (is_key) { space -= 2 * sizeof(*offp); if (space > data->ulen) goto back_up; *offp-- = key_off; *offp-- = key_size; } saveoff = offp; if ((ret = __bam_bulk_duplicates(dbc, pgno, dbuf, is_key ? offp + 2 : NULL, &offp, &np, &space, no_dup)) != 0) { if (ret == ENOMEM) { size = space; if (is_key && saveoff == offp) { offp += 2; goto back_up; } goto get_space; } return (ret); } break; case H_OFFPAGE: space -= (is_key ? 4 : 2) * sizeof(*offp); if (space > data->ulen) goto back_up; memcpy(&size, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); memcpy(&pgno, HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); if (size > space) goto back_up; if ((ret = __bam_bulk_overflow(dbc, size, pgno, np)) != 0) return (ret); if (is_key) { *offp-- = key_off; *offp-- = key_size; } *offp-- = (int32_t)(np - dbuf); *offp-- = size; np += size; space -= size; break; } } while (next_key && (indx += 2) < NUM_ENT(pg)); cp->indx = indx; cp->dup_len = dup_len; cp->dup_off = dup_off; cp->dup_tlen = dup_tlen; /* If we are off the page then try to the next page. */ if (ret == 0 && next_key && indx >= NUM_ENT(pg)) { if ((ret = __ham_item_next(dbc, lock_mode, &pgno)) == 0) goto next_pg; if (ret != DB_NOTFOUND) return (ret); if ((ret = mpf->put(dbc->dbp->mpf, cp->page, 0)) != 0) return (ret); cp->page = NULL; if ((ret = __ham_get_meta(dbc)) != 0) return (ret); cp->bucket++; if (cp->bucket > cp->hdr->max_bucket) { /* * Restore cursor to its previous state. We're past * the last item in the last bucket, so the next * DBC->c_get(DB_NEXT) will return DB_NOTFOUND. */ cp->bucket--; ret = DB_NOTFOUND; } else { /* * Start on the next bucket. * * Note that if this new bucket happens to be empty, * but there's another non-empty bucket after it, * we'll return early. This is a rare case, and we * don't guarantee any particular number of keys * returned on each call, so just let the next call * to bulk get move forward by yet another bucket. */ cp->pgno = BUCKET_TO_PAGE(cp, cp->bucket); cp->indx = NDX_INVALID; F_CLR(cp, H_ISDUP); ret = __ham_item_next(dbc, lock_mode, &pgno); } if ((t_ret = __ham_release_meta(dbc)) != 0) return (t_ret); if (ret == 0) goto next_pg; if (ret != DB_NOTFOUND) return (ret); } *offp = (u_int32_t) -1; return (0);}static int__ham_c_put(dbc, key, data, flags, pgnop) DBC *dbc; DBT *key; DBT *data; u_int32_t flags; db_pgno_t *pgnop;{ DB *dbp; DB_MPOOLFILE *mpf; DBT tmp_val, *myval; HASH_CURSOR *hcp; u_int32_t nbytes; int ret, t_ret; /* * The compiler doesn't realize that we only use this when ret is * equal to 0 and that if ret is equal to 0, that we must have set * myval. So, we initialize it here to shut the compiler up. */ COMPQUIET(myval, NULL); dbp = dbc->dbp; mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; if (F_ISSET(hcp, H_DELETED) && flags != DB_KEYFIRST && flags != DB_KEYLAST) return (DB_NOTFOUND); if ((ret = __ham_get_meta(dbc)) != 0) goto err1; switch (flags) { case DB_KEYLAST: case DB_KEYFIRST: case DB_NODUPDATA: nbytes = (ISBIG(hcp, key->size) ? HOFFPAGE_PSIZE : HKEYDATA_PSIZE(key->size)) + (ISBIG(hcp, data->size) ? HOFFPAGE_PSIZE : HKEYDATA_PSIZE(data->size)); if ((ret = __ham_lookup(dbc, key, nbytes, DB_LOCK_WRITE, pgnop)) == DB_NOTFOUND) { ret = 0; if (hcp->seek_found_page != PGNO_INVALID && hcp->seek_found_page != hcp->pgno) { if ((ret = mpf->put(mpf, hcp->page, 0)) != 0) goto err2; hcp->page = NULL; hcp->pgno = hcp->seek_found_page; hcp->indx = NDX_INVALID; } if (F_ISSET(data, DB_DBT_PARTIAL) && data->doff != 0) { /* * A partial put, but the key does not exist * and we are not beginning the write at 0. * We must create a data item padded up to doff * and then write the new bytes represented by * val. */ if ((ret = __ham_init_dbt(dbp->dbenv, &tmp_val, data->size + data->doff, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) == 0) { memset(tmp_val.data, 0, data->doff); memcpy((u_int8_t *)tmp_val.data + data->doff, data->data, data->size); myval = &tmp_val; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -