split buckets when exceeding the next bucket's size, to make sure we split before risking discarding nodes because the next bucket is smaller
This commit is contained in:
parent
c6b75fa79e
commit
07ddb010c5
|
@ -634,7 +634,11 @@ routing_table::add_node_status_t routing_table::add_node_impl(node_entry e)
|
||||||
bucket_t& b = i->live_nodes;
|
bucket_t& b = i->live_nodes;
|
||||||
bucket_t& rb = i->replacements;
|
bucket_t& rb = i->replacements;
|
||||||
int const bucket_index = std::distance(m_buckets.begin(), i);
|
int const bucket_index = std::distance(m_buckets.begin(), i);
|
||||||
|
// compare against the max size of the next bucket. Otherwise we may wait too
|
||||||
|
// long to split, and lose nodes (in the case where lower-numbered buckets
|
||||||
|
// are larger)
|
||||||
int const bucket_size_limit = bucket_limit(bucket_index);
|
int const bucket_size_limit = bucket_limit(bucket_index);
|
||||||
|
int const next_bucket_size_limit = bucket_limit(bucket_index + 1);
|
||||||
|
|
||||||
bucket_t::iterator j;
|
bucket_t::iterator j;
|
||||||
|
|
||||||
|
@ -714,8 +718,20 @@ routing_table::add_node_status_t routing_table::add_node_impl(node_entry e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can we split the bucket?
|
||||||
|
// only nodes that haven't failed can split the bucket, and we can only
|
||||||
|
// split the last bucket
|
||||||
|
bool const can_split = (boost::next(i) == m_buckets.end()
|
||||||
|
&& m_buckets.size() < 159)
|
||||||
|
&& e.fail_count() == 0
|
||||||
|
&& (i == m_buckets.begin() || boost::prior(i)->live_nodes.size() > 1);
|
||||||
|
|
||||||
// if there's room in the main bucket, just insert it
|
// if there's room in the main bucket, just insert it
|
||||||
if (int(b.size()) < bucket_size_limit)
|
// if we can split the bucket (i.e. it's the last bucket) use the next
|
||||||
|
// bucket's size limit. This makes use split the low-numbered buckets split
|
||||||
|
// earlier when we have larger low buckets, to make it less likely that we
|
||||||
|
// lose nodes
|
||||||
|
if (int(b.size()) < (can_split ? next_bucket_size_limit : bucket_size_limit))
|
||||||
{
|
{
|
||||||
if (b.empty()) b.reserve(bucket_size_limit);
|
if (b.empty()) b.reserve(bucket_size_limit);
|
||||||
b.push_back(e);
|
b.push_back(e);
|
||||||
|
@ -733,14 +749,6 @@ routing_table::add_node_status_t routing_table::add_node_impl(node_entry e)
|
||||||
// as the last replacement strategy, if the node we found matching our
|
// as the last replacement strategy, if the node we found matching our
|
||||||
// bit prefix has higher RTT than the new node, replace it.
|
// bit prefix has higher RTT than the new node, replace it.
|
||||||
|
|
||||||
// can we split the bucket?
|
|
||||||
// only nodes that haven't failed can split the bucket, and we can only
|
|
||||||
// split the last bucket
|
|
||||||
bool const can_split = (boost::next(i) == m_buckets.end()
|
|
||||||
&& m_buckets.size() < 159)
|
|
||||||
&& e.fail_count() == 0
|
|
||||||
&& (i == m_buckets.begin() || boost::prior(i)->live_nodes.size() > 1);
|
|
||||||
|
|
||||||
if (e.pinged() && e.fail_count() == 0)
|
if (e.pinged() && e.fail_count() == 0)
|
||||||
{
|
{
|
||||||
// if the node we're trying to insert is considered pinged,
|
// if the node we're trying to insert is considered pinged,
|
||||||
|
@ -949,7 +957,7 @@ void routing_table::split_bucket()
|
||||||
|
|
||||||
int const bucket_index = m_buckets.size()-1;
|
int const bucket_index = m_buckets.size()-1;
|
||||||
int const bucket_size_limit = bucket_limit(bucket_index);
|
int const bucket_size_limit = bucket_limit(bucket_index);
|
||||||
TORRENT_ASSERT(int(m_buckets.back().live_nodes.size()) >= bucket_size_limit);
|
TORRENT_ASSERT(int(m_buckets.back().live_nodes.size()) >= bucket_limit(bucket_index + 1));
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -2325,11 +2325,18 @@ TORRENT_TEST(routing_table_extended)
|
||||||
node_id id = to_hash("1234876923549721020394873245098347598635");
|
node_id id = to_hash("1234876923549721020394873245098347598635");
|
||||||
node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061");
|
node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061");
|
||||||
|
|
||||||
|
// we can't add the nodes in straight 0,1,2,3 order. That way the routing
|
||||||
|
// table would get unbalanced and intermediate nodes would be dropped
|
||||||
|
std::vector<boost::uint8_t> node_id_prefix;
|
||||||
|
node_id_prefix.reserve(256);
|
||||||
|
for (int i = 0; i < 256; ++i) node_id_prefix.push_back(i);
|
||||||
|
std::random_shuffle(node_id_prefix.begin(), node_id_prefix.end());
|
||||||
|
|
||||||
routing_table tbl(id, 8, sett, &observer);
|
routing_table tbl(id, 8, sett, &observer);
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
add_and_replace(id, diff);
|
add_and_replace(id, diff);
|
||||||
id[0] = i;
|
id[0] = node_id_prefix[i];
|
||||||
tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
|
tbl.node_seen(id, rand_udp_ep(), 20 + (id[19] & 0xff));
|
||||||
}
|
}
|
||||||
TEST_EQUAL(tbl.num_active_buckets(), 6);
|
TEST_EQUAL(tbl.num_active_buckets(), 6);
|
||||||
|
|
Loading…
Reference in New Issue