1
0
Fork 0

implement a more robust method of determining dominant member

This commit is contained in:
Kevin Matz 2022-11-20 15:22:51 -05:00
parent 3672b1d49f
commit 4a52f7302d
2 changed files with 60 additions and 34 deletions

View File

@ -23,6 +23,7 @@
*/
#include "arbitratinguniverse.h"
#include <map>
namespace sACN {
@ -282,45 +283,69 @@ double ArbitratingUniverse::rxRate()
*/
std::shared_ptr<Universe> ArbitratingUniverse::dominant_()
{
bool sourceListChanged = false;
std::shared_ptr<Universe> ret = nullptr;
if (sources_.empty())
return nullptr;
for(auto it = sources_.begin(); it != sources_.end(); )
// cache the age of each universe
std::unordered_map<DATA::data_header,uint> ages;
for (const auto& [header, universe] : sources_)
ages.insert({header, universe->rxAge()});
purge_stale_sources_(&ages);
// order universe into a two dimentional container; priority then age
std::map<uint,std::multimap<uint,std::shared_ptr<Universe>>> by_priority;
for (const auto& [header, universe] : sources_)
{
auto universe = it->second;
if (!ret && HoldLastLook)
{ // anything is better than nothing
++it;
ret = universe;
continue;
}
auto age = universe->rxAge();
if (age > E131_NETWORK_DATA_LOSS_TIMEOUT)
{ // clean up zombie universes
it = sources_.erase(it);
sourceListChanged = true;
continue;
}
if (age > DMX::E111_DATA_LOSS_TIMEOUT)
{
++it;
continue; // stale universes cannot be dominant
}
if (universe->provenance()->priority > ret->provenance()->priority)
ret = universe; // rank by provenance
++it;
auto age = ages.at(header);
auto priority = header.priority;
if (!by_priority.count(priority))
by_priority.emplace(priority, std::multimap<uint,std::shared_ptr<Universe>>({{age,universe}}));
else
by_priority.at(priority).insert({age, universe});
}
if (sourceListChanged)
doListChangeCallbacks();
// freshest universe at the hightest priority
return by_priority.rbegin()->second.begin()->second;
}
return ret;
/**
* @brief ArbitratingUniverse::purge_stale_sources_
* @param age_cache
*/
void ArbitratingUniverse::purge_stale_sources_(std::unordered_map<DATA::data_header,uint> *age_cache)
{
std::unordered_map<DATA::data_header,uint> ages;
if (age_cache)
ages = *age_cache;
else
for (const auto& [header, universe] : sources_)
ages.insert({header, universe->rxAge()});
// order the member universes by age
std::multimap<uint,DATA::data_header> by_age;
for (const auto& [header, _] : sources_)
by_age.insert({ages.at(header), header});
// clean up stale universes, oldest first
for(auto it = by_age.crbegin(); it != by_age.crend(); it++)
{
auto age = it->first;
auto key = it->second;
// the lastest source universe is never purged if holding the last look
if (sources_.size() == 1 && HoldLastLook)
break;
// it's a sorted container. If this universe is live, so are the remainder.
if (age < E131_NETWORK_DATA_LOSS_TIMEOUT)
break;
// erase the zombie universe
sources_.erase(key);
}
// if zombies were erased, notify about the changes
if (sources_.size() != by_age.size())
doListChangeCallbacks();
}
} // namespace SACN

View File

@ -102,6 +102,7 @@ private:
bool HoldLastLook;
std::shared_ptr<Universe> dominant_();
void purge_stale_sources_(std::unordered_map<DATA::data_header, uint> * = nullptr);
bool hasSourceUniverse(const DATA::data_header&) const;
};