use DHT table for floodfills

This commit is contained in:
orignal 2023-02-22 15:58:20 -05:00
parent 692600dfac
commit d40cd00cdb
4 changed files with 49 additions and 87 deletions

View File

@ -186,7 +186,7 @@ namespace data
return false; return false;
} }
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) const
{ {
if (filter) m_Filter = filter; if (filter) m_Filter = filter;
auto r = FindClosest (h, m_Root, 0); auto r = FindClosest (h, m_Root, 0);
@ -194,7 +194,7 @@ namespace data
return r; return r;
} }
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) const
{ {
bool split = false; bool split = false;
do do
@ -241,7 +241,7 @@ namespace data
return nullptr; return nullptr;
} }
std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) const
{ {
std::vector<std::shared_ptr<RouterInfo> > vec; std::vector<std::shared_ptr<RouterInfo> > vec;
if (num > 0) if (num > 0)
@ -253,7 +253,7 @@ namespace data
return vec; return vec;
} }
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const
{ {
if (hashes.size () >= num) return; if (hashes.size () >= num) return;
bool split = false; bool split = false;
@ -292,7 +292,7 @@ namespace data
} }
} }
void DHTTable::Cleanup (Filter filter) void DHTTable::Cleanup (const Filter& filter)
{ {
if (filter) if (filter)
{ {

View File

@ -44,20 +44,20 @@ namespace data
void Insert (const std::shared_ptr<RouterInfo>& r); void Insert (const std::shared_ptr<RouterInfo>& r);
bool Remove (const IdentHash& h); bool Remove (const IdentHash& h);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr) const;
std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr); std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr) const;
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 Clear ();
void Cleanup (Filter filter); void Cleanup (const Filter& filter);
private: private:
void Insert (const std::shared_ptr<RouterInfo>& r, 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);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level) const;
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes); void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const;
void Cleanup (DHTNode * root); void Cleanup (DHTNode * root);
void Print (std::stringstream& s, DHTNode * root, int level); void Print (std::stringstream& s, DHTNode * root, int level);
@ -66,7 +66,7 @@ namespace data
DHTNode * m_Root; DHTNode * m_Root;
size_t m_Size; size_t m_Size;
// transient // transient
Filter m_Filter; mutable Filter m_Filter;
}; };
} }
} }

View File

@ -55,7 +55,7 @@ namespace data
Load (); Load ();
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{ {
Reseed (); Reseed ();
} }
@ -66,13 +66,13 @@ namespace data
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
{ {
// remove own router // remove own router
m_Floodfills.remove (it->second); m_Floodfills.Remove (it->second->GetIdentHash ());
m_RouterInfos.erase (it); m_RouterInfos.erase (it);
} }
// insert own router // insert own router
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ()); m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ()); m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles); i2p::config::GetOption("persist.profiles", m_PersistProfiles);
@ -88,7 +88,7 @@ namespace data
SaveProfiles (); SaveProfiles ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.Clear ();
if (m_Thread) if (m_Thread)
{ {
m_IsRunning = false; m_IsRunning = false;
@ -289,7 +289,7 @@ namespace data
if (wasFloodfill) if (wasFloodfill)
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.remove (r); m_Floodfills.Remove (r->GetIdentHash ());
} }
m_Requests.RequestComplete (ident, nullptr); m_Requests.RequestComplete (ident, nullptr);
return nullptr; return nullptr;
@ -301,9 +301,9 @@ namespace data
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
if (wasFloodfill) if (wasFloodfill)
m_Floodfills.remove (r); m_Floodfills.Remove (r->GetIdentHash ());
else if (r->IsEligibleFloodfill ()) else if (r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -329,7 +329,7 @@ namespace data
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -530,7 +530,7 @@ namespace data
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second) if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{ {
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -614,7 +614,7 @@ namespace data
{ {
// make sure we cleanup netDb from previous attempts // make sure we cleanup netDb from previous attempts
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.Clear ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
std::vector<std::string> files; std::vector<std::string> files;
@ -622,14 +622,14 @@ namespace data
for (const auto& path : files) for (const auto& path : files)
LoadRouterInfo (path, ts); LoadRouterInfo (path, ts);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)"); LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.GetSize (), " floodfils)");
} }
void NetDb::SaveUpdated () void NetDb::SaveUpdated ()
{ {
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0; int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
auto totalFloodfills = m_Floodfills.size (); auto totalFloodfills = m_Floodfills.GetSize ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime (); auto uptime = i2p::context.GetUptime ();
@ -721,11 +721,10 @@ namespace data
// clean up expired floodfills or not floodfills anymore // clean up expired floodfills or not floodfills anymore
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();) m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool
if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ()) {
it = m_Floodfills.erase (it); return r && r->IsFloodfill () && !r->IsUnreachable ();
else });
it++;
} }
} }
} }
@ -1362,74 +1361,37 @@ 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) const const std::set<IdentHash>& excluded) const
{ {
std::shared_ptr<const RouterInfo> r;
XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{ {
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ()) return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
{ !excluded.count (r->GetIdentHash ());
XORMetric m = destKey ^ it->GetIdentHash (); });
if (m < minMetric && !excluded.count (it->GetIdentHash ()))
{
minMetric = m;
r = it;
}
}
}
return r;
} }
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly) const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{ {
struct Sorted std::vector<IdentHash> res;
{
std::shared_ptr<const RouterInfo> r;
XORMetric metric;
bool operator< (const Sorted& other) const { return metric < other.metric; };
};
std::set<Sorted> sorted;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
XORMetric ourMetric; std::vector<std::shared_ptr<RouterInfo> > v;
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{ {
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ()) return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
{ !excluded.count (r->GetIdentHash ());
XORMetric m = destKey ^ it->GetIdentHash (); });
if (closeThanUsOnly && ourMetric < m) continue;
if (sorted.size () < num)
sorted.insert ({it, m});
else if (m < sorted.rbegin ()->metric)
{
sorted.insert ({it, m});
sorted.erase (std::prev (sorted.end ()));
}
}
}
} }
if (v.empty ()) return res;
std::vector<IdentHash> res; XORMetric ourMetric;
size_t i = 0; if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
for (const auto& it: sorted) for (auto& it: v)
{ {
if (i < num) if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break;
{ res.push_back (it->GetIdentHash ());
const auto& ident = it.r->GetIdentHash ();
if (!excluded.count (ident))
{
res.push_back (ident);
i++;
}
}
else
break;
} }
return res; return res;
} }

View File

@ -12,7 +12,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
#include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@ -31,6 +30,7 @@
#include "Family.h" #include "Family.h"
#include "version.h" #include "version.h"
#include "util.h" #include "util.h"
#include "KadDHT.h"
namespace i2p namespace i2p
{ {
@ -110,7 +110,7 @@ namespace data
// for web interface // for web interface
int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumRouters () const { return m_RouterInfos.size (); };
int GetNumFloodfills () const { return m_Floodfills.size (); }; int GetNumFloodfills () const { return m_Floodfills.GetSize (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); };
/** visit all lease sets we currently store */ /** visit all lease sets we currently store */
@ -164,7 +164,7 @@ namespace data
mutable std::mutex m_RouterInfosMutex; mutable std::mutex m_RouterInfosMutex;
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; DHTTable m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;