forked from premiere/premiere-libtorrent
extend DHT unit test and fix bug in routing_table bucket splitting
This commit is contained in:
parent
7f4ca24f8b
commit
51e99ba3e5
|
@ -170,6 +170,8 @@ private:
|
||||||
|
|
||||||
table_t::iterator find_bucket(node_id const& id);
|
table_t::iterator find_bucket(node_id const& id);
|
||||||
|
|
||||||
|
void split_bucket();
|
||||||
|
|
||||||
// return a pointer the node_entry with the given endpoint
|
// return a pointer the node_entry with the given endpoint
|
||||||
// or 0 if we don't have such a node. Both the address and the
|
// or 0 if we don't have such a node. Both the address and the
|
||||||
// port has to match
|
// port has to match
|
||||||
|
|
|
@ -175,6 +175,7 @@ void routing_table::print_state(std::ostream& os) const
|
||||||
{
|
{
|
||||||
// if (i->live_nodes.empty()) continue;
|
// if (i->live_nodes.empty()) continue;
|
||||||
os << "=== BUCKET == " << bucket_index
|
os << "=== BUCKET == " << bucket_index
|
||||||
|
<< " == " << i->live_nodes.size() << "|" << i->replacements.size()
|
||||||
<< " == " << total_seconds(time_now() - i->last_active)
|
<< " == " << total_seconds(time_now() - i->last_active)
|
||||||
<< " seconds ago ===== \n";
|
<< " seconds ago ===== \n";
|
||||||
for (bucket_t::const_iterator j = i->live_nodes.begin()
|
for (bucket_t::const_iterator j = i->live_nodes.begin()
|
||||||
|
@ -535,8 +536,8 @@ bool routing_table::add_node(node_entry e)
|
||||||
// with nodes from that cache.
|
// with nodes from that cache.
|
||||||
|
|
||||||
j = std::max_element(b.begin(), b.end()
|
j = std::max_element(b.begin(), b.end()
|
||||||
, boost::bind(&node_entry::fail_count, _1)
|
, boost::bind(&node_entry::fail_count, _1)
|
||||||
< boost::bind(&node_entry::fail_count, _2));
|
< boost::bind(&node_entry::fail_count, _2));
|
||||||
|
|
||||||
if (j != b.end() && j->fail_count() > 0)
|
if (j != b.end() && j->fail_count() > 0)
|
||||||
{
|
{
|
||||||
|
@ -552,8 +553,8 @@ bool routing_table::add_node(node_entry e)
|
||||||
// in order to keep lookup times small, prefer nodes with low RTTs
|
// in order to keep lookup times small, prefer nodes with low RTTs
|
||||||
|
|
||||||
j = std::max_element(b.begin(), b.end()
|
j = std::max_element(b.begin(), b.end()
|
||||||
, boost::bind(&node_entry::rtt, _1)
|
, boost::bind(&node_entry::rtt, _1)
|
||||||
< boost::bind(&node_entry::rtt, _2));
|
< boost::bind(&node_entry::rtt, _2));
|
||||||
|
|
||||||
if (j != b.end() && j->rtt > e.rtt)
|
if (j != b.end() && j->rtt > e.rtt)
|
||||||
{
|
{
|
||||||
|
@ -605,6 +606,35 @@ bool routing_table::add_node(node_entry e)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
split_bucket();
|
||||||
|
|
||||||
|
// now insert the new node in the appropriate bucket
|
||||||
|
i = find_bucket(e.id);
|
||||||
|
int dst_bucket = std::distance(m_buckets.begin(), i);
|
||||||
|
bucket_t& nb = i->live_nodes;
|
||||||
|
bucket_t& nrb = i->replacements;
|
||||||
|
|
||||||
|
if (int(nb.size()) < bucket_limit(dst_bucket))
|
||||||
|
nb.push_back(e);
|
||||||
|
else if (int(nrb.size()) < m_bucket_size)
|
||||||
|
nrb.push_back(e);
|
||||||
|
|
||||||
|
m_ips.insert(e.addr.to_v4().to_bytes());
|
||||||
|
|
||||||
|
while (m_buckets.back().live_nodes.size() > bucket_limit(m_buckets.size()-1))
|
||||||
|
split_bucket();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void routing_table::split_bucket()
|
||||||
|
{
|
||||||
|
int bucket_index = m_buckets.size()-1;
|
||||||
|
int bucket_size_limit = bucket_limit(bucket_index);
|
||||||
|
TORRENT_ASSERT(m_buckets.back().live_nodes.size() >= bucket_size_limit);
|
||||||
|
|
||||||
|
bucket_t& b = m_buckets.back().live_nodes;
|
||||||
|
bucket_t& rb = m_buckets.back().replacements;
|
||||||
|
|
||||||
// this is the last bucket, and it's full already. Split
|
// this is the last bucket, and it's full already. Split
|
||||||
// it by adding another bucket
|
// it by adding another bucket
|
||||||
m_buckets.push_back(routing_table_node());
|
m_buckets.push_back(routing_table_node());
|
||||||
|
@ -625,10 +655,7 @@ bool routing_table::add_node(node_entry e)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// this entry belongs in the new bucket
|
// this entry belongs in the new bucket
|
||||||
if (int(new_bucket.size()) < bucket_size_limit)
|
new_bucket.push_back(*j);
|
||||||
new_bucket.push_back(*j);
|
|
||||||
else if (int(new_replacement_bucket.size()) < m_bucket_size)
|
|
||||||
new_replacement_bucket.push_back(*j);
|
|
||||||
j = b.erase(j);
|
j = b.erase(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,37 +683,6 @@ bool routing_table::add_node(node_entry e)
|
||||||
}
|
}
|
||||||
j = rb.erase(j);
|
j = rb.erase(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool added = false;
|
|
||||||
// now insert the new node in the appropriate bucket
|
|
||||||
if (distance_exp(m_id, e.id) >= 159 - bucket_index)
|
|
||||||
{
|
|
||||||
if (int(b.size()) < bucket_size_limit)
|
|
||||||
{
|
|
||||||
b.push_back(e);
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
else if (int(rb.size()) < m_bucket_size)
|
|
||||||
{
|
|
||||||
rb.push_back(e);
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (int(new_bucket.size()) < new_bucket_size)
|
|
||||||
{
|
|
||||||
new_bucket.push_back(e);
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
else if (int(new_replacement_bucket.size()) < m_bucket_size)
|
|
||||||
{
|
|
||||||
new_replacement_bucket.push_back(e);
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (added) m_ips.insert(e.addr.to_v4().to_bytes());
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void routing_table::for_each_node(
|
void routing_table::for_each_node(
|
||||||
|
|
|
@ -62,6 +62,11 @@ address rand_v4()
|
||||||
return address_v4((rand() << 16 | rand()) & 0xffffffff);
|
return address_v4((rand() << 16 | rand()) & 0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
udp::endpoint rand_ep()
|
||||||
|
{
|
||||||
|
return udp::endpoint(rand_v4(), rand());
|
||||||
|
}
|
||||||
|
|
||||||
sha1_hash generate_next()
|
sha1_hash generate_next()
|
||||||
{
|
{
|
||||||
sha1_hash ret;
|
sha1_hash ret;
|
||||||
|
@ -69,6 +74,14 @@ sha1_hash generate_next()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_id random_id()
|
||||||
|
{
|
||||||
|
node_id ret;
|
||||||
|
for (int i = 0; i < 20; ++i)
|
||||||
|
ret[i] = rand();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
boost::array<char, 64> generate_key()
|
boost::array<char, 64> generate_key()
|
||||||
{
|
{
|
||||||
boost::array<char, 64> ret;
|
boost::array<char, 64> ret;
|
||||||
|
@ -591,6 +604,39 @@ int test_main()
|
||||||
}
|
}
|
||||||
#endif // TORRENT_USE_OPENSSL
|
#endif // TORRENT_USE_OPENSSL
|
||||||
|
|
||||||
|
// test routing table
|
||||||
|
|
||||||
|
{
|
||||||
|
sett.extended_routing_table = false;
|
||||||
|
routing_table tbl(random_id(), 8, sett);
|
||||||
|
|
||||||
|
// insert 256 nodes evenly distributed across the ID space.
|
||||||
|
// we expect to fill the top 5 buckets
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
node_id id = random_id();
|
||||||
|
id[0] = i;
|
||||||
|
tbl.node_seen(id, rand_ep(), 50);
|
||||||
|
}
|
||||||
|
TEST_EQUAL(tbl.num_active_buckets(), 6);
|
||||||
|
|
||||||
|
tbl.print_state(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
sett.extended_routing_table = true;
|
||||||
|
routing_table tbl(random_id(), 8, sett);
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
node_id id = random_id();
|
||||||
|
id[0] = i;
|
||||||
|
tbl.node_seen(id, rand_ep(), 50);
|
||||||
|
}
|
||||||
|
TEST_EQUAL(tbl.num_active_buckets(), 6);
|
||||||
|
|
||||||
|
tbl.print_state(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue