Merge pull request #194 from moneroexamples/remove_caches

block and tx caches removed
This commit is contained in:
moneroexamples 2019-10-23 19:58:18 +08:00 committed by GitHub
commit 69df5ef4b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 87 additions and 880 deletions

View file

@ -1,138 +0,0 @@
#ifndef CACHE_HPP
#define CACHE_HPP
#include <cstddef>
#include <limits>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "cache_policy.hpp"
namespace caches
{
// Base class for caching algorithms
template <typename Key, typename Value, typename Policy = NoCachePolicy<Key>>
class fixed_sized_cache
{
public:
using iterator = typename std::unordered_map<Key, Value>::iterator;
using const_iterator =
typename std::unordered_map<Key, Value>::const_iterator;
using operation_guard = typename std::lock_guard<std::mutex>;
fixed_sized_cache(
size_t max_size,
const Policy& policy = Policy())
: max_cache_size{max_size},
cache_policy(policy)
{
if (max_cache_size == 0)
{
max_cache_size = std::numeric_limits<size_t>::max();
}
}
void Put(const Key& key, const Value& value)
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
if (elem_it == cache_items_map.end())
{
// add new element to the cache
if (Size() + 1 > max_cache_size)
{
auto disp_candidate_key = cache_policy.ReplCandidate();
Erase(disp_candidate_key);
}
Insert(key, value);
}
else
{
// update previous value
Update(key, value);
}
}
bool Contains(const Key& key)
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
return elem_it != cache_items_map.end();
}
const Value& Get(const Key& key) const
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
if (elem_it == cache_items_map.end())
{
throw std::range_error{"No such element in the cache"};
}
cache_policy.Touch(key);
return elem_it->second;
}
const size_t Size() const
{
operation_guard{safe_op};
return cache_items_map.size();
}
// return a key of a displacement candidate
void Clear()
{
operation_guard{safe_op};
cache_policy.Clear();
cache_items_map.clear();
}
protected:
void Insert(const Key& key, const Value& value)
{
cache_policy.Insert(key);
cache_items_map.emplace(std::make_pair(key, value));
}
void Erase(const Key& key)
{
cache_policy.Erase(key);
cache_items_map.erase(key);
}
void Update(const Key& key, const Value& value)
{
cache_policy.Touch(key);
cache_items_map[key] = value;
}
const_iterator FindElem(const Key& key) const
{
return cache_items_map.find(key);
}
private:
std::unordered_map<Key, Value> cache_items_map;
mutable Policy cache_policy;
mutable std::mutex safe_op;
size_t max_cache_size;
};
}
#endif // CACHE_HPP

View file

@ -1,77 +0,0 @@
#ifndef CACHE_POLICY_HPP
#define CACHE_POLICY_HPP
#include <unordered_set>
namespace caches
{
template <typename Key>
class ICachePolicy
{
public:
virtual ~ICachePolicy() {}
// handle element insertion in a cache
virtual void Insert(const Key& key) = 0;
// handle request to the key-element in a cache
virtual void Touch(const Key& key) = 0;
// handle element deletion from a cache
virtual void Erase(const Key& key) = 0;
// return a key of a replacement candidate
virtual const Key& ReplCandidate() const = 0;
// clear the cache
virtual void Clear() = 0;
};
template <typename Key>
class NoCachePolicy : public ICachePolicy<Key>
{
public:
NoCachePolicy() = default;
~NoCachePolicy() override = default;
void Insert(const Key& key) override
{
key_storage.emplace(key);
}
void Touch(const Key& key) override
{
// do not do anything
}
void Erase(const Key& key) override
{
key_storage.erase(key);
}
// return a key of a displacement candidate
const Key& ReplCandidate() const override
{
return *key_storage.crbegin();
}
// return a key of a displacement candidate
void Clear() override
{
key_storage.clear();
}
private:
std::unordered_set<Key> key_storage;
};
} // namespace caches
#endif // CACHE_POLICY_HPP

View file

@ -1,53 +0,0 @@
#ifndef FIFO_CACHE_POLICY_HPP
#define FIFO_CACHE_POLICY_HPP
#include <list>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class FIFOCachePolicy : public ICachePolicy<Key>
{
public:
FIFOCachePolicy() = default;
~FIFOCachePolicy() = default;
void Insert(const Key& key) override
{
fifo_queue.emplace_front(key);
}
// handle request to the key-element in a cache
void Touch(const Key& key) override
{
// nothing to do here in the FIFO strategy
}
// handle element deletion from a cache
void Erase(const Key& key) override
{
fifo_queue.pop_back();
}
// return a key of a replacement candidate
const Key& ReplCandidate() const override
{
return fifo_queue.back();
}
// return a key of a displacement candidate
void Clear() override
{
fifo_queue.clear();
}
private:
std::list<Key> fifo_queue;
};
} // namespace caches
#endif // FIFO_CACHE_POLICY_HPP

View file

@ -1,76 +0,0 @@
#ifndef LFU_CACHE_POLICY_HPP
#define LFU_CACHE_POLICY_HPP
#include <cstddef>
#include <unordered_map>
#include <map>
#include <iostream>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class LFUCachePolicy : public ICachePolicy<Key>
{
public:
using lfu_iterator = typename std::multimap<std::size_t, Key>::iterator;
LFUCachePolicy() = default;
~LFUCachePolicy() override = default;
void Insert(const Key& key) override
{
constexpr std::size_t INIT_VAL = 1;
// all new value initialized with the frequency 1
lfu_storage[key] = frequency_storage.emplace_hint(
frequency_storage.cbegin(), INIT_VAL, key);
}
void Touch(const Key& key) override
{
// get the previous frequency value of a key
auto elem_for_update = lfu_storage[key];
auto updated_elem = std::make_pair(
elem_for_update->first + 1, elem_for_update->second);
// update the previous value
frequency_storage.erase(elem_for_update);
lfu_storage[key] = frequency_storage.emplace_hint(
frequency_storage.cend(), std::move(updated_elem));
}
void Erase(const Key& key) override
{
frequency_storage.erase(lfu_storage[key]);
lfu_storage.erase(key);
}
const Key& ReplCandidate() const override
{
// at the beginning of the frequency_storage we have the
// least frequency used value
return frequency_storage.cbegin()->second;
}
// return a key of a displacement candidate
void Clear() override
{
frequency_storage.clear();
lfu_storage.clear();
}
private:
std::multimap<std::size_t, Key> frequency_storage;
std::unordered_map<Key, lfu_iterator> lfu_storage;
};
} // namespace caches
#endif // LFU_CACHE_POLICY_HPP

View file

@ -1,63 +0,0 @@
#ifndef LRU_CACHE_POLICY_HPP
#define LRU_CACHE_POLICY_HPP
#include <list>
#include <unordered_map>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class LRUCachePolicy : public ICachePolicy<Key>
{
public:
using lru_iterator = typename std::list<Key>::const_iterator;
LRUCachePolicy() = default;
~LRUCachePolicy() = default;
void Insert(const Key& key) override
{
lru_queue.emplace_front(key);
key_finder[key] = lru_queue.cbegin();
}
void Touch(const Key& key) override
{
// move the touched element at the beginning of the lru_queue
lru_queue.splice(lru_queue.cbegin(), lru_queue, key_finder[key]);
}
void Erase(const Key& key) override
{
// remove the least recently used element
key_finder.erase(lru_queue.back());
lru_queue.pop_back();
}
// return a key of a displacement candidate
const Key& ReplCandidate() const override
{
return lru_queue.back();
}
// return a key of a displacement candidate
void Clear() override
{
lru_queue.clear();
key_finder.clear();
}
private:
std::list<Key> lru_queue;
std::unordered_map<Key, lru_iterator> key_finder;
};
} // namespace caches
#endif // LRU_CACHE_POLICY_HPP

View file

@ -41,6 +41,7 @@ struct jsonresponse: public crow::response
int int
main(int ac, const char* av[]) main(int ac, const char* av[])
{ {
// get command line options // get command line options
xmreg::CmdLineOptions opts {ac, av}; xmreg::CmdLineOptions opts {ac, av};
@ -73,10 +74,7 @@ main(int ac, const char* av[])
auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details"); auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
auto enable_json_api_opt = opts.get_option<bool>("enable-json-api"); auto enable_json_api_opt = opts.get_option<bool>("enable-json-api");
auto enable_as_hex_opt = opts.get_option<bool>("enable-as-hex"); auto enable_as_hex_opt = opts.get_option<bool>("enable-as-hex");
auto enable_tx_cache_opt = opts.get_option<bool>("enable-tx-cache");
auto concurrency_opt = opts.get_option<size_t>("concurrency"); auto concurrency_opt = opts.get_option<size_t>("concurrency");
auto enable_block_cache_opt = opts.get_option<bool>("enable-block-cache");
auto show_cache_times_opt = opts.get_option<bool>("show-cache-times");
auto enable_emission_monitor_opt = opts.get_option<bool>("enable-emission-monitor"); auto enable_emission_monitor_opt = opts.get_option<bool>("enable-emission-monitor");
@ -101,10 +99,7 @@ main(int ac, const char* av[])
bool enable_mixin_details {*enable_mixin_details_opt}; bool enable_mixin_details {*enable_mixin_details_opt};
bool enable_json_api {*enable_json_api_opt}; bool enable_json_api {*enable_json_api_opt};
bool enable_as_hex {*enable_as_hex_opt}; bool enable_as_hex {*enable_as_hex_opt};
bool enable_tx_cache {*enable_tx_cache_opt};
bool enable_block_cache {*enable_block_cache_opt};
bool enable_emission_monitor {*enable_emission_monitor_opt}; bool enable_emission_monitor {*enable_emission_monitor_opt};
bool show_cache_times {*show_cache_times_opt};
// set monero log output level // set monero log output level
@ -279,9 +274,6 @@ main(int ac, const char* av[])
enable_output_key_checker, enable_output_key_checker,
enable_autorefresh_option, enable_autorefresh_option,
enable_mixin_details, enable_mixin_details,
enable_tx_cache,
enable_block_cache,
show_cache_times,
no_blocks_on_index, no_blocks_on_index,
mempool_info_timeout, mempool_info_timeout,
*testnet_url, *testnet_url,

View file

@ -37,12 +37,6 @@ namespace xmreg
"enable outputs key file checker") "enable outputs key file checker")
("enable-json-api", value<bool>()->default_value(false)->implicit_value(true), ("enable-json-api", value<bool>()->default_value(false)->implicit_value(true),
"enable JSON REST api") "enable JSON REST api")
("enable-tx-cache", value<bool>()->default_value(false)->implicit_value(true),
"enable caching of transaction details")
("show-cache-times", value<bool>()->default_value(false)->implicit_value(true),
"show times of getting data from cache vs no cache")
("enable-block-cache", value<bool>()->default_value(false)->implicit_value(true),
"enable caching of block details")
("enable-as-hex", value<bool>()->default_value(false)->implicit_value(true), ("enable-as-hex", value<bool>()->default_value(false)->implicit_value(true),
"enable links to provide hex represtations of a tx and a block") "enable links to provide hex represtations of a tx and a block")
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true), ("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),

View file

@ -137,8 +137,26 @@ MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
if (m_blockchain_storage.have_tx(tx_hash)) if (m_blockchain_storage.have_tx(tx_hash))
{ {
// get transaction with given hash // get transaction with given hash
try
{
tx = m_blockchain_storage.get_db().get_tx(tx_hash); tx = m_blockchain_storage.get_db().get_tx(tx_hash);
} }
catch (TX_DNE const& e)
{
try
{
// coinbase txs are not considered pruned
tx = m_blockchain_storage.get_db().get_pruned_tx(tx_hash);
return true;
}
catch (TX_DNE const& e)
{
cerr << "MicroCore::get_tx: " << e.what() << endl;
}
return false;
}
}
else else
{ {
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl; cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;

View file

@ -31,9 +31,6 @@
#include "../ext/json.hpp" #include "../ext/json.hpp"
#include "../ext/vpetrigocaches/cache.hpp"
#include "../ext/vpetrigocaches/lru_cache_policy.hpp"
#include "../ext/vpetrigocaches/fifo_cache_policy.hpp"
#include "../ext/mstch/src/visitor/render_node.hpp" #include "../ext/mstch/src/visitor/render_node.hpp"
extern "C" uint64_t me_rx_seedheight(const uint64_t height); extern "C" uint64_t me_rx_seedheight(const uint64_t height);
@ -85,31 +82,6 @@ extern __thread randomx_vm *rx_vm;
MAKE_ONIONEXPLORER_RPC_VERSION(ONIONEXPLORER_RPC_VERSION_MAJOR, ONIONEXPLORER_RPC_VERSION_MINOR) MAKE_ONIONEXPLORER_RPC_VERSION(ONIONEXPLORER_RPC_VERSION_MAJOR, ONIONEXPLORER_RPC_VERSION_MINOR)
// basic info about tx to be stored in cashe.
// we need to store block_no and timestamp,
// as this time and number of confirmation needs
// to be updated between requests. Just cant
// get it from cash, as it will be old very soon
struct tx_info_cache
{
uint64_t block_no;
uint64_t timestamp;
mstch::map tx_map;
// custom key for use in cache.
// cache uses unordeded map for keys
struct key
{
crypto::hash tx_hash;
bool detailed;
bool operator==(const key &other) const
{
return (tx_hash == other.tx_hash && detailed == other.detailed);
}
};
};
// helper to ignore any number of template parametrs // helper to ignore any number of template parametrs
template<typename...> using VoidT = void; template<typename...> using VoidT = void;
@ -147,22 +119,6 @@ struct OutputIndicesReturnVectOfVectT<
>>: std::true_type >>: std::true_type
{}; {};
// indect overload of hash for tx_info_cache::key
namespace std
{
template<>
struct hash<tx_info_cache::key>
{
size_t operator()(const tx_info_cache::key& k) const
{
size_t const h1 ( std::hash<crypto::hash>{}(k.tx_hash) );
size_t const h2 ( std::hash<bool>{}(k.detailed) );
return h1 ^ (h2 << 1);
};
};
}
/** /**
* visitor to produce json representations of * visitor to produce json representations of
@ -521,15 +477,10 @@ bool enable_pusher;
bool enable_key_image_checker; bool enable_key_image_checker;
bool enable_output_key_checker; bool enable_output_key_checker;
bool enable_mixins_details; bool enable_mixins_details;
bool enable_tx_cache;
bool enable_block_cache;
bool enable_as_hex; bool enable_as_hex;
bool show_cache_times;
bool enable_autorefresh_option; bool enable_autorefresh_option;
uint64_t no_of_mempool_tx_of_frontpage; uint64_t no_of_mempool_tx_of_frontpage;
uint64_t no_blocks_on_index; uint64_t no_blocks_on_index;
uint64_t mempool_info_timeout; uint64_t mempool_info_timeout;
@ -548,24 +499,6 @@ string js_html_files_all_in_one;
// read operation in OS // read operation in OS
map<string, string> template_file; map<string, string> template_file;
// alias for easy class typing
template <typename Key, typename Value>
using lru_cache_t = caches::fixed_sized_cache<Key, Value, caches::LRUCachePolicy<Key>>;
// alias for easy class typing
template <typename Key, typename Value>
using fifo_cache_t = caches::fixed_sized_cache<Key, Value, caches::FIFOCachePolicy<Key>>;
// cache of txs_map of txs in blocks. this is useful for
// index2 page, so that we dont parse txs in each block
// for each request.
fifo_cache_t<uint64_t, vector<pair<crypto::hash, mstch::node>>> block_tx_cache;
lru_cache_t<tx_info_cache::key, tx_info_cache> tx_context_cache;
public: public:
page(MicroCore* _mcore, page(MicroCore* _mcore,
@ -578,9 +511,6 @@ page(MicroCore* _mcore,
bool _enable_output_key_checker, bool _enable_output_key_checker,
bool _enable_autorefresh_option, bool _enable_autorefresh_option,
bool _enable_mixins_details, bool _enable_mixins_details,
bool _enable_tx_cache,
bool _enable_block_cache,
bool _show_cache_times,
uint64_t _no_blocks_on_index, uint64_t _no_blocks_on_index,
uint64_t _mempool_info_timeout, uint64_t _mempool_info_timeout,
string _testnet_url, string _testnet_url,
@ -597,16 +527,11 @@ page(MicroCore* _mcore,
enable_output_key_checker {_enable_output_key_checker}, enable_output_key_checker {_enable_output_key_checker},
enable_autorefresh_option {_enable_autorefresh_option}, enable_autorefresh_option {_enable_autorefresh_option},
enable_mixins_details {_enable_mixins_details}, enable_mixins_details {_enable_mixins_details},
enable_tx_cache {_enable_tx_cache},
enable_block_cache {_enable_block_cache},
show_cache_times {_show_cache_times},
no_blocks_on_index {_no_blocks_on_index}, no_blocks_on_index {_no_blocks_on_index},
mempool_info_timeout {_mempool_info_timeout}, mempool_info_timeout {_mempool_info_timeout},
testnet_url {_testnet_url}, testnet_url {_testnet_url},
stagenet_url {_stagenet_url}, stagenet_url {_stagenet_url},
mainnet_url {_mainnet_url}, mainnet_url {_mainnet_url}
block_tx_cache(200),
tx_context_cache(1000)
{ {
mainnet = nettype == cryptonote::network_type::MAINNET; mainnet = nettype == cryptonote::network_type::MAINNET;
testnet = nettype == cryptonote::network_type::TESTNET; testnet = nettype == cryptonote::network_type::TESTNET;
@ -705,8 +630,7 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
{"enable_pusher" , enable_pusher}, {"enable_pusher" , enable_pusher},
{"enable_key_image_checker" , enable_key_image_checker}, {"enable_key_image_checker" , enable_key_image_checker},
{"enable_output_key_checker", enable_output_key_checker}, {"enable_output_key_checker", enable_output_key_checker},
{"enable_autorefresh_option", enable_autorefresh_option}, {"enable_autorefresh_option", enable_autorefresh_option}
{"show_cache_times" , show_cache_times}
}; };
context.emplace("txs", mstch::array()); // will keep tx to show context.emplace("txs", mstch::array()); // will keep tx to show
@ -724,12 +648,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
vector<double> blk_sizes; vector<double> blk_sizes;
// measure time of cache based execution, and non-cached execution
double duration_cached {0.0};
double duration_non_cached {0.0};
uint64_t cache_hits {0};
uint64_t cache_misses {0};
// loop index // loop index
int64_t i = end_height; int64_t i = end_height;
@ -764,119 +682,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
context["age_format"] = age.second; context["age_format"] = age.second;
if (enable_block_cache && block_tx_cache.Contains(i))
{
// get txs info in the ith block from
// our cache
// start measure time here
auto start = std::chrono::steady_clock::now();
const vector<pair<crypto::hash, mstch::node>>& txd_pairs
= block_tx_cache.Get(i);
// copy tx maps from txs_maps_tmp into txs array,
// that will go to templates
for (const pair<crypto::hash, mstch::node>& txd_pair: txd_pairs)
{
// we need to check if the given transaction is still
// in the same block as when it was cached. it is possible
// the block got orphaned, and this tx is in mempool
// or different block, and what we have in cache
// is thus wrong
// but we do this only for first top blocks. no sense
// doing it for all blocks
bool is_tx_still_in_block_as_expected {true};
if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height)
{
const crypto::hash& tx_hash = txd_pair.first;
if (core_storage->have_tx(tx_hash))
{
try
{
uint64_t tx_height_in_blockchain =
core_storage->get_db().get_tx_block_height(tx_hash);
// check if height of the given tx that we have in cache,
// denoted by i, is same as what is acctually stored
// in blockchain
if (tx_height_in_blockchain == i)
{
is_tx_still_in_block_as_expected = true;
}
else
{
// if no tx in the given block, just stop
// any futher search. no need. we are going
// to ditch the cache, in a monent
is_tx_still_in_block_as_expected = false;
break;
}
}
catch (const TX_DNE& e)
{
cerr << "Tx from cache" << pod_to_hex(tx_hash)
<< " is no longer in the blockchain "
<< endl;
is_tx_still_in_block_as_expected = false;
break;
}
}
else
{
is_tx_still_in_block_as_expected = false;
break;
}
} // if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height)
if (!is_tx_still_in_block_as_expected)
{
// if some tx in cache is not in blockchain
// where it should be, its probably better to
// ditch entire cache, as redo it below.
block_tx_cache.Clear();
txs.clear();
i = end_height;
continue; // reado the main loop
}
// if we got to here, it means that everything went fine
// and no unexpeced things happended.
mstch::map txd_map = boost::get<mstch::map>(txd_pair.second);
// now we need to update age of txs from cashe
if (!boost::get<string>(txd_map["age"]).empty())
{
txd_map["age"] = age.first;
}
txs.push_back(txd_map);
} // for (const pair<crypto::hash, mstch::map>& txd_pair: txd_pairs)
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - start);
// cout << "block_tx_json_cache from cache" << endl;
duration_cached += duration.count();
++cache_hits;
}
else
{
// this is new block. not in cashe.
// need to process its txs and add to cache
// start measure time here // start measure time here
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
@ -895,7 +700,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
uint64_t tx_i {0}; uint64_t tx_i {0};
// this vector will go into block_tx cache
// tx_hash , txd_map // tx_hash , txd_map
vector<pair<crypto::hash, mstch::node>> txd_pairs; vector<pair<crypto::hash, mstch::node>> txd_pairs;
@ -940,18 +744,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
auto duration = std::chrono::duration_cast<std::chrono::microseconds> auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - start); (std::chrono::steady_clock::now() - start);
duration_non_cached += duration.count();
++cache_misses;
if (enable_block_cache)
{
// save in block_tx cache
block_tx_cache.Put(i, txd_pairs);
}
} // else if (block_tx_json_cache.Contains(i))
--i; // go to next block number --i; // go to next block number
} // while (i <= end_height) } // while (i <= end_height)
@ -959,30 +751,20 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
// calculate median size of the blocks shown // calculate median size of the blocks shown
//double blk_size_median = xmreg::calc_median(blk_sizes.begin(), blk_sizes.end()); //double blk_size_median = xmreg::calc_median(blk_sizes.begin(), blk_sizes.end());
// save computational times for disply in the frontend
context["construction_time_cached"] = fmt::format(
"{:0.4f}", duration_cached/1.0e6);
context["construction_time_non_cached"] = fmt::format(
"{:0.4f}", duration_non_cached/1.0e6);
context["construction_time_total"] = fmt::format(
"{:0.4f}", (duration_non_cached+duration_cached)/1.0e6);
context["cache_hits"] = cache_hits;
context["cache_misses"] = cache_misses;
// get current network info from MemoryStatus thread. // get current network info from MemoryStatus thread.
MempoolStatus::network_info current_network_info MempoolStatus::network_info current_network_info
= MempoolStatus::current_network_info; = MempoolStatus::current_network_info;
// perapre network info mstch::map for the front page // perapre network info mstch::map for the front page
string hash_rate; string hash_rate;
double hr_d; double hr_d;
char metric_prefix; char metric_prefix;
cryptonote::difficulty_type hr = make_difficulty(current_network_info.hash_rate, current_network_info.hash_rate_top64);
cryptonote::difficulty_type hr = make_difficulty(
current_network_info.hash_rate,
current_network_info.hash_rate_top64);
get_metric_prefix(hr, hr_d, metric_prefix); get_metric_prefix(hr, hr_d, metric_prefix);
if (metric_prefix != 0) if (metric_prefix != 0)
@ -1001,7 +783,7 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
} }
context["network_info"] = mstch::map { context["network_info"] = mstch::map {
{"difficulty" , make_difficulty(current_network_info.difficulty, current_network_info.difficulty_top64).str()}, {"difficulty" , current_network_info.difficulty},
{"hash_rate" , hash_rate}, {"hash_rate" , hash_rate},
{"fee_per_kb" , print_money(current_network_info.fee_per_kb)}, {"fee_per_kb" , print_money(current_network_info.fee_per_kb)},
{"alt_blocks_no" , current_network_info.alt_blocks_count}, {"alt_blocks_no" , current_network_info.alt_blocks_count},
@ -1101,7 +883,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
// initalise page tempate map with basic info about mempool // initalise page tempate map with basic info about mempool
mstch::map context { mstch::map context {
{"mempool_size" , static_cast<uint64_t>(total_no_of_mempool_tx)}, // total no of mempool txs {"mempool_size" , static_cast<uint64_t>(total_no_of_mempool_tx)}, // total no of mempool txs
{"show_cache_times" , show_cache_times},
{"mempool_refresh_time" , MempoolStatus::mempool_refresh_time} {"mempool_refresh_time" , MempoolStatus::mempool_refresh_time}
}; };
@ -1110,11 +891,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
// get reference to blocks template map to be field below // get reference to blocks template map to be field below
mstch::array& txs = boost::get<mstch::array>(context["mempooltxs"]); mstch::array& txs = boost::get<mstch::array>(context["mempooltxs"]);
double duration_cached {0.0};
double duration_non_cached {0.0};
uint64_t cache_hits {0};
uint64_t cache_misses {0};
uint64_t local_copy_server_timestamp = server_timestamp; uint64_t local_copy_server_timestamp = server_timestamp;
// for each transaction in the memory pool // for each transaction in the memory pool
@ -1145,7 +921,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
delta_time[3], delta_time[4]); delta_time[3], delta_time[4]);
} }
// cout << "block_tx_json_cache from cache" << endl;
// set output page template map // set output page template map
txs.push_back(mstch::map { txs.push_back(mstch::map {
@ -1583,150 +1358,9 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
mstch::map tx_context; mstch::map tx_context;
if (enable_tx_cache && tx_context_cache.Contains({tx_hash, static_cast<bool>(with_ring_signatures)}))
{
// with_ring_signatures == 0 means that cache is not used
// when obtaining detailed information about tx is requested.
// we are going to measure time for the construction of the
// tx context from cashe. just for fun, to see if cache is any faster.
auto start = std::chrono::steady_clock::now();
const tx_info_cache& tx_info_cashed
= tx_context_cache.Get({tx_hash, static_cast<bool>(with_ring_signatures)});
tx_context = tx_info_cashed.tx_map;
//cout << "get tx from cash: " << tx_hash_str <<endl;
//cout << " - tx_blk_height: " << boost::get<uint64_t>(tx_context["tx_blk_height"]) <<endl;
//cout << " - blk_timestamp_uint: " << boost::get<uint64_t>(tx_context["blk_timestamp_uint"]) <<endl;
// now have to update age and confirmation numbers of the tx.
uint64_t tx_blk_height = boost::get<uint64_t>(tx_context["tx_blk_height"]);
uint64_t blk_timestamp_uint = boost::get<uint64_t>(tx_context["blk_timestamp_uint"]);
if (tx_blk_height > 0)
{
// seems to be in blockchain. off course it could have been orphaned
// so double check if its for sure in blockchain
if (core_storage->have_tx(tx_hash))
{
// ok, it is still in blockchain
// update its age and number of confirmations
pair<string, string> age
= get_age(std::time(nullptr),
blk_timestamp_uint,
FULL_AGE_FORMAT);
tx_context["delta_time"] = age.first;
uint64_t bc_height = core_storage->get_current_blockchain_height();
tx_context["confirmations"] = bc_height - (tx_blk_height - 1);
// marke it as from cashe. useful if we want to show
// info about cashed/not cashed in frontend.
tx_context["from_cache"] = true;
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - start);
tx_context["construction_time"] = fmt::format(
"{:0.4f}", static_cast<double>(duration.count())/1.0e6);
// normally we should update this into in the cache.
// but since we make this check all the time,
// we can skip updating cashed version
} // if (core_storage->have_tx(tx_hash))
else
{
// its not in blockchain, but it was there when we cashed it.
// so we update it in cash, as it should be back in mempool
tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures)); tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
tx_context_cache.Put(
{tx_hash, static_cast<bool>(with_ring_signatures)},
tx_info_cache {
boost::get<uint64_t>(tx_context["tx_blk_height"]),
boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
tx_context}
);
}
} // if (tx_blk_height > 0)
else
{
// the tx was cashed when in mempool.
// since then, it might have been included in some block.
// so we check it.
if (core_storage->have_tx(tx_hash))
{
// checking if in blockchain already
// it was before in mempool, but now maybe already in blockchain
tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
tx_context_cache.Put(
{tx_hash, static_cast<bool>(with_ring_signatures)},
tx_info_cache {
boost::get<uint64_t>(tx_context["tx_blk_height"]),
boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
tx_context});
} // if (core_storage->have_tx(tx_hash))
else
{
// still seems to be in mempool only.
// so just get its time duration, as its read only
// from cache
tx_context["from_cache"] = true;
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - start);
tx_context["construction_time"] = fmt::format(
"{:0.4f}", static_cast<double>(duration.count())/1.0e6);
}
} // else if (tx_blk_height > 0)
} // if (tx_context_cache.Contains(tx_hash))
else
{
// we are going to measure time for the construction of the
// tx context. just for fun, to see if cache is any faster.
auto start = std::chrono::steady_clock::now();
tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - start);
if (enable_tx_cache)
{
tx_context_cache.Put(
{tx_hash, static_cast<bool>(with_ring_signatures)},
tx_info_cache {
boost::get<uint64_t>(tx_context["tx_blk_height"]),
boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
tx_context});
}
tx_context["construction_time"] = fmt::format(
"{:0.4f}", static_cast<double>(duration.count())/1.0e6);
} // else if (tx_context_cache.Contains(tx_hash))
tx_context["show_more_details_link"] = show_more_details_link; tx_context["show_more_details_link"] = show_more_details_link;
if (boost::get<bool>(tx_context["has_error"])) if (boost::get<bool>(tx_context["has_error"]))
@ -1737,7 +1371,6 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
mstch::map context { mstch::map context {
{"testnet" , this->testnet}, {"testnet" , this->testnet},
{"stagenet" , this->stagenet}, {"stagenet" , this->stagenet},
{"show_cache_times" , show_cache_times},
{"txs" , mstch::array{}}, {"txs" , mstch::array{}},
{"refresh" , refresh_page}, {"refresh" , refresh_page},
{"tx_hash" , tx_hash_str} {"tx_hash" , tx_hash_str}
@ -4878,11 +4511,6 @@ json_transaction(string tx_hash_str)
no_confirmations = txd.no_confirmations; no_confirmations = txd.no_confirmations;
} }
// get tx from tx fetched. can be use to double check
// if what we return in the json response agrees with
// what tx_hash was requested
string tx_hash_str_again = pod_to_hex(get_transaction_hash(tx));
// get basic tx info // get basic tx info
j_data = get_tx_json(tx, txd); j_data = get_tx_json(tx, txd);
@ -6447,7 +6075,6 @@ construct_tx_context(transaction tx, uint16_t with_ring_signatures = 0)
{"error_msg" , string("")}, {"error_msg" , string("")},
{"have_raw_tx" , false}, {"have_raw_tx" , false},
{"show_more_details_link", true}, {"show_more_details_link", true},
{"from_cache" , false},
{"construction_time" , string {}}, {"construction_time" , string {}},
}; };
@ -6863,7 +6490,15 @@ get_tx_details(const transaction& tx,
tx_details txd; tx_details txd;
// get tx hash // get tx hash
if (!tx.pruned)
{
txd.hash = get_transaction_hash(tx); txd.hash = get_transaction_hash(tx);
}
else
{
txd.hash = get_pruned_transaction_hash(tx, tx.prunable_hash);
}
// get tx public key from extra // get tx public key from extra
// this check if there are two public keys // this check if there are two public keys

View file

@ -111,14 +111,3 @@
</div> </div>
{{#show_cache_times}}
<div class="center">
<h6 style="margin-top: 1px;color:#949490">
Tx details construction time: {{construction_time_total}} s
<br/>
includes {{construction_time_cached}} s from block cache ({{cache_hits}} hits)
and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses)
</h6>
</div>
{{/show_cache_times}}

View file

@ -300,18 +300,4 @@
{{/with_ring_signatures}} {{/with_ring_signatures}}
{{/have_raw_tx}} {{/have_raw_tx}}
{{#show_cache_times}}
<div class="center">
{{#construction_time}}
<h6 style="margin-top: 1px;color:#949490">
Tx details construction time: {{construction_time}} s
{{#from_cache}}
<br/>Tx read from the tx cache
{{/from_cache}}
</h6>
{{/construction_time}}
</div>
{{/show_cache_times}}
</div> </div>