1 #include "hmbdc/Copyright.hpp" 3 #include "hmbdc/tips/reliable/TcpEpollFd.hpp" 4 #include "hmbdc/tips/reliable/AttBufferAdaptor.hpp" 5 #include "hmbdc/app/Message.hpp" 6 #include "hmbdc/app/Config.hpp" 7 #include "hmbdc/app/Logger.hpp" 8 #include "hmbdc/pattern/SeqArb.hpp" 9 #include "hmbdc/time/Time.hpp" 10 #include "hmbdc/comm/inet/Misc.hpp" 12 #include <unordered_set> 13 #include <boost/lexical_cast.hpp> 22 namespace hmbdc {
namespace tips {
namespace reliable {
24 using Tags = std::unordered_set<uint16_t>;
26 namespace backuprecvsessiont_detail {
27 template <
typename TransportMessageHeader
28 ,
typename SessionStarted
29 ,
typename SessionDropped
31 ,
typename OutputBufferIn
33 ,
typename AttachmentAllocator>
42 , AttachmentAllocator>>;
44 , SendFrom
const& sendFrom
46 , OutputBufferIn& outputBuffer
51 , minSeq_(std::numeric_limits<HMBDC_SEQ_TYPE>::max())
52 , subscriptions_(subscriptions)
54 , outputBuffer_(outputBuffer)
55 , bufSize_(config.
getExt<
size_t>(
"maxTcpReadBytes"))
56 , buf_((
char*)memalign(SMP_CACHE_BYTES, bufSize_))
59 , seqArb_(std::numeric_limits<HMBDC_SEQ_TYPE>::max())
63 , recvBackupMessageCount_(0)
68 sendGapReport(seqArb_.expectingSeq(), 0);
75 HMBDC_LOG_N(
"BackupRecvSession retired: ",
id(),
" lifetime recved:", recvBackupMessageCount_);
79 outputBuffer_.putSome(sessionDropped_);
82 void start(in_addr_t ip, uint16_t port) {
83 sockaddr_in remoteAddr = {0};
84 remoteAddr.sin_family = AF_INET;
85 remoteAddr.sin_addr.s_addr = ip;
86 remoteAddr.sin_port = htons(port);
87 if (connect(writeFd_.fd, (sockaddr*)&remoteAddr,
sizeof(remoteAddr)) < 0) {
88 if (errno != EINPROGRESS) {
89 HMBDC_THROW(std::runtime_error,
"connect fail, errno=" << errno);
93 auto forRead = dup(writeFd_.fd);
95 HMBDC_THROW(std::runtime_error,
"dup failed errno=" << errno);
99 hmbdc::app::utils::EpollTask::instance().add(hmbdc::app::utils::EpollTask::EPOLLOUT
100 | hmbdc::app::utils::EpollTask::EPOLLET, writeFd_);
101 hmbdc::app::utils::EpollTask::instance().add(hmbdc::app::utils::EpollTask::EPOLLIN
102 | hmbdc::app::utils::EpollTask::EPOLLET, readFd_);
106 if (hmbdc_unlikely(stopped_))
return false;
107 if (hmbdc_unlikely(!initialized_ && writeFd_.isFdReady())) {
110 }
catch (std::exception
const& e) {
111 HMBDC_LOG_W(e.what());
114 HMBDC_LOG_C(
"unknown exception");
121 void sendSubscribe(uint16_t t) {
123 auto l = sprintf(buf,
"+%d\t", t) - 1;
124 if (hmbdc_unlikely(send(writeFd_.fd, buf, l, MSG_NOSIGNAL) != l)) {
125 HMBDC_LOG_C(
"error when sending subscribe to ",
id());
130 void sendUnsubscribe(uint16_t
const& t) {
132 auto l = sprintf(buf,
"-%d\t", t) - 1;
133 if (hmbdc_unlikely(l != send(writeFd_.fd, buf, l, MSG_NOSIGNAL))) {
134 HMBDC_LOG_C(
"error when sending unsubscribe to ",
id(),
" errno=", errno);
139 void sendGapReport(HMBDC_SEQ_TYPE missSeq,
size_t len) {
140 if (hmbdc_likely(!gapPending_ && missSeq != std::numeric_limits<HMBDC_SEQ_TYPE>::max())) {
142 auto l = sprintf(buf,
"=%" PRIu64
",%zu\t", missSeq, len);
144 if (hmbdc_unlikely(l != send(writeFd_.fd, buf, l, MSG_NOSIGNAL))) {
145 HMBDC_LOG_C(
"error when sending gap report to ",
id(),
" errno=", errno);
150 gapPendingSeq_ = missSeq + len - 1;
156 char const* id()
const {
160 int accept(TransportMessageHeader* h) {
161 auto seq = h->getSeq();
162 auto a = arb(0, seq, h);
164 auto tag = h->typeTag();
165 if (tag == app::StartMemorySegTrain::typeTag) {
166 tag = h->template wrapped<app::StartMemorySegTrain>().inbandUnderlyingTypeTag;
168 if (subscriptions_.check(tag)) {
169 outputBuffer_.put(h);
175 int arb(uint16_t part, HMBDC_SEQ_TYPE seq
176 , TransportMessageHeader* h) HMBDC_RESTRICT {
178 if (hmbdc_unlikely(gapPending_ && part == 0))
return 0;
179 if (seq != std::numeric_limits<HMBDC_SEQ_TYPE>::max()) {
180 auto res = seqArb_(part, seq, [](
size_t) {
184 sendGapReport(seqArb_.expectingSeq(), seq - seqArb_.expectingSeq());
185 }
else if (seq == gapPendingSeq_) {
189 }
else if (h->typeTag() == SeqAlert::typeTag) {
190 auto& alert = h->template wrapped<SeqAlert>();
191 auto nextSeq = alert.expectSeq;
193 if (seqArb_.expectingSeq() < nextSeq) {
194 sendGapReport(seqArb_.expectingSeq(), nextSeq - seqArb_.expectingSeq());
202 SendFrom
const sendFrom;
205 void initializeConn() {
206 int flags = fcntl(writeFd_.fd, F_GETFL, 0);
207 flags &= ~O_NONBLOCK;
208 if (fcntl(writeFd_.fd, F_SETFL, flags) < 0) {
209 HMBDC_THROW(std::runtime_error,
"fcntl failed errno=" << errno);
212 auto sz = config_.
getExt<
int>(
"tcpRecvBufferBytes");
214 if (setsockopt(readFd_.fd, SOL_SOCKET, SO_RCVBUF, &sz,
sizeof(sz)) < 0) {
215 HMBDC_LOG_C(
"failed to set send buffer size=", sz);
219 auto flag = config_.
getExt<
bool>(
"nagling")?0:1;
220 if (setsockopt(writeFd_.fd, IPPROTO_TCP, TCP_NODELAY, (
char*) &flag,
sizeof(flag)) < 0) {
221 HMBDC_LOG_C(
"failed to set TCP_NODELAY, errno=", errno);
224 auto addrPort = hmbdc::comm::inet::getPeerIpPort(writeFd_.fd);
225 id_ = addrPort.first +
":" + std::to_string(addrPort.second);
226 strncpy(sessionStarted_.payload.ip, id_.c_str()
227 ,
sizeof(sessionStarted_.payload.ip));
228 sessionStarted_.payload.ip[
sizeof(sessionStarted_.payload.ip) - 1] = 0;
229 strncpy(sessionDropped_.payload.ip, id_.c_str()
230 ,
sizeof(sessionDropped_.payload.ip));
231 sessionDropped_.payload.ip[
sizeof(sessionDropped_.payload.ip) - 1] = 0;
232 outputBuffer_.putSome(sessionStarted_);
237 void sendSubscriptions() {
238 std::ostringstream oss;
239 subscriptions_.exportTo([&oss](uint16_t tag,
auto&& count) {
241 oss <<
'+' << tag <<
'\t';
244 auto s = oss.str() +
"+\t";
245 auto sz = size_t(send(writeFd_.fd, s.c_str(), s.size(), MSG_NOSIGNAL));
246 if (hmbdc_unlikely(sz != s.size())) {
247 HMBDC_LOG_C(
"error when sending subscriptions to ",
id());
253 doRead() HMBDC_RESTRICT {
254 if (hmbdc_unlikely(seqArb_.expectingSeq() == std::numeric_limits<HMBDC_SEQ_TYPE>::max()) &&
255 filledLen_ >=
sizeof(HMBDC_SEQ_TYPE)) {
256 minSeq_ = *
reinterpret_cast<HMBDC_SEQ_TYPE*
>(bufCur_);
257 auto wireSize =
sizeof(HMBDC_SEQ_TYPE);
259 filledLen_ -= wireSize;
260 HMBDC_LOG_N(
"BackupRecvSession started ",
id(),
" with minSeq=", minSeq_);
261 seqArb_.expectingSeq() = minSeq_;
263 while (minSeq_ != std::numeric_limits<HMBDC_SEQ_TYPE>::max()
264 && filledLen_ >=
sizeof(TransportMessageHeader)) {
265 auto h =
reinterpret_cast<TransportMessageHeader*
>(bufCur_);
266 auto wireSize = h->wireSize();
268 if (hmbdc_likely(filledLen_ >= wireSize)) {
269 if (hmbdc_likely(h->messagePayloadLen
270 && subscriptions_.check(h->typeTag()))) {
271 outputBuffer_.put(h);
275 filledLen_ -= wireSize;
277 arb(1, seqArb_.expectingSeq(), h);
278 recvBackupMessageCount_++;
283 memmove(buf_, bufCur_, filledLen_);
286 if (readFd_.isFdReady()) {
287 auto l = recv(readFd_.fd, buf_ + filledLen_, bufSize_ - filledLen_
288 , MSG_NOSIGNAL|MSG_DONTWAIT);
289 if (hmbdc_unlikely(l < 0)) {
290 if (hmbdc_unlikely(!readFd_.checkErr())) {
291 HMBDC_LOG_C(
"recv failed errno=", errno);
295 }
else if (hmbdc_unlikely(l == 0)) {
296 HMBDC_LOG_W(
"peer dropped:",
id());
306 HMBDC_SEQ_TYPE minSeq_;
314 size_t const bufSize_;
322 size_t recvBackupMessageCount_;
324 HMBDC_SEQ_TYPE gapPendingSeq_;
325 uint16_t attTypeTag_;
326 void* attUserScratchpad_;
330 template <
typename TransportMessageHeader
331 ,
typename SessionStarted
332 ,
typename SessionDropped
334 ,
typename OutputBuffer
336 ,
typename AttachmentAllocator>
339 TransportMessageHeader
345 , AttachmentAllocator
T getExt(const path_type ¶m, bool throwIfMissing=true) const
get a value from the config
Definition: Config.hpp:238
Definition: TcpEpollFd.hpp:14
class to hold an hmbdc configuration
Definition: Config.hpp:44
Definition: SeqArb.hpp:164
Definition: Timers.hpp:70
Definition: EpollTask.hpp:87
Definition: Timers.hpp:117
Definition: BackupRecvSessionT.hpp:34