split bucket

This commit is contained in:
orignal committed 2026-09-21 20:23:01 -04:00
1 parent 9539637d79
commit cff9f8ecc0
2 files changed
+113 -15

No files matched your search

+87 -11
View File
@@ -17,24 +17,86 @@ namespace i2p
{
namespace torrents
{
NodeID Bucket::GetMiddleID () const
{
NodeID middleID = start;
int bit = std::max (start.FindLowestBit (), next ? next->start.FindLowestBit () : -1) + 1;
middleID[bit >> 3] |= (0x80 >> (bit & 0x07));
return middleID;
}
void Bucket::Split ()
{
auto middleID = GetMiddleID ();
auto newBucket = new Bucket (middleID);
newBucket->next = next;
next = newBucket;
// move some nodes
auto it = nodes.begin ();
while (it != nodes.end ())
{
if ((*it)->id < middleID)
it++; // stay in old bucket
else
{
// move to new bucket
auto node = *it;
it = nodes.erase (it);
newBucket->nodes.push_back (node);
}
}
}
RoutingTable::RoutingTable (const NodeID& ourNode):
m_OurNode (ourNode)
{
m_Buckets.push_back (std::make_shared<Bucket> ());
m_Buckets = new Bucket;
}
std::shared_ptr<Bucket> RoutingTable::FindBucket (const Torrent::InfoHash& id) const
RoutingTable::~RoutingTable ()
{
if (m_Buckets.empty ()) return nullptr;
auto it = m_Buckets.begin ();
while (std::next (it) != m_Buckets.end ())
while (m_Buckets)
{
if (id < (*std::next (it))->start)
return *it;
it++;
auto bucket = m_Buckets;
m_Buckets = m_Buckets->next;
delete bucket;
}
}
Bucket * RoutingTable::FindBucket (const Torrent::InfoHash& id) const
{
if (!m_Buckets) return nullptr;
auto bucket = m_Buckets;
while (bucket->next)
{
if (id < bucket->next->start)
return bucket;
bucket = bucket->next;
}
return bucket;
}
void RoutingTable::RemoveEmptyBuckers ()
{
if (m_Buckets)
{
auto prev = m_Buckets, bucket = m_Buckets->next;
while (bucket)
{
if (bucket->nodes.empty ())
{
prev->next = bucket->next;
auto tmp = bucket;
bucket = bucket->next;
delete tmp;
}
else
{
prev = bucket;
bucket = bucket->next;
}
}
}
return *it;
}
std::shared_ptr<Node> RoutingTable::AddNode (const NodeID& id, i2p::data::IdentHash& peer, uint16_t port)
@@ -42,8 +104,22 @@ namespace torrents
if (id == m_OurNode) return nullptr;
auto bucket = FindBucket (id);
if (!bucket) return nullptr;
auto node = std::make_shared<Node>(id, peer, port);
bucket->nodes.emplace_back (node);
if (bucket->IsFull () && !bucket->IsInBucket (m_OurNode)) return nullptr;
std::shared_ptr<Node> node;
do
{
bucket->Split ();
bucket = FindBucket (id);
}
while (bucket->IsFull ());
if (bucket)
{
node = std::make_shared<Node>(id, peer, port);
bucket->nodes.emplace_back (node);
}
RemoveEmptyBuckers ();
return node;
}
+26 -4
View File
@@ -31,13 +31,27 @@ namespace torrents
struct NodeID: public Torrent::InfoHash
{
static constexpr size_t len = std::tuple_size<Torrent::InfoHash>::value;
constexpr Distance operator^(const Torrent::InfoHash& hash)
constexpr Distance operator^(const Torrent::InfoHash& hash) const
{
Distance d;
for (size_t i = 0; i < size (); i++)
d[i] = (*this)[i] ^ hash[i];
return d;
}
constexpr int FindLowestBit () const // -1 in not found
{
for (int i = size () - 1; i >= 0; i--)
{
uint8_t byte = (*this)[i];
if (byte)
{
for (int j = 7; j >= 0; j--)
if (byte & (0x80 >> j))
return i*8 + j;
}
}
return -1;
}
};
struct Node
@@ -53,10 +67,16 @@ namespace torrents
constexpr size_t MAX_BUCKET_CAPACITY = 8;
struct Bucket
{
Bucket * next;
std::list<std::shared_ptr<Node> > nodes;
NodeID start;
Bucket (): start{} {}
Bucket (): next (nullptr), start{} {}
Bucket (const NodeID& start1): next (nullptr), start (start1) {}
bool IsFull () const { return nodes.size () >= MAX_BUCKET_CAPACITY; }
bool IsInBucket (const NodeID& id) const { return id >= start && (!next || id < next->start); }
NodeID GetMiddleID () const;
void Split ();
};
class RoutingTable
@@ -64,17 +84,19 @@ namespace torrents
public:
RoutingTable (const NodeID& ourNode);
~RoutingTable ();
std::shared_ptr<Node> AddNode (const NodeID& id, i2p::data::IdentHash& peer, uint16_t port);
std::list<std::pair<std::shared_ptr<Node>, Distance> > FindClosestNodes (const Torrent::InfoHash& infoHash, size_t num) const;
private:
std::shared_ptr<Bucket> FindBucket (const Torrent::InfoHash& id) const;
Bucket * FindBucket (const Torrent::InfoHash& id) const;
void RemoveEmptyBuckers ();
private:
std::list<std::shared_ptr<Bucket> > m_Buckets;
Bucket * m_Buckets;
NodeID m_OurNode;
};