33 #include <unordered_map> 34 #include <boost/uuid/nil_generator.hpp> 35 #include <boost/uuid/uuid_io.hpp> 41 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 42 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "cn.block_queue" 45 static_assert(
sizeof(
size_t) <=
sizeof(
boost::uuids::uuid),
"boost::uuids::uuid too small");
48 return reinterpret_cast<const std::size_t &
>(_v);
58 boost::unique_lock<boost::recursive_mutex> lock(mutex);
59 std::vector<crypto::hash>
hashes;
66 requested_hashes.insert(h);
67 have_blocks.insert(h);
76 boost::unique_lock<boost::recursive_mutex> lock(mutex);
82 boost::unique_lock<boost::recursive_mutex> lock(mutex);
83 block_map::iterator i =
blocks.begin();
86 block_map::iterator j = i++;
87 if (j->connection_id == connection_id && (all || j->blocks.size() == 0))
94 void block_queue::erase_block(block_map::iterator j)
99 requested_hashes.erase(h);
100 have_blocks.erase(h);
107 boost::unique_lock<boost::recursive_mutex> lock(mutex);
108 block_map::iterator i =
blocks.begin();
111 block_map::iterator j = i++;
112 if (j->blocks.empty() && live_connections.find(j->connection_id) == live_connections.end())
121 boost::unique_lock<boost::recursive_mutex> lock(mutex);
122 for (block_map::iterator i =
blocks.begin(); i !=
blocks.end(); ++i)
124 if (i->start_block_height == start_block_height)
137 boost::unique_lock<boost::recursive_mutex> lock(mutex);
138 for (block_map::iterator i =
blocks.begin(); i !=
blocks.end(); )
140 block_map::iterator j = i++;
141 if (j->connection_id == connection_id && j->start_block_height <= start_block_height)
150 boost::unique_lock<boost::recursive_mutex> lock(mutex);
163 boost::unique_lock<boost::recursive_mutex> lock(mutex);
165 return blockchain_height;
166 uint64_t last_needed_height = blockchain_height;
173 return last_needed_height;
177 return last_needed_height;
182 boost::unique_lock<boost::recursive_mutex> lock(mutex);
183 MDEBUG(
"Block queue has " <<
blocks.size() <<
" spans");
190 boost::unique_lock<boost::recursive_mutex> lock(mutex);
193 block_map::const_iterator i =
blocks.begin();
195 uint64_t expected = blockchain_height;
198 if (expected > i->start_block_height)
204 if (expected < i->start_block_height)
205 s +=
std::string(std::max((
uint64_t)1, (i->start_block_height - expected) / (i->nblocks ? i->nblocks : 1)),
'_');
206 s += i->blocks.empty() ?
"." : i->start_block_height == blockchain_height ?
"m" :
"o";
207 expected = i->start_block_height + i->nblocks;
217 return requested_hashes.find(
hash) != requested_hashes.end();
222 boost::unique_lock<boost::recursive_mutex> lock(mutex);
223 return requested_internal(
hash);
228 boost::unique_lock<boost::recursive_mutex> lock(mutex);
229 return have_blocks.find(
hash) != have_blocks.end();
234 boost::unique_lock<boost::recursive_mutex> lock(mutex);
236 MDEBUG(
"reserve_span: first_block_height " << first_block_height <<
", last_block_height " << last_block_height
238 blockchain_height <<
", block hashes size " << block_hashes.size());
239 if (last_block_height < first_block_height || max_blocks == 0)
241 MDEBUG(
"reserve_span: early out: first_block_height " << first_block_height <<
", last_block_height " << last_block_height <<
", max_blocks " << max_blocks);
242 return std::make_pair(0, 0);
244 if (block_hashes.size() > last_block_height)
246 MDEBUG(
"reserve_span: more block hashes than fit within last_block_height: " << block_hashes.size() <<
" and " << last_block_height);
247 return std::make_pair(0, 0);
251 uint64_t span_start_height = last_block_height - block_hashes.size() + 1;
252 std::vector<crypto::hash>::const_iterator i = block_hashes.begin();
253 while (i != block_hashes.end() && requested_internal(*i))
261 MDEBUG(
"reserve_span: next_unpruned_height " << next_unpruned_height <<
" from " << span_start_height <<
" and seed " 265 MDEBUG(
"We can download from next span: ideal height " << span_start_height <<
", next unpruned height " << next_unpruned_height <<
266 "(+" << next_unpruned_height - span_start_height <<
"), current seed " << pruning_seed);
267 span_start_height = next_unpruned_height;
269 MDEBUG(
"span_start_height: " <<span_start_height);
270 const uint64_t block_hashes_start_height = last_block_height - block_hashes.size() + 1;
271 if (span_start_height >= block_hashes.size() + block_hashes_start_height)
273 MDEBUG(
"Out of hashes, cannot reserve");
274 return std::make_pair(0, 0);
277 i = block_hashes.begin() + span_start_height - block_hashes_start_height;
278 while (i != block_hashes.end() && requested_internal(*i))
285 std::vector<crypto::hash>
hashes;
286 while (i != block_hashes.end() && span_length < max_blocks &&
tools::has_unpruned_block(span_start_height + span_length, blockchain_height, pruning_seed))
292 if (span_length == 0)
294 MDEBUG(
"span_length 0, cannot reserve");
295 return std::make_pair(0, 0);
297 MDEBUG(
"Reserving span " << span_start_height <<
" - " << (span_start_height + span_length - 1) <<
" for " << connection_id);
300 return std::make_pair(span_start_height, span_length);
305 boost::unique_lock<boost::recursive_mutex> lock(mutex);
307 return std::make_pair(0, 0);
308 block_map::const_iterator i =
blocks.begin();
310 return std::make_pair(0, 0);
311 if (!i->blocks.empty())
312 return std::make_pair(0, 0);
314 connection_id = i->connection_id;
316 return std::make_pair(i->start_block_height, i->nblocks);
321 boost::unique_lock<boost::recursive_mutex> lock(mutex);
323 block_map::iterator i =
blocks.begin();
326 (boost::posix_time::ptime&)i->time = t;
331 boost::unique_lock<boost::recursive_mutex> lock(mutex);
332 for (block_map::iterator i =
blocks.begin(); i !=
blocks.end(); ++i)
334 if (i->start_block_height == start_height && i->connection_id == connection_id)
340 requested_hashes.insert(h);
349 boost::unique_lock<boost::recursive_mutex> lock(mutex);
352 block_map::const_iterator i =
blocks.begin();
353 for (; i !=
blocks.end(); ++i)
355 if (!filled || !i->blocks.empty())
357 height = i->start_block_height;
359 connection_id = i->connection_id;
368 boost::unique_lock<boost::recursive_mutex> lock(mutex);
371 block_map::const_iterator i =
blocks.begin();
374 if (i->connection_id != connection_id)
376 filled = !i->blocks.empty();
383 boost::unique_lock<boost::recursive_mutex> lock(mutex);
386 block_map::const_iterator i =
blocks.begin();
389 if (i->start_block_height >
height)
391 filled = !i->blocks.empty();
393 connection_id = i->connection_id;
399 boost::unique_lock<boost::recursive_mutex> lock(mutex);
408 boost::unique_lock<boost::recursive_mutex> lock(mutex);
412 block_map::const_iterator i =
blocks.begin();
414 while (i !=
blocks.end() && !i->blocks.empty())
424 boost::unique_lock<boost::recursive_mutex> lock(mutex);
434 boost::unique_lock<boost::recursive_mutex> lock(mutex);
463 boost::unique_lock<boost::recursive_mutex> lock(mutex);
464 std::unordered_map<boost::uuids::uuid, float> speeds;
472 std::unordered_map<boost::uuids::uuid, float>::iterator i = speeds.find(
span.
connection_id);
473 if (i == speeds.end())
476 i->second = (i->second +
span.
rate) / 2;
478 float conn_rate = -1, best_rate = 0;
479 for (
const auto &i: speeds)
481 if (i.first == connection_id)
482 conn_rate = i.second;
483 if (i.second > best_rate)
484 best_rate = i.second;
492 const float speed = conn_rate / best_rate;
493 MTRACE(
" Relative speed for " << connection_id <<
": " << speed <<
" (" << conn_rate <<
"/" << best_rate);
499 boost::unique_lock<boost::recursive_mutex> lock(mutex);
500 float conn_rate = -1.f;
513 conn_rate = (conn_rate +
span.
rate) / 2;
518 MTRACE(
"Download rate for " << connection_id <<
": " << conn_rate <<
" b/s");
524 boost::unique_lock<boost::recursive_mutex> lock(mutex);
525 block_map::const_iterator i =
blocks.begin();
size_t get_data_size() const
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
uint64_t get_next_needed_height(uint64_t blockchain_height) const
std::pair< uint64_t, uint64_t > reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector< crypto::hash > &block_hashes, boost::posix_time::ptime time=boost::posix_time::microsec_clock::universal_time())
size_t get_num_filled_spans() const
bool foreach(std::function< bool(const span &)> f) const
uint64_t start_block_height
void flush_spans(const boost::uuids::uuid &connection_id, bool all=false)
struct hash_func hashes[]
size_t get_num_filled_spans_prefix() const
void reset_next_span_time(boost::posix_time::ptime t=boost::posix_time::microsec_clock::universal_time())
float get_download_rate(const boost::uuids::uuid &connection_id) const
std::vector< crypto::hash > hashes
void remove_spans(const boost::uuids::uuid &connection_id, uint64_t start_block_height)
Holds cryptonote related classes and helpers.
#define CRYPTONOTE_PRUNING_STRIPE_SIZE
void flush_stale_spans(const std::set< boost::uuids::uuid > &live_connections)
std::string get_overview(uint64_t blockchain_height) const
void add_blocks(uint64_t height, std::vector< cryptonote::block_complete_entry > bcel, const boost::uuids::uuid &connection_id, float rate, size_t size)
bool have(const crypto::hash &hash) const
float get_speed(const boost::uuids::uuid &connection_id) const
unsigned __int64 uint64_t
std::pair< uint64_t, uint64_t > get_next_span_if_scheduled(std::vector< crypto::hash > &hashes, boost::uuids::uuid &connection_id, boost::posix_time::ptime &time) const
bool get_next_span(uint64_t &height, std::vector< cryptonote::block_complete_entry > &bcel, boost::uuids::uuid &connection_id, bool filled=true) const
bool remove_span(uint64_t start_block_height, std::vector< crypto::hash > *hashes=NULL)
bool has_spans(const boost::uuids::uuid &connection_id) const
const T & move(const T &t)
uint64_t get_max_block_height() const
boost::uuids::uuid connection_id
crypto::hash get_last_known_hash(const boost::uuids::uuid &connection_id) const
bool has_next_span(const boost::uuids::uuid &connection_id, bool &filled, boost::posix_time::ptime &time) const
bool requested(const crypto::hash &hash) const
void set_span_hashes(uint64_t start_height, const boost::uuids::uuid &connection_id, std::vector< crypto::hash > hashes)
std::size_t operator()(const boost::uuids::uuid &_v) const
std::vector< cryptonote::block_complete_entry > blocks