mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-10-22 15:21:45 +00:00
split bucket
This commit is contained in:
1 parent
9539637d79
commit
cff9f8ecc0
2 files changed
+113
-15
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user