1 #include "hmbdc/Copyright.hpp" 3 #include "hmbdc/app/Logger.hpp" 4 #include "hmbdc/tips/tcpcast/SendServer.hpp" 5 #include "hmbdc/tips/tcpcast/Transport.hpp" 6 #include "hmbdc/tips/tcpcast/Messages.hpp" 7 #include "hmbdc/tips/udpcast/SendTransportEngine.hpp" 8 #include "hmbdc/tips/tcpcast/DefaultUserConfig.hpp" 9 #include "hmbdc//MetaUtils.hpp" 10 #include "hmbdc/time/Time.hpp" 11 #include "hmbdc/time/Rater.hpp" 12 #include "hmbdc/numeric/BitMath.hpp" 14 #include <boost/circular_buffer.hpp> 18 #include <type_traits> 21 namespace hmbdc {
namespace tips {
namespace tcpcast {
23 namespace send_detail {
24 HMBDC_CLASS_HAS_DECLARE(hmbdc_net_queued_ts);
25 using pattern::MonoLockFreeBuffer;
39 size_t subscribingPartyDetectedCount(uint16_t tag)
const {
40 return outboundSubscriptions_.check(tag);
43 size_t bufferedMessageCount()
const {
44 return buffer_.remainingSize();
47 template <MessageC Message>
48 void queue(Message&& msg) {
49 if (!minRecvToStart_ && !outboundSubscriptions_.check(msg.getTypeTag())) {
50 using M =
typename std::decay<Message>::type;
51 if constexpr (std::is_base_of<app::hasMemoryAttachment, M>::value) {
57 auto it = buffer_.claim(n);
58 queue(it, std::forward<Message>(msg));
59 buffer_.commit(it, n);
62 template <MessageC Message>
63 bool tryQueue(Message&& msg) {
64 if (!minRecvToStart_ && !outboundSubscriptions_.check(msg.getTypeTag())) {
65 using M =
typename std::decay<Message>::type;
66 if constexpr (std::is_base_of<app::hasMemoryAttachment, M>::value) {
72 auto it = buffer_.tryClaim(n);
74 queue(it, std::forward<Message>(msg));
75 buffer_.commit(it, n);
81 template <
typename Message,
typename ... Args>
82 void queueInPlace(Args&&... args) {
83 static_assert(!std::is_base_of<app::JustBytes, Message>::value
84 ,
"use queueJustBytes instead");
85 static_assert(std::is_trivially_destructible<Message>::value
86 ,
"cannot send message with dtor");
87 static_assert(!std::is_base_of<app::hasMemoryAttachment, Message>::value
89 ,
"hasMemoryAttachment has to the first base for Message");
90 auto s = buffer_.claim();
91 char* addr =
static_cast<char*
>(*s);
94 if (hmbdc_likely(
sizeof(Message) <= maxMessageSize_)) {
97 h->flag = wrap->scratchpad().desc.flag;
99 HMBDC_THROW(std::out_of_range
100 ,
"maxMessageSize too small to hold a message");
105 void queueJustBytes(uint16_t tag,
void const* bytes,
size_t len
107 if (!minRecvToStart_ && !outboundSubscriptions_.check(tag)) {
113 auto s = buffer_.claim();
114 char* addr =
static_cast<char*
>(*s);
117 if (hmbdc_likely(len <= maxMessageSize_)) {
120 h->flag = wrap->scratchpad().desc.flag;
122 HMBDC_THROW(std::out_of_range
123 ,
"maxMessageSize too small to hold a message");
131 size_t maxMessageSize_;
132 size_t minRecvToStart_;
135 std::unique_ptr<udpcast::SendTransport> mcSendTransport_;
141 template<
typename M,
typename ... Messages>
143 using Message =
typename std::decay<M>::type;
144 static_assert(std::is_trivially_destructible<Message>::value,
"cannot send message with dtor");
145 static_assert(!std::is_base_of<app::hasMemoryAttachment, Message>::value
147 ,
"hasMemoryAttachment has to the first base for Message");
150 char* addr =
static_cast<char*
>(s);
153 if (hmbdc_likely(
sizeof(Message) <= maxMessageSize_)) {
156 h->flag = wrap->scratchpad().desc.flag;
158 HMBDC_THROW(std::out_of_range,
"maxMessageSize too small to hold a message when constructing SendTransportEngine");
160 if constexpr (has_hmbdc_net_queued_ts<Message>::value) {
161 h->template wrapped<Message>().hmbdc_net_queued_ts = hmbdc::time::SysTime::now();
163 queue(++it, std::forward<Messages>(msgs)...);
175 using SendTransport::hmbdcName;
176 using SendTransport::schedSpec;
178 template <MessageTupleC Messages,
typename Node>
179 void advertiseFor(
Node const& node, uint16_t mod, uint16_t res) {
180 std::scoped_lock<std::mutex> g(advertisedTypeTags_.lock);
181 advertisedTypeTags_.markPubsFor<Messages>(node, mod, res);
182 server_->advertisingMessages(advertisedTypeTags_);
186 this->checkTimers(hmbdc::time::SysTime::now());
193 mcSendTransport_->runOnce(
true);
209 return server_->readySessionCount();
214 auto seq = buffer_.readSeq();
215 if (seq == lastSeq_ && buffer_.isFull()) {
216 server_->killSlowestSession();
224 size_t maxSendBatch_;
225 bool waitForSlowReceivers_;
226 MonoLockFreeBuffer::iterator begin_;
230 std::optional<SendServer> server_;
236 using SendTransport = send_detail::SendTransport;
237 using SendTransportEngine = send_detail::SendTransportEngine;
240 namespace hmbdc {
namespace tips {
namespace tcpcast {
242 namespace send_detail {
243 using pattern::MonoLockFreeBuffer;
248 ,
size_t maxMessageSize)
249 :
Transport((cfg.setAdditionalFallbackConfig(
hmbdc::app::Config(DefaultUserConfig))
250 , cfg.resetSection(
"tx", false)))
251 , maxMessageSize_(maxMessageSize)
252 , minRecvToStart_(config_.getExt<size_t>(
"minRecvToStart"))
254 , config_.getExt<uint16_t>(
"outBufferSizePower2")
255 ?config_.getExt<uint16_t>(
"outBufferSizePower2")
256 :
hmbdc::numeric::log2Upper(128ul * 1024ul / maxMessageSize)
258 , rater_(
hmbdc::time::Duration::seconds(1u)
259 , config_.getExt<size_t>(
"sendBytesPerSec")
260 , config_.getExt<size_t>(
"sendBytesBurst")
261 , config_.getExt<size_t>(
"sendBytesBurst") != 0ul
263 , mcConfig_(config_) {
264 mcConfig_.
put(
"loopback",
true);
266 mcConfig_.
put(
"outBufferSizePower2", 3u);
280 SendTransportEngine::
282 ,
size_t maxMessageSize)
284 ,
hmbdc::time::ReoccuringTimer(
285 hmbdc::time::Duration::seconds(config_.getExt<size_t>(
"typeTagAdvertisePeriodSeconds")))
286 , mtu_(config_.getExt<size_t>(
"mtu") - 20 - 20)
287 , maxSendBatch_(config_.getExt<size_t>(
"maxSendBatch"))
288 , waitForSlowReceivers_(config_.getExt<bool>(
"waitForSlowReceivers"))
291 toSend_.reserve(maxSendBatch_ * 2);
293 MonoLockFreeBuffer::iterator end;
294 buffer_.peek(begin_, end, 0);
296 server_.emplace(config_, buffer_.capacity(), outboundSubscriptions_);
299 std::unique_lock<std::mutex> g(advertisedTypeTags_.lock, std::try_to_lock);
300 if (!g.owns_lock())
return;
301 for (
auto& ad : server_->advertisingMessages()) {
302 mcSendTransport_->queue(ad);
304 if (!waitForSlowReceivers_) cullSlow();
308 schedule(hmbdc::time::SysTime::now(), *
this);
313 SendTransportEngine::
314 runOnce() HMBDC_RESTRICT {
315 MonoLockFreeBuffer::iterator begin, end;
318 if (hmbdc_likely(!minRecvToStart_
319 || server_->readySessionCount() >= minRecvToStart_)) {
321 buffer_.peek(begin, end, maxSendBatch_);
323 buffer_.peek(begin, end, 0);
327 uint16_t currentTypeTag = 0;
328 size_t toSendByteSize = 0;
332 auto item =
static_cast<TransportMessageHeader*
>(ptr);
334 if (hmbdc_unlikely(!rater_.check(item->wireSize())))
break;
335 if (hmbdc_unlikely(!item->flag
336 && toSendByteSize + item->wireSize() > mtu_))
break;
338 if (hmbdc_unlikely(!currentTypeTag)) {
339 currentTypeTag = item->typeTag();
340 toSendByteSize = item->wireSize();
341 toSend_.push_back(iovec{ptr, item->wireSize()});
342 }
else if (item->typeTag() == currentTypeTag) {
343 toSendByteSize += item->wireSize();
344 toSend_.push_back(iovec{ptr, item->wireSize()});
346 server_->queue(currentTypeTag
352 currentTypeTag = item->typeTag();
353 toSendByteSize = item->wireSize();
354 toSend_.push_back(iovec{ptr, item->wireSize()});
357 if (hmbdc_unlikely(item->flag == app::hasMemoryAttachment::flag)) {
358 auto& a = item->wrapped<app::hasMemoryAttachment>();
359 toSend_.push_back(iovec{a.attachment, a.len});
360 toSendByteSize += a.len;
365 if (toSend_.size()) {
366 server_->queue(currentTypeTag
374 auto newStart = server_->runOnce(begin, it);
376 for (
auto it = begin; it != newStart; ++it) {
378 auto item =
static_cast<TransportMessageHeader*
>(ptr);
379 if (hmbdc_unlikely(item->flag == app::hasMemoryAttachment::flag)) {
380 auto& a = item->wrapped<app::hasMemoryAttachment>();
void invokedCb(size_t) HMBDC_RESTRICT override
this callback is called all the time (frequently) - the exact timing is after a batch of messages are...
Definition: SendTransportEngine.hpp:191
Definition: MonoLockFreeBuffer.hpp:16
size_t sessionsRemainingActive() const
check how many recipient sessions are still active
Definition: SendTransportEngine.hpp:208
class to hold an hmbdc configuration
Definition: Config.hpp:44
bool droppedCb() override
callback called after the Client is safely taken out of the Context
Definition: SendTransportEngine.hpp:197
SendTransport(hmbdc::app::Config, size_t)
ctor
Definition: SendTransportEngine.hpp:247
Definition: Timers.hpp:70
Definition: SendTransportEngine.hpp:24
Definition: Transport.hpp:65
Definition: SendTransportEngine.hpp:169
Definition: Message.hpp:212
Definition: Message.hpp:391
Definition: Message.hpp:263
Config & put(Args &&... args)
forward the call to ptree's put but return Configure
Definition: Config.hpp:194
a Node is a thread of execution that can suscribe and receive Messages
Definition: Node.hpp:51
capture the transportation mechanism
Definition: SendTransportEngine.hpp:30
A Client represents a thread of execution/a task. The execution is managed by a Context. a Client object could participate in message dispatching as the receiver of specifed message types.
Definition: Client.hpp:128
if a specific hmbdc network transport (for example tcpcast, rmcast, and rnetmap) supports message wit...
Definition: Message.hpp:125
void wasteAfterPeek(iterator, size_t, bool=false)
if size not matching - please refer to the impl for details
Definition: MonoLockFreeBuffer.hpp:160
Definition: Timers.hpp:117
Definition: LockFreeBufferMisc.hpp:89