aboutsummaryrefslogtreecommitdiff
path: root/src/blockchain_db
diff options
context:
space:
mode:
Diffstat (limited to 'src/blockchain_db')
-rw-r--r--src/blockchain_db/blockchain_db.h2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp141
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h9
3 files changed, 103 insertions, 49 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index da6738878..fc1f98ce0 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1218,7 +1218,7 @@ public:
* @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata
*/
- virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) = 0;
+ virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) = 0;
/*
* FIXME: Need to check with git blame and ask what this does to
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 508b546c7..f6a4534fb 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -377,7 +377,50 @@ void mdb_txn_safe::allow_new_txns()
creation_gate.clear();
}
+void lmdb_resized(MDB_env *env)
+{
+ mdb_txn_safe::prevent_new_txns();
+
+ MGINFO("LMDB map resize detected.");
+
+ MDB_envinfo mei;
+
+ mdb_env_info(env, &mei);
+ uint64_t old = mei.me_mapsize;
+
+ mdb_txn_safe::wait_no_active_txns();
+
+ int result = mdb_env_set_mapsize(env, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to set new mapsize: ", result).c_str()));
+
+ mdb_env_info(env, &mei);
+ uint64_t new_mapsize = mei.me_mapsize;
+
+ MGINFO("LMDB Mapsize increased." << " Old: " << old / (1024 * 1024) << "MiB" << ", New: " << new_mapsize / (1024 * 1024) << "MiB");
+
+ mdb_txn_safe::allow_new_txns();
+}
+
+inline int lmdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn)
+{
+ int res = mdb_txn_begin(env, parent, flags, txn);
+ if (res == MDB_MAP_RESIZED) {
+ lmdb_resized(env);
+ res = mdb_txn_begin(env, parent, flags, txn);
+ }
+ return res;
+}
+inline int lmdb_txn_renew(MDB_txn *txn)
+{
+ int res = mdb_txn_renew(txn);
+ if (res == MDB_MAP_RESIZED) {
+ lmdb_resized(mdb_txn_env(txn));
+ res = mdb_txn_renew(txn);
+ }
+ return res;
+}
void BlockchainLMDB::do_resize(uint64_t increase_size)
{
@@ -561,7 +604,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
{
LOG_PRINT_L1("No existing blocks to check for average block size");
}
- else if (m_cum_count)
+ else if (m_cum_count >= num_prev_blocks)
{
avg_block_size = m_cum_size / m_cum_count;
LOG_PRINT_L1("average block size across recent " << m_cum_count << " blocks: " << avg_block_size);
@@ -570,6 +613,9 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
}
else
{
+ MDB_txn *rtxn;
+ mdb_txn_cursors *rcurs;
+ block_rtxn_start(&rtxn, &rcurs);
for (uint64_t block_num = block_start; block_num <= block_stop; ++block_num)
{
uint32_t block_size = get_block_size(block_num);
@@ -578,6 +624,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
// some blocks were to be skipped for being outliers.
++num_blocks_used;
}
+ block_rtxn_stop();
avg_block_size = total_block_size / num_blocks_used;
LOG_PRINT_L1("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size);
}
@@ -702,7 +749,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
uint64_t m_height = height();
int result;
- uint64_t tx_id = m_num_txs;
+ uint64_t tx_id = num_txs();
CURSOR(txs)
CURSOR(tx_indices)
@@ -735,7 +782,6 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx blob to db transaction: ", result).c_str()));
- m_num_txs++;
return tx_id;
}
@@ -783,8 +829,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
// Don't delete the tx_indices entry until the end, after we're done with val_tx_id
if (mdb_cursor_del(m_cur_tx_indices, 0))
throw1(DB_ERROR("Failed to add removal of tx index to db transaction"));
-
- m_num_txs--;
}
uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
@@ -797,6 +841,7 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
uint64_t m_height = height();
+ uint64_t m_num_outputs = num_outputs();
int result = 0;
@@ -849,7 +894,6 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
if ((result = mdb_cursor_put(m_cur_output_amounts, &val_amount, &data, MDB_APPENDDUP)))
throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str()));
- m_num_outputs++;
return ok.amount_index;
}
@@ -934,8 +978,6 @@ void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_in
result = mdb_cursor_del(m_cur_output_amounts, 0);
if (result)
throw0(DB_ERROR(lmdb_error(std::string("Error deleting amount for output index ").append(boost::lexical_cast<std::string>(out_index).append(": ")).c_str(), result).c_str()));
-
- m_num_outputs--;
}
void BlockchainLMDB::add_spent_key(const crypto::key_image& k_image)
@@ -1000,7 +1042,7 @@ tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const
void BlockchainLMDB::check_open() const
{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+// LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (!m_open)
throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
}
@@ -1155,16 +1197,6 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
LOG_PRINT_L2("Setting m_height to: " << db_stats.ms_entries);
uint64_t m_height = db_stats.ms_entries;
- // get and keep current number of txs
- if ((result = mdb_stat(txn, m_txs, &db_stats)))
- throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
- m_num_txs = db_stats.ms_entries;
-
- // get and keep current number of outputs
- if ((result = mdb_stat(txn, m_output_txs, &db_stats)))
- throw0(DB_ERROR(lmdb_error("Failed to query m_output_txs: ", result).c_str()));
- m_num_outputs = db_stats.ms_entries;
-
bool compatible = true;
MDB_val_copy<const char*> k("version");
@@ -1270,7 +1302,7 @@ void BlockchainLMDB::reset()
check_open();
mdb_txn_safe txn;
- if (auto result = mdb_txn_begin(m_env, NULL, 0, txn))
+ if (auto result = lmdb_txn_begin(m_env, NULL, 0, txn))
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
if (auto result = mdb_drop(txn, m_blocks, 0))
@@ -1304,7 +1336,6 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to write version to database: ", result).c_str()));
txn.commit();
- m_num_outputs = 0;
m_cum_size = 0;
m_cum_count = 0;
}
@@ -1354,7 +1385,7 @@ void BlockchainLMDB::unlock()
txn_ptr = m_write_txn; \
else \
{ \
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
+ if (auto mdb_res = lmdb_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())); \
} \
@@ -1388,7 +1419,7 @@ void BlockchainLMDB::unlock()
txn_ptr = m_write_txn; \
else \
{ \
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
+ if (auto mdb_res = lmdb_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())); \
} \
@@ -1710,6 +1741,34 @@ uint64_t BlockchainLMDB::height() const
return db_stats.ms_entries;
}
+uint64_t BlockchainLMDB::num_txs() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
+
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_txs, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txs: ", result).c_str()));
+ return db_stats.ms_entries;
+}
+
+uint64_t BlockchainLMDB::num_outputs() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
+
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_output_txs, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_output_txs: ", result).c_str()));
+ return db_stats.ms_entries;
+}
+
bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2262,7 +2321,7 @@ bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
m_write_batch_txn = new mdb_txn_safe();
// NOTE: need to make sure it's destroyed properly when done
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, *m_write_batch_txn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, 0, *m_write_batch_txn))
{
delete m_write_batch_txn;
m_write_batch_txn = nullptr;
@@ -2381,12 +2440,12 @@ bool BlockchainLMDB::block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) co
m_tinfo.reset(new mdb_threadinfo);
memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
ret = true;
} else if (!m_tinfo->m_ti_rflags.m_rf_txn)
{
- if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
ret = true;
}
@@ -2419,12 +2478,12 @@ void BlockchainLMDB::block_txn_start(bool readonly)
m_tinfo.reset(new mdb_threadinfo);
memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
didit = true;
} else if (!m_tinfo->m_ti_rflags.m_rf_txn)
{
- if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
didit = true;
}
@@ -2450,7 +2509,7 @@ void BlockchainLMDB::block_txn_start(bool readonly)
{
m_writer = boost::this_thread::get_id();
m_write_txn = new mdb_txn_safe();
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, *m_write_txn))
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, 0, *m_write_txn))
{
delete m_write_txn;
m_write_txn = nullptr;
@@ -2528,8 +2587,6 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
}
}
- uint64_t num_txs = m_num_txs;
- uint64_t num_outputs = m_num_outputs;
try
{
BlockchainDB::add_block(blk, block_size, cumulative_difficulty, coins_generated, txs);
@@ -2540,8 +2597,6 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
}
catch (...)
{
- m_num_txs = num_txs;
- m_num_outputs = num_outputs;
block_txn_abort();
throw;
}
@@ -2556,8 +2611,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
block_txn_start(false);
- uint64_t num_txs = m_num_txs;
- uint64_t num_outputs = m_num_outputs;
try
{
BlockchainDB::pop_block(blk, txs);
@@ -2565,8 +2618,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
}
catch (...)
{
- m_num_txs = num_txs;
- m_num_outputs = num_outputs;
block_txn_abort();
throw;
}
@@ -2600,7 +2651,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY();
}
-void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs)
+void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
TIME_MEASURE_START(db3);
@@ -2618,7 +2669,14 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
auto get_result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND)
+ {
+ if (allow_partial)
+ {
+ MDEBUG("Partial result: " << outputs.size() << "/" << offsets.size());
+ break;
+ }
throw1(OUTPUT_DNE((std::string("Attempting to get output pubkey by global index (amount ") + boost::lexical_cast<std::string>(amount) + ", index " + boost::lexical_cast<std::string>(index) + ", count " + boost::lexical_cast<std::string>(get_num_outputs(amount)) + "), but key does not exist").c_str()));
+ }
else if (get_result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output pubkey from the db", get_result).c_str()));
@@ -3240,8 +3298,6 @@ void BlockchainLMDB::migrate_0_1()
lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts");
mdb_set_dupsort(txn, m_output_amounts, compare_uint64);
txn.commit();
- m_num_txs = 0;
- m_num_outputs = 0;
} while(0);
do {
@@ -3312,12 +3368,9 @@ void BlockchainLMDB::migrate_0_1()
throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs: ", result).c_str()));
if (!i) {
MDB_stat ms;
- mdb_stat(txn, m_output_txs, &ms);
- m_num_outputs = ms.ms_entries;
mdb_stat(txn, m_txs, &ms);
- m_num_txs = i = ms.ms_entries;
+ i = ms.ms_entries;
if (i) {
- m_num_txs = i;
MDB_val_set(pk, "txblk");
result = mdb_cursor_get(c_props, &pk, &k, MDB_SET);
if (result)
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 13d1ecf38..5ea642d23 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -219,7 +219,7 @@ public:
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
virtual output_data_t get_output_key(const uint64_t& global_index) const;
- virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs);
+ virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -310,6 +310,9 @@ private:
virtual void remove_spent_key(const crypto::key_image& k_image);
+ uint64_t num_txs() const;
+ uint64_t num_outputs() const;
+
// Hard fork
virtual void set_hard_fork_version(uint64_t height, uint8_t version);
virtual uint8_t get_hard_fork_version(uint64_t height) const;
@@ -367,10 +370,8 @@ private:
MDB_dbi m_properties;
- uint64_t m_num_txs;
- uint64_t m_num_outputs;
mutable uint64_t m_cum_size; // used in batch size estimation
- mutable int m_cum_count;
+ mutable unsigned int m_cum_count;
std::string m_folder;
mdb_txn_safe* m_write_txn; // may point to either a short-lived txn or a batch txn
mdb_txn_safe* m_write_batch_txn; // persist batch txn outside of BlockchainLMDB