db_lmdb: always use a batch tx if possible

Also wrap that code in two prefix/suffix macros so they are
easier to use and not forget. Also add consts to returned data
casts where applicable.
This commit is contained in:
moneromooo-monero 2015-12-14 18:47:13 +00:00
parent 3a4db6346b
commit d462c62343
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3

View file

@ -29,6 +29,7 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/current_function.hpp>
#include <memory> // std::unique_ptr #include <memory> // std::unique_ptr
#include <cstring> // memcpy #include <cstring> // memcpy
#include <random> #include <random>
@ -1232,28 +1233,45 @@ void BlockchainLMDB::unlock()
check_open(); check_open();
} }
#define TXN_PREFIX(flags); \
mdb_txn_safe auto_txn; \
mdb_txn_safe* txn_ptr = &auto_txn; \
if (m_batch_active) \
txn_ptr = m_write_txn; \
else \
{ \
if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \
} \
#define TXN_PREFIX_RDONLY(); TXN_PREFIX(MDB_RDONLY);
#define TXN_POSTFIX_SUCCESS() \
do { \
if (! m_batch_active) \
auto_txn.commit(); \
} while(0)
bool BlockchainLMDB::block_exists(const crypto::hash& h) const bool BlockchainLMDB::block_exists(const crypto::hash& h) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
auto get_result = mdb_get(txn, m_block_heights, &key, &result); auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
txn.commit(); TXN_POSTFIX_SUCCESS();
LOG_PRINT_L3("Block with hash " << epee::string_tools::pod_to_hex(h) << " not found in db"); LOG_PRINT_L3("Block with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
return false; return false;
} }
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch block index from hash")); throw0(DB_ERROR("DB error attempting to fetch block index from hash"));
txn.commit(); TXN_POSTFIX_SUCCESS();
return true; return true;
} }
@ -1270,21 +1288,18 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
auto get_result = mdb_get(txn, m_block_heights, &key, &result); auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(BLOCK_DNE("Attempted to retrieve non-existent block height")); throw1(BLOCK_DNE("Attempted to retrieve non-existent block height"));
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a block height from the db")); throw0(DB_ERROR("Error attempting to retrieve a block height from the db"));
ret = *(const uint64_t *)result.mv_data; uint64_t ret = *(const uint64_t *)result.mv_data;
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -1302,13 +1317,11 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
auto get_result = mdb_get(txn, m_blocks, &key, &result); auto get_result = mdb_get(*txn_ptr, m_blocks, &key, &result);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block not in db").c_str())); throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block not in db").c_str()));
@ -1323,7 +1336,7 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
if (!parse_and_validate_block_from_blob(bd, b)) if (!parse_and_validate_block_from_blob(bd, b))
throw0(DB_ERROR("Failed to parse block from blob retrieved from the db")); throw0(DB_ERROR("Failed to parse block from blob retrieved from the db"));
txn.commit(); TXN_POSTFIX_SUCCESS();
return b; return b;
} }
@ -1333,16 +1346,8 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
auto get_result = mdb_get(*txn_ptr, m_block_timestamps, &key, &result); auto get_result = mdb_get(*txn_ptr, m_block_timestamps, &key, &result);
@ -1353,9 +1358,8 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db")); throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db"));
ret = *(const uint64_t *)result.mv_data; uint64_t ret = *(const uint64_t *)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1378,17 +1382,8 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
size_t ret;
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
auto get_result = mdb_get(*txn_ptr, m_block_sizes, &key, &result); auto get_result = mdb_get(*txn_ptr, m_block_sizes, &key, &result);
@ -1399,9 +1394,8 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a block size from the db")); throw0(DB_ERROR("Error attempting to retrieve a block size from the db"));
ret = *(const size_t *)result.mv_data; size_t ret = *(const size_t *)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1410,16 +1404,8 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " height: " << height); LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " height: " << height);
check_open(); check_open();
difficulty_type ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
auto get_result = mdb_get(*txn_ptr, m_block_diffs, &key, &result); auto get_result = mdb_get(*txn_ptr, m_block_diffs, &key, &result);
@ -1430,9 +1416,8 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db")); throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db"));
ret = *(difficulty_type*)result.mv_data; difficulty_type ret = *(const difficulty_type*)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1458,16 +1443,7 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
@ -1479,9 +1455,8 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db")); throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db"));
ret = *(const uint64_t*)result.mv_data; uint64_t ret = *(const uint64_t*)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1490,16 +1465,7 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
crypto::hash ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<uint64_t> key(height); MDB_val_copy<uint64_t> key(height);
MDB_val result; MDB_val result;
@ -1512,9 +1478,8 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
throw0(DB_ERROR(std::string("Error attempting to retrieve a block hash from the db: "). throw0(DB_ERROR(std::string("Error attempting to retrieve a block hash from the db: ").
append(mdb_strerror(get_result)).c_str())); append(mdb_strerror(get_result)).c_str()));
ret = *(crypto::hash*)result.mv_data; crypto::hash ret = *(const crypto::hash*)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1585,15 +1550,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
@ -1602,8 +1559,9 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
auto get_result = mdb_get(*txn_ptr, m_txs, &key, &result); auto get_result = mdb_get(*txn_ptr, m_txs, &key, &result);
TIME_MEASURE_FINISH(time1); TIME_MEASURE_FINISH(time1);
time_tx_exists += time1; time_tx_exists += time1;
if (! m_batch_active)
txn.commit(); TXN_POSTFIX_SUCCESS();
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db"); LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
@ -1620,21 +1578,18 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
auto get_result = mdb_get(txn, m_tx_unlocks, &key, &result); auto get_result = mdb_get(*txn_ptr, m_tx_unlocks, &key, &result);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(std::string("tx unlock time with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); throw1(TX_DNE(std::string("tx unlock time with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch tx unlock time from hash")); throw0(DB_ERROR("DB error attempting to fetch tx unlock time from hash"));
ret = *(const uint64_t*)result.mv_data; uint64_t ret = *(const uint64_t*)result.mv_data;
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -1643,15 +1598,7 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
@ -1667,8 +1614,8 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
transaction tx; transaction tx;
if (!parse_and_validate_tx_from_blob(bd, tx)) if (!parse_and_validate_tx_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
if (! m_batch_active)
txn.commit(); TXN_POSTFIX_SUCCESS();
return tx; return tx;
} }
@ -1678,15 +1625,13 @@ uint64_t BlockchainLMDB::get_tx_count() const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_stat db_stats; MDB_stat db_stats;
if (mdb_stat(txn, m_txs, &db_stats)) if (mdb_stat(*txn_ptr, m_txs, &db_stats))
throw0(DB_ERROR("Failed to query m_txs")); throw0(DB_ERROR("Failed to query m_txs"));
txn.commit(); TXN_POSTFIX_SUCCESS();
return db_stats.ms_entries; return db_stats.ms_entries;
} }
@ -1710,16 +1655,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<crypto::hash> key(h); MDB_val_copy<crypto::hash> key(h);
MDB_val result; MDB_val result;
@ -1731,10 +1667,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"));
ret = *(const uint64_t*)result.mv_data; uint64_t ret = *(const uint64_t*)result.mv_data;
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1743,17 +1677,16 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
lmdb_cur cur(txn, m_output_amounts); lmdb_cur cur(*txn_ptr, m_output_amounts);
MDB_val_copy<uint64_t> k(amount); MDB_val_copy<uint64_t> k(amount);
MDB_val v; MDB_val v;
auto result = mdb_cursor_get(cur, &k, &v, MDB_SET); auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND) if (result == MDB_NOTFOUND)
{ {
TXN_POSTFIX_SUCCESS();
return 0; return 0;
} }
else if (result) else if (result)
@ -1762,7 +1695,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
size_t num_elems = 0; size_t num_elems = 0;
mdb_cursor_count(cur, &num_elems); mdb_cursor_count(cur, &num_elems);
txn.commit(); TXN_POSTFIX_SUCCESS();
return num_elems; return num_elems;
} }
@ -1772,21 +1705,18 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
output_data_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<uint64_t> k(global_index); MDB_val_copy<uint64_t> k(global_index);
MDB_val v; MDB_val v;
auto get_result = mdb_get(txn, m_output_keys, &k, &v); auto get_result = mdb_get(*txn_ptr, m_output_keys, &k, &v);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist")); throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist"));
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db")); throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db"));
ret = *(output_data_t *) v.mv_data; output_data_t ret = *(const output_data_t *) v.mv_data;
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index)
@ -1803,16 +1733,8 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
tx_out_index ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
MDB_val_copy<uint64_t> k(index); MDB_val_copy<uint64_t> k(index);
MDB_val v; MDB_val v;
@ -1822,7 +1744,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch output tx hash")); throw0(DB_ERROR("DB error attempting to fetch output tx hash"));
crypto::hash tx_hash = *(crypto::hash*)v.mv_data; crypto::hash tx_hash = *(const crypto::hash*)v.mv_data;
get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v); get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
@ -1830,10 +1752,8 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch output tx index")); throw0(DB_ERROR("DB error attempting to fetch output tx index"));
ret = tx_out_index(tx_hash, *(const uint64_t *)v.mv_data); tx_out_index ret = tx_out_index(tx_hash, *(const uint64_t *)v.mv_data);
if (! m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -1856,11 +1776,9 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
check_open(); check_open();
std::vector<uint64_t> index_vec; std::vector<uint64_t> index_vec;
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
lmdb_cur cur(txn, m_tx_outputs); lmdb_cur cur(*txn_ptr, m_tx_outputs);
MDB_val_copy<crypto::hash> k(h); MDB_val_copy<crypto::hash> k(h);
MDB_val v; MDB_val v;
@ -1883,7 +1801,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
} }
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
return index_vec; return index_vec;
} }
@ -1901,9 +1819,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
transaction tx = get_tx(h); transaction tx = get_tx(h);
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
uint64_t i = 0; uint64_t i = 0;
uint64_t global_index; uint64_t global_index;
@ -1913,7 +1829,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
global_index = index_vec[i]; global_index = index_vec[i];
lmdb_cur cur(txn, m_output_amounts); lmdb_cur cur(*txn_ptr, m_output_amounts);
MDB_val_copy<uint64_t> k(amount); MDB_val_copy<uint64_t> k(amount);
MDB_val v; MDB_val v;
@ -1952,7 +1868,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
{ {
// not found // not found
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
throw1(OUTPUT_DNE("specified output not found in db")); throw1(OUTPUT_DNE("specified output not found in db"));
} }
@ -1960,7 +1876,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
++i; ++i;
} }
txn.commit(); TXN_POSTFIX_SUCCESS();
return index_vec2; return index_vec2;
} }
@ -1972,19 +1888,17 @@ bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val_copy<crypto::key_image> val_key(img); MDB_val_copy<crypto::key_image> val_key(img);
MDB_val unused; MDB_val unused;
if (mdb_get(txn, m_spent_keys, &val_key, &unused) == 0) if (mdb_get(*txn_ptr, m_spent_keys, &val_key, &unused) == 0)
{ {
txn.commit(); TXN_POSTFIX_SUCCESS();
return true; return true;
} }
txn.commit(); TXN_POSTFIX_SUCCESS();
return false; return false;
} }
@ -1993,15 +1907,13 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val k; MDB_val k;
MDB_val v; MDB_val v;
bool ret = true; bool ret = true;
lmdb_cur cur(txn, m_spent_keys); lmdb_cur cur(*txn_ptr, m_spent_keys);
MDB_cursor_op op = MDB_FIRST; MDB_cursor_op op = MDB_FIRST;
while (1) while (1)
{ {
@ -2011,7 +1923,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
break; break;
if (ret < 0) if (ret < 0)
throw0(DB_ERROR("Failed to enumerate key images")); throw0(DB_ERROR("Failed to enumerate key images"));
const crypto::key_image k_image = *(crypto::key_image*)k.mv_data; const crypto::key_image k_image = *(const crypto::key_image*)k.mv_data;
if (!f(k_image)) { if (!f(k_image)) {
ret = false; ret = false;
break; break;
@ -2019,7 +1931,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
} }
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -2029,15 +1941,13 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val k; MDB_val k;
MDB_val v; MDB_val v;
bool ret = true; bool ret = true;
lmdb_cur cur(txn, m_blocks); lmdb_cur cur(*txn_ptr, m_blocks);
MDB_cursor_op op = MDB_FIRST; MDB_cursor_op op = MDB_FIRST;
while (1) while (1)
{ {
@ -2047,7 +1957,7 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
break; break;
if (ret) if (ret)
throw0(DB_ERROR("Failed to enumerate blocks")); throw0(DB_ERROR("Failed to enumerate blocks"));
uint64_t height = *(uint64_t*)k.mv_data; uint64_t height = *(const uint64_t*)k.mv_data;
blobdata bd; blobdata bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size); bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
block b; block b;
@ -2063,7 +1973,7 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
} }
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -2073,15 +1983,13 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val k; MDB_val k;
MDB_val v; MDB_val v;
bool ret = true; bool ret = true;
lmdb_cur cur(txn, m_txs); lmdb_cur cur(*txn_ptr, m_txs);
MDB_cursor_op op = MDB_FIRST; MDB_cursor_op op = MDB_FIRST;
while (1) while (1)
{ {
@ -2091,7 +1999,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
break; break;
if (ret) if (ret)
throw0(DB_ERROR("Failed to enumerate transactions")); throw0(DB_ERROR("Failed to enumerate transactions"));
const crypto::hash hash = *(crypto::hash*)k.mv_data; const crypto::hash hash = *(const crypto::hash*)k.mv_data;
blobdata bd; blobdata bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size); bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
transaction tx; transaction tx;
@ -2104,7 +2012,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
} }
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -2114,15 +2022,13 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
MDB_val k; MDB_val k;
MDB_val v; MDB_val v;
bool ret = true; bool ret = true;
lmdb_cur cur(txn, m_output_amounts); lmdb_cur cur(*txn_ptr, m_output_amounts);
MDB_cursor_op op = MDB_FIRST; MDB_cursor_op op = MDB_FIRST;
while (1) while (1)
{ {
@ -2132,8 +2038,8 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
break; break;
if (ret) if (ret)
throw0(DB_ERROR("Failed to enumerate outputs")); throw0(DB_ERROR("Failed to enumerate outputs"));
uint64_t amount = *(uint64_t*)k.mv_data; uint64_t amount = *(const uint64_t*)k.mv_data;
uint64_t global_index = *(uint64_t*)v.mv_data; uint64_t global_index = *(const uint64_t*)v.mv_data;
tx_out_index toi = get_output_tx_and_index_from_global(global_index); tx_out_index toi = get_output_tx_and_index_from_global(global_index);
if (!f(amount, toi.first, toi.second)) { if (!f(amount, toi.first, toi.second)) {
ret = false; ret = false;
@ -2142,7 +2048,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
} }
cur.close(); cur.close();
txn.commit(); TXN_POSTFIX_SUCCESS();
return ret; return ret;
} }
@ -2335,15 +2241,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
check_open(); check_open();
tx_out_indices.clear(); tx_out_indices.clear();
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
for (const uint64_t &index : global_indices) for (const uint64_t &index : global_indices)
{ {
@ -2356,7 +2254,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
else if (get_result) else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch output tx hash")); throw0(DB_ERROR("DB error attempting to fetch output tx hash"));
crypto::hash tx_hash = *(crypto::hash*) v.mv_data; crypto::hash tx_hash = *(const crypto::hash*) v.mv_data;
get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v); get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
@ -2368,8 +2266,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
tx_out_indices.push_back(result); tx_out_indices.push_back(result);
} }
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
} }
void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std::vector<uint64_t> &offsets, void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std::vector<uint64_t> &offsets,
@ -2387,15 +2284,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
max = index; max = index;
} }
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if(m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
lmdb_cur cur(*txn_ptr, m_output_amounts); lmdb_cur cur(*txn_ptr, m_output_amounts);
@ -2474,8 +2363,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
} }
cur.close(); cur.close();
if(!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
TIME_MEASURE_FINISH(txx); TIME_MEASURE_FINISH(txx);
LOG_PRINT_L3("txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan); LOG_PRINT_L3("txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan);
@ -2493,15 +2381,8 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
if (global_indices.size() > 0) if (global_indices.size() > 0)
{ {
mdb_txn_safe txn; TXN_PREFIX_RDONLY();
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
for (const uint64_t &index : global_indices) for (const uint64_t &index : global_indices)
{ {
MDB_val_copy<uint64_t> k(index); MDB_val_copy<uint64_t> k(index);
@ -2513,12 +2394,11 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
else if (get_result) else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db")); throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db"));
output_data_t data = *(output_data_t *) v.mv_data; output_data_t data = *(const output_data_t *) v.mv_data;
outputs.push_back(data); outputs.push_back(data);
} }
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
} }
TIME_MEASURE_FINISH(db3); TIME_MEASURE_FINISH(db3);
@ -2548,24 +2428,14 @@ void BlockchainLMDB::set_hard_fork_starting_height(uint8_t version, uint64_t hei
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
mdb_txn_safe txn; TXN_PREFIX(0);
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
txn_ptr = &txn;
}
MDB_val_copy<uint8_t> val_key(version); MDB_val_copy<uint8_t> val_key(version);
MDB_val_copy<uint64_t> val_value(height); MDB_val_copy<uint64_t> val_value(height);
if (auto result = mdb_put(*txn_ptr, m_hf_starting_heights, &val_key, &val_value, 0)) if (auto result = mdb_put(*txn_ptr, m_hf_starting_heights, &val_key, &val_value, 0))
throw1(DB_ERROR(std::string("Error adding hard fork starting height to db transaction: ").append(mdb_strerror(result)).c_str())); throw1(DB_ERROR(std::string("Error adding hard fork starting height to db transaction: ").append(mdb_strerror(result)).c_str()));
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
} }
uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
@ -2573,17 +2443,7 @@ uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
txn_ptr = &txn;
}
MDB_val_copy<uint8_t> val_key(version); MDB_val_copy<uint8_t> val_key(version);
MDB_val val_ret; MDB_val val_ret;
@ -2593,9 +2453,8 @@ uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
if (result) if (result)
throw0(DB_ERROR("Error attempting to retrieve a hard fork starting height from the db")); throw0(DB_ERROR("Error attempting to retrieve a hard fork starting height from the db"));
ret = *(const uint64_t*)val_ret.mv_data; uint64_t ret = *(const uint64_t*)val_ret.mv_data;
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }
@ -2604,25 +2463,14 @@ void BlockchainLMDB::set_hard_fork_version(uint64_t height, uint8_t version)
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
//LOG_PRINT_L1("BlockchainLMDB::set_hard_fork_version: batch " << m_batch_active << ", height " << height << ", version " << (int)version); TXN_PREFIX(0);
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
txn_ptr = &txn;
}
MDB_val_copy<uint64_t> val_key(height); MDB_val_copy<uint64_t> val_key(height);
MDB_val_copy<uint8_t> val_value(version); MDB_val_copy<uint8_t> val_value(version);
if (auto result = mdb_put(*txn_ptr, m_hf_versions, &val_key, &val_value, 0)) if (auto result = mdb_put(*txn_ptr, m_hf_versions, &val_key, &val_value, 0))
throw1(DB_ERROR(std::string("Error adding hard fork version to db transaction: ").append(mdb_strerror(result)).c_str())); throw1(DB_ERROR(std::string("Error adding hard fork version to db transaction: ").append(mdb_strerror(result)).c_str()));
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
} }
uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
@ -2630,17 +2478,7 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint8_t ret; TXN_PREFIX_RDONLY();
mdb_txn_safe txn;
mdb_txn_safe* txn_ptr = &txn;
if (m_batch_active)
txn_ptr = m_write_txn;
else
{
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
txn_ptr = &txn;
}
MDB_val_copy<uint64_t> val_key(height); MDB_val_copy<uint64_t> val_key(height);
MDB_val val_ret; MDB_val val_ret;
@ -2648,9 +2486,8 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
if (result == MDB_NOTFOUND || result) if (result == MDB_NOTFOUND || result)
throw0(DB_ERROR("Error attempting to retrieve a hard fork version from the db")); throw0(DB_ERROR("Error attempting to retrieve a hard fork version from the db"));
ret = *(const uint8_t*)val_ret.mv_data; uint8_t ret = *(const uint8_t*)val_ret.mv_data;
if (!m_batch_active) TXN_POSTFIX_SUCCESS();
txn.commit();
return ret; return ret;
} }