optimize DHT

This commit is contained in:
Arvid Norberg 2013-10-20 07:06:42 +00:00
parent 416d064489
commit 1b888eeec6
2 changed files with 44 additions and 36 deletions

View File

@ -646,24 +646,35 @@ bool routing_table::add_node(node_entry e)
// nodes sharing a prefix. Find all nodes that do not // nodes sharing a prefix. Find all nodes that do not
// have a unique prefix // have a unique prefix
std::sort(b.begin(), b.end(), boost::bind(&node_entry::id, _1) < boost::bind(&node_entry::id, _2)); // find node entries with duplicate prefixes in O(1)
std::vector<bucket_t::iterator> prefix(1 << (8 - mask_shift), b.end());
TORRENT_ASSERT(prefix.size() >= bucket_size_limit);
// the begin iterator from this object is used as a placeholder
// for an occupied slot whose node has already been added to the
// duplicate nodes list.
bucket_t placeholder;
int last_prefix = -1;
nodes.reserve(b.size()); nodes.reserve(b.size());
for (j = b.begin(); j != b.end(); ++j) for (j = b.begin(); j != b.end(); ++j)
{ {
node_id id = j->id; node_id id = j->id;
id <<= bucket_index + 1; id <<= bucket_index + 1;
int this_prefix = id[0] & mask; int this_prefix = (id[0] & mask) >> mask_shift;
if (this_prefix != last_prefix) TORRENT_ASSERT(this_prefix >= 0);
TORRENT_ASSERT(this_prefix < prefix.size());
if (prefix[this_prefix] != b.end())
{ {
last_prefix = this_prefix; // there's already a node with this prefix. Remember both
continue; // duplicates.
} nodes.push_back(j);
if (nodes.empty() || nodes.back() != j-1) if (prefix[this_prefix] != placeholder.begin())
nodes.push_back(j-1); {
nodes.push_back(j); nodes.push_back(prefix[this_prefix]);
prefix[this_prefix] = placeholder.begin();
}
}
} }
if (!nodes.empty()) if (!nodes.empty())
@ -959,6 +970,7 @@ void routing_table::find_node(node_id const& target
table_t::iterator j = i; table_t::iterator j = i;
int unsorted_start_idx = 0;
for (; j != m_buckets.end() && int(l.size()) < count; ++j) for (; j != m_buckets.end() && int(l.size()) < count; ++j)
{ {
bucket_t& b = j->live_nodes; bucket_t& b = j->live_nodes;
@ -974,32 +986,30 @@ void routing_table::find_node(node_id const& target
, !boost::bind(&node_entry::confirmed, _1)); , !boost::bind(&node_entry::confirmed, _1));
} }
if (int(l.size()) >= count) if (int(l.size()) == count) return;
if (int(l.size()) > count)
{ {
// sort the nodes by how close they are to the target // sort the nodes by how close they are to the target
std::sort(l.begin(), l.end(), boost::bind(&compare_ref std::sort(l.begin() + unsorted_start_idx, l.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1) , boost::bind(&node_entry::id, _1)
, boost::bind(&node_entry::id, _2), target)); , boost::bind(&node_entry::id, _2), target));
l.resize(count); l.resize(count);
return; return;
} }
unsorted_start_idx = int(l.size());
} }
// if we still don't have enough nodes, copy nodes // if we still don't have enough nodes, copy nodes
// further away from us // further away from us
if (i == m_buckets.begin()) if (i == m_buckets.begin())
{
// sort the nodes by how close they are to the target
std::sort(l.begin(), l.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1)
, boost::bind(&node_entry::id, _2), target));
return; return;
}
j = i; j = i;
unsorted_start_idx = int(l.size());
do do
{ {
--j; --j;
@ -1015,26 +1025,23 @@ void routing_table::find_node(node_id const& target
, !boost::bind(&node_entry::confirmed, _1)); , !boost::bind(&node_entry::confirmed, _1));
} }
if (int(l.size()) >= count) if (int(l.size()) == count) return;
if (int(l.size()) > count)
{ {
// sort the nodes by how close they are to the target // sort the nodes by how close they are to the target
std::sort(l.begin(), l.end(), boost::bind(&compare_ref std::sort(l.begin() + unsorted_start_idx, l.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1) , boost::bind(&node_entry::id, _1)
, boost::bind(&node_entry::id, _2), target)); , boost::bind(&node_entry::id, _2), target));
l.resize(count); l.resize(count);
return; return;
} }
unsorted_start_idx = int(l.size());
} }
while (j != m_buckets.begin() && int(l.size()) < count); while (j != m_buckets.begin() && int(l.size()) < count);
// sort the nodes by how close they are to the target TORRENT_ASSERT(int(l.size()) <= count);
std::sort(l.begin(), l.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1)
, boost::bind(&node_entry::id, _2), target));
if (int(l.size()) >= count)
l.resize(count);
} }
} } // namespace libtorrent::dht } } // namespace libtorrent::dht

View File

@ -988,7 +988,8 @@ int test_main()
dht_settings s; dht_settings s;
// s.restrict_routing_ips = false; // s.restrict_routing_ips = false;
node_id id = to_hash("3123456789abcdef01232456789abcdef0123456"); node_id id = to_hash("3123456789abcdef01232456789abcdef0123456");
dht::routing_table table(id, 10, s); const int bucket_size = 10;
dht::routing_table table(id, bucket_size, s);
std::vector<node_entry> nodes; std::vector<node_entry> nodes;
TEST_EQUAL(table.size().get<0>(), 0); TEST_EQUAL(table.size().get<0>(), 0);
@ -1107,9 +1108,9 @@ int test_main()
TEST_EQUAL(temp.size(), nodes.size()); TEST_EQUAL(temp.size(), nodes.size());
std::generate(tmp.begin(), tmp.end(), &std::rand); std::generate(tmp.begin(), tmp.end(), &std::rand);
table.find_node(tmp, temp, 0, 7); table.find_node(tmp, temp, 0, bucket_size);
std::cout << "returned: " << temp.size() << std::endl; std::cout << "returned: " << temp.size() << std::endl;
TEST_EQUAL(temp.size(), 7); TEST_EQUAL(temp.size(), bucket_size);
std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1) , boost::bind(&node_entry::id, _1)
@ -1123,16 +1124,16 @@ int test_main()
{ {
int hit = std::find_if(nodes.begin(), nodes.end() int hit = std::find_if(nodes.begin(), nodes.end()
, boost::bind(&node_entry::id, _1) == i->id) - nodes.begin(); , boost::bind(&node_entry::id, _1) == i->id) - nodes.begin();
// std::cerr << hit << std::endl; std::cerr << hit << std::endl;
if (hit < int(temp.size())) ++hits; if (hit < int(temp.size())) ++hits;
} }
std::cout << "hits: " << hits << std::endl; std::cout << "hits: " << hits << std::endl;
TEST_CHECK(hits == int(temp.size())); TEST_EQUAL(hits, int(temp.size()));
std::generate(tmp.begin(), tmp.end(), &std::rand); std::generate(tmp.begin(), tmp.end(), &std::rand);
table.find_node(tmp, temp, 0, 15); table.find_node(tmp, temp, 0, bucket_size * 2);
std::cout << "returned: " << temp.size() << std::endl; std::cout << "returned: " << temp.size() << std::endl;
TEST_EQUAL(int(temp.size()), (std::min)(15, int(nodes.size()))); TEST_EQUAL(int(temp.size()), (std::min)(bucket_size * 2, int(nodes.size())));
std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref
, boost::bind(&node_entry::id, _1) , boost::bind(&node_entry::id, _1)
@ -1146,11 +1147,11 @@ int test_main()
{ {
int hit = std::find_if(nodes.begin(), nodes.end() int hit = std::find_if(nodes.begin(), nodes.end()
, boost::bind(&node_entry::id, _1) == i->id) - nodes.begin(); , boost::bind(&node_entry::id, _1) == i->id) - nodes.begin();
// std::cerr << hit << std::endl; std::cerr << hit << std::endl;
if (hit < int(temp.size())) ++hits; if (hit < int(temp.size())) ++hits;
} }
std::cout << "hits: " << hits << std::endl; std::cout << "hits: " << hits << std::endl;
TEST_CHECK(hits == int(temp.size())); TEST_EQUAL(hits, int(temp.size()));
using namespace libtorrent::dht; using namespace libtorrent::dht;