store RouterInfo in DHT

This commit is contained in:
orignal 2023-02-21 19:08:12 -05:00
parent ebee6c5f13
commit abf687ff09
4 changed files with 177 additions and 72 deletions

View File

@ -14,7 +14,7 @@ namespace i2p
namespace data namespace data
{ {
DHTNode::DHTNode (): DHTNode::DHTNode ():
zero (nullptr), one (nullptr), hash (nullptr) zero (nullptr), one (nullptr)
{ {
} }
@ -22,17 +22,16 @@ namespace data
{ {
if (zero) delete zero; if (zero) delete zero;
if (one) delete one; if (one) delete one;
if (hash) delete hash;
} }
void DHTNode::MoveHashUp (bool fromOne) void DHTNode::MoveRouterUp (bool fromOne)
{ {
DHTNode *& side = fromOne ? one : zero; DHTNode *& side = fromOne ? one : zero;
if (side) if (side)
{ {
if (hash) delete hash; // shouldn't happen if (router) router = nullptr; // shouldn't happen
hash = side->hash; router = side->router;
side->hash = nullptr; side->router = nullptr;
delete side; delete side;
side = nullptr; side = nullptr;
} }
@ -49,38 +48,46 @@ namespace data
delete m_Root; delete m_Root;
} }
DHTNode * DHTTable::Insert (const IdentHash& h) void DHTTable::Clear ()
{ {
return Insert (new IdentHash (h), m_Root, 0); m_Size = 0;
delete m_Root;
m_Root = new DHTNode;
} }
DHTNode * DHTTable::Insert (IdentHash * h, DHTNode * root, int level) void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r)
{ {
if (root->hash) if (!r) return;
{ return Insert (r, m_Root, 0);
if (*(root->hash) == *h)
{
delete h;
return root;
} }
auto h2 = root->hash;
root->hash = nullptr; m_Size--; void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level)
{
if (root->router)
{
if (root->router->GetIdentHash () == r->GetIdentHash ())
{
root->router = r; // replace
return;
}
auto r2 = root->router;
root->router = nullptr; m_Size--;
int bit1, bit2; int bit1, bit2;
do do
{ {
bit1 = h->GetBit (level); bit1 = r->GetIdentHash ().GetBit (level);
bit2 = h2->GetBit (level); bit2 = r2->GetIdentHash ().GetBit (level);
if (bit1 == bit2) if (bit1 == bit2)
{ {
if (bit1) if (bit1)
{ {
if (root->one) return nullptr; // someting wrong if (root->one) return; // someting wrong
root->one = new DHTNode; root->one = new DHTNode;
root = root->one; root = root->one;
} }
else else
{ {
if (root->zero) return nullptr; // someting wrong if (root->zero) return; // someting wrong
root->zero = new DHTNode; root->zero = new DHTNode;
root = root->zero; root = root->zero;
} }
@ -95,37 +102,36 @@ namespace data
root->one = new DHTNode; root->one = new DHTNode;
if (bit1) if (bit1)
{ {
Insert (h2, root->zero, level + 1); Insert (r2, root->zero, level + 1);
return Insert (h, root->one, level + 1); Insert (r, root->one, level + 1);
} }
else else
{ {
Insert (h2, root->one, level + 1); Insert (r2, root->one, level + 1);
return Insert (h, root->zero, level + 1); Insert (r, root->zero, level + 1);
} }
} }
else else
{ {
if (!root->zero && !root->one) if (!root->zero && !root->one)
{ {
root->hash = h; m_Size++; root->router = r; m_Size++;
return root; return;
} }
int bit = h->GetBit (level); int bit = r->GetIdentHash ().GetBit (level);
if (bit) if (bit)
{ {
if (!root->one) if (!root->one)
root->one = new DHTNode; root->one = new DHTNode;
return Insert (h, root->one, level + 1); Insert (r, root->one, level + 1);
} }
else else
{ {
if (!root->zero) if (!root->zero)
root->zero = new DHTNode; root->zero = new DHTNode;
return Insert (h, root->zero, level + 1); Insert (r, root->zero, level + 1);
} }
} }
return nullptr;
} }
bool DHTTable::Remove (const IdentHash& h) bool DHTTable::Remove (const IdentHash& h)
@ -137,9 +143,9 @@ namespace data
{ {
if (root) if (root)
{ {
if (root->hash && *(root->hash) == h) if (root->router && root->router->GetIdentHash () == h)
{ {
delete root->hash; root->hash = nullptr; root->router = nullptr;
m_Size--; m_Size--;
return true; return true;
} }
@ -152,11 +158,11 @@ namespace data
{ {
delete root->one; delete root->one;
root->one = nullptr; root->one = nullptr;
if (root->zero && root->zero->hash) if (root->zero && root->zero->router)
root->MoveHashUp (false); root->MoveRouterUp (false);
} }
else if (root->one->hash && !root->zero) else if (root->one->router && !root->zero)
root->MoveHashUp (true); root->MoveRouterUp (true);
return true; return true;
} }
} }
@ -168,11 +174,11 @@ namespace data
{ {
delete root->zero; delete root->zero;
root->zero = nullptr; root->zero = nullptr;
if (root->one && root->one->hash) if (root->one && root->one->router)
root->MoveHashUp (true); root->MoveRouterUp (true);
} }
else if (root->zero->hash && !root->one) else if (root->zero->router && !root->one)
root->MoveHashUp (false); root->MoveRouterUp (false);
return true; return true;
} }
} }
@ -180,48 +186,95 @@ namespace data
return false; return false;
} }
IdentHash * DHTTable::FindClosest (const IdentHash& h) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter)
{ {
return FindClosest (h, m_Root, 0); if (filter) m_Filter = filter;
auto r = FindClosest (h, m_Root, 0);
m_Filter = nullptr;
return r;
} }
IdentHash * DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level)
{ {
if (root->hash) return root->hash; bool split = false;
do
{
if (root->router)
return (!m_Filter || m_Filter (root->router)) ? root->router : nullptr;
split = root->zero && root->one;
if (!split)
{
if (root->zero) root = root->zero;
else if (root->one) root = root->one;
else return nullptr;
level++;
}
}
while (!split);
int bit = h.GetBit (level); int bit = h.GetBit (level);
if (bit) if (bit)
{ {
if (root->one) if (root->one)
return FindClosest (h, root->one, level + 1); {
auto r = FindClosest (h, root->one, level + 1);
if (r) return r;
}
if (root->zero) if (root->zero)
return FindClosest (h, root->zero, level + 1); {
auto r = FindClosest (h, root->zero, level + 1);
if (r) return r;
}
} }
else else
{ {
if (root->zero) if (root->zero)
return FindClosest (h, root->zero, level + 1); {
auto r = FindClosest (h, root->zero, level + 1);
if (r) return r;
}
if (root->one) if (root->one)
return FindClosest (h, root->one, level + 1); {
auto r = FindClosest (h, root->one, level + 1);
if (r) return r;
}
} }
return nullptr; return nullptr;
} }
std::vector<IdentHash *> DHTTable::FindClosest (const IdentHash& h, size_t num) std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter)
{ {
std::vector<IdentHash *> vec; std::vector<std::shared_ptr<RouterInfo> > vec;
if (num > 0) if (num > 0)
{
if (filter) m_Filter = filter;
FindClosest (h, num, m_Root, 0, vec); FindClosest (h, num, m_Root, 0, vec);
m_Filter = nullptr;
}
return vec; return vec;
} }
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<IdentHash *>& hashes) void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes)
{ {
if (hashes.size () >= num) return; if (hashes.size () >= num) return;
if (root->hash) bool split = false;
do
{ {
hashes.push_back (root->hash); if (root->router)
{
if (!m_Filter || m_Filter (root->router))
hashes.push_back (root->router);
return; return;
} }
split = root->zero && root->one;
if (!split)
{
if (root->zero) root = root->zero;
else if (root->one) root = root->one;
else return;
level++;
}
}
while (!split);
int bit = h.GetBit (level); int bit = h.GetBit (level);
if (bit) if (bit)
{ {
@ -239,6 +292,54 @@ namespace data
} }
} }
void DHTTable::Cleanup (Filter filter)
{
if (filter)
{
m_Filter = filter;
Cleanup (m_Root);
m_Filter = nullptr;
}
else
Clear ();
}
void DHTTable::Cleanup (DHTNode * root)
{
if (!root) return;
if (root->router)
{
if (!m_Filter || !m_Filter (root->router))
{
m_Size--;
root->router = nullptr;
}
return;
}
if (root->zero)
{
Cleanup (root->zero);
if (root->zero->IsEmpty ())
{
delete root->zero;
root->zero = nullptr;
}
}
if (root->one)
{
Cleanup (root->one);
if (root->one->IsEmpty ())
{
delete root->one;
root->one = nullptr;
if (root->zero && root->zero->router)
root->MoveRouterUp (false);
}
else if (root->one->router && !root->zero)
root->MoveRouterUp (true);
}
}
void DHTTable::Print (std::stringstream& s) void DHTTable::Print (std::stringstream& s)
{ {
Print (s, m_Root, 0); Print (s, m_Root, 0);
@ -248,10 +349,10 @@ namespace data
{ {
if (!root) return; if (!root) return;
s << std::string (level, '-'); s << std::string (level, '-');
if (root->hash) if (root->router)
{ {
if (!root->zero && !root->one) if (!root->zero && !root->one)
s << '>' << GetIdentHashAbbreviation (*(root->hash)); s << '>' << GetIdentHashAbbreviation (root->router->GetIdentHash ());
else else
s << "error"; s << "error";
} }

View File

@ -13,7 +13,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include "Identity.h" #include <functional>
#include "RouterInfo.h"
// Kademlia DHT (XOR distance) // Kademlia DHT (XOR distance)
@ -24,42 +25,48 @@ namespace data
struct DHTNode struct DHTNode
{ {
DHTNode * zero, * one; DHTNode * zero, * one;
IdentHash * hash; std::shared_ptr<RouterInfo> router;
DHTNode (); DHTNode ();
~DHTNode (); ~DHTNode ();
bool IsEmpty () const { return !zero && !one && !hash; }; bool IsEmpty () const { return !zero && !one && !router; };
void MoveHashUp (bool fromOne); void MoveRouterUp (bool fromOne);
}; };
class DHTTable class DHTTable
{ {
typedef std::function<bool (const std::shared_ptr<RouterInfo>&)> Filter;
public: public:
DHTTable (); DHTTable ();
~DHTTable (); ~DHTTable ();
DHTNode * Insert (const IdentHash& h); void Insert (const std::shared_ptr<RouterInfo>& r);
bool Remove (const IdentHash& h); bool Remove (const IdentHash& h);
IdentHash * FindClosest (const IdentHash& h); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr);
std::vector<IdentHash *> FindClosest (const IdentHash& h, size_t num); std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr);
void Print (std::stringstream& s); void Print (std::stringstream& s);
size_t GetSize () const { return m_Size; }; size_t GetSize () const { return m_Size; };
void Clear ();
void Cleanup (Filter filter);
private: private:
DHTNode * Insert (IdentHash * h, DHTNode * root, int level); // recursive void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive
bool Remove (const IdentHash& h, DHTNode * root, int level); bool Remove (const IdentHash& h, DHTNode * root, int level);
IdentHash * FindClosest (const IdentHash& h, DHTNode * root, int level); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level);
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<IdentHash *>& hashes); void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes);
void Cleanup (DHTNode * root);
void Print (std::stringstream& s, DHTNode * root, int level); void Print (std::stringstream& s, DHTNode * root, int level);
private: private:
DHTNode * m_Root; DHTNode * m_Root;
size_t m_Size; size_t m_Size;
// transient
Filter m_Filter;
}; };
} }
} }

View File

@ -1355,14 +1355,11 @@ namespace data
} }
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded, bool closeThanUsOnly) const const std::set<IdentHash>& excluded) const
{ {
std::shared_ptr<const RouterInfo> r; std::shared_ptr<const RouterInfo> r;
XORMetric minMetric; XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
if (closeThanUsOnly)
minMetric = destKey ^ i2p::context.GetIdentHash ();
else
minMetric.SetMax (); minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) for (const auto& it: m_Floodfills)

View File

@ -93,7 +93,7 @@ namespace data
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;