Faster hash table, various other optimizations and simplification.

This commit is contained in:
Adam Ierymenko 2020-03-28 01:06:29 -07:00
parent cbf174f96d
commit 87da45b3f5
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
25 changed files with 495 additions and 380 deletions

View file

@ -355,11 +355,11 @@ public:
private:
template<typename O>
static ZT_INLINE unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
static ZT_INLINE unsigned long _hc(const uint64_t i) noexcept { return (unsigned long)(i ^ (i >> 32U)); }
static ZT_INLINE unsigned long _hc(const uint64_t i) noexcept { return (unsigned long)(i + (i >> 32U)); }
static ZT_INLINE unsigned long _hc(const uint32_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static ZT_INLINE unsigned long _hc(const uint16_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static ZT_INLINE unsigned long _hc(const uint8_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static ZT_INLINE unsigned long _hc(const int64_t i) noexcept { return (unsigned long)((unsigned long long)i ^ ((unsigned long long)i >> 32U)); }
static ZT_INLINE unsigned long _hc(const int64_t i) noexcept { return (unsigned long)((unsigned long long)i + ((unsigned long long)i >> 32U)); }
static ZT_INLINE unsigned long _hc(const int32_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static ZT_INLINE unsigned long _hc(const int16_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
static ZT_INLINE unsigned long _hc(const int8_t i) noexcept { return ((unsigned long)i * (unsigned long)0x9e3779b1); }

View file

@ -70,11 +70,6 @@ public:
*/
ZT_INLINE void zero() noexcept { _a = 0; }
/**
* @return Hash code for use with Hashtable
*/
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)_a; }
/**
* @param s String with at least 11 characters of space available (10 + terminating NULL)
* @return Hexadecimal string
@ -108,6 +103,7 @@ public:
*/
ZT_INLINE bool isReserved() const noexcept { return ((!_a) || ((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); }
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)_a; }
ZT_INLINE operator bool() const noexcept { return (_a != 0); }
ZT_INLINE bool operator==(const Address &a) const noexcept { return _a == a._a; }

View file

@ -17,7 +17,7 @@ set(core_headers
Expect.hpp
FCV.hpp
Fingerprint.hpp
Hashtable.hpp
FlatMap.hpp
Identity.hpp
InetAddress.hpp
Locator.hpp

View file

@ -17,10 +17,10 @@
#include "Constants.hpp"
#include "Buf.hpp"
#include "SharedPtr.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "Path.hpp"
#include "FCV.hpp"
#include "FlatMap.hpp"
#include <cstring>
#include <cstdlib>
@ -89,10 +89,7 @@ public:
ERR_OUT_OF_MEMORY
};
ZT_INLINE Defragmenter() :
_messages(GCT * 2)
{
}
ZT_INLINE Defragmenter() {}
/**
* Process a fragment of a multi-part message
@ -167,12 +164,8 @@ public:
std::vector<std::pair<int64_t,uint64_t> > messagesByLastUsedTime;
messagesByLastUsedTime.reserve(_messages.size());
typename Hashtable<uint64_t,_E>::Iterator i(_messages);
uint64_t *mk = nullptr;
_E *mv = nullptr;
while (i.next(mk,mv))
messagesByLastUsedTime.push_back(std::pair<int64_t,uint64_t>(mv->lastUsed,*mk));
for(typename FlatMap< uint64_t,_E >::const_iterator i(_messages.begin());i!=_messages.end();++i)
messagesByLastUsedTime.push_back(std::pair<int64_t,uint64_t>(i->second.lastUsed,i->first));
std::sort(messagesByLastUsedTime.begin(),messagesByLastUsedTime.end());
ml.writing(); // acquire write lock on _messages
@ -295,7 +288,21 @@ public:
private:
struct _E
{
ZT_INLINE _E() noexcept : id(0),lastUsed(0),totalFragmentsExpected(0),fragmentsReceived(0),via(),message(),lock() {}
ZT_INLINE _E() noexcept :
id(0),
lastUsed(0),
totalFragmentsExpected(0),
fragmentsReceived(0) {}
ZT_INLINE _E(const _E &e) noexcept :
id(e.id),
lastUsed(e.lastUsed),
totalFragmentsExpected(e.totalFragmentsExpected),
fragmentsReceived(e.fragmentsReceived),
via(e.via),
message(e.message),
lock() {}
ZT_INLINE ~_E()
{
if (via) {
@ -304,6 +311,7 @@ private:
via->_inboundFragmentedMessages_l.unlock();
}
}
uint64_t id;
volatile int64_t lastUsed;
unsigned int totalFragmentsExpected;
@ -313,7 +321,7 @@ private:
Mutex lock;
};
Hashtable< uint64_t,_E > _messages;
FlatMap< uint64_t,_E > _messages;
RWMutex _messages_l;
};

View file

@ -44,8 +44,8 @@ std::vector<uint8_t> &Dictionary::operator[](const char *k)
const std::vector<uint8_t> &Dictionary::operator[](const char *k) const
{
static const std::vector<uint8_t> emptyEntry;
const std::vector<uint8_t> *const e = _t.get(_toKey(k));
return (e) ? *e : emptyEntry;
std::map< uint64_t,std::vector<uint8_t> >::const_iterator e(_t.find(_toKey(k)));
return (e == _t.end()) ? emptyEntry : e->second;
}
void Dictionary::add(const char *k,bool v)
@ -170,11 +170,8 @@ void Dictionary::encode(std::vector<uint8_t> &out) const
out.clear();
Hashtable< uint64_t,std::vector<uint8_t> >::Iterator ti(const_cast<Dictionary *>(this)->_t);
uint64_t *kk = nullptr;
std::vector<uint8_t> *vv = nullptr;
while (ti.next(kk,vv)) {
str[0] = *kk;
for(std::map< uint64_t,std::vector<uint8_t> >::const_iterator ti(_t.begin());ti!=_t.end();++ti) {
str[0] = ti->first;
const char *k = (const char *)str;
for(;;) {
@ -186,7 +183,7 @@ void Dictionary::encode(std::vector<uint8_t> &out) const
out.push_back(61); // =
for(std::vector<uint8_t>::const_iterator i(vv->begin());i!=vv->end();++i) {
for(std::vector<uint8_t>::const_iterator i(ti->second.begin());i!=ti->second.end();++i) {
uint8_t c = *i;
switch(c) {
case 0:

View file

@ -18,10 +18,10 @@
#include "Utils.hpp"
#include "Address.hpp"
#include "Buf.hpp"
#include "Hashtable.hpp"
#include <cstdint>
#include <vector>
#include <map>
namespace ZeroTier {
@ -168,7 +168,7 @@ public:
bool decode(const void *data,unsigned int len);
private:
Hashtable< uint64_t,std::vector<uint8_t> > _t;
std::map< uint64_t,std::vector<uint8_t> > _t;
};
} // namespace ZeroTier

245
node/FlatMap.hpp Normal file
View file

@ -0,0 +1,245 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_FLATMAP_HPP
#define ZT_FLATMAP_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include <list>
#include <vector>
#include <utility>
namespace ZeroTier {
/**
* A very simple and fast flat hash table
*
* This is designed to prioritize performance over memory, though with
* endpoint ZeroTier nodes this is used in cases where the data set is not
* that large (e.g. networks, peers) and so memory consumption should not
* be much.
*
* It creates a flat hash table that maps keys to values and doubles its
* size whenever a collision occurs. The size is always a power of two so
* that only very fast operations like add, XOR, and bit mask can be used
* for hash table lookup.
*
* It also saves actual key/value pairs in a linked list for relatively
* fast iteration compared to a hash table where you have to iterate through
* a bunch of empty buckets. Iteration order should be considered undefined.
*
* @tparam K Key type
* @tparam V Value type
* @tparam IC Initial capacity (must be a power of two)
*/
template<typename K,typename V,unsigned long IC = 16>
class FlatMap
{
public:
typedef K key_type;
typedef V mapped_type;
typedef std::pair<K,V> value_type;
typedef typename std::list< std::pair<K,V> >::iterator iterator;
typedef typename std::list< std::pair<K,V> >::const_iterator const_iterator;
ZT_INLINE FlatMap() :
_d(),
_null(),
_b(new iterator[IC]),
_s(IC),
_m(IC - 1)
{
}
ZT_INLINE FlatMap(const FlatMap &m) :
_d(m._d),
_null(),
_b(new iterator[m._s]),
_s(m._s),
_m(m._m)
{
try {
for (iterator i=_d.begin();i!=_d.end();++i)
_b[_hc(i->first) & _m] = i;
} catch ( ... ) {
delete [] _b;
throw;
}
}
ZT_INLINE ~FlatMap()
{
delete [] _b;
}
ZT_INLINE FlatMap &operator=(const FlatMap &m)
{
_d = m._d;
delete [] _b;
_b = nullptr;
_b = new iterator[m._s];
_s = m._s;
_m = m._m;
for(iterator i=_d.begin();i!=_d.end();++i)
_b[_hc(i->first) & _m] = i;
}
ZT_INLINE void clear()
{
_d.clear();
delete [] _b;
_b = nullptr;
_b = new iterator[IC];
_s = IC;
_m = IC - 1;
}
ZT_INLINE V *get(const K &key) noexcept
{
const unsigned long hb = _hc(key) & _m;
if ((_b[hb] != _null)&&(_b[hb]->first == key))
return &(_b[hb]->second);
return nullptr;
}
ZT_INLINE const V *get(const K &key) const noexcept
{
const unsigned long hb = _hc(key) & _m;
if ((_b[hb] != _null)&&(_b[hb]->first == key))
return &(_b[hb]->second);
return nullptr;
}
ZT_INLINE iterator find(const K &key) noexcept
{
const unsigned long hb = _hc(key) & _m;
if ((_b[hb] != _null)&&(_b[hb]->first == key))
return _b[hb];
return _d.end();
}
ZT_INLINE const_iterator find(const K &key) const noexcept
{
const unsigned long hb = _hc(key) & _m;
if ((_b[hb] != _null)&&(_b[hb]->first == key))
return _b[hb];
return _d.end();
}
ZT_INLINE V &set(const K &key,const V &value)
{
unsigned long hb = _hc(key) & _m;
if (_b[hb] == _null) {
#ifdef __CPP11__
_d.emplace_back(key,value);
#else
_d.push_back(std::pair<K,V>(key,value));
#endif
return (_b[hb] = --_d.end())->second;
} else {
if (_b[hb]->first == key) {
_b[hb]->second = value;
return _b[hb]->second;
}
#ifdef __CPP11__
_d.emplace_back(key,value);
#else
_d.push_back(std::pair<K,V>(key,value));
#endif
_grow();
return _b[_hc(key) & _m]->second;
}
}
ZT_INLINE V &operator[](const K &key)
{
unsigned long hb = _hc(key) & _m;
if (_b[hb] == _null) {
#ifdef __CPP11__
_d.emplace_back(key,V());
#else
_d.push_back(std::pair<K,V>(key,V()));
#endif
return (_b[hb] = --_d.end())->second;
} else {
if (_b[hb]->first == key)
return _b[hb]->second;
#ifdef __CPP11__
_d.emplace_back(key,V());
#else
_d.push_back(std::pair<K,V>(key,V()));
#endif
_grow();
return _b[_hc(key) & _m]->second;
}
}
ZT_INLINE void erase(const iterator &i)
{
_b[_hc(i->first) & _m] = _null;
_d.erase(i);
}
ZT_INLINE void erase(const K &key)
{
iterator e(find(key));
if (e != end())
erase(e);
}
ZT_INLINE iterator begin() noexcept { return _d.begin(); }
ZT_INLINE iterator end() noexcept { return _d.end(); }
ZT_INLINE const_iterator begin() const noexcept { return _d.begin(); }
ZT_INLINE const_iterator end() const noexcept { return _d.end(); }
ZT_INLINE unsigned long size() const { return (unsigned long)_d.size(); }
ZT_INLINE bool empty() const { return _d.empty(); }
ZT_INLINE unsigned long hashSize() const { return _s; }
private:
template<typename O>
static ZT_INLINE unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
static ZT_INLINE unsigned long _hc(const uint64_t i) noexcept { return (unsigned long)(i + (i >> 32U)); }
static ZT_INLINE unsigned long _hc(const int64_t i) noexcept { return (unsigned long)((uint64_t)i + ((uint64_t)i >> 32U)); }
static ZT_INLINE unsigned long _hc(const uint32_t i) noexcept { return Utils::hash32(i); }
ZT_INLINE void _grow()
{
unsigned long hb;
enlarge_again:
delete [] _b;
_b = nullptr; // in case 'new' throws
_b = new iterator[_s <<= 1U];
_m = _s - 1;
for(iterator i=_d.begin();i!=_d.end();++i) {
hb = _hc(i->first) & _m;
if (_b[hb] == _null) {
_b[hb] = i;
} else {
goto enlarge_again;
}
}
}
std::list< std::pair<K,V> > _d;
const iterator _null; // prototype of a "null" / default iterator
iterator *_b;
unsigned long _s;
unsigned long _m;
};
} // namespace ZeroTier
#endif

View file

@ -25,11 +25,7 @@ Membership::Membership() :
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_comAgreementLocalTimestamp(0),
_comAgreementRemoteTimestamp(0),
_revocations(4),
_remoteTags(4),
_remoteCaps(4),
_remoteCoos(4)
_comAgreementRemoteTimestamp(0)
{
}
@ -163,8 +159,8 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
// 3/5 of the credential types have identical addCredential() code
template<typename C>
static ZT_INLINE Membership::AddCredentialResult _addCredImpl(
Hashtable<uint32_t,C> &remoteCreds,
const Hashtable<uint64_t,int64_t> &revocations,
FlatMap<uint32_t,C> &remoteCreds,
const FlatMap<uint64_t,int64_t> &revocations,
const RuntimeEnvironment *const RR,
void *const tPtr,
const Identity &sourcePeerIdentity,

View file

@ -18,7 +18,7 @@
#include "Constants.hpp"
#include "Credential.hpp"
#include "Hashtable.hpp"
#include "FlatMap.hpp"
#include "CertificateOfMembership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
@ -106,11 +106,8 @@ public:
{
if (_isUnspoofableAddress(nconf,r))
return true;
uint32_t *k = nullptr;
CertificateOfOwnership *v = nullptr;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
while (i.next(k,v)) {
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
for(FlatMap< uint32_t,CertificateOfOwnership >::const_iterator i(_remoteCoos.begin());i!=_remoteCoos.end();++i) {
if (_isCredentialTimestampValid(nconf,i->second)&&(i->second.owns(r)))
return true;
}
return false;
@ -179,14 +176,12 @@ private:
}
template<typename C>
ZT_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
ZT_INLINE void _cleanCredImpl(const NetworkConfig &nconf,FlatMap<uint32_t,C> &remoteCreds)
{
uint32_t *k = nullptr;
C *v = nullptr;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
while (i.next(k,v)) {
if (!_isCredentialTimestampValid(nconf,*v))
remoteCreds.erase(*k);
for(typename FlatMap<uint32_t,C>::iterator i(remoteCreds.begin());i!=remoteCreds.end();) {
if (!_isCredentialTimestampValid(nconf,i->second))
remoteCreds.erase(i++);
else ++i;
}
}
@ -203,21 +198,19 @@ private:
CertificateOfMembership _com;
// Revocations by credentialKey()
Hashtable< uint64_t,int64_t > _revocations;
FlatMap< uint64_t,int64_t > _revocations;
// Remote credentials that we have received from this member (and that are valid)
Hashtable< uint32_t,Tag > _remoteTags;
Hashtable< uint32_t,Capability > _remoteCaps;
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos;
FlatMap< uint32_t,Tag > _remoteTags;
FlatMap< uint32_t,Capability > _remoteCaps;
FlatMap< uint32_t,CertificateOfOwnership > _remoteCoos;
public:
class CapabilityIterator
{
public:
ZT_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) noexcept :
_hti(m._remoteCaps),
_k(nullptr),
_c(nullptr),
_hti(m._remoteCaps.begin()),
_m(m),
_nconf(nconf)
{
@ -225,17 +218,16 @@ public:
ZT_INLINE Capability *next() noexcept
{
while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c))
return _c;
while (_hti != _m._remoteCaps.end()) {
FlatMap< uint32_t,Capability >::iterator i(_hti++);
if (_m._isCredentialTimestampValid(_nconf,i->second))
return &(i->second);
}
return nullptr;
}
private:
Hashtable< uint32_t,Capability >::Iterator _hti;
uint32_t *_k;
Capability *_c;
FlatMap< uint32_t,Capability >::iterator _hti;
Membership &_m;
const NetworkConfig &_nconf;
};

View file

@ -598,7 +598,7 @@ Network::~Network()
// This is done in Node::leave() so we can pass tPtr properly
//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
} else {
RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp);
RR->node->configureVirtualNetworkPort(nullptr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp);
}
}
@ -626,7 +626,7 @@ bool Network::filterOutgoingPacket(
Mutex::Lock l1(_memberships_l);
Mutex::Lock l2(_config_l);
Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0;
Membership *const membership = (ztDest) ? _memberships.get(ztDest) : nullptr;
switch(_doZtFilter(RR,rrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch,qosBucket)) {
@ -745,7 +745,7 @@ int Network::filterIncomingPacket(
Address cc;
unsigned int ccLength = 0;
bool ccWatch = false;
const Capability *c = (Capability *)0;
const Capability *c = nullptr;
uint8_t qosBucket = 255; // For incoming packets this is a dummy value
@ -1099,13 +1099,8 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now)
{
Mutex::Lock l1(_memberships_l);
{
Address *a = nullptr;
Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m))
m->clean(now,_config);
}
for(FlatMap<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i)
i->second.clean(now,_config);
{
Mutex::Lock l2(_myMulticastGroups_l);
@ -1133,32 +1128,24 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
// Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
Hashtable< Address,unsigned long > counts;
FlatMap< Address,unsigned long > counts;
Address maxAddr;
unsigned long maxCount = 0;
MAC *m = nullptr;
Address *a = nullptr;
// Find the address responsible for the most entries
{
Hashtable<MAC,Address>::Iterator i(_remoteBridgeRoutes);
while (i.next(m,a)) {
const unsigned long c = ++counts[*a];
if (c > maxCount) {
maxCount = c;
maxAddr = *a;
}
for(FlatMap<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();++i) {
const unsigned long c = ++counts[i->second];
if (c > maxCount) {
maxCount = c;
maxAddr = i->second;
}
}
// Kill this address from our table, since it's most likely spamming us
{
Hashtable<MAC,Address>::Iterator i(_remoteBridgeRoutes);
while (i.next(m,a)) {
if (*a == maxAddr)
_remoteBridgeRoutes.erase(*m);
}
for(FlatMap<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();) {
if (i->second == maxAddr)
_remoteBridgeRoutes.erase(i++);
else ++i;
}
}
}
@ -1198,24 +1185,24 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,sourcePeerIdentity,_config,rev);
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
Address *a = nullptr;
Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) {
// TODO
/*
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
outp.append((uint8_t)0x00); // no COM
outp.append((uint16_t)0); // no capabilities
outp.append((uint16_t)0); // no tags
outp.append((uint16_t)1); // one revocation!
rev.serialize(outp);
outp.append((uint16_t)0); // no certificates of ownership
RR->sw->send(tPtr,outp,true);
*/
}
}
// TODO
/*
Address *a = nullptr;
Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) {
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
outp.append((uint8_t)0x00); // no COM
outp.append((uint16_t)0); // no capabilities
outp.append((uint16_t)0); // no tags
outp.append((uint16_t)1); // one revocation!
rev.serialize(outp);
outp.append((uint16_t)0); // no certificates of ownership
RR->sw->send(tPtr,outp,true);
}
}
*/
}
return result;
@ -1493,21 +1480,21 @@ void Network::_announceMulticastGroups(void *tPtr,bool force)
// Assumes _myMulticastGroups_l and _memberships_l are locked
const std::vector<MulticastGroup> groups(_allMulticastGroups());
_announceMulticastGroupsTo(tPtr,controller(),groups);
{
Address *a = nullptr;
Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
// TODO
/*
bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time
if ((!announce)&&(force))
announce = true;
if ((announce)&&(m->isAllowedOnNetwork(_config)))
_announceMulticastGroupsTo(tPtr,*a,groups);
*/
// TODO
/*
Address *a = nullptr;
Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time
if ((!announce)&&(force))
announce = true;
if ((announce)&&(m->isAllowedOnNetwork(_config)))
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}
*/
}
void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups)
@ -1542,7 +1529,8 @@ std::vector<MulticastGroup> Network::_allMulticastGroups() const
std::vector<MulticastGroup> mgs;
mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
_multicastGroupsBehindMe.appendKeys(mgs);
for(FlatMap< MulticastGroup,uint64_t >::const_iterator i(_multicastGroupsBehindMe.begin());i!=_multicastGroupsBehindMe.end();++i)
mgs.push_back(i->first);
if ((_config)&&(_config.enableBroadcast()))
mgs.push_back(Network::BROADCAST);
std::sort(mgs.begin(),mgs.end());

View file

@ -15,7 +15,6 @@
#define ZT_NETWORK_HPP
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Address.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
@ -26,6 +25,7 @@
#include "Membership.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
#include "FlatMap.hpp"
#include <cstdint>
#include <string>
@ -160,7 +160,7 @@ public:
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
return true;
else if (includeBridgedGroups)
return _multicastGroupsBehindMe.contains(mg);
return (_multicastGroupsBehindMe.find(mg) != _multicastGroupsBehindMe.end());
return false;
}
@ -326,11 +326,8 @@ public:
ZT_INLINE void eachMember(F f)
{
Mutex::Lock ml(_memberships_l);
Hashtable<Address,Membership>::Iterator i(_memberships);
Address *a = nullptr;
Membership *m = nullptr;
while (i.next(a,m)) {
if (!f(*a,*m))
for(FlatMap<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i) {
if (!f(i->first,i->second))
break;
}
}
@ -356,8 +353,8 @@ private:
bool _portInitialized;
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap)
Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
FlatMap< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
FlatMap< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config;
std::atomic<int64_t> _lastConfigUpdate;
@ -380,7 +377,7 @@ private:
NETCONF_FAILURE_INIT_FAILED
} _netconfFailure;
Hashtable<Address,Membership> _memberships;
FlatMap<Address,Membership> _memberships;
Mutex _myMulticastGroups_l;
Mutex _remoteBridgeRoutes_l;

View file

@ -30,7 +30,6 @@
#include "Capability.hpp"
#include "Tag.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include "Trace.hpp"

View file

@ -82,7 +82,6 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
_cb(*callbacks),
_uPtr(uPtr),
_networks(),
_networksMask(15),
_now(now),
_lastPing(0),
_lastHousekeepingRun(0),
@ -91,8 +90,6 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
_natMustDie(true),
_online(false)
{
_networks.resize(16); // _networksMask + 1, must be power of two
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
std::vector<uint8_t> data(stateObjectGet(tPtr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp));
bool haveIdentity = false;
@ -133,15 +130,9 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
Node::~Node()
{
// Let go of all networks to leave them. Do it this way in case Network wants to
// do anything in its destructor that locks the _networks lock to avoid a deadlock.
std::vector< SharedPtr<Network> > networks;
{
RWMutex::Lock _l(_networks_m);
networks.swap(_networks);
}
networks.clear();
_networks_m.lock();
_networks_m.unlock();
_networks.clear();
_networks_m.lock();
_networks_m.unlock();
@ -277,10 +268,8 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
_lastHousekeepingRun = now;
{
RWMutex::RLock l(_networks_m);
for(std::vector< SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i) {
if ((*i))
(*i)->doPeriodicTasks(tPtr,now);
}
for(FlatMap< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
i->second->doPeriodicTasks(tPtr,now);
}
}
@ -292,13 +281,10 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
// or trust nodes without doing an extra cert check.
{
_localControllerAuthorizations_m.lock();
Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
_LocalControllerAuth *k = (_LocalControllerAuth *)0;
int64_t *v = (int64_t *)0;
while (i.next(k,v)) {
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
_localControllerAuthorizations.erase(*k);
}
for(FlatMap<_LocalControllerAuth,int64_t>::iterator i(_localControllerAuthorizations.begin());i!=_localControllerAuthorizations.end();) {
if ((i->second - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
_localControllerAuthorizations.erase(i++);
else ++i;
}
_localControllerAuthorizations_m.unlock();
}
@ -349,72 +335,40 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
ZT_ResultCode Node::join(uint64_t nwid,const ZT_Fingerprint *controllerFingerprint,void *uptr,void *tptr)
{
RWMutex::Lock l(_networks_m);
const uint64_t nwidHashed = nwid + (nwid >> 32U);
SharedPtr<Network> *nw = &(_networks[(unsigned long)(nwidHashed & _networksMask)]);
// Enlarge flat hash table of networks until all networks fit without collisions.
if (*nw) {
unsigned long newNetworksSize = (unsigned long)_networks.size();
std::vector< SharedPtr<Network> > newNetworks;
uint64_t newNetworksMask,id;
std::vector< SharedPtr<Network> >::const_iterator i;
try_larger_network_hashtable:
newNetworksSize <<= 1U; // must remain a power of two
newNetworks.clear();
newNetworks.resize(newNetworksSize);
newNetworksMask = (uint64_t)(newNetworksSize - 1);
for(i=_networks.begin();i!=_networks.end();++i) {
id = (*i)->id();
nw = &(newNetworks[(unsigned long)((id + (id >> 32U)) & newNetworksMask)]);
if (*nw)
goto try_larger_network_hashtable;
*nw = *i;
}
if (newNetworks[(unsigned long)(nwidHashed & newNetworksMask)])
goto try_larger_network_hashtable;
_networks.swap(newNetworks);
_networksMask = newNetworksMask;
nw = &(_networks[(unsigned long)(nwidHashed & newNetworksMask)]);
}
Fingerprint fp;
if (controllerFingerprint)
Utils::copy<sizeof(ZT_Fingerprint)>(fp.apiFingerprint(),controllerFingerprint);
nw->set(new Network(RR,tptr,nwid,fp,uptr,(const NetworkConfig *)0));
RWMutex::Lock l(_networks_m);
SharedPtr<Network> &nw = _networks[nwid];
if (nw)
return ZT_RESULT_OK;
nw.set(new Network(RR,tptr,nwid,fp,uptr,nullptr));
return ZT_RESULT_OK;
}
ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
{
const uint64_t nwidHashed = nwid + (nwid >> 32U);
ZT_VirtualNetworkConfig ctmp;
void **nUserPtr = (void **)0;
{
RWMutex::RLock l(_networks_m);
SharedPtr<Network> &nw = _networks[(unsigned long)(nwidHashed & _networksMask)];
if (!nw)
return ZT_RESULT_OK;
if (uptr)
*uptr = nw->userPtr();
nw->externalConfig(&ctmp);
nw->destroy();
nUserPtr = nw->userPtr();
}
if (nUserPtr)
RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
{
RWMutex::Lock _l(_networks_m);
_networks[(unsigned long)(nwidHashed & _networksMask)].zero();
_networks_m.lock();
FlatMap< uint64_t,SharedPtr<Network> >::iterator nwi(_networks.find(nwid));
if (nwi == _networks.end()) {
_networks_m.unlock();
return ZT_RESULT_OK;
}
SharedPtr<Network> nw(nwi->second);
_networks.erase(nwi);
_networks_m.unlock();
if (uptr)
*uptr = *nw->userPtr();
nw->externalConfig(&ctmp);
nw->destroy();
nw.zero();
RR->node->configureVirtualNetworkPort(tptr,nwid,uptr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
@ -539,30 +493,22 @@ ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const
nw->externalConfig(nc);
return nc;
}
return (ZT_VirtualNetworkConfig *)0;
return nullptr;
}
ZT_VirtualNetworkList *Node::networks() const
{
RWMutex::RLock l(_networks_m);
unsigned long networkCount = 0;
for(std::vector< SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i) {
if ((*i))
++networkCount;
}
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * networkCount));
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size()));
if (!buf)
return (ZT_VirtualNetworkList *)0;
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
nl->networkCount = 0;
for(std::vector< SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i) {
if ((*i))
(*i)->externalConfig(&(nl->networks[nl->networkCount++]));
}
for(FlatMap< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
i->second->externalConfig(&(nl->networks[nl->networkCount++]));
return nl;
}
@ -650,12 +596,10 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const i
{
{
RWMutex::RLock l(_networks_m);
for (std::vector<SharedPtr<Network> >::iterator i(_networks.begin()); i != _networks.end(); ++i) {
if ((*i)) {
for (unsigned int k = 0,j = (*i)->config().staticIpCount; k < j; ++k) {
if ((*i)->config().staticIps[k].containsAddress(remoteAddress))
return false;
}
for (FlatMap< uint64_t,SharedPtr<Network> >::iterator i(_networks.begin()); i != _networks.end(); ++i) {
for (unsigned int k = 0,j = i->second->config().staticIpCount; k < j; ++k) {
if (i->second->config().staticIps[k].containsAddress(remoteAddress))
return false;
}
}
}

View file

@ -23,8 +23,8 @@
#include "Path.hpp"
#include "Salsa20.hpp"
#include "NetworkController.hpp"
#include "Hashtable.hpp"
#include "Buf.hpp"
#include "FlatMap.hpp"
#include <cstdio>
#include <cstdlib>
@ -172,7 +172,10 @@ public:
ZT_INLINE SharedPtr<Network> network(uint64_t nwid) const noexcept
{
RWMutex::RLock l(_networks_m);
return _networks[(unsigned long)((nwid + (nwid >> 32U)) & _networksMask)];
const SharedPtr<Network> *const n = _networks.get(nwid);
if (n)
return *n;
return SharedPtr<Network>();
}
/**
@ -342,7 +345,7 @@ private:
// in each peer if that peer object is still held in memory. Calling alarm() unnecessarily on a peer
// is harmless. This just exists as an optimization to prevent having to iterate through all peers
// on every processBackgroundTasks call. A simple map<> is used here because there are usually only
// a few of these, if any, and it's slightly faster and lower memory in that case than a Hashtable.
// a few of these, if any.
std::map<Address,int64_t> _peerAlarms;
RWMutex _peerAlarms_l;
@ -355,17 +358,16 @@ private:
{
uint64_t nwid,address;
ZT_INLINE _LocalControllerAuth(const uint64_t nwid_,const Address &address_) noexcept: nwid(nwid_),address(address_.toInt()) {}
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)(nwid ^ address); }
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)(nwid + address); }
ZT_INLINE bool operator==(const _LocalControllerAuth &a) const noexcept { return ((a.nwid == nwid) && (a.address == address)); }
ZT_INLINE bool operator!=(const _LocalControllerAuth &a) const noexcept { return ((a.nwid != nwid) || (a.address != address)); }
};
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
FlatMap<_LocalControllerAuth,int64_t> _localControllerAuthorizations;
Mutex _localControllerAuthorizations_m;
// Networks are stored in a flat hash table that is resized on any network ID collision. This makes
// network lookup by network ID a few bitwise ops and an array index.
std::vector< SharedPtr<Network> > _networks;
uint64_t _networksMask;
FlatMap< uint64_t,SharedPtr<Network> > _networks;
RWMutex _networks_m;
// These are local interface addresses that have been configured via the API

View file

@ -23,7 +23,6 @@
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "Endpoint.hpp"
#include "Locator.hpp"

View file

@ -77,7 +77,7 @@ void armor(Buf &pkt,int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],
ph.mac = mac[0];
} break;
case ZT_PROTO_CIPHER_SUITE__AES_GCM_NRH: {
case ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV: {
} break;
}
}

View file

@ -46,8 +46,7 @@ private:
};
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
RR(renv),
_phy(256)
RR(renv)
{
}
@ -70,14 +69,10 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv
// Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing'
// due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified.
{
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = nullptr;
PhySurfaceEntry *e = nullptr;
while (i.next(k,e)) {
if ((k->scope == scope)&&(k->reporterPhysicalAddress != reporterPhysicalAddress))
_phy.erase(*k);
}
for(FlatMap<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
if ((i->first.scope == scope)&&(i->first.reporterPhysicalAddress != reporterPhysicalAddress))
_phy.erase(i++);
else ++i;
}
// Reset all paths within this scope and address family
@ -96,36 +91,28 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv
void SelfAwareness::clean(int64_t now)
{
Mutex::Lock l(_phy_l);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = nullptr;
PhySurfaceEntry *e = nullptr;
while (i.next(k,e)) {
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
_phy.erase(*k);
for(FlatMap<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
if ((now - i->second.ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
_phy.erase(i++);
else ++i;
}
}
std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
{
std::multimap<unsigned long,InetAddress> r;
Hashtable<InetAddress,unsigned long> counts(16);
FlatMap<InetAddress,unsigned long,256> counts;
{
Mutex::Lock l(_phy_l);
Hashtable<PhySurfaceKey,PhySurfaceEntry>::Iterator i(const_cast<SelfAwareness *>(this)->_phy);
PhySurfaceKey *k = nullptr;
PhySurfaceEntry *e = nullptr;
while (i.next(k,e)) {
if ((now - e->ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
++counts[e->mySurface];
for(FlatMap<PhySurfaceKey,PhySurfaceEntry>::const_iterator i(_phy.begin());i!=_phy.end();++i) {
if ((now - i->second.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
++counts[i->second.mySurface];
}
}
Hashtable<InetAddress,unsigned long>::Iterator i(counts);
InetAddress *k = nullptr;
unsigned long *c = nullptr;
while (i.next(k,c))
r.insert(std::pair<unsigned long,InetAddress>(*c,*k));
for(FlatMap<InetAddress,unsigned long,256>::iterator i(counts.begin());i!=counts.end();++i)
r.insert(std::pair<unsigned long,InetAddress>(i->second,i->first));
return r;
}

View file

@ -16,7 +16,7 @@
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "FlatMap.hpp"
#include "Address.hpp"
#include "Mutex.hpp"
@ -92,7 +92,7 @@ private:
};
const RuntimeEnvironment *RR;
Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy;
FlatMap< PhySurfaceKey,PhySurfaceEntry > _phy;
Mutex _phy_l;
};

View file

@ -34,12 +34,11 @@
#include "Tag.hpp"
#include "Capability.hpp"
#include "NetworkConfig.hpp"
#include "LZ4.hpp"
#include "Hashtable.hpp"
#include "FCV.hpp"
#include "SHA512.hpp"
#include "Defragmenter.hpp"
#include "Fingerprint.hpp"
#include "FlatMap.hpp"
#include <cstdint>
#include <cstring>
@ -467,54 +466,34 @@ extern "C" const char *ZTT_general()
}
{
ZT_T_PRINTF("[general] Testing Hashtable... ");
long cnt = 0;
Hashtable< unsigned int,LifeCycleTracker > test,test2;
for(unsigned int i=0;i<512;++i)
test[i] = LifeCycleTracker(cnt);
if (cnt != 512) {
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S,cnt);
return "Hashtable test failed (1)";
}
test2 = test;
if (cnt != 1024) {
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S,cnt);
return "Hashtable test failed (2)";
}
test.clear();
if (cnt != 512) {
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S,cnt);
return "Hashtable test failed (3)";
}
for(unsigned int i=0;i<512;++i)
test[i] = LifeCycleTracker(cnt);
if (cnt != 1024) {
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S,cnt);
return "Hashtable test failed (4)";
}
test.clear();
test2.clear();
if (cnt != 0) {
ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S,cnt);
return "Hashtable test failed (5)";
}
Hashtable< unsigned int,unsigned int > test3;
for(unsigned int i=0;i<1111;++i)
test3[i] = i;
if (test3.size() != 1111) {
ZT_T_PRINTF("FAILED (size() incorrect)" ZT_EOL_S);
return "Hashtable test failed (size() incorrect)";
}
for(unsigned int i=0;i<1111;++i) {
if (test3[i] != i) {
ZT_T_PRINTF("FAILED (lookup test)" ZT_EOL_S);
return "Hashtable test failed (lookup)";
ZT_T_PRINTF("[general] Testing FlatMap... ");
FlatMap<uint64_t,uint64_t> tm;
for(uint64_t i=0;i<10000;++i)
tm.set(i,i);
for(uint64_t i=0;i<10000;++i) {
uint64_t *v = tm.get(i);
if ((!v)||(*v != i)) {
ZT_T_PRINTF("FAILED (get() failed)" ZT_EOL_S);
return "FlatMap::get() failed";
}
}
ZT_T_PRINTF("OK" ZT_EOL_S);
for(FlatMap<uint64_t,uint64_t>::iterator i(tm.begin());i!=tm.end();) {
if ((i->first & 1U) == 0)
tm.erase(i++);
else ++i;
}
if (tm.size() != 5000) {
ZT_T_PRINTF("FAILED (erase() failed (1))" ZT_EOL_S);
return "FlatMap::erase() failed (1)";
}
for(uint64_t i=0;i<10000;++i) {
uint64_t *v = tm.get(i);
if (((i & 1U) == 0)&&(v)) {
ZT_T_PRINTF("FAILED (erase() failed (2))" ZT_EOL_S);
return "FlatMap::erase() failed (2)";
}
}
ZT_T_PRINTF("OK (hash size: %lu)" ZT_EOL_S,tm.hashSize());
}
{

View file

@ -36,11 +36,7 @@ struct _RootSortComparisonOperator
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
RR(renv),
_numConfiguredPhysicalPaths(0),
_peers(256),
_peersByIncomingProbe(256),
_peersByIdentityHash(256),
_paths(1024)
_numConfiguredPhysicalPaths(0)
{
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
@ -103,11 +99,8 @@ void Topology::getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
RWMutex::RLock l(_peers_l);
allPeers.clear();
allPeers.reserve(_peers.size());
Hashtable< Address,SharedPtr<Peer> >::Iterator i(*(const_cast<Hashtable< Address,SharedPtr<Peer> > *>(&_peers)));
Address *a = nullptr;
SharedPtr<Peer> *p = nullptr;
while (i.next(a,p))
allPeers.push_back(*p);
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
allPeers.push_back(i->second);
}
void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
@ -205,26 +198,21 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
{
{
RWMutex::Lock l1(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = nullptr;
SharedPtr<Peer> *p = nullptr;
while (i.next(a,p)) {
if ( (!(*p)->alive(now)) && (_roots.count((*p)->identity()) == 0) ) {
(*p)->save(tPtr);
_peersByIncomingProbe.erase((*p)->incomingProbe());
_peersByIdentityHash.erase((*p)->identity().fingerprint());
_peers.erase(*a);
}
for(FlatMap< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();) {
if ( (!i->second->alive(now)) && (_roots.count(i->second->identity()) == 0) ) {
i->second->save(tPtr);
_peersByIncomingProbe.erase(i->second->incomingProbe());
_peersByIdentityHash.erase(i->second->identity().fingerprint());
_peers.erase(i++);
} else ++i;
}
}
{
RWMutex::Lock l1(_paths_l);
Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(_paths);
uint64_t *k = nullptr;
SharedPtr<Path> *p = nullptr;
while (i.next(k,p)) {
if ((p->references() <= 1)&&(!(*p)->alive(now)))
_paths.erase(*k);
for(FlatMap< uint64_t,SharedPtr<Path> >::iterator i(_paths.begin());i!=_paths.end();) {
if ((i->second.references() <= 1)&&(!i->second->alive(now)))
_paths.erase(i++);
else ++i;
}
}
}
@ -232,11 +220,8 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
void Topology::saveAll(void *tPtr)
{
RWMutex::RLock l(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = nullptr;
SharedPtr<Peer> *p = nullptr;
while (i.next(a,p))
(*p)->save(tPtr);
for(FlatMap< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();++i)
i->second->save(tPtr);
}
void Topology::_loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer)

View file

@ -27,10 +27,10 @@
#include "Path.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "SharedPtr.hpp"
#include "ScopedPtr.hpp"
#include "Fingerprint.hpp"
#include "FlatMap.hpp"
namespace ZeroTier {
@ -179,11 +179,8 @@ public:
ZT_INLINE void eachPeer(F f) const
{
RWMutex::RLock l(_peers_l);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
Address *a = nullptr;
SharedPtr<Peer> *p = nullptr;
while (i.next(a,p))
f(*((const SharedPtr<Peer> *)p));
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
f(i->second);
}
/**
@ -207,11 +204,8 @@ public:
std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
try {
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
Address *a = nullptr;
SharedPtr<Peer> *p = nullptr;
while (i.next(a,p))
f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr()));
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
} catch ( ... ) {} // should not throw
}
@ -225,11 +219,8 @@ public:
ZT_INLINE void eachPath(F f) const
{
RWMutex::RLock l(_paths_l);
Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
uint64_t *k = nullptr;
SharedPtr<Path> *p = nullptr;
while (i.next(k,p))
f(*((const SharedPtr<Path> *)p));
for(FlatMap< uint64_t,SharedPtr<Path> >::const_iterator i(_paths.begin());i!=_paths.end();++i)
f(i->second);
}
/**
@ -363,10 +354,10 @@ private:
std::pair< InetAddress,ZT_PhysicalPathConfiguration > _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
unsigned int _numConfiguredPhysicalPaths;
Hashtable< Address,SharedPtr<Peer> > _peers;
Hashtable< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
Hashtable< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
Hashtable< uint64_t,SharedPtr<Path> > _paths;
FlatMap< Address,SharedPtr<Peer> > _peers;
FlatMap< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
FlatMap< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
FlatMap< uint64_t,SharedPtr<Path> > _paths;
std::set< Identity > _roots; // locked by _peers_l
std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
};

View file

@ -263,6 +263,20 @@ static ZT_INLINE uint64_t hash64(uint64_t x) noexcept
return x;
}
/**
* Mix bits in a 32-bit integer
*
* @param x Integer to mix
* @return Hashed value
*/
static ZT_INLINE uint32_t hash32(uint32_t x) noexcept
{
x = ((x >> 16U) ^ x) * 0x45d9f3b;
x = ((x >> 16U) ^ x) * 0x45d9f3b;
x = (x >> 16U) ^ x;
return x;
}
/**
* Check if a buffer's contents are all zero
*/

View file

@ -440,14 +440,11 @@ void VL1::_sendPendingWhois(void *const tPtr,const int64_t now)
std::vector<Address> toSend;
{
Mutex::Lock wl(_whoisQueue_l);
Hashtable<Address,_WhoisQueueItem>::Iterator wi(_whoisQueue);
Address *a = nullptr;
_WhoisQueueItem *wq = nullptr;
while (wi.next(a,wq)) {
if ((now - wq->lastRetry) >= ZT_WHOIS_RETRY_DELAY) {
wq->lastRetry = now;
++wq->retries;
toSend.push_back(*a);
for(std::map<Address,_WhoisQueueItem>::iterator wi(_whoisQueue.begin());wi!=_whoisQueue.end();++wi) {
if ((now - wi->second.lastRetry) >= ZT_WHOIS_RETRY_DELAY) {
wi->second.lastRetry = now;
++wi->second.retries;
toSend.push_back(wi->first);
}
}
}

View file

@ -19,10 +19,10 @@
#include "Buf.hpp"
#include "Address.hpp"
#include "Protocol.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "FCV.hpp"
#include <map>
#include <vector>
namespace ZeroTier {
@ -89,7 +89,7 @@ private:
Defragmenter<ZT_MAX_PACKET_FRAGMENTS> _inputPacketAssembler;
Hashtable<Address,_WhoisQueueItem> _whoisQueue;
std::map<Address,_WhoisQueueItem> _whoisQueue;
Mutex _whoisQueue_l;
};

View file

@ -18,7 +18,6 @@
#include "Buf.hpp"
#include "Address.hpp"
#include "Protocol.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "FCV.hpp"