Skip to content

Commit

Permalink
quality logic reintroduced in description gate
Browse files Browse the repository at this point in the history
  • Loading branch information
rex-schilasky committed Mar 22, 2024
1 parent 577e85a commit 412d4ac
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 63 deletions.
251 changes: 224 additions & 27 deletions ecal/core/src/ecal_descgate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,52 @@
#include "ecal_globals.h"
#include "ecal_descgate.h"

#include <algorithm>

namespace
{
// TODO: remove me with new CDescGate
eCAL::CDescGate::QualityFlags GetServiceMethodQuality(const eCAL::SDataTypeInformation& request_info_, const eCAL::SDataTypeInformation& response_info_)
{
eCAL::CDescGate::QualityFlags quality = eCAL::CDescGate::QualityFlags::NO_QUALITY;
if (!(request_info_.name.empty() && response_info_.name.empty()))
quality |= eCAL::CDescGate::QualityFlags::TYPE_AVAILABLE;
if (!(request_info_.descriptor.empty() && response_info_.descriptor.empty()))
quality |= eCAL::CDescGate::QualityFlags::DESCRIPTION_AVAILABLE;

return quality;
}

eCAL::CDescGate::QualityFlags GetPublisherQuality(const eCAL::SDataTypeInformation& topic_info_)
{
eCAL::CDescGate::QualityFlags quality = eCAL::CDescGate::QualityFlags::NO_QUALITY;
if (!topic_info_.name.empty() || !topic_info_.encoding.empty())
quality |= eCAL::CDescGate::QualityFlags::TYPE_AVAILABLE;
if (!topic_info_.descriptor.empty())
quality |= eCAL::CDescGate::QualityFlags::DESCRIPTION_AVAILABLE;
quality |= eCAL::CDescGate::QualityFlags::INFO_COMES_FROM_CORRECT_ENTITY;
quality |= eCAL::CDescGate::QualityFlags::INFO_COMES_FROM_PRODUCER;

return quality;
}

eCAL::CDescGate::QualityFlags GetSubscriberQuality(const eCAL::SDataTypeInformation& topic_info_)
{
eCAL::CDescGate::QualityFlags quality = eCAL::CDescGate::QualityFlags::NO_QUALITY;
if (!topic_info_.name.empty() || !topic_info_.encoding.empty())
quality |= eCAL::CDescGate::QualityFlags::TYPE_AVAILABLE;
if (!topic_info_.descriptor.empty())
quality |= eCAL::CDescGate::QualityFlags::DESCRIPTION_AVAILABLE;
quality |= eCAL::CDescGate::QualityFlags::INFO_COMES_FROM_CORRECT_ENTITY;

return quality;
}
}

namespace eCAL
{
CDescGate::CDescGate() :
m_topic_info_map (std::chrono::milliseconds(Config::GetMonitoringTimeoutMs())),
m_topic_info_map(std::chrono::milliseconds(Config::GetMonitoringTimeoutMs())),
m_service_info_map(std::chrono::milliseconds(Config::GetMonitoringTimeoutMs()))
{
}
Expand Down Expand Up @@ -64,7 +106,7 @@ namespace eCAL

for (const auto& topic_info : (*m_topic_info_map.map))
{
map.emplace(topic_info.first, topic_info.second);
map.emplace(topic_info.first, topic_info.second.info);
}
topic_info_map_.swap(map);
}
Expand Down Expand Up @@ -92,7 +134,7 @@ namespace eCAL
const auto topic_info_it = m_topic_info_map.map->find(topic_name_);

if (topic_info_it == m_topic_info_map.map->end()) return(false);
topic_info_ = (*topic_info_it).second;
topic_info_ = (*topic_info_it).second.info;
return(true);
}

Expand All @@ -105,7 +147,7 @@ namespace eCAL

for (const auto& service_info : (*m_service_info_map.map))
{
map.emplace(service_info.first, service_info.second);
map.emplace(service_info.first, service_info.second.info);
}
service_info_map_.swap(map);
}
Expand Down Expand Up @@ -133,8 +175,8 @@ namespace eCAL
auto service_info_map_it = m_service_info_map.map->find(service_method_tuple);

if (service_info_map_it == m_service_info_map.map->end()) return false;
req_type_name_ = (*service_info_map_it).second.request_type.name;
resp_type_name_ = (*service_info_map_it).second.response_type.name;
req_type_name_ = (*service_info_map_it).second.info.request_type.name;
resp_type_name_ = (*service_info_map_it).second.info.response_type.name;
return true;
}

Expand All @@ -147,8 +189,8 @@ namespace eCAL
auto service_info_map_it = m_service_info_map.map->find(service_method_tuple);

if (service_info_map_it == m_service_info_map.map->end()) return false;
req_type_desc_ = (*service_info_map_it).second.request_type.descriptor;
resp_type_desc_ = (*service_info_map_it).second.response_type.descriptor;
req_type_desc_ = (*service_info_map_it).second.info.request_type.descriptor;
resp_type_desc_ = (*service_info_map_it).second.info.response_type.descriptor;
return true;
}

Expand All @@ -165,21 +207,23 @@ namespace eCAL
{
for (const auto& method : sample_.service.methods)
{
SDataTypeInformation request_type;
SDataTypeInformation request_type{};
request_type.name = method.req_type;
request_type.descriptor = method.req_desc;

SDataTypeInformation response_type{};
response_type.name = method.resp_type;
response_type.descriptor = method.resp_desc;

ApplyServiceDescription(sample_.service.sname, method.mname, request_type, response_type);
ApplyServiceDescription(sample_.service.sname, method.mname, request_type, response_type, GetServiceMethodQuality(request_type, response_type));
}
}
break;
break;
case bct_unreg_service:
// TODO: Implement fast unregistration
break;
case bct_reg_client:
// TODO: Implement this after client methods are available
//for (const auto& method : sample_.client.methods)
//{
// SDataTypeInformation request_type;
Expand All @@ -190,20 +234,23 @@ namespace eCAL
// response_type.name = method.resp_type;
// response_type.descriptor = method.resp_desc;

// ApplyClientDescription(sample_.service.sname, method.mname, request_type, response_type);
// ApplyClientDescription(sample_.service.sname, method.mname, request_type, response_type, GetQuality(sample_));
//}
break;
case bct_unreg_client:
// TODO: Implement fast unregistration
break;
case bct_reg_publisher:
ApplyTopicDescription(sample_.topic.tname, sample_.topic.tdatatype);
ApplyTopicDescription(sample_.topic.tname, sample_.topic.tdatatype, GetPublisherQuality(sample_.topic.tdatatype));
break;
case bct_unreg_publisher:
// TODO: Implement fast unregistration
break;
case bct_reg_subscriber:
ApplyTopicDescription(sample_.topic.tname, sample_.topic.tdatatype);
ApplyTopicDescription(sample_.topic.tname, sample_.topic.tdatatype, GetSubscriberQuality(sample_.topic.tdatatype));
break;
case bct_unreg_subscriber:
// TODO: Implement fast unregistration
break;
default:
{
Expand All @@ -215,33 +262,183 @@ namespace eCAL
return true;
}

bool CDescGate::ApplyTopicDescription(const std::string& topic_name_, const SDataTypeInformation& topic_info_)
bool CDescGate::ApplyTopicDescription(const std::string& topic_name_, const SDataTypeInformation& topic_info_, const QualityFlags description_quality_)
{
const std::unique_lock<std::mutex> lock(m_topic_info_map.sync);
m_topic_info_map.map->remove_deprecated();

// update topic entry (and its timestamp)
(*m_topic_info_map.map)[topic_name_] = topic_info_;
return true;
const auto topic_info_it = m_topic_info_map.map->find(topic_name_);

// new element (no need to check anything, just add it)
if (topic_info_it == m_topic_info_map.map->end())
{
// create a new topic entry
STopicInfoQuality& topic_info = (*m_topic_info_map.map)[topic_name_];
topic_info.info = topic_info_;
topic_info.quality = description_quality_;
return true;
}

// we do not use the [] operator here to not update the timestamp
// by accessing the map entry
//
// a topic with the same name but different type name or different description
// should NOT update the timestamp of an existing entry
//
// otherwise there could be a scenario where a "lower quality topic" would keep a
// "higher quality topic" alive (even it is no more existing)
STopicInfoQuality topic_info = (*topic_info_it).second;

// first let's check whether the current information has a higher quality
// if it has a higher quality, we overwrite it
if (description_quality_ > topic_info.quality)
{
// overwrite attributes
topic_info.info = topic_info_;
topic_info.quality = description_quality_;

// update attributes and return
(*m_topic_info_map.map)[topic_name_] = topic_info;
return true;
}

// this is the same topic (topic name, topic type name, topic type description)
if (topic_info.info == topic_info_)
{
// update timestamp (by just accessing the entry) and return
(*m_topic_info_map.map)[topic_name_] = topic_info;
return false;
}

// topic type name or topic description differ but we logged this before
if (topic_info.type_missmatch_logged)
{
return false;
}

// topic type name or topic description differ and this is not logged yet
// so we log the error and update the entry one time
bool update_topic_info(false);

// topic type name differs
// we log the error and update the entry one time
if (!topic_info_.encoding.empty()
&& !topic_info.info.encoding.empty()
&& (topic_info.info.encoding != topic_info_.encoding)
)
{
std::string tencoding1 = topic_info.info.encoding;
std::string tencoding2 = topic_info_.encoding;
std::replace(tencoding1.begin(), tencoding1.end(), '\0', '?');
std::replace(tencoding1.begin(), tencoding1.end(), '\t', '?');
std::replace(tencoding2.begin(), tencoding2.end(), '\0', '?');
std::replace(tencoding2.begin(), tencoding2.end(), '\t', '?');
std::string msg = "eCAL Pub/Sub encoding mismatch for topic ";
msg += topic_name_;
msg += " (\'";
msg += tencoding1;
msg += "\' <> \'";
msg += tencoding2;
msg += "\')";
eCAL::Logging::Log(log_level_warning, msg);

// mark as logged
topic_info.type_missmatch_logged = true;
// and update its attributes
update_topic_info = true;
}

// topic type name differs
// we log the error and update the entry one time
if (!topic_info_.name.empty()
&& !topic_info.info.name.empty()
&& (topic_info.info.name != topic_info_.name)
)
{
std::string ttype1 = topic_info.info.name;
std::string ttype2 = topic_info_.name;
std::replace(ttype1.begin(), ttype1.end(), '\0', '?');
std::replace(ttype1.begin(), ttype1.end(), '\t', '?');
std::replace(ttype2.begin(), ttype2.end(), '\0', '?');
std::replace(ttype2.begin(), ttype2.end(), '\t', '?');
std::string msg = "eCAL Pub/Sub type mismatch for topic ";
msg += topic_name_;
msg += " (\'";
msg += ttype1;
msg += "\' <> \'";
msg += ttype2;
msg += "\')";
eCAL::Logging::Log(log_level_warning, msg);

// mark as logged
topic_info.type_missmatch_logged = true;
// and update its attributes
update_topic_info = true;
}

// topic type description differs
// we log the error and update the entry one time
if (!topic_info_.descriptor.empty()
&& !topic_info.info.descriptor.empty()
&& (topic_info.info.descriptor != topic_info_.descriptor)
)
{
std::string msg = "eCAL Pub/Sub description mismatch for topic ";
msg += topic_name_;
eCAL::Logging::Log(log_level_warning, msg);

// mark as logged
topic_info.type_missmatch_logged = true;
// and update its attributes
update_topic_info = true;
}

// update topic info attributes
if (update_topic_info)
{
(*m_topic_info_map.map)[topic_name_] = topic_info;
}

return false;
}

bool CDescGate::ApplyServiceDescription(const std::string& service_name_
, const std::string& method_name_
, const SDataTypeInformation& request_type_information_
, const SDataTypeInformation& response_type_information_)
, const std::string& method_name_
, const SDataTypeInformation& request_type_information_
, const SDataTypeInformation& response_type_information_
, const QualityFlags description_quality_)
{
std::tuple<std::string, std::string> service_method_tuple = std::make_tuple(service_name_, method_name_);

const std::lock_guard<std::mutex> lock(m_service_info_map.sync);
m_service_info_map.map->remove_deprecated();

// aggregate service information
SServiceMethodInformation service_info;
service_info.request_type = request_type_information_;
service_info.response_type = response_type_information_;

auto service_info_map_it = m_service_info_map.map->find(service_method_tuple);
if (service_info_map_it == m_service_info_map.map->end())
{
// create a new service entry
SServiceMethodInfoQuality& service_info = (*m_service_info_map.map)[service_method_tuple];
service_info.info.request_type = request_type_information_;
service_info.info.response_type = response_type_information_;
service_info.quality = description_quality_;
return true;
}

// let's check whether the current information has a higher quality
// if it has a higher quality, we overwrite it
bool ret_value(false);
SServiceMethodInfoQuality service_info = (*service_info_map_it).second;
if (description_quality_ > service_info.quality)
{
service_info.info.request_type = request_type_information_;
service_info.info.response_type = response_type_information_;
service_info.quality = description_quality_;
ret_value = true;
}

// update service entry (and its timestamp)
(*m_service_info_map.map)[service_method_tuple] = service_info;
return true;

return ret_value;
}
}
Loading

0 comments on commit 412d4ac

Please sign in to comment.