Use DUPFIXED for tx_indices

Small space savings, no measurable speedup
This commit is contained in:
Howard Chu 2016-03-06 07:08:22 +00:00
parent a12f9365f8
commit 8e9d8e3364

View file

@ -158,11 +158,6 @@ const char* const LMDB_PROPERTIES = "properties";
const char zerokey[8] = {0}; const char zerokey[8] = {0};
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey }; const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
typedef struct blk_height {
crypto::hash key;
uint64_t height;
} blk_height;
const std::string lmdb_error(const std::string& error_string, int mdb_res) const std::string lmdb_error(const std::string& error_string, int mdb_res)
{ {
const std::string full_string = error_string + mdb_strerror(mdb_res); const std::string full_string = error_string + mdb_strerror(mdb_res);
@ -210,6 +205,16 @@ typedef struct mdb_block_info
crypto::hash bi_hash; crypto::hash bi_hash;
} mdb_block_info; } mdb_block_info;
typedef struct blk_height {
crypto::hash key;
uint64_t height;
} blk_height;
typedef struct txindex {
crypto::hash key;
tx_data_t data;
} txindex;
std::atomic<uint64_t> mdb_txn_safe::num_active_txns{0}; std::atomic<uint64_t> mdb_txn_safe::num_active_txns{0};
std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT; std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT;
@ -618,23 +623,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
CURSOR(txs) CURSOR(txs)
CURSOR(tx_indices) CURSOR(tx_indices)
txindex ti = {tx_hash};
MDB_val_copy<uint64_t> val_tx_index(tx_index); MDB_val_copy<uint64_t> val_tx_index(tx_index);
MDB_val_copy<crypto::hash> val_h(tx_hash); MDB_val val_h = {sizeof(ti), (void *)&ti};
MDB_val unused; result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH);
result = mdb_cursor_get(m_cur_tx_indices, &val_h, &unused, MDB_SET); if (result == 0) {
if (result == 0) txindex *tip = (txindex *)val_h.mv_data;
throw1(TX_EXISTS(std::string("Attempting to add transaction that's already in the db (tx index ").append(boost::lexical_cast<std::string>(*(const uint64_t*)unused.mv_data)).append(")").c_str())); throw1(TX_EXISTS(std::string("Attempting to add transaction that's already in the db (tx index ").append(boost::lexical_cast<std::string>(tip->data.tx_index)).append(")").c_str()));
else if (result != MDB_NOTFOUND) } else if (result != MDB_NOTFOUND) {
throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str())); throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str()));
}
tx_data_t td; ti.data.tx_index = tx_index;
td.tx_index = tx_index; ti.data.unlock_time = tx.unlock_time;
td.unlock_time = tx.unlock_time; ti.data.height = m_height;
td.height = m_height;
MDB_val_copy<tx_data_t> tx_data(td); val_h.mv_size = sizeof(ti);
val_h.mv_data = (void *)&ti;
result = mdb_cursor_put(m_cur_tx_indices, &val_h, &tx_data, 0); result = mdb_cursor_put(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, 0);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str()));
@ -654,13 +661,17 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
MDB_val_copy<crypto::hash> val_h(tx_hash); mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(tx_indices)
txindex ti = {tx_hash};
MDB_val val_h = {sizeof(ti), (void *)&ti};
MDB_val v; MDB_val v;
if (mdb_get(*m_write_txn, m_tx_indices, &val_h, &v)) if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH))
throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); throw1(TX_DNE("Attempting to remove transaction that isn't in the db"));
tx_data_t td = *(const tx_data_t*)v.mv_data; txindex *tip = (txindex *)val_h.mv_data;
uint64_t tx_index = td.tx_index; uint64_t tx_index = tip->data.tx_index;
MDB_val_copy<uint64_t> val_tx_index(tx_index); MDB_val_copy<uint64_t> val_tx_index(tx_index);
if (mdb_del(*m_write_txn, m_txs, &val_tx_index, NULL)) if (mdb_del(*m_write_txn, m_txs, &val_tx_index, NULL))
@ -677,7 +688,9 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
// Though other things could change, so long as earlier functions (like // Though other things could change, so long as earlier functions (like
// remove_tx_outputs) need to do the lookup of tx hash -> tx index, don't // remove_tx_outputs) need to do the lookup of tx hash -> tx index, don't
// delete the tx_indices entry until the end. // delete the tx_indices entry until the end.
if (mdb_del(*m_write_txn, m_tx_indices, &val_h, NULL)) if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH))
throw1(TX_DNE("Attempting to remove transaction that isn't in the db"));
if (mdb_cursor_del(m_cur_tx_indices, 0))
throw1(DB_ERROR("Failed to add removal of tx index to db transaction")); throw1(DB_ERROR("Failed to add removal of tx index to db transaction"));
m_num_txs--; m_num_txs--;
@ -1078,7 +1091,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
lmdb_db_open(txn, LMDB_BLOCK_HEIGHTS, MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_heights, "Failed to open db handle for m_block_heights"); lmdb_db_open(txn, LMDB_BLOCK_HEIGHTS, MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_heights, "Failed to open db handle for m_block_heights");
lmdb_db_open(txn, LMDB_TXS, MDB_INTEGERKEY | MDB_CREATE, m_txs, "Failed to open db handle for m_txs"); lmdb_db_open(txn, LMDB_TXS, MDB_INTEGERKEY | MDB_CREATE, m_txs, "Failed to open db handle for m_txs");
lmdb_db_open(txn, LMDB_TX_INDICES, MDB_CREATE, m_tx_indices, "Failed to open db handle for m_tx_indices"); lmdb_db_open(txn, LMDB_TX_INDICES, MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_tx_indices, "Failed to open db handle for m_tx_indices");
lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_INTEGERKEY | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs"); lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_INTEGERKEY | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs");
lmdb_db_open(txn, LMDB_OUTPUT_TXS, MDB_INTEGERKEY | MDB_CREATE, m_output_txs, "Failed to open db handle for m_output_txs"); lmdb_db_open(txn, LMDB_OUTPUT_TXS, MDB_INTEGERKEY | MDB_CREATE, m_output_txs, "Failed to open db handle for m_output_txs");
@ -1095,7 +1108,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
mdb_set_dupsort(txn, m_spent_keys, compare_hash32); mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
mdb_set_dupsort(txn, m_block_heights, compare_hash32); mdb_set_dupsort(txn, m_block_heights, compare_hash32);
mdb_set_compare(txn, m_tx_indices, compare_hash32); mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
mdb_set_compare(txn, m_hf_starting_heights, compare_uint8); mdb_set_compare(txn, m_hf_starting_heights, compare_uint8);
mdb_set_compare(txn, m_properties, compare_string); mdb_set_compare(txn, m_properties, compare_string);
@ -1669,11 +1682,10 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
RCURSOR(txs); RCURSOR(txs);
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val v;
bool tx_found = false; bool tx_found = false;
TIME_MEASURE_START(time1); TIME_MEASURE_START(time1);
auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &v, MDB_SET); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &key, MDB_GET_BOTH);
if (get_result == 0) if (get_result == 0)
tx_found = true; tx_found = true;
else if (get_result != MDB_NOTFOUND) else if (get_result != MDB_NOTFOUND)
@ -1709,13 +1721,17 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors; const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
RCURSOR(tx_indices); RCURSOR(tx_indices);
MDB_val_copy<crypto::hash> key(h); txindex ti = {h};
MDB_val v; MDB_val v = {sizeof(ti), (void *)&ti};
TIME_MEASURE_START(time1); TIME_MEASURE_START(time1);
auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &v, MDB_SET); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
TIME_MEASURE_FINISH(time1); TIME_MEASURE_FINISH(time1);
time_tx_exists += time1; time_tx_exists += time1;
if (!get_result) {
txindex *tip = (txindex *)v.mv_data;
tx_index = tip->data.tx_index;
}
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
@ -1726,11 +1742,6 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
} }
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch transaction from hash")); throw0(DB_ERROR("DB error attempting to fetch transaction from hash"));
else
{
tx_data_t td = *(const tx_data_t*)v.mv_data;
tx_index = td.tx_index;
}
return true; return true;
} }
@ -1743,16 +1754,16 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors; const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
RCURSOR(tx_indices); RCURSOR(tx_indices);
MDB_val_copy<crypto::hash> key(h); txindex ti = {h};
MDB_val v; MDB_val v = {sizeof(ti), (void *)&ti};
auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &v, MDB_SET); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(lmdb_error(std::string("tx data with hash ") + epee::string_tools::pod_to_hex(h) + " not found in db: ", get_result).c_str())); throw1(TX_DNE(lmdb_error(std::string("tx data with hash ") + epee::string_tools::pod_to_hex(h) + " not found in db: ", get_result).c_str()));
else if (get_result) else if (get_result)
throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx data from hash: ", get_result).c_str())); throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx data from hash: ", get_result).c_str()));
tx_data_t td = *(const tx_data_t*)v.mv_data; txindex *tip = (txindex *)v.mv_data;
uint64_t ret = td.unlock_time; uint64_t ret = tip->data.unlock_time;
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
return ret; return ret;
} }
@ -1767,14 +1778,14 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
RCURSOR(tx_indices); RCURSOR(tx_indices);
RCURSOR(txs); RCURSOR(txs);
MDB_val_copy<crypto::hash> key(h); txindex ti = {h};
MDB_val v; MDB_val v = {sizeof(ti), (void *)&ti};
MDB_val result; MDB_val result;
auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &v, MDB_SET); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == 0) if (get_result == 0)
{ {
tx_data_t td = *(const tx_data_t*)v.mv_data; txindex *tip = (txindex *)v.mv_data;
uint64_t tx_index = td.tx_index; uint64_t tx_index = tip->data.tx_index;
MDB_val_copy<uint64_t> val_tx_index(tx_index); MDB_val_copy<uint64_t> val_tx_index(tx_index);
get_result = mdb_cursor_get(m_cur_txs, &val_tx_index, &result, MDB_SET); get_result = mdb_cursor_get(m_cur_txs, &val_tx_index, &result, MDB_SET);
} }
@ -1834,9 +1845,9 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors; const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
RCURSOR(tx_indices); RCURSOR(tx_indices);
MDB_val_copy<crypto::hash> key(h); txindex ti = {h};
MDB_val v; MDB_val v = {sizeof(ti), (void *)&ti};
auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &v, MDB_SET); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
throw1(TX_DNE(std::string("tx_data_t with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); throw1(TX_DNE(std::string("tx_data_t with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
@ -1844,8 +1855,8 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch tx height from hash")); throw0(DB_ERROR("DB error attempting to fetch tx height from hash"));
tx_data_t res = *(const tx_data_t *)v.mv_data; txindex *tip = (txindex *)v.mv_data;
uint64_t ret = res.height; uint64_t ret = tip->data.height;
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
return ret; return ret;
} }
@ -1969,7 +1980,6 @@ void BlockchainLMDB::get_amount_and_global_output_indices(const uint64_t tx_inde
// create a new read-only txn here, which is incorrect. // create a new read-only txn here, which is incorrect.
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors; const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
RCURSOR(tx_indices);
RCURSOR(tx_outputs); RCURSOR(tx_outputs);
int result = 0; int result = 0;