From 8d12a8df2cf27713509c039c91fb9180e010011a Mon Sep 17 00:00:00 2001 From: warptangent Date: Fri, 4 Mar 2016 10:59:20 -0800 Subject: [PATCH] Schema update: tx_indices - improve further with less indirection --- src/blockchain_db/blockchain_db.h | 5 ++- src/blockchain_db/lmdb/db_lmdb.cpp | 60 +++++++++++++++++++++++------- src/blockchain_db/lmdb/db_lmdb.h | 7 ++-- src/cryptonote_core/blockchain.cpp | 5 ++- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 2cdaaea6..933cc34f 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -473,6 +473,7 @@ public: // return true if a transaction with hash exists virtual bool tx_exists(const crypto::hash& h) const = 0; + virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const = 0; // return unlock time of tx with hash virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; @@ -516,13 +517,13 @@ public: // return two vectors of indices: vector of amount output indices and global // output indices, corresponding to each output in the transaction with hash // - virtual void get_amount_and_global_output_indices(const crypto::hash& h, + virtual void get_amount_and_global_output_indices(const uint64_t tx_index, std::vector& amount_output_indices, std::vector& global_output_indices) const = 0; // return a vector of indices corresponding to the amount output index for // each output in the transaction with hash - virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const = 0; + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const = 0; // returns true if key image is present in spent key images storage virtual bool has_key_image(const crypto::key_image& img) const = 0; diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 4c377544..a07b257a 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -672,6 +672,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const if (mdb_get(*m_write_txn, m_tx_indices, &val_h, &val_tx_index)) throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); + uint64_t tx_index = *(uint64_t*)val_tx_index.mv_data; if (mdb_del(*m_write_txn, m_txs, &val_tx_index, NULL)) throw1(DB_ERROR("Failed to add removal of tx to db transaction")); @@ -680,7 +681,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const if (mdb_del(*m_write_txn, m_tx_heights, &val_tx_index, NULL)) throw1(DB_ERROR("Failed to add removal of tx block height to db transaction")); - remove_tx_outputs(tx_hash, tx); + remove_tx_outputs(tx_index, tx); int result = mdb_del(*m_write_txn, m_tx_outputs, &val_tx_index, NULL); if (result == MDB_NOTFOUND) @@ -796,13 +797,13 @@ void BlockchainLMDB::add_amount_and_global_output_indices(const crypto::hash& tx throw0(DB_ERROR(std::string("Failed to add to db transaction: ").append(mdb_strerror(result)).c_str())); } -void BlockchainLMDB::remove_tx_outputs(const crypto::hash& tx_hash, const transaction& tx) +void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_index, const transaction& tx) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); // only need global_output_indices std::vector amount_output_indices, global_output_indices; - get_amount_and_global_output_indices(tx_hash, amount_output_indices, global_output_indices); + get_amount_and_global_output_indices(tx_index, amount_output_indices, global_output_indices); if (global_output_indices.empty()) { @@ -1122,6 +1123,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) mdb_set_compare(txn, m_spent_keys, compare_hash32); mdb_set_compare(txn, m_block_heights, compare_hash32); mdb_set_compare(txn, m_tx_indices, compare_hash32); + mdb_set_compare(txn, m_hf_starting_heights, compare_uint8); mdb_set_compare(txn, m_hf_versions, compare_uint64); mdb_set_compare(txn, m_properties, compare_string); @@ -1726,6 +1728,43 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const return true; } +bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors; + RCURSOR(tx_indices); + RCURSOR(txs); + + MDB_val_copy key(h); + MDB_val val_tx_index; + MDB_val result; + + TIME_MEASURE_START(time1); + auto get_result = mdb_cursor_get(m_cur_tx_indices, &key, &val_tx_index, MDB_SET); + if (get_result == 0) { + get_result = mdb_cursor_get(m_cur_txs, &val_tx_index, &result, MDB_SET); + } + TIME_MEASURE_FINISH(time1); + time_tx_exists += time1; + + TXN_POSTFIX_RDONLY(); + + if (get_result == MDB_NOTFOUND) + { + LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db"); + return false; + } + else if (get_result) + throw0(DB_ERROR("DB error attempting to fetch transaction from hash")); + else + tx_index = *(uint64_t*)val_tx_index.mv_data; + + return true; +} + uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -1950,7 +1989,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, con return indices[0]; } -void BlockchainLMDB::get_amount_and_global_output_indices(const crypto::hash& h, +void BlockchainLMDB::get_amount_and_global_output_indices(const uint64_t tx_index, std::vector& amount_output_indices, std::vector& global_output_indices) const { @@ -1970,16 +2009,9 @@ void BlockchainLMDB::get_amount_and_global_output_indices(const crypto::hash& h, RCURSOR(tx_outputs); int result = 0; - MDB_val_copy k(h); - MDB_val val_tx_index; + MDB_val_copy val_tx_index(tx_index); MDB_val v; - result = mdb_cursor_get(m_cur_tx_indices, &k, &val_tx_index, MDB_SET); - if (result == MDB_NOTFOUND) - throw1(OUTPUT_DNE(std::string("Failed to get tx index for tx hash ").append(epee::string_tools::pod_to_hex(h)).c_str())); - else if (result) - throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch transaction index from hash ") + epee::string_tools::pod_to_hex(h) + ": ", result).c_str())); - result = mdb_cursor_get(m_cur_tx_outputs, &val_tx_index, &v, MDB_SET); if (result == MDB_NOTFOUND) LOG_PRINT_L0("WARNING: Unexpected: tx has no amount and global indices stored in " @@ -2005,13 +2037,13 @@ void BlockchainLMDB::get_amount_and_global_output_indices(const crypto::hash& h, TXN_POSTFIX_RDONLY(); } -std::vector BlockchainLMDB::get_tx_amount_output_indices(const crypto::hash& h) const +std::vector BlockchainLMDB::get_tx_amount_output_indices(const uint64_t tx_index) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); std::vector amount_output_indices, global_output_indices; // only need amount_output_indices - get_amount_and_global_output_indices(h, amount_output_indices, global_output_indices); + get_amount_and_global_output_indices(tx_index, amount_output_indices, global_output_indices); return amount_output_indices; } diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 41dccfed..ef47ea5f 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -212,6 +212,7 @@ public: virtual uint64_t height() const; virtual bool tx_exists(const crypto::hash& h) const; + virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const; virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const; @@ -237,11 +238,11 @@ public: virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices); virtual void get_output_global_indices(const uint64_t& amount, const std::vector &offsets, std::vector &indices); - virtual void get_amount_and_global_output_indices(const crypto::hash& h, + virtual void get_amount_and_global_output_indices(const uint64_t tx_index, std::vector& amount_output_indices, std::vector& global_output_indices) const; - virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const; + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const; virtual bool has_key_image(const crypto::key_image& img) const; @@ -307,7 +308,7 @@ private: virtual void remove_output(const tx_out& tx_output); - void remove_tx_outputs(const crypto::hash& tx_hash, const transaction& tx); + void remove_tx_outputs(const uint64_t tx_index, const transaction& tx); void remove_output(const uint64_t& out_index, const uint64_t amount); void remove_amount_output_index(const uint64_t amount, const uint64_t global_output_index); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2aa8ecec..f5c912d7 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1949,14 +1949,15 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vectortx_exists(tx_id)) + uint64_t tx_index; + if (!m_db->tx_exists(tx_id, tx_index)) { LOG_PRINT_RED_L1("warning: get_tx_outputs_gindexs failed to find transaction with id = " << tx_id); return false; } // get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts - indexs = m_db->get_tx_amount_output_indices(tx_id); + indexs = m_db->get_tx_amount_output_indices(tx_index); CHECK_AND_ASSERT_MES(indexs.size(), false, "internal error: global indexes for transaction " << tx_id << " is empty"); return true;