Skip to content

Commit 4c751df

Browse files
committed
[core] Send publisher data only through transport layers with active subscribers. (#2680)
Co-authored-by: Kerstin Keller <13848742+KerstinKeller@users.noreply.github.com>
1 parent 6ddb7e4 commit 4c751df

2 files changed

Lines changed: 136 additions & 41 deletions

File tree

ecal/core/src/pubsub/ecal_publisher_impl.cpp

Lines changed: 109 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,64 @@ namespace
104104

105105
namespace eCAL
106106
{
107+
void CPublisherImpl::SSendLayerConnectionCounters::Increment(TransportLayer::eType layer_)
108+
{
109+
switch (layer_)
110+
{
111+
case TransportLayer::eType::udp_mc:
112+
udp.fetch_add(1, std::memory_order_relaxed);
113+
break;
114+
case TransportLayer::eType::shm:
115+
shm.fetch_add(1, std::memory_order_relaxed);
116+
break;
117+
case TransportLayer::eType::tcp:
118+
tcp.fetch_add(1, std::memory_order_relaxed);
119+
break;
120+
default:
121+
break;
122+
}
123+
}
124+
125+
void CPublisherImpl::SSendLayerConnectionCounters::Decrement(TransportLayer::eType layer_)
126+
{
127+
switch (layer_)
128+
{
129+
case TransportLayer::eType::udp_mc:
130+
udp.fetch_sub(1, std::memory_order_relaxed);
131+
break;
132+
case TransportLayer::eType::shm:
133+
shm.fetch_sub(1, std::memory_order_relaxed);
134+
break;
135+
case TransportLayer::eType::tcp:
136+
tcp.fetch_sub(1, std::memory_order_relaxed);
137+
break;
138+
default:
139+
break;
140+
}
141+
}
142+
143+
void CPublisherImpl::SSendLayerConnectionCounters::Reset()
144+
{
145+
udp.store(0, std::memory_order_relaxed);
146+
shm.store(0, std::memory_order_relaxed);
147+
tcp.store(0, std::memory_order_relaxed);
148+
}
149+
150+
bool CPublisherImpl::SSendLayerConnectionCounters::UdpEnabled() const
151+
{
152+
return (udp.load(std::memory_order_relaxed) > 0);
153+
}
154+
155+
bool CPublisherImpl::SSendLayerConnectionCounters::ShmEnabled() const
156+
{
157+
return (shm.load(std::memory_order_relaxed) > 0);
158+
}
159+
160+
bool CPublisherImpl::SSendLayerConnectionCounters::TcpEnabled() const
161+
{
162+
return (tcp.load(std::memory_order_relaxed) > 0);
163+
}
164+
107165
CPublisherImpl::CPublisherImpl(const SDataTypeInformation& topic_info_, const eCAL::eCALWriter::SAttributes& attr_, SPublisherGlobalContext global_context_)
108166
: m_publisher_id(eCAL::Util::GenerateUniqueEntityId())
109167
, m_topic_info(topic_info_)
@@ -141,6 +199,7 @@ namespace eCAL
141199
{
142200
const std::lock_guard<std::mutex> lock(m_connection_map_mutex);
143201
m_connection_map.clear();
202+
m_connection_count.store(0, std::memory_order_relaxed);
144203
}
145204

146205
// mark as no more created
@@ -154,6 +213,15 @@ namespace eCAL
154213
{
155214
// get payload buffer size (one time, to avoid multiple computations)
156215
const size_t payload_buf_size(payload_.GetSize());
216+
#if ECAL_CORE_TRANSPORT_SHM
217+
const bool shm_send_enabled = m_writer_shm && m_send_layer_connection_counters.ShmEnabled();
218+
#endif
219+
#if ECAL_CORE_TRANSPORT_UDP
220+
const bool udp_send_enabled = m_writer_udp && m_send_layer_connection_counters.UdpEnabled();
221+
#endif
222+
#if ECAL_CORE_TRANSPORT_TCP
223+
const bool tcp_send_enabled = m_writer_tcp && m_send_layer_connection_counters.TcpEnabled();
224+
#endif
157225

158226
// are we allowed to perform zero copy writing?
159227
bool allow_zero_copy(false);
@@ -162,11 +230,11 @@ namespace eCAL
162230
#endif
163231
#if ECAL_CORE_TRANSPORT_UDP
164232
// udp is active -> no zero copy
165-
allow_zero_copy &= !m_writer_udp;
233+
allow_zero_copy &= !udp_send_enabled;
166234
#endif
167235
#if ECAL_CORE_TRANSPORT_TCP
168236
// tcp is active -> no zero copy
169-
allow_zero_copy &= !m_writer_tcp;
237+
allow_zero_copy &= !tcp_send_enabled;
170238
#endif
171239

172240
// create a payload copy for all layer
@@ -186,7 +254,7 @@ namespace eCAL
186254
// SHM
187255
////////////////////////////////////////////////////////////////////////////
188256
#if ECAL_CORE_TRANSPORT_SHM
189-
if (m_writer_shm)
257+
if (shm_send_enabled)
190258
{
191259
#ifndef NDEBUG
192260
eCAL::Logging::Log(Logging::log_level_debug3, m_attributes.topic_name + "::CPublisherImpl::Write::SHM");
@@ -249,7 +317,7 @@ namespace eCAL
249317
// UDP (MC)
250318
////////////////////////////////////////////////////////////////////////////
251319
#if ECAL_CORE_TRANSPORT_UDP
252-
if (m_writer_udp)
320+
if (udp_send_enabled)
253321
{
254322
#ifndef NDEBUG
255323
eCAL::Logging::Log(Logging::log_level_debug3, m_attributes.topic_name + "::CPublisherImpl::Write::udp");
@@ -298,7 +366,7 @@ namespace eCAL
298366
// TCP
299367
////////////////////////////////////////////////////////////////////////////
300368
#if ECAL_CORE_TRANSPORT_TCP
301-
if (m_writer_tcp)
369+
if (tcp_send_enabled)
302370
{
303371
#ifndef NDEBUG
304372
eCAL::Logging::Log(Logging::log_level_debug3, m_attributes.topic_name + "::CPublisherImpl::Send::TCP");
@@ -406,8 +474,8 @@ namespace eCAL
406474
#endif
407475

408476
// determine if we need to start a transport layer
409-
const TransportLayer::eType layer2activate = DetermineTransportLayer2Start(pub_layers, sub_layers, m_attributes.host_name == subscription_info_.host_name);
410-
switch (layer2activate)
477+
const TransportLayer::eType transport_layer_for_subscription = DetermineTransportLayer(pub_layers, sub_layers, m_attributes.host_name == subscription_info_.host_name);
478+
switch (transport_layer_for_subscription)
411479
{
412480
case TransportLayer::eType::udp_mc:
413481
StartUdpLayer();
@@ -445,27 +513,30 @@ namespace eCAL
445513

446514
if (subscription_info_iter == m_connection_map.end())
447515
{
448-
// add subscriber to connection map, connection state false
449-
m_connection_map[subscription_info_] = SConnection{ data_type_info_, sub_layer_states_, false };
516+
m_connection_map[subscription_info_] = SConnection{ data_type_info_, sub_layer_states_, transport_layer_for_subscription, eConnectionState::pending };
517+
m_send_layer_connection_counters.Increment(transport_layer_for_subscription);
450518
}
451519
else
452520
{
453-
// existing connection, we got the second update now
454521
auto& connection = subscription_info_iter->second;
455522

456-
// if this connection was inactive before
457-
// activate it now and flag a new connection finally
458-
if (!connection.state)
523+
#ifndef NDEBUG
524+
if (connection.selected_layer != transport_layer_for_subscription)
525+
{
526+
eCAL::Logging::Log(Logging::log_level_warning, m_attributes.topic_name + "::CPublisherImpl::ApplySubscriberRegistration - selected transport layer changed unexpectedly for connection");
527+
}
528+
#endif
529+
530+
if (connection.state == eConnectionState::pending)
459531
{
460532
is_new_connection = true;
533+
m_connection_count.fetch_add(1, std::memory_order_relaxed);
534+
connection.state = eConnectionState::established;
461535
}
462536

463-
// update the data type, the layer states and set the state active
464-
connection = SConnection{ data_type_info_, sub_layer_states_, true };
537+
connection.data_type_info = data_type_info_;
538+
connection.layer_states = sub_layer_states_;
465539
}
466-
467-
// update connection count
468-
m_connection_count = GetConnectionCount();
469540
}
470541

471542

@@ -497,11 +568,24 @@ namespace eCAL
497568
{
498569
const std::lock_guard<std::mutex> lock(m_connection_map_mutex);
499570

500-
// remove key from connection map
501-
m_connection_map.erase(subscription_info_);
571+
auto subscription_info_iter = m_connection_map.find(subscription_info_);
572+
if (subscription_info_iter != m_connection_map.end())
573+
{
574+
auto& connection = subscription_info_iter->second;
575+
if (connection.state == eConnectionState::established)
576+
{
577+
m_connection_count.fetch_sub(1, std::memory_order_relaxed);
578+
}
502579

503-
// update connection count
504-
m_connection_count = GetConnectionCount();
580+
if (connection.state != eConnectionState::closed)
581+
{
582+
m_send_layer_connection_counters.Decrement(connection.selected_layer);
583+
connection.state = eConnectionState::closed;
584+
}
585+
586+
// remove key from connection map
587+
m_connection_map.erase(subscription_info_iter);
588+
}
505589
}
506590

507591
// fire disconnect event
@@ -702,20 +786,6 @@ namespace eCAL
702786
FireEvent(ePublisherEvent::disconnected, subscription_info_, data_type_info_);
703787
}
704788

705-
size_t CPublisherImpl::GetConnectionCount()
706-
{
707-
// no need to lock map here for now, map locked by caller
708-
size_t count(0);
709-
for (const auto& sub : m_connection_map)
710-
{
711-
if (sub.second.state)
712-
{
713-
count++;
714-
}
715-
}
716-
return count;
717-
}
718-
719789
bool CPublisherImpl::StartUdpLayer()
720790
{
721791
#if ECAL_CORE_TRANSPORT_UDP
@@ -819,6 +889,8 @@ namespace eCAL
819889
// destroy writer
820890
m_writer_tcp.reset();
821891
#endif
892+
893+
m_send_layer_connection_counters.Reset();
822894
}
823895

824896
size_t CPublisherImpl::PrepareWrite(long long id_, size_t len_)
@@ -840,7 +912,7 @@ namespace eCAL
840912
return snd_hash;
841913
}
842914

843-
TransportLayer::eType CPublisherImpl::DetermineTransportLayer2Start(const std::vector<eTLayerType>& enabled_pub_layer_, const std::vector<eTLayerType>& enabled_sub_layer_, bool same_host_)
915+
TransportLayer::eType CPublisherImpl::DetermineTransportLayer(const std::vector<eTLayerType>& enabled_pub_layer_, const std::vector<eTLayerType>& enabled_sub_layer_, bool same_host_)
844916
{
845917
// determine the priority list to use
846918
const Publisher::Configuration::LayerPriorityVector& layer_priority_vector = same_host_ ? m_attributes.layer_priority_local : m_attributes.layer_priority_remote;

ecal/core/src/pubsub/ecal_publisher_impl.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,9 @@ namespace eCAL
130130
void FireConnectEvent (const SSubscriptionInfo& subscription_info_, const SDataTypeInformation& data_type_info_);
131131
void FireDisconnectEvent(const SSubscriptionInfo& subscription_info_, const SDataTypeInformation& data_type_info_);
132132

133-
size_t GetConnectionCount();
134-
135133
size_t PrepareWrite(long long id_, size_t len_);
136134

137-
TransportLayer::eType DetermineTransportLayer2Start(const std::vector<eTLayerType>& enabled_pub_layer_, const std::vector<eTLayerType>& enabled_sub_layer_, bool same_host_);
135+
TransportLayer::eType DetermineTransportLayer(const std::vector<eTLayerType>& enabled_pub_layer_, const std::vector<eTLayerType>& enabled_sub_layer_, bool same_host_);
138136

139137
int32_t GetFrequency();
140138

@@ -146,16 +144,41 @@ namespace eCAL
146144

147145
std::vector<char> m_payload_buffer;
148146

147+
enum class eConnectionState
148+
{
149+
pending,
150+
established,
151+
closed
152+
};
153+
149154
struct SConnection
150155
{
151156
SDataTypeInformation data_type_info;
152157
SLayerStates layer_states;
153-
bool state = false;
158+
TransportLayer::eType selected_layer = TransportLayer::eType::none;
159+
eConnectionState state = eConnectionState::closed;
154160
};
155161
using SSubscriptionMapT = std::map<SSubscriptionInfo, SConnection>;
162+
163+
struct SSendLayerConnectionCounters
164+
{
165+
void Increment(TransportLayer::eType layer_);
166+
void Decrement(TransportLayer::eType layer_);
167+
void Reset();
168+
169+
bool UdpEnabled() const;
170+
bool ShmEnabled() const;
171+
bool TcpEnabled() const;
172+
173+
std::atomic<size_t> udp{ 0 };
174+
std::atomic<size_t> shm{ 0 };
175+
std::atomic<size_t> tcp{ 0 };
176+
};
177+
156178
mutable std::mutex m_connection_map_mutex;
157179
SSubscriptionMapT m_connection_map;
158180
std::atomic<size_t> m_connection_count{ 0 };
181+
SSendLayerConnectionCounters m_send_layer_connection_counters;
159182

160183
std::mutex m_event_id_callback_mutex;
161184
PubEventCallbackT m_event_id_callback;

0 commit comments

Comments
 (0)