aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-02-12 17:17:30 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-02-12 17:17:30 +0000
commit8bdc86beb4c17b6970f25f00d35fe45977681956 (patch)
tree5143eb76118b38631df645a8564d83e90063dfbe
parentepee: fix some log macros not printing context nicely (diff)
downloadmonero-8bdc86beb4c17b6970f25f00d35fe45977681956.tar.xz
protocol: speed up sync by minimizing duplicate work
In particular, the prepare_handle_incoming_blocks call is pretty lengthy, and entirely pointless in the common case where several different connections will prepare the exact same blocks.
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl32
2 files changed, 31 insertions, 2 deletions
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 7a3a2d325..fd4f03690 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -135,6 +135,7 @@ namespace cryptonote
std::atomic<bool> m_synchronized;
bool m_one_request = true;
std::atomic<bool> m_stopping;
+ epee::critical_section m_sync_lock;
boost::mutex m_buffer_mutex;
double get_avg_block_size();
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 151a661d9..f1317a838 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -790,6 +790,8 @@ namespace cryptonote
context.m_remote_blockchain_height = arg.current_blockchain_height;
size_t count = 0;
+ std::vector<crypto::hash> block_hashes;
+ block_hashes.reserve(arg.blocks.size());
for(const block_complete_entry& block_entry: arg.blocks)
{
if (m_stopping)
@@ -807,9 +809,10 @@ namespace cryptonote
return 1;
}
//to avoid concurrency in core between connections, suspend connections which delivered block later then first one
+ const crypto::hash block_hash = get_block_hash(b);
if(count == 2)
{
- if(m_core.have_block(get_block_hash(b)))
+ if(m_core.have_block(block_hash))
{
context.m_state = cryptonote_connection_context::state_idle;
context.m_needed_objects.clear();
@@ -819,7 +822,7 @@ namespace cryptonote
}
}
- auto req_it = context.m_requested_objects.find(get_block_hash(b));
+ auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
@@ -836,6 +839,7 @@ namespace cryptonote
}
context.m_requested_objects.erase(req_it);
+ block_hashes.push_back(block_hash);
}
if(context.m_requested_objects.size())
@@ -858,7 +862,31 @@ namespace cryptonote
uint64_t previous_height = m_core.get_current_blockchain_height();
+ // we lock all the rest to avoid having multiple connections redo a lot
+ // of the same work, and one of them doing it for nothing: subsequent
+ // connections will wait until the current one's added its blocks, then
+ // will add any extra it has, if any
+ CRITICAL_REGION_LOCAL(m_sync_lock);
+
+ // dismiss what another connection might already have done (likely everything)
+ uint64_t top_height;
+ crypto::hash top_hash;
+ if (m_core.get_blockchain_top(top_height, top_hash)) {
+ uint64_t dismiss = 1;
+ for (const auto &h: block_hashes) {
+ if (top_hash == h) {
+ LOG_DEBUG_CC(context, "Found current top block in synced blocks, dismissing "
+ << dismiss << "/" << arg.blocks.size() << " blocks");
+ while (dismiss--)
+ arg.blocks.pop_front();
+ break;
+ }
+ ++dismiss;
+ }
+ }
+
m_core.prepare_handle_incoming_blocks(arg.blocks);
+
for(const block_complete_entry& block_entry: arg.blocks)
{
if (m_stopping)