summaryrefslogtreecommitdiff
path: root/src/hash/hash_page.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hash/hash_page.c')
-rw-r--r--src/hash/hash_page.c126
1 files changed, 91 insertions, 35 deletions
diff --git a/src/hash/hash_page.c b/src/hash/hash_page.c
index 7576fe61..8e0f897d 100644
--- a/src/hash/hash_page.c
+++ b/src/hash/hash_page.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 1990, 1993, 1994
@@ -129,7 +129,7 @@ recheck:
/* Fetch next page. */
if (NEXT_PGNO(hcp->page) == PGNO_INVALID) {
F_SET(hcp, H_NOMORE);
- return (DB_NOTFOUND);
+ return (DBC_ERR(dbc, DB_NOTFOUND));
}
next_pgno = NEXT_PGNO(hcp->page);
hcp->indx = 0;
@@ -344,7 +344,7 @@ __ham_item_prev(dbc, mode, pgnop)
if (hcp->pgno == PGNO_INVALID) {
/* Beginning of bucket. */
F_SET(hcp, H_NOMORE);
- return (DB_NOTFOUND);
+ return (DBC_ERR(dbc, DB_NOTFOUND));
} else if ((ret =
__ham_next_cpage(dbc, hcp->pgno)) != 0)
return (ret);
@@ -371,7 +371,7 @@ __ham_item_prev(dbc, mode, pgnop)
if (hcp->indx == 0) {
/* Bucket was empty. */
F_SET(hcp, H_NOMORE);
- return (DB_NOTFOUND);
+ return (DBC_ERR(dbc, DB_NOTFOUND));
}
}
@@ -497,7 +497,8 @@ __ham_insertpair(dbc, p, indxp, key_dbt, data_dbt, key_type, data_type)
inp = P_INP(dbp, p);
ksize = (key_type == H_OFFPAGE) ?
key_dbt->size : HKEYDATA_SIZE(key_dbt->size);
- dsize = (data_type == H_OFFPAGE || data_type == H_OFFDUP) ?
+ dsize = (data_type == H_OFFPAGE ||
+ data_type == H_OFFDUP || data_type == H_BLOB) ?
data_dbt->size : HKEYDATA_SIZE(data_dbt->size);
increase = ksize + dsize;
@@ -579,7 +580,8 @@ __ham_insertpair(dbc, p, indxp, key_dbt, data_dbt, key_type, data_type)
else
PUT_HKEYDATA(P_ENTRY(dbp, p, indx), key_dbt->data,
key_dbt->size, key_type);
- if (data_type == H_OFFPAGE || data_type == H_OFFDUP)
+ if (data_type == H_BLOB ||
+ data_type == H_OFFPAGE || data_type == H_OFFDUP)
memcpy(P_ENTRY(dbp, p, indx+1), data_dbt->data,
data_dbt->size);
else
@@ -618,6 +620,8 @@ __ham_getindex(dbc, p, key, key_type, match, indx)
{
/* Since all entries are key/data pairs. */
DB_ASSERT(dbc->env, NUM_ENT(p)%2 == 0 );
+ /* Blob files can only be stored as data items. */
+ DB_ASSERT(dbc->env, key_type != H_BLOB );
/* Support pre 4.6 unsorted hash pages. */
if (p->type == P_HASH_UNSORTED)
@@ -672,7 +676,7 @@ __ham_getindex_unsorted(dbc, p, key, match, indx)
memcpy(&pgno,
HOFFPAGE_PGNO(hk), sizeof(db_pgno_t));
if ((ret = __db_moff(dbc, key, pgno, tlen,
- t->h_compare, &res)) != 0)
+ t->h_compare, &res, NULL)) != 0)
return (ret);
}
break;
@@ -681,7 +685,7 @@ __ham_getindex_unsorted(dbc, p, key, match, indx)
DB_INIT_DBT(pg_dbt,
HKEYDATA_DATA(hk), key->size);
if (t->h_compare(
- dbp, key, &pg_dbt) != 0)
+ dbp, key, &pg_dbt, NULL) != 0)
break;
} else if (key->size ==
LEN_HKEY(dbp, p, dbp->pgsize, i))
@@ -784,7 +788,7 @@ __ham_getindex_sorted(dbc, p, key, key_type, match, indxp)
(void)__ua_memcpy(&off_pgno,
HOFFPAGE_PGNO(offp), sizeof(db_pgno_t));
if ((ret = __db_moff(dbc, key, off_pgno,
- itemlen, t->h_compare, &res)) != 0)
+ itemlen, t->h_compare, &res, NULL)) != 0)
return (ret);
}
} else {
@@ -799,7 +803,7 @@ __ham_getindex_sorted(dbc, p, key, key_type, match, indxp)
(void)__ua_memcpy(&off_len, HOFFPAGE_TLEN(offp),
sizeof(u_int32_t));
if ((ret = __db_moff(dbc, &tmp_dbt, off_pgno,
- off_len, t->h_compare, &res)) != 0)
+ off_len, t->h_compare, &res, NULL)) != 0)
return (ret);
/*
* Since we switched the key/match parameters
@@ -810,7 +814,7 @@ __ham_getindex_sorted(dbc, p, key, key_type, match, indxp)
} else if (t->h_compare != NULL) {
/* Case 4, with a user comparison func */
DB_INIT_DBT(tmp_dbt, data, itemlen);
- res = t->h_compare(dbp, key, &tmp_dbt);
+ res = t->h_compare(dbp, key, &tmp_dbt, NULL);
} else {
/* Case 4, without a user comparison func */
if ((res = memcmp(key->data, data,
@@ -899,8 +903,8 @@ __ham_verify_sorted_page (dbc, p)
sizeof(u_int32_t));
memcpy(&tpgno, HOFFPAGE_PGNO(H_PAIRKEY(dbp, p, i-2)),
sizeof(db_pgno_t));
- if ((ret = __db_moff(dbc,
- &curr_dbt, tpgno, tlen, t->h_compare, &res)) != 0)
+ if ((ret = __db_moff(dbc, &curr_dbt,
+ tpgno, tlen, t->h_compare, &res, NULL)) != 0)
return (ret);
} else if (HPAGE_TYPE(dbp, p, i) == H_OFFPAGE) {
memset(&prev_dbt, 0, sizeof(prev_dbt));
@@ -910,8 +914,8 @@ __ham_verify_sorted_page (dbc, p)
sizeof(u_int32_t));
memcpy(&tpgno, HOFFPAGE_PGNO(H_PAIRKEY(dbp, p, i)),
sizeof(db_pgno_t));
- if ((ret = __db_moff(dbc,
- &prev_dbt, tpgno, tlen, t->h_compare, &res)) != 0)
+ if ((ret = __db_moff(dbc, &prev_dbt, tpgno, tlen,
+ t->h_compare, &res, NULL)) != 0)
return (ret);
} else
res = memcmp(prev, curr, min(curr_len, prev_len));
@@ -1047,9 +1051,11 @@ __ham_del_pair(dbc, flags, ppg)
DBT data_dbt, key_dbt;
DB_LSN new_lsn, *n_lsn, tmp_lsn;
DB_MPOOLFILE *mpf;
+ HBLOB hblob;
HASH_CURSOR *hcp;
PAGE *n_pagep, *nn_pagep, *p, *p_pagep;
db_ham_mode op;
+ db_seq_t blob_id;
db_indx_t ndx;
db_pgno_t chg_pgno, pgno, tmp_pgno;
u_int32_t data_type, key_type, order;
@@ -1067,6 +1073,8 @@ __ham_del_pair(dbc, flags, ppg)
DB_MPOOL_CREATE | DB_MPOOL_DIRTY, &hcp->page)) != 0)
return (ret);
p = hcp->page;
+ key_type = HPAGE_PTYPE(H_PAIRKEY(dbp, p, ndx));
+ data_type = HPAGE_PTYPE(H_PAIRDATA(dbp, p, ndx));
/*
* We optimize for the normal case which is when neither the key nor
@@ -1075,8 +1083,7 @@ __ham_del_pair(dbc, flags, ppg)
* to remove the big item and then update the page to remove the
* entry referring to the big item.
*/
- if (!LF_ISSET(HAM_DEL_IGNORE_OFFPAGE) &&
- HPAGE_PTYPE(H_PAIRKEY(dbp, p, ndx)) == H_OFFPAGE) {
+ if (!LF_ISSET(HAM_DEL_IGNORE_OFFPAGE) && key_type == H_OFFPAGE) {
memcpy(&pgno, HOFFPAGE_PGNO(P_ENTRY(dbp, p, H_KEYINDEX(ndx))),
sizeof(db_pgno_t));
ret = __db_doff(dbc, pgno);
@@ -1084,7 +1091,13 @@ __ham_del_pair(dbc, flags, ppg)
ret = 0;
if (!LF_ISSET(HAM_DEL_IGNORE_OFFPAGE) && ret == 0)
- switch (HPAGE_PTYPE(H_PAIRDATA(dbp, p, ndx))) {
+ switch (data_type) {
+ case H_BLOB:
+ memcpy(&hblob,
+ P_ENTRY(dbp, p, H_DATAINDEX(ndx)), HBLOB_SIZE);
+ blob_id = (db_seq_t)hblob.id;
+ ret = __blob_del(dbc, blob_id);
+ break;
case H_OFFPAGE:
memcpy(&pgno,
HOFFPAGE_PGNO(P_ENTRY(dbp, p, H_DATAINDEX(ndx))),
@@ -1111,7 +1124,7 @@ __ham_del_pair(dbc, flags, ppg)
/* Now log the delete off this page. */
if (DBC_LOGGING(dbc)) {
hk = H_PAIRKEY(dbp, hcp->page, ndx);
- if ((key_type = HPAGE_PTYPE(hk)) == H_OFFPAGE) {
+ if (key_type == H_OFFPAGE) {
key_dbt.data = hk;
key_dbt.size = HOFFPAGE_SIZE;
} else {
@@ -1120,9 +1133,12 @@ __ham_del_pair(dbc, flags, ppg)
LEN_HKEY(dbp, hcp->page, dbp->pgsize, ndx);
}
hk = H_PAIRDATA(dbp, hcp->page, ndx);
- if ((data_type = HPAGE_PTYPE(hk)) == H_OFFPAGE) {
+ if (data_type == H_OFFPAGE) {
data_dbt.data = hk;
data_dbt.size = HOFFPAGE_SIZE;
+ } else if (data_type == H_BLOB) {
+ data_dbt.data = hk;
+ data_dbt.size = HBLOB_SIZE;
} else if (data_type == H_OFFDUP) {
data_dbt.data = hk;
data_dbt.size = HOFFDUP_SIZE;
@@ -1404,6 +1420,8 @@ __ham_replpair(dbc, dbt, newtype)
* unless it is an append, when we extend the offpage item, and
* update the HOFFPAGE item on the current page to have the new size
* via a delete/add.
+ *
+ * Updating a record won't cause it to become a blob file or vice versa.
*/
dbp = dbc->dbp;
env = dbp->env;
@@ -2464,15 +2482,18 @@ __ham_add_el(dbc, key, val, type)
const DBT *pkey, *pdata;
DB *dbp;
DBT key_dbt, data_dbt;
- DB_LSN new_lsn;
+ DB_LSN blob_lsn, new_lsn;
DB_MPOOLFILE *mpf;
HASH_CURSOR *hcp;
HOFFPAGE doff, koff;
+ HBLOB dblob;
PAGE *new_pagep;
db_pgno_t next_pgno, pgno;
+ off_t file_size;
+ db_seq_t blob_id;
u_int32_t data_size, data_type, key_size, key_type;
u_int32_t pages, pagespace, pairsize;
- int do_expand, is_keybig, is_databig, match, ret;
+ int do_expand, is_keybig, match, ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
@@ -2485,14 +2506,33 @@ __ham_add_el(dbc, key, val, type)
dbc->thread_info, dbc->txn, DB_MPOOL_CREATE, &hcp->page)) != 0)
return (ret);
+ /*
+ * Key is either:
+ * - On page
+ * - On overflow page(s)
+ */
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 is either:
+ * - On page (H_KEYDATA or H_DUPLICATE)
+ * - On overflow page(s)
+ * - In a blob file
+ */
+ data_type =
+ (dbp->blob_threshold && (val->size >= dbp->blob_threshold ||
+ F_ISSET(val, DB_DBT_BLOB))) ?
+ H_BLOB : (ISBIG(hcp, val->size)) ? H_OFFPAGE : H_KEYDATA;
+ if (data_type == H_KEYDATA || data_type == H_DUPLICATE)
+ data_size = HKEYDATA_PSIZE(val->size);
+ else if (data_type == H_OFFPAGE)
data_size = HOFFPAGE_PSIZE;
+ else { /* H_BLOB */
+ DB_ASSERT(dbp->env, data_type == H_BLOB);
+ data_size = HBLOB_PSIZE;
+ }
pairsize = key_size + data_size;
@@ -2536,17 +2576,17 @@ __ham_add_el(dbc, key, val, type)
* run out of file space before updating the key or data.
*/
if (dbc->txn == NULL &&
- dbp->mpf->mfp->maxpgno != 0 && (is_keybig || is_databig)) {
+ dbp->mpf->mfp->maxpgno != 0 &&
+ (is_keybig || data_type == H_OFFPAGE)) {
pagespace = P_MAXSPACE(dbp, dbp->pgsize);
pages = 0;
- if (is_databig)
+ if (data_type == H_OFFPAGE)
pages = ((data_size - 1) / pagespace) + 1;
- if (is_keybig) {
+ if (is_keybig)
pages += ((key->size - 1) / pagespace) + 1;
- if (pages >
- (dbp->mpf->mfp->maxpgno - dbp->mpf->mfp->last_pgno))
- return (__db_space_err(dbp));
- }
+ if (pages >
+ (dbp->mpf->mfp->maxpgno - dbp->mpf->mfp->last_pgno))
+ return (__db_space_err(dbp));
}
if ((ret = __memp_dirty(mpf,
@@ -2575,7 +2615,7 @@ __ham_add_el(dbc, key, val, type)
key_type = H_KEYDATA;
}
- if (is_databig) {
+ if (data_type == H_OFFPAGE) {
doff.type = H_OFFPAGE;
UMRW_SET(doff.unused[0]);
UMRW_SET(doff.unused[1]);
@@ -2587,6 +2627,22 @@ __ham_add_el(dbc, key, val, type)
data_dbt.size = sizeof(doff);
pdata = &data_dbt;
data_type = H_OFFPAGE;
+ } else if (data_type == H_BLOB) {
+ memset(&dblob, 0, HBLOB_SIZE);
+ dblob.type = H_BLOB;
+ blob_id = 0;
+ file_size = 0;
+ if ((ret = __blob_put(
+ dbc, (DBT *)val, &blob_id, &file_size, &blob_lsn)) != 0)
+ return (ret);
+ SET_BLOB_ID(&dblob, blob_id, HBLOB);
+ SET_BLOB_SIZE(&dblob, file_size, HBLOB);
+ SET_BLOB_FILE_ID(&dblob, dbp->blob_file_id, HBLOB);
+ SET_BLOB_SDB_ID(&dblob, dbp->blob_sdb_id, HBLOB);
+ data_dbt.data = &dblob;
+ data_dbt.size = sizeof(dblob);
+ pdata = &data_dbt;
+ data_type = H_BLOB;
} else {
pdata = val;
data_type = type;
@@ -2673,7 +2729,7 @@ __ham_add_el(dbc, key, val, type)
/*
* Special insert pair call -- copies a key/data pair from one page to
* another. Works for all types of hash entries (H_OFFPAGE, H_KEYDATA,
- * H_DUPLICATE, H_OFFDUP). Since we log splits at a high level, we
+ * H_DUPLICATE, H_OFFDUP, H_BLOB). Since we log splits at a high level, we
* do not need to log them here.
*
* dest_indx is an optional parameter, it serves several purposes:
@@ -2715,7 +2771,7 @@ __ham_copypair(dbc, src_page, src_ndx, dest_page, dest_indx, log)
tkey.data = HKEYDATA_DATA(P_ENTRY(dbp, src_page, kindx));
tkey.size = LEN_HKEYDATA(dbp, src_page, dbp->pgsize, kindx);
}
- if (dtype == H_OFFPAGE || dtype == H_OFFDUP) {
+ if (dtype == H_OFFPAGE || dtype == H_OFFDUP || dtype == H_BLOB) {
tdata.data = P_ENTRY(dbp, src_page, dindx);
tdata.size = LEN_HITEM(dbp, src_page, dbp->pgsize, dindx);
} else {