aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorAlexey Borzenkov <snaury@yandex-team.ru>2022-02-10 16:47:41 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:47:41 +0300
commit22d92781ba2a10b7fb5b977b7d1a5c40ff53885f (patch)
tree852611fd27f734847435b37aa5b0ad5d8b1c10ac /library/cpp
parent667a4ee7da2e004784b9c3cfab824a81e96f4d66 (diff)
downloadydb-22d92781ba2a10b7fb5b977b7d1a5c40ff53885f.tar.gz
Restoring authorship annotation for Alexey Borzenkov <snaury@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp')
-rw-r--r--library/cpp/actors/core/actor.cpp46
-rw-r--r--library/cpp/actors/core/actor.h88
-rw-r--r--library/cpp/actors/core/actor_coroutine.cpp8
-rw-r--r--library/cpp/actors/core/actorid.h14
-rw-r--r--library/cpp/actors/core/actorsystem.cpp40
-rw-r--r--library/cpp/actors/core/actorsystem.h54
-rw-r--r--library/cpp/actors/core/events.h8
-rw-r--r--library/cpp/actors/core/events_undelivered.cpp6
-rw-r--r--library/cpp/actors/core/executor_pool_basic.cpp64
-rw-r--r--library/cpp/actors/core/executor_pool_basic_ut.cpp78
-rw-r--r--library/cpp/actors/core/executor_pool_io.cpp42
-rw-r--r--library/cpp/actors/core/executor_pool_io.h2
-rw-r--r--library/cpp/actors/core/executor_pool_united.cpp8
-rw-r--r--library/cpp/actors/core/executor_pool_united_ut.cpp26
-rw-r--r--library/cpp/actors/core/executor_thread.cpp10
-rw-r--r--library/cpp/actors/core/executor_thread.h2
-rw-r--r--library/cpp/actors/core/log.cpp4
-rw-r--r--library/cpp/actors/core/log.h4
-rw-r--r--library/cpp/actors/core/log_settings.cpp12
-rw-r--r--library/cpp/actors/core/log_settings.h4
-rw-r--r--library/cpp/actors/core/mailbox.cpp2
-rw-r--r--library/cpp/actors/core/mailbox.h2
-rw-r--r--library/cpp/actors/core/monotonic.cpp46
-rw-r--r--library/cpp/actors/core/monotonic.h222
-rw-r--r--library/cpp/actors/core/scheduler_actor.cpp24
-rw-r--r--library/cpp/actors/core/scheduler_actor.h6
-rw-r--r--library/cpp/actors/core/scheduler_basic.cpp200
-rw-r--r--library/cpp/actors/core/scheduler_basic.h20
-rw-r--r--library/cpp/actors/core/scheduler_queue.h8
-rw-r--r--library/cpp/actors/core/ya.make2
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver.cpp950
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver.h256
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching.cpp1460
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp1260
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp124
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp48
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ut.cpp196
-rw-r--r--library/cpp/actors/dnsresolver/ut/ya.make40
-rw-r--r--library/cpp/actors/dnsresolver/ya.make40
-rw-r--r--library/cpp/actors/interconnect/interconnect.h44
-rw-r--r--library/cpp/actors/interconnect/interconnect_nameserver_table.cpp2
-rw-r--r--library/cpp/actors/interconnect/interconnect_resolve.cpp348
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp8
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_session.cpp12
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_session.h2
-rw-r--r--library/cpp/actors/interconnect/mock/ic_mock.cpp18
-rw-r--r--library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h6
-rw-r--r--library/cpp/actors/interconnect/ut/lib/node.h6
-rw-r--r--library/cpp/actors/interconnect/ya.make4
-rw-r--r--library/cpp/actors/testlib/test_runtime.cpp134
-rw-r--r--library/cpp/actors/testlib/test_runtime.h148
-rw-r--r--library/cpp/actors/util/unordered_cache.h250
-rw-r--r--library/cpp/actors/util/unordered_cache_ut.cpp276
-rw-r--r--library/cpp/actors/util/ut/ya.make2
-rw-r--r--library/cpp/actors/ya.make2
-rw-r--r--library/cpp/execprofile/profile.cpp8
-rw-r--r--library/cpp/grpc/client/grpc_client_low.cpp574
-rw-r--r--library/cpp/grpc/client/grpc_client_low.h1234
-rw-r--r--library/cpp/grpc/client/grpc_common.h16
-rw-r--r--library/cpp/grpc/server/grpc_counters.h12
-rw-r--r--library/cpp/grpc/server/grpc_request.h56
-rw-r--r--library/cpp/grpc/server/grpc_request_base.h6
-rw-r--r--library/cpp/grpc/server/grpc_server.cpp12
-rw-r--r--library/cpp/grpc/server/grpc_server.h198
-rw-r--r--library/cpp/lfalloc/lf_allocX64.h10
-rw-r--r--library/cpp/terminate_handler/segv_handler.cpp2
-rw-r--r--library/cpp/threading/future/core/future-inl.h8
-rw-r--r--library/cpp/threading/future/core/future.h22
-rw-r--r--library/cpp/threading/future/future_ut.cpp8
-rw-r--r--library/cpp/threading/skip_list/skiplist_ut.cpp204
70 files changed, 4529 insertions, 4529 deletions
diff --git a/library/cpp/actors/core/actor.cpp b/library/cpp/actors/core/actor.cpp
index 6f9ba6a42b..638bfb72fa 100644
--- a/library/cpp/actors/core/actor.cpp
+++ b/library/cpp/actors/core/actor.cpp
@@ -37,10 +37,10 @@ namespace NActors {
TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie);
}
- void TActivationContext::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
- TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie);
- }
-
+ void TActivationContext::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie);
+ }
+
void TActivationContext::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
TlsActivationContext->ExecutorThread.Schedule(delta, ev, cookie);
}
@@ -87,14 +87,14 @@ namespace NActors {
return TlsActivationContext->ExecutorThread.ActorSystem;
}
- i64 TActivationContext::GetCurrentEventTicks() {
+ i64 TActivationContext::GetCurrentEventTicks() {
return GetCycleCountFast() - TlsActivationContext->EventStart;
- }
-
- double TActivationContext::GetCurrentEventTicksAsSeconds() {
- return NHPTimer::GetSeconds(GetCurrentEventTicks());
- }
-
+ }
+
+ double TActivationContext::GetCurrentEventTicksAsSeconds() {
+ return NHPTimer::GetSeconds(GetCurrentEventTicks());
+ }
+
TActorId TActorContext::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const {
return ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfID);
}
@@ -107,10 +107,10 @@ namespace NActors {
ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie);
}
- void TActorContext::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
- ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie);
- }
-
+ void TActorContext::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
+ ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie);
+ }
+
void TActorContext::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const {
ExecutorThread.Schedule(delta, new IEventHandle(SelfID, TActorId(), ev), cookie);
}
@@ -119,10 +119,10 @@ namespace NActors {
TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
}
- void IActor::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
- TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
- }
-
+ void IActor::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
+ }
+
void IActor::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
TlsActivationContext->ExecutorThread.Schedule(delta, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
}
@@ -131,10 +131,10 @@ namespace NActors {
return TlsActivationContext->ExecutorThread.ActorSystem->Timestamp();
}
- TMonotonic TActivationContext::Monotonic() {
- return TlsActivationContext->ExecutorThread.ActorSystem->Monotonic();
- }
-
+ TMonotonic TActivationContext::Monotonic() {
+ return TlsActivationContext->ExecutorThread.ActorSystem->Monotonic();
+ }
+
TInstant TActorContext::Now() const {
return ExecutorThread.ActorSystem->Timestamp();
}
diff --git a/library/cpp/actors/core/actor.h b/library/cpp/actors/core/actor.h
index ed29bd14b9..9c167ab595 100644
--- a/library/cpp/actors/core/actor.h
+++ b/library/cpp/actors/core/actor.h
@@ -1,7 +1,7 @@
#pragma once
#include "event.h"
-#include "monotonic.h"
+#include "monotonic.h"
#include <util/system/tls.h>
#include <library/cpp/actors/util/local_process_key.h>
@@ -24,13 +24,13 @@ namespace NActors {
public:
TMailboxHeader& Mailbox;
TExecutorThread& ExecutorThread;
- const NHPTimer::STime EventStart;
+ const NHPTimer::STime EventStart;
protected:
- explicit TActivationContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart)
+ explicit TActivationContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart)
: Mailbox(mailbox)
, ExecutorThread(executorThread)
- , EventStart(eventStart)
+ , EventStart(eventStart)
{
}
@@ -40,22 +40,22 @@ namespace NActors {
/**
* Schedule one-shot event that will be send at given time point in the future.
*
- * @param deadline the wallclock time point in future when event must be send
+ * @param deadline the wallclock time point in future when event must be send
* @param ev the event to send
* @param cookie cookie that will be piggybacked with event
*/
static void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
/**
- * Schedule one-shot event that will be send at given time point in the future.
- *
- * @param deadline the monotonic time point in future when event must be send
- * @param ev the event to send
- * @param cookie cookie that will be piggybacked with event
- */
- static void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
-
- /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ static void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+
+ /**
* Schedule one-shot event that will be send after given delay.
*
* @param delta the time from now to delay event sending
@@ -65,7 +65,7 @@ namespace NActors {
static void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
static TInstant Now();
- static TMonotonic Monotonic();
+ static TMonotonic Monotonic();
NLog::TSettings* LoggerSettings() const;
// register new actor in ActorSystem on new fresh mailbox.
@@ -83,16 +83,16 @@ namespace NActors {
static TActorId InterconnectProxy(ui32 nodeid);
static TActorSystem* ActorSystem();
-
- static i64 GetCurrentEventTicks();
- static double GetCurrentEventTicksAsSeconds();
+
+ static i64 GetCurrentEventTicks();
+ static double GetCurrentEventTicksAsSeconds();
};
struct TActorContext: public TActivationContext {
const TActorId SelfID;
explicit TActorContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart, const TActorId& selfID)
- : TActivationContext(mailbox, executorThread, eventStart)
+ : TActivationContext(mailbox, executorThread, eventStart)
, SelfID(selfID)
{
}
@@ -110,22 +110,22 @@ namespace NActors {
/**
* Schedule one-shot event that will be send at given time point in the future.
*
- * @param deadline the wallclock time point in future when event must be send
+ * @param deadline the wallclock time point in future when event must be send
* @param ev the event to send
* @param cookie cookie that will be piggybacked with event
*/
void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
/**
- * Schedule one-shot event that will be send at given time point in the future.
- *
- * @param deadline the monotonic time point in future when event must be send
- * @param ev the event to send
- * @param cookie cookie that will be piggybacked with event
- */
- void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
-
- /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
* Schedule one-shot event that will be send after given delay.
*
* @param delta the time from now to delay event sending
@@ -135,7 +135,7 @@ namespace NActors {
void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
TActorContext MakeFor(const TActorId& otherId) const {
- return TActorContext(Mailbox, ExecutorThread, EventStart, otherId);
+ return TActorContext(Mailbox, ExecutorThread, EventStart, otherId);
}
// register new actor in ActorSystem on new fresh mailbox.
@@ -179,22 +179,22 @@ namespace NActors {
/**
* Schedule one-shot event that will be send at given time point in the future.
*
- * @param deadline the wallclock time point in future when event must be send
+ * @param deadline the wallclock time point in future when event must be send
* @param ev the event to send
* @param cookie cookie that will be piggybacked with event
*/
virtual void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
/**
- * Schedule one-shot event that will be send at given time point in the future.
- *
- * @param deadline the monotonic time point in future when event must be send
- * @param ev the event to send
- * @param cookie cookie that will be piggybacked with event
- */
- virtual void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
-
- /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ virtual void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
+
+ /**
* Schedule one-shot event that will be send after given delay.
*
* @param delta the time from now to delay event sending
@@ -240,11 +240,11 @@ namespace NActors {
INTERCONNECT_SESSION_KILLER = 286,
ACTOR_SYSTEM_SCHEDULER_ACTOR = 312,
ACTOR_FUTURE_CALLBACK = 337,
- INTERCONNECT_MONACTOR = 362,
+ INTERCONNECT_MONACTOR = 362,
INTERCONNECT_LOAD_ACTOR = 376,
INTERCONNECT_LOAD_RESPONDER = 377,
NAMESERVICE = 450,
- DNS_RESOLVER = 481,
+ DNS_RESOLVER = 481,
INTERCONNECT_PROXY_WRAPPER = 546,
};
@@ -362,7 +362,7 @@ namespace NActors {
}
void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
- void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
// register new actor in ActorSystem on new fresh mailbox.
@@ -456,7 +456,7 @@ namespace NActors {
inline TActorContext TActivationContext::ActorContextFor(TActorId id) {
auto& tls = *TlsActivationContext;
- return TActorContext(tls.Mailbox, tls.ExecutorThread, tls.EventStart, id);
+ return TActorContext(tls.Mailbox, tls.ExecutorThread, tls.EventStart, id);
}
class TDecorator : public IActor {
diff --git a/library/cpp/actors/core/actor_coroutine.cpp b/library/cpp/actors/core/actor_coroutine.cpp
index 0ab4d2b24d..d3bcdafbd3 100644
--- a/library/cpp/actors/core/actor_coroutine.cpp
+++ b/library/cpp/actors/core/actor_coroutine.cpp
@@ -1,9 +1,9 @@
#include "actor_coroutine.h"
#include "executor_thread.h"
-#include <util/system/sanitizers.h>
+#include <util/system/sanitizers.h>
#include <util/system/type_name.h>
-
+
namespace NActors {
static constexpr size_t StackOverflowGap = 4096;
static char GoodStack[StackOverflowGap];
@@ -92,8 +92,8 @@ namespace NActors {
}
// prepare actor context for in-coroutine use
- TActivationContext *ac = TlsActivationContext;
- TlsActivationContext = nullptr;
+ TActivationContext *ac = TlsActivationContext;
+ TlsActivationContext = nullptr;
TActorContext ctx(ac->Mailbox, ac->ExecutorThread, ac->EventStart, SelfActorId);
ActorContext = &ctx;
diff --git a/library/cpp/actors/core/actorid.h b/library/cpp/actors/core/actorid.h
index d972b1a0ff..c9e6173173 100644
--- a/library/cpp/actors/core/actorid.h
+++ b/library/cpp/actors/core/actorid.h
@@ -12,13 +12,13 @@ namespace NActors {
// next 20 bits - node id itself
struct TActorId {
- static constexpr ui32 MaxServiceIDLength = 12;
- static constexpr ui32 MaxPoolID = 0x000007FF;
- static constexpr ui32 MaxNodeId = 0x000FFFFF;
- static constexpr ui32 PoolIndexShift = 20;
- static constexpr ui32 PoolIndexMask = MaxPoolID << PoolIndexShift;
- static constexpr ui32 ServiceMask = 0x80000000;
- static constexpr ui32 NodeIdMask = MaxNodeId;
+ static constexpr ui32 MaxServiceIDLength = 12;
+ static constexpr ui32 MaxPoolID = 0x000007FF;
+ static constexpr ui32 MaxNodeId = 0x000FFFFF;
+ static constexpr ui32 PoolIndexShift = 20;
+ static constexpr ui32 PoolIndexMask = MaxPoolID << PoolIndexShift;
+ static constexpr ui32 ServiceMask = 0x80000000;
+ static constexpr ui32 NodeIdMask = MaxNodeId;
private:
union {
diff --git a/library/cpp/actors/core/actorsystem.cpp b/library/cpp/actors/core/actorsystem.cpp
index c58698a206..4130b0d4da 100644
--- a/library/cpp/actors/core/actorsystem.cpp
+++ b/library/cpp/actors/core/actorsystem.cpp
@@ -43,7 +43,7 @@ namespace NActors {
, Scheduler(setup->Scheduler)
, InterconnectCount((ui32)setup->Interconnect.ProxyActors.size())
, CurrentTimestamp(0)
- , CurrentMonotonic(0)
+ , CurrentMonotonic(0)
, CurrentIDCounter(RandomNumber<ui64>())
, SystemSetup(setup.Release())
, DefSelfID(NodeId, "actorsystem")
@@ -69,15 +69,15 @@ namespace NActors {
#endif
TActorId recipient = ev->GetRecipientRewrite();
- const ui32 recpNodeId = recipient.NodeId();
+ const ui32 recpNodeId = recipient.NodeId();
if (recpNodeId != NodeId && recpNodeId != 0) {
// if recipient is not local one - rewrite with forward instruction
Y_VERIFY_DEBUG(!ev->HasEvent() || ev->GetBase()->IsSerializable());
- Y_VERIFY(ev->Recipient == recipient,
- "Event rewrite from %s to %s would be lost via interconnect",
- ev->Recipient.ToString().c_str(),
- recipient.ToString().c_str());
+ Y_VERIFY(ev->Recipient == recipient,
+ "Event rewrite from %s to %s would be lost via interconnect",
+ ev->Recipient.ToString().c_str(),
+ recipient.ToString().c_str());
recipient = InterconnectProxy(recpNodeId);
ev->Rewrite(TEvInterconnect::EvForward, recipient);
}
@@ -119,20 +119,20 @@ namespace NActors {
}
void TActorSystem::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
- Schedule(deadline - Timestamp(), ev, cookie);
- }
-
- void TActorSystem::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
- const auto current = Monotonic();
- if (deadline < current)
- deadline = current;
-
- TTicketLock::TGuard guard(&ScheduleLock);
- ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ Schedule(deadline - Timestamp(), ev, cookie);
}
+ void TActorSystem::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
+ const auto current = Monotonic();
+ if (deadline < current)
+ deadline = current;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
void TActorSystem::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
- const auto deadline = Monotonic() + delta;
+ const auto deadline = Monotonic() + delta;
TTicketLock::TGuard guard(&ScheduleLock);
ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
@@ -211,7 +211,7 @@ namespace NActors {
TVector<NSchedulerQueue::TReader*> scheduleReaders;
scheduleReaders.push_back(&ScheduleQueue->Reader);
CpuManager->PrepareStart(scheduleReaders, this);
- Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic);
+ Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic);
Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size());
// setup interconnect proxies
@@ -242,9 +242,9 @@ namespace NActors {
// ok, setup complete, we could destroy setup config
SystemSetup.Destroy();
- Scheduler->PrepareStart();
+ Scheduler->PrepareStart();
CpuManager->Start();
- Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic));
+ Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic));
Scheduler->Start();
}
diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h
index 40499d7586..80d33901b0 100644
--- a/library/cpp/actors/core/actorsystem.h
+++ b/library/cpp/actors/core/actorsystem.h
@@ -27,7 +27,7 @@ namespace NActors {
char data[12];
memcpy(data, "ICProxy@", 8);
memcpy(data + 8, &destNodeId, sizeof(ui32));
- return TActorId(0, TStringBuf(data, 12));
+ return TActorId(0, TStringBuf(data, 12));
}
inline bool IsInterconnectProxyId(const TActorId& actorId) {
@@ -69,7 +69,7 @@ namespace NActors {
/**
* Schedule one-shot event that will be send at given time point in the future.
*
- * @param deadline the wallclock time point in future when event must be send
+ * @param deadline the wallclock time point in future when event must be send
* @param ev the event to send
* @param cookie cookie that will be piggybacked with event
* @param workerId index of thread which will perform event dispatching
@@ -77,16 +77,16 @@ namespace NActors {
virtual void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0;
/**
- * Schedule one-shot event that will be send at given time point in the future.
- *
- * @param deadline the monotonic time point in future when event must be send
- * @param ev the event to send
- * @param cookie cookie that will be piggybacked with event
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
* @param workerId index of thread which will perform event dispatching
- */
+ */
virtual void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0;
-
- /**
+
+ /**
* Schedule one-shot event that will be send after given delay.
*
* @param delta the time from now to delay event sending
@@ -136,9 +136,9 @@ namespace NActors {
virtual ~ISchedulerThread() {
}
- virtual void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) = 0;
+ virtual void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) = 0;
virtual void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) = 0;
- virtual void PrepareStart() { /* empty */ }
+ virtual void PrepareStart() { /* empty */ }
virtual void Start() = 0;
virtual void PrepareStop() = 0;
virtual void Stop() = 0;
@@ -226,7 +226,7 @@ namespace NActors {
TArrayHolder<TActorId> Interconnect;
volatile ui64 CurrentTimestamp;
- volatile ui64 CurrentMonotonic;
+ volatile ui64 CurrentMonotonic;
volatile ui64 CurrentIDCounter;
THolder<NSchedulerQueue::TQueueType> ScheduleQueue;
@@ -264,22 +264,22 @@ namespace NActors {
/**
* Schedule one-shot event that will be send at given time point in the future.
*
- * @param deadline the wallclock time point in future when event must be send
+ * @param deadline the wallclock time point in future when event must be send
* @param ev the event to send
* @param cookie cookie that will be piggybacked with event
*/
void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
/**
- * Schedule one-shot event that will be send at given time point in the future.
- *
- * @param deadline the monotonic time point in future when event must be send
- * @param ev the event to send
- * @param cookie cookie that will be piggybacked with event
- */
- void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
-
- /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
* Schedule one-shot event that will be send after given delay.
*
* @param delta the time from now to delay event sending
@@ -340,10 +340,10 @@ namespace NActors {
return TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp));
}
- TMonotonic Monotonic() const {
- return TMonotonic::MicroSeconds(RelaxedLoad(&CurrentMonotonic));
- }
-
+ TMonotonic Monotonic() const {
+ return TMonotonic::MicroSeconds(RelaxedLoad(&CurrentMonotonic));
+ }
+
template <typename T>
T* AppData() const {
return (T*)AppData0;
diff --git a/library/cpp/actors/core/events.h b/library/cpp/actors/core/events.h
index 702cf50fad..381dac03af 100644
--- a/library/cpp/actors/core/events.h
+++ b/library/cpp/actors/core/events.h
@@ -4,7 +4,7 @@
#include "event_pb.h"
#include <library/cpp/actors/protos/actors.pb.h>
-#include <util/system/unaligned_mem.h>
+#include <util/system/unaligned_mem.h>
namespace NActors {
struct TEvents {
@@ -161,9 +161,9 @@ namespace NActors {
private:
static TString MakeData(ui32 sourceType, ui32 reason) {
TString s = TString::Uninitialized(sizeof(ui32) + sizeof(ui32));
- char *p = s.Detach();
- WriteUnaligned<ui32>(p + 0, sourceType);
- WriteUnaligned<ui32>(p + 4, reason);
+ char *p = s.Detach();
+ WriteUnaligned<ui32>(p + 0, sourceType);
+ WriteUnaligned<ui32>(p + 4, reason);
return s;
}
};
diff --git a/library/cpp/actors/core/events_undelivered.cpp b/library/cpp/actors/core/events_undelivered.cpp
index 23deaffd10..3b96625cab 100644
--- a/library/cpp/actors/core/events_undelivered.cpp
+++ b/library/cpp/actors/core/events_undelivered.cpp
@@ -32,9 +32,9 @@ namespace NActors {
IEventBase* TEvents::TEvUndelivered::Load(TEventSerializedData* bufs) {
TString str = bufs->GetString();
Y_VERIFY(str.size() == (sizeof(ui32) + sizeof(ui32)));
- const char* p = str.data();
- const ui64 sourceType = ReadUnaligned<ui32>(p + 0);
- const ui64 reason = ReadUnaligned<ui32>(p + 4);
+ const char* p = str.data();
+ const ui64 sourceType = ReadUnaligned<ui32>(p + 0);
+ const ui64 reason = ReadUnaligned<ui32>(p + 4);
return new TEvUndelivered(sourceType, reason);
}
diff --git a/library/cpp/actors/core/executor_pool_basic.cpp b/library/cpp/actors/core/executor_pool_basic.cpp
index 4dce16939a..87315a6a6a 100644
--- a/library/cpp/actors/core/executor_pool_basic.cpp
+++ b/library/cpp/actors/core/executor_pool_basic.cpp
@@ -87,17 +87,17 @@ namespace NActors {
if (x < 0) {
#if defined ACTORSLIB_COLLECT_EXEC_STATS
if (AtomicGetAndIncrement(ThreadUtilization) == 0) {
- // Initially counter contains -t0, the pool start timestamp
- // When the first thread goes to sleep we add t1, so the counter
- // becomes t1-t0 >= 0, or the duration of max utilization so far.
- // If the counter was negative and becomes positive, that means
- // counter just turned into a duration and we should store that
- // duration. Otherwise another thread raced with us and
- // subtracted some other timestamp t2.
+ // Initially counter contains -t0, the pool start timestamp
+ // When the first thread goes to sleep we add t1, so the counter
+ // becomes t1-t0 >= 0, or the duration of max utilization so far.
+ // If the counter was negative and becomes positive, that means
+ // counter just turned into a duration and we should store that
+ // duration. Otherwise another thread raced with us and
+ // subtracted some other timestamp t2.
const i64 t = GetCycleCountFast();
- const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t);
- if (x < 0 && x + t > 0)
- AtomicStore(&MaxUtilizationAccumulator, x + t);
+ const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t);
+ if (x < 0 && x + t > 0)
+ AtomicStore(&MaxUtilizationAccumulator, x + t);
}
#endif
@@ -126,7 +126,7 @@ namespace NActors {
if (!doSpin) {
break;
}
- if (RelaxedLoad(&StopFlag)) {
+ if (RelaxedLoad(&StopFlag)) {
break;
}
}
@@ -159,20 +159,20 @@ namespace NActors {
#if defined ACTORSLIB_COLLECT_EXEC_STATS
if (AtomicDecrement(ThreadUtilization) == 0) {
- // When we started sleeping counter contained t1-t0, or the
- // last duration of max utilization. Now we subtract t2 >= t1,
- // which turns counter negative again, and the next sleep cycle
- // at timestamp t3 would be adding some new duration t3-t2.
- // If the counter was positive and becomes negative that means
- // there are no current races with other threads and we should
- // store the last positive duration we observed. Multiple
- // threads may be adding and subtracting values in potentially
- // arbitrary order, which would cause counter to oscillate
- // around zero. When it crosses zero is a good indication of a
- // correct value.
+ // When we started sleeping counter contained t1-t0, or the
+ // last duration of max utilization. Now we subtract t2 >= t1,
+ // which turns counter negative again, and the next sleep cycle
+ // at timestamp t3 would be adding some new duration t3-t2.
+ // If the counter was positive and becomes negative that means
+ // there are no current races with other threads and we should
+ // store the last positive duration we observed. Multiple
+ // threads may be adding and subtracting values in potentially
+ // arbitrary order, which would cause counter to oscillate
+ // around zero. When it crosses zero is a good indication of a
+ // correct value.
const i64 t = GetCycleCountFast();
- const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t);
- if (x > 0 && x - t < 0)
+ const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t);
+ if (x > 0 && x - t < 0)
AtomicStore(&MaxUtilizationAccumulator, x);
}
#endif
@@ -305,18 +305,18 @@ namespace NActors {
void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
Y_VERIFY_DEBUG(workerId < PoolThreads);
-
- const auto current = ActorSystem->Monotonic();
- if (deadline < current)
- deadline = current;
-
+
+ const auto current = ActorSystem->Monotonic();
+ if (deadline < current)
+ deadline = current;
+
ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie);
- }
-
+ }
+
void TBasicExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
Y_VERIFY_DEBUG(workerId < PoolThreads);
- const auto deadline = ActorSystem->Monotonic() + delta;
+ const auto deadline = ActorSystem->Monotonic() + delta;
ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie);
}
diff --git a/library/cpp/actors/core/executor_pool_basic_ut.cpp b/library/cpp/actors/core/executor_pool_basic_ut.cpp
index 76dff693af..b3d6d8b329 100644
--- a/library/cpp/actors/core/executor_pool_basic_ut.cpp
+++ b/library/cpp/actors/core/executor_pool_basic_ut.cpp
@@ -47,8 +47,8 @@ public:
if (GetCounter() == 0) {
break;
}
-
- Sleep(TDuration::MilliSeconds(1));
+
+ Sleep(TDuration::MilliSeconds(1));
}
}
@@ -69,8 +69,8 @@ private:
{
Y_UNUSED(ev);
Action();
- TAtomicBase count = AtomicDecrement(Counter);
- Y_VERIFY(count != Max<TAtomicBase>());
+ TAtomicBase count = AtomicDecrement(Counter);
+ Y_VERIFY(count != Max<TAtomicBase>());
if (count) {
Send(Receiver, new TEvMsg());
}
@@ -206,19 +206,19 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) {
actorSystem.Send(changerActorId, new TEvMsg());
while (true) {
- size_t maxCounter = 0;
+ size_t maxCounter = 0;
for (size_t i = 0; i < size; ++i) {
- maxCounter = Max(maxCounter, actors[i]->GetCounter());
- }
-
- if (maxCounter == 0) {
- break;
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
}
+ if (maxCounter == 0) {
+ break;
+ }
+
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
changerActor->Stop();
@@ -242,9 +242,9 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) {
while (actor->GetCounter()) {
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
-
- Sleep(TDuration::MilliSeconds(1));
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
+
+ Sleep(TDuration::MilliSeconds(1));
}
}
@@ -275,19 +275,19 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) {
while (true) {
- size_t maxCounter = 0;
+ size_t maxCounter = 0;
for (size_t i = 0; i < size; ++i) {
- maxCounter = Max(maxCounter, actors[i]->GetCounter());
- }
-
- if (maxCounter == 0) {
- break;
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
}
+ if (maxCounter == 0) {
+ break;
+ }
+
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
}
@@ -319,19 +319,19 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) {
while (true) {
- size_t maxCounter = 0;
+ size_t maxCounter = 0;
for (size_t i = 0; i < actorsCount; ++i) {
- maxCounter = Max(maxCounter, actors[i]->GetCounter());
- }
-
- if (maxCounter == 0) {
- break;
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
}
+ if (maxCounter == 0) {
+ break;
+ }
+
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
}
@@ -362,19 +362,19 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) {
}
while (true) {
- size_t maxCounter = 0;
+ size_t maxCounter = 0;
for (size_t i = 0; i < actorsCount; ++i) {
- maxCounter = Max(maxCounter, actors[i]->GetCounter());
- }
-
- if (maxCounter == 0) {
- break;
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
}
+ if (maxCounter == 0) {
+ break;
+ }
+
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
}
diff --git a/library/cpp/actors/core/executor_pool_io.cpp b/library/cpp/actors/core/executor_pool_io.cpp
index fb557ae6b0..f4f13c9c20 100644
--- a/library/cpp/actors/core/executor_pool_io.cpp
+++ b/library/cpp/actors/core/executor_pool_io.cpp
@@ -30,33 +30,33 @@ namespace NActors {
ui32 workerId = wctx.WorkerId;
Y_VERIFY_DEBUG(workerId < PoolThreads);
- NHPTimer::STime elapsed = 0;
- NHPTimer::STime parked = 0;
+ NHPTimer::STime elapsed = 0;
+ NHPTimer::STime parked = 0;
NHPTimer::STime hpstart = GetCycleCountFast();
- NHPTimer::STime hpnow;
-
+ NHPTimer::STime hpnow;
+
const TAtomic x = AtomicDecrement(Semaphore);
if (x < 0) {
TThreadCtx& threadCtx = Threads[workerId];
ThreadQueue.Push(workerId + 1, revolvingCounter);
hpnow = GetCycleCountFast();
- elapsed += hpnow - hpstart;
+ elapsed += hpnow - hpstart;
if (threadCtx.Pad.Park())
return 0;
hpstart = GetCycleCountFast();
- parked += hpstart - hpnow;
+ parked += hpstart - hpnow;
}
while (!RelaxedLoad(&StopFlag)) {
- if (const ui32 activation = Activations.Pop(++revolvingCounter)) {
+ if (const ui32 activation = Activations.Pop(++revolvingCounter)) {
hpnow = GetCycleCountFast();
- elapsed += hpnow - hpstart;
+ elapsed += hpnow - hpstart;
wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed);
- if (parked > 0) {
+ if (parked > 0) {
wctx.AddParkedCycles(parked);
- }
+ }
return activation;
- }
+ }
SpinLockPause();
}
@@ -69,18 +69,18 @@ namespace NActors {
void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
Y_UNUSED(workerId);
-
- const auto current = ActorSystem->Monotonic();
- if (deadline < current)
- deadline = current;
-
- TTicketLock::TGuard guard(&ScheduleLock);
- ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
- }
-
+
+ const auto current = ActorSystem->Monotonic();
+ if (deadline < current)
+ deadline = current;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
void TIOExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
Y_UNUSED(workerId);
- const auto deadline = ActorSystem->Monotonic() + delta;
+ const auto deadline = ActorSystem->Monotonic() + delta;
TTicketLock::TGuard guard(&ScheduleLock);
ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
diff --git a/library/cpp/actors/core/executor_pool_io.h b/library/cpp/actors/core/executor_pool_io.h
index e576d642a1..7de6fd0528 100644
--- a/library/cpp/actors/core/executor_pool_io.h
+++ b/library/cpp/actors/core/executor_pool_io.h
@@ -17,7 +17,7 @@ namespace NActors {
};
TArrayHolder<TThreadCtx> Threads;
- TUnorderedCache<ui32, 512, 4> ThreadQueue;
+ TUnorderedCache<ui32, 512, 4> ThreadQueue;
THolder<NSchedulerQueue::TQueueType> ScheduleQueue;
TTicketLock ScheduleLock;
diff --git a/library/cpp/actors/core/executor_pool_united.cpp b/library/cpp/actors/core/executor_pool_united.cpp
index dac6245635..4ae9ec4c73 100644
--- a/library/cpp/actors/core/executor_pool_united.cpp
+++ b/library/cpp/actors/core/executor_pool_united.cpp
@@ -1235,7 +1235,7 @@ namespace NActors {
inline void TUnitedWorkers::TryWake(TPoolId pool) {
// Avoid using multiple atomic seq_cst loads in cycle, use barrier once
AtomicBarrier();
-
+
// Scan every allowed cpu in pool's wakeup order and try to wake the first idle cpu
if (RelaxedLoad(&Pools[pool].Waiters) > 0) {
for (TCpu* cpu : Pools[pool].WakeOrderCpus) {
@@ -1247,11 +1247,11 @@ namespace NActors {
// Cpu has not been woken up
}
-
+
inline void TUnitedWorkers::BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) {
Pools[pool].BeginExecution(activation, revolvingCounter);
- }
-
+ }
+
inline bool TUnitedWorkers::NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) {
return Pools[pool].NextExecution(activation, revolvingCounter);
}
diff --git a/library/cpp/actors/core/executor_pool_united_ut.cpp b/library/cpp/actors/core/executor_pool_united_ut.cpp
index d4df17f1b8..ddc4c348ee 100644
--- a/library/cpp/actors/core/executor_pool_united_ut.cpp
+++ b/library/cpp/actors/core/executor_pool_united_ut.cpp
@@ -58,8 +58,8 @@ public:
if (GetCounter() == 0) {
break;
}
-
- Sleep(TDuration::MilliSeconds(1));
+
+ Sleep(TDuration::MilliSeconds(1));
}
}
@@ -78,8 +78,8 @@ private:
void Handle(TEvMsg::TPtr &ev) {
Y_UNUSED(ev);
Action();
- TAtomicBase count = AtomicDecrement(Counter);
- Y_VERIFY(count != Max<TAtomicBase>());
+ TAtomicBase count = AtomicDecrement(Counter);
+ Y_VERIFY(count != Max<TAtomicBase>());
if (count) {
Send(Receiver, new TEvMsg());
}
@@ -149,9 +149,9 @@ Y_UNIT_TEST_SUITE(UnitedExecutorPool) {
while (actor->GetCounter()) {
auto now = TInstant::Now();
- UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
-
- Sleep(TDuration::MilliSeconds(1));
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
+
+ Sleep(TDuration::MilliSeconds(1));
}
TVector<TExecutorThreadStats> stats;
@@ -212,11 +212,11 @@ Y_UNIT_TEST_SUITE(UnitedExecutorPool) {
left += actor->GetCounter();
}
if (left == 0) {
- break;
- }
+ break;
+ }
auto now = TInstant::Now();
UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
for (size_t pool = 0; pool < pools; pool++) {
@@ -311,11 +311,11 @@ Y_UNIT_TEST_SUITE(UnitedExecutorPool) {
left += actor->GetCounter();
}
if (left == 0) {
- break;
- }
+ break;
+ }
auto now = TInstant::Now();
UNIT_ASSERT_C(now - begin < TDuration::Seconds(15), "left " << left);
- Sleep(TDuration::MilliSeconds(1));
+ Sleep(TDuration::MilliSeconds(1));
}
for (size_t pool = 0; pool < pools; pool++) {
diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp
index 446b651efd..7e961584e6 100644
--- a/library/cpp/actors/core/executor_thread.cpp
+++ b/library/cpp/actors/core/executor_thread.cpp
@@ -76,11 +76,11 @@ namespace NActors {
Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId);
}
- void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
- ++CurrentActorScheduledEventsCounter;
+ void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ ++CurrentActorScheduledEventsCounter;
Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId);
- }
-
+ }
+
void TExecutorThread::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
++CurrentActorScheduledEventsCounter;
Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId);
@@ -145,7 +145,7 @@ namespace NActors {
NHPTimer::STime hpnow;
recipient = ev->GetRecipientRewrite();
if (actor = mailbox->FindActor(recipient.LocalId())) {
- TActorContext ctx(*mailbox, *this, hpprev, recipient);
+ TActorContext ctx(*mailbox, *this, hpprev, recipient);
TlsActivationContext = &ctx;
#ifdef USE_ACTOR_CALLSTACK
diff --git a/library/cpp/actors/core/executor_thread.h b/library/cpp/actors/core/executor_thread.h
index 9d3c573f0d..72b8f28c1d 100644
--- a/library/cpp/actors/core/executor_thread.h
+++ b/library/cpp/actors/core/executor_thread.h
@@ -47,7 +47,7 @@ namespace NActors {
const std::vector<THolder<IActor>>& GetUnregistered() const { return DyingActors; }
void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
- void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
bool Send(TAutoPtr<IEventHandle> ev) {
diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp
index 5f63b5af58..391844dcff 100644
--- a/library/cpp/actors/core/log.cpp
+++ b/library/cpp/actors/core/log.cpp
@@ -223,9 +223,9 @@ namespace NActors {
}
}
- void TLoggerActor::Throttle(const NLog::TSettings& settings) {
+ void TLoggerActor::Throttle(const NLog::TSettings& settings) {
if (AtomicGet(IsOverflow))
- Sleep(settings.ThrottleDelay);
+ Sleep(settings.ThrottleDelay);
}
void TLoggerActor::LogIgnoredCount(TInstant now) {
diff --git a/library/cpp/actors/core/log.h b/library/cpp/actors/core/log.h
index c11a7cf3c1..f063642ad2 100644
--- a/library/cpp/actors/core/log.h
+++ b/library/cpp/actors/core/log.h
@@ -232,7 +232,7 @@ namespace NActors {
// Directly call logger instead of sending a message
void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...);
- static void Throttle(const NLog::TSettings& settings);
+ static void Throttle(const NLog::TSettings& settings);
private:
TIntrusivePtr<NLog::TSettings> Settings;
@@ -322,7 +322,7 @@ namespace NActors {
inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str)
{
const NLog::TSettings *mSettings = ctx.LoggerSettings();
- TLoggerActor::Throttle(*mSettings);
+ TLoggerActor::Throttle(*mSettings);
ctx.Send(new IEventHandle(mSettings->LoggerActorId, TActorId(), new NLog::TEvLog(mPriority, mComponent, std::move(str))));
}
diff --git a/library/cpp/actors/core/log_settings.cpp b/library/cpp/actors/core/log_settings.cpp
index f52f2fc5d2..d77688021d 100644
--- a/library/cpp/actors/core/log_settings.cpp
+++ b/library/cpp/actors/core/log_settings.cpp
@@ -12,7 +12,7 @@ namespace NActors {
, LoggerComponent(loggerComponent)
, TimeThresholdMs(timeThresholdMs)
, AllowDrop(true)
- , ThrottleDelay(TDuration::MilliSeconds(100))
+ , ThrottleDelay(TDuration::MilliSeconds(100))
, MinVal(0)
, MaxVal(0)
, Mask(0)
@@ -34,7 +34,7 @@ namespace NActors {
, LoggerComponent(loggerComponent)
, TimeThresholdMs(timeThresholdMs)
, AllowDrop(true)
- , ThrottleDelay(TDuration::MilliSeconds(100))
+ , ThrottleDelay(TDuration::MilliSeconds(100))
, MinVal(0)
, MaxVal(0)
, Mask(0)
@@ -205,10 +205,10 @@ namespace NActors {
AllowDrop = val;
}
- void TSettings::SetThrottleDelay(TDuration value) {
- ThrottleDelay = value;
- }
-
+ void TSettings::SetThrottleDelay(TDuration value) {
+ ThrottleDelay = value;
+ }
+
void TSettings::SetUseLocalTimestamps(bool value) {
UseLocalTimestamps = value;
}
diff --git a/library/cpp/actors/core/log_settings.h b/library/cpp/actors/core/log_settings.h
index 7fe4504edd..5f4898bda1 100644
--- a/library/cpp/actors/core/log_settings.h
+++ b/library/cpp/actors/core/log_settings.h
@@ -73,7 +73,7 @@ namespace NActors {
EComponent LoggerComponent;
ui64 TimeThresholdMs;
bool AllowDrop;
- TDuration ThrottleDelay;
+ TDuration ThrottleDelay;
TArrayHolder<TAtomic> ComponentInfo;
TVector<TString> ComponentNames;
EComponent MinVal;
@@ -162,7 +162,7 @@ namespace NActors {
static bool IsValidPriority(EPriority priority);
bool IsValidComponent(EComponent component);
void SetAllowDrop(bool val);
- void SetThrottleDelay(TDuration value);
+ void SetThrottleDelay(TDuration value);
void SetUseLocalTimestamps(bool value);
private:
diff --git a/library/cpp/actors/core/mailbox.cpp b/library/cpp/actors/core/mailbox.cpp
index d84b4f9e46..b63577c7d6 100644
--- a/library/cpp/actors/core/mailbox.cpp
+++ b/library/cpp/actors/core/mailbox.cpp
@@ -529,7 +529,7 @@ namespace NActors {
Y_FAIL();
}
- AtomicStore(Lines + lineIndex, header);
+ AtomicStore(Lines + lineIndex, header);
ui32 ret = lineIndexMask | 1;
diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h
index 0bd9c4d314..8f4f901bd9 100644
--- a/library/cpp/actors/core/mailbox.h
+++ b/library/cpp/actors/core/mailbox.h
@@ -277,7 +277,7 @@ namespace NActors {
TAtomic LastAllocatedLine;
TAtomic AllocatedMailboxCount;
- typedef TUnorderedCache<ui32, 512, 4> TMailboxCache;
+ typedef TUnorderedCache<ui32, 512, 4> TMailboxCache;
TMailboxCache MailboxCacheSimple;
TAtomic CachedSimpleMailboxes;
TMailboxCache MailboxCacheRevolving;
diff --git a/library/cpp/actors/core/monotonic.cpp b/library/cpp/actors/core/monotonic.cpp
index 3465149dbe..eefd8913cc 100644
--- a/library/cpp/actors/core/monotonic.cpp
+++ b/library/cpp/actors/core/monotonic.cpp
@@ -1,23 +1,23 @@
-#include "monotonic.h"
-
-#include <chrono>
-
-namespace NActors {
-
- namespace {
- // Unfortunately time_since_epoch() is sometimes negative on wine
- // Remember initial time point at program start and use offsets from that
- std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now();
- }
-
- ui64 GetMonotonicMicroSeconds() {
- auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count();
- // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations
- if (Y_UNLIKELY(microseconds < 0)) {
- microseconds = 0;
- }
- // Add one so we never return zero
- return microseconds + 1;
- }
-
-} // namespace NActors
+#include "monotonic.h"
+
+#include <chrono>
+
+namespace NActors {
+
+ namespace {
+ // Unfortunately time_since_epoch() is sometimes negative on wine
+ // Remember initial time point at program start and use offsets from that
+ std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now();
+ }
+
+ ui64 GetMonotonicMicroSeconds() {
+ auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count();
+ // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations
+ if (Y_UNLIKELY(microseconds < 0)) {
+ microseconds = 0;
+ }
+ // Add one so we never return zero
+ return microseconds + 1;
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/core/monotonic.h b/library/cpp/actors/core/monotonic.h
index 6fceb91dbe..cc0136b558 100644
--- a/library/cpp/actors/core/monotonic.h
+++ b/library/cpp/actors/core/monotonic.h
@@ -1,111 +1,111 @@
-#pragma once
-
-#include <util/datetime/base.h>
-
-namespace NActors {
-
- /**
- * Returns current monotonic time in microseconds
- */
- ui64 GetMonotonicMicroSeconds();
-
- /**
- * Similar to TInstant, but measuring monotonic time
- */
- class TMonotonic : public TTimeBase<TMonotonic> {
- using TBase = TTimeBase<TMonotonic>;
-
- private:
- constexpr explicit TMonotonic(TValue value) noexcept
- : TBase(value)
- { }
-
- public:
- constexpr TMonotonic() noexcept {
- }
-
- static constexpr TMonotonic FromValue(TValue value) noexcept {
- return TMonotonic(value);
- }
-
- static inline TMonotonic Now() {
- return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds());
- }
-
- using TBase::Days;
- using TBase::Hours;
- using TBase::MicroSeconds;
- using TBase::MilliSeconds;
- using TBase::Minutes;
- using TBase::Seconds;
-
- static constexpr TMonotonic Max() noexcept {
- return TMonotonic(::Max<ui64>());
- }
-
- static constexpr TMonotonic Zero() noexcept {
- return TMonotonic();
- }
-
- static constexpr TMonotonic MicroSeconds(ui64 us) noexcept {
- return TMonotonic(TInstant::MicroSeconds(us).GetValue());
- }
-
- static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept {
- return TMonotonic(TInstant::MilliSeconds(ms).GetValue());
- }
-
- static constexpr TMonotonic Seconds(ui64 s) noexcept {
- return TMonotonic(TInstant::Seconds(s).GetValue());
- }
-
- static constexpr TMonotonic Minutes(ui64 m) noexcept {
- return TMonotonic(TInstant::Minutes(m).GetValue());
- }
-
- static constexpr TMonotonic Hours(ui64 h) noexcept {
- return TMonotonic(TInstant::Hours(h).GetValue());
- }
-
- static constexpr TMonotonic Days(ui64 d) noexcept {
- return TMonotonic(TInstant::Days(d).GetValue());
- }
-
- template<class T>
- inline TMonotonic& operator+=(const T& t) noexcept {
- return (*this = (*this + t));
- }
-
- template<class T>
- inline TMonotonic& operator-=(const T& t) noexcept {
- return (*this = (*this - t));
- }
- };
-} // namespace NActors
-
-Y_DECLARE_PODTYPE(NActors::TMonotonic);
-
-template<>
-struct THash<NActors::TMonotonic> {
- size_t operator()(const NActors::TMonotonic& key) const {
- return THash<NActors::TMonotonic::TValue>()(key.GetValue());
- }
-};
-
-namespace NActors {
-
- constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) {
- return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue());
- }
-
- constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) {
- TInstant result = TInstant::FromValue(l.GetValue()) + r;
- return TMonotonic::FromValue(result.GetValue());
- }
-
- constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) {
- TInstant result = TInstant::FromValue(l.GetValue()) - r;
- return TMonotonic::FromValue(result.GetValue());
- }
-
-} // namespace NActors
+#pragma once
+
+#include <util/datetime/base.h>
+
+namespace NActors {
+
+ /**
+ * Returns current monotonic time in microseconds
+ */
+ ui64 GetMonotonicMicroSeconds();
+
+ /**
+ * Similar to TInstant, but measuring monotonic time
+ */
+ class TMonotonic : public TTimeBase<TMonotonic> {
+ using TBase = TTimeBase<TMonotonic>;
+
+ private:
+ constexpr explicit TMonotonic(TValue value) noexcept
+ : TBase(value)
+ { }
+
+ public:
+ constexpr TMonotonic() noexcept {
+ }
+
+ static constexpr TMonotonic FromValue(TValue value) noexcept {
+ return TMonotonic(value);
+ }
+
+ static inline TMonotonic Now() {
+ return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds());
+ }
+
+ using TBase::Days;
+ using TBase::Hours;
+ using TBase::MicroSeconds;
+ using TBase::MilliSeconds;
+ using TBase::Minutes;
+ using TBase::Seconds;
+
+ static constexpr TMonotonic Max() noexcept {
+ return TMonotonic(::Max<ui64>());
+ }
+
+ static constexpr TMonotonic Zero() noexcept {
+ return TMonotonic();
+ }
+
+ static constexpr TMonotonic MicroSeconds(ui64 us) noexcept {
+ return TMonotonic(TInstant::MicroSeconds(us).GetValue());
+ }
+
+ static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept {
+ return TMonotonic(TInstant::MilliSeconds(ms).GetValue());
+ }
+
+ static constexpr TMonotonic Seconds(ui64 s) noexcept {
+ return TMonotonic(TInstant::Seconds(s).GetValue());
+ }
+
+ static constexpr TMonotonic Minutes(ui64 m) noexcept {
+ return TMonotonic(TInstant::Minutes(m).GetValue());
+ }
+
+ static constexpr TMonotonic Hours(ui64 h) noexcept {
+ return TMonotonic(TInstant::Hours(h).GetValue());
+ }
+
+ static constexpr TMonotonic Days(ui64 d) noexcept {
+ return TMonotonic(TInstant::Days(d).GetValue());
+ }
+
+ template<class T>
+ inline TMonotonic& operator+=(const T& t) noexcept {
+ return (*this = (*this + t));
+ }
+
+ template<class T>
+ inline TMonotonic& operator-=(const T& t) noexcept {
+ return (*this = (*this - t));
+ }
+ };
+} // namespace NActors
+
+Y_DECLARE_PODTYPE(NActors::TMonotonic);
+
+template<>
+struct THash<NActors::TMonotonic> {
+ size_t operator()(const NActors::TMonotonic& key) const {
+ return THash<NActors::TMonotonic::TValue>()(key.GetValue());
+ }
+};
+
+namespace NActors {
+
+ constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) {
+ return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue());
+ }
+
+ constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) + r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
+
+ constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) - r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/core/scheduler_actor.cpp b/library/cpp/actors/core/scheduler_actor.cpp
index febc5e40dd..c189653e99 100644
--- a/library/cpp/actors/core/scheduler_actor.cpp
+++ b/library/cpp/actors/core/scheduler_actor.cpp
@@ -43,7 +43,7 @@ namespace NActors {
TPollerToken::TPtr PollerToken;
ui64 RealTime;
- ui64 MonotonicTime;
+ ui64 MonotonicTime;
ui64 ActiveTick;
typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues
@@ -56,7 +56,7 @@ namespace NActors {
static const ui64 IntrasecondThreshold = 1048576; // ~second
TAutoPtr<TMomentMap> ActiveSec;
volatile ui64* CurrentTimestamp = nullptr;
- volatile ui64* CurrentMonotonic = nullptr;
+ volatile ui64* CurrentMonotonic = nullptr;
TDeque<TAutoPtr<IEventHandle>> EventsToBeSent;
public:
@@ -84,9 +84,9 @@ namespace NActors {
Y_ASSERT(evInitialize.CurrentTimestamp != nullptr);
CurrentTimestamp = evInitialize.CurrentTimestamp;
- Y_ASSERT(evInitialize.CurrentMonotonic != nullptr);
- CurrentMonotonic = evInitialize.CurrentMonotonic;
-
+ Y_ASSERT(evInitialize.CurrentMonotonic != nullptr);
+ CurrentMonotonic = evInitialize.CurrentMonotonic;
+
struct itimerspec new_time;
memset(&new_time, 0, sizeof(new_time));
new_time.it_value.tv_nsec = Cfg.ResolutionMicroseconds * 1000;
@@ -96,10 +96,10 @@ namespace NActors {
const bool success = ctx.Send(PollerActor, new TEvPollerRegister(TimerDescriptor, SelfId(), {}));
Y_VERIFY(success);
- RealTime = RelaxedLoad(CurrentTimestamp);
- MonotonicTime = RelaxedLoad(CurrentMonotonic);
+ RealTime = RelaxedLoad(CurrentTimestamp);
+ MonotonicTime = RelaxedLoad(CurrentMonotonic);
- ActiveTick = AlignUp<ui64>(MonotonicTime, IntrasecondThreshold);
+ ActiveTick = AlignUp<ui64>(MonotonicTime, IntrasecondThreshold);
}
void Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx) {
@@ -108,10 +108,10 @@ namespace NActors {
}
void UpdateTime() {
- RealTime = TInstant::Now().MicroSeconds();
- MonotonicTime = Max(MonotonicTime, GetMonotonicMicroSeconds());
- AtomicStore(CurrentTimestamp, RealTime);
- AtomicStore(CurrentMonotonic, MonotonicTime);
+ RealTime = TInstant::Now().MicroSeconds();
+ MonotonicTime = Max(MonotonicTime, GetMonotonicMicroSeconds());
+ AtomicStore(CurrentTimestamp, RealTime);
+ AtomicStore(CurrentMonotonic, MonotonicTime);
}
void TryUpdateTime(NHPTimer::STime* lastTimeUpdate) {
diff --git a/library/cpp/actors/core/scheduler_actor.h b/library/cpp/actors/core/scheduler_actor.h
index c2c561b43d..4209db0ab6 100644
--- a/library/cpp/actors/core/scheduler_actor.h
+++ b/library/cpp/actors/core/scheduler_actor.h
@@ -9,12 +9,12 @@ namespace NActors {
struct TEvSchedulerInitialize : TEventLocal<TEvSchedulerInitialize, TEvents::TSystem::Bootstrap> {
TVector<NSchedulerQueue::TReader*> ScheduleReaders;
volatile ui64* CurrentTimestamp;
- volatile ui64* CurrentMonotonic;
+ volatile ui64* CurrentMonotonic;
- TEvSchedulerInitialize(const TVector<NSchedulerQueue::TReader*>& scheduleReaders, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic)
+ TEvSchedulerInitialize(const TVector<NSchedulerQueue::TReader*>& scheduleReaders, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic)
: ScheduleReaders(scheduleReaders)
, CurrentTimestamp(currentTimestamp)
- , CurrentMonotonic(currentMonotonic)
+ , CurrentMonotonic(currentMonotonic)
{
}
};
diff --git a/library/cpp/actors/core/scheduler_basic.cpp b/library/cpp/actors/core/scheduler_basic.cpp
index fba200e16b..b0c80eb6d2 100644
--- a/library/cpp/actors/core/scheduler_basic.cpp
+++ b/library/cpp/actors/core/scheduler_basic.cpp
@@ -9,35 +9,35 @@
#endif
namespace NActors {
-
- struct TBasicSchedulerThread::TMonCounters {
- NMonitoring::TDynamicCounters::TCounterPtr TimeDelayMs;
- NMonitoring::TDynamicCounters::TCounterPtr QueueSize;
- NMonitoring::TDynamicCounters::TCounterPtr EventsSent;
- NMonitoring::TDynamicCounters::TCounterPtr EventsDropped;
- NMonitoring::TDynamicCounters::TCounterPtr EventsAdded;
- NMonitoring::TDynamicCounters::TCounterPtr Iterations;
- NMonitoring::TDynamicCounters::TCounterPtr Sleeps;
- NMonitoring::TDynamicCounters::TCounterPtr ElapsedMicrosec;
-
- TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
- : TimeDelayMs(counters->GetCounter("Scheduler/TimeDelayMs", false))
- , QueueSize(counters->GetCounter("Scheduler/QueueSize", false))
- , EventsSent(counters->GetCounter("Scheduler/EventsSent", true))
- , EventsDropped(counters->GetCounter("Scheduler/EventsDropped", true))
- , EventsAdded(counters->GetCounter("Scheduler/EventsAdded", true))
- , Iterations(counters->GetCounter("Scheduler/Iterations", true))
- , Sleeps(counters->GetCounter("Scheduler/Sleeps", true))
- , ElapsedMicrosec(counters->GetCounter("Scheduler/ElapsedMicrosec", true))
- { }
- };
-
+
+ struct TBasicSchedulerThread::TMonCounters {
+ NMonitoring::TDynamicCounters::TCounterPtr TimeDelayMs;
+ NMonitoring::TDynamicCounters::TCounterPtr QueueSize;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsSent;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsDropped;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsAdded;
+ NMonitoring::TDynamicCounters::TCounterPtr Iterations;
+ NMonitoring::TDynamicCounters::TCounterPtr Sleeps;
+ NMonitoring::TDynamicCounters::TCounterPtr ElapsedMicrosec;
+
+ TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
+ : TimeDelayMs(counters->GetCounter("Scheduler/TimeDelayMs", false))
+ , QueueSize(counters->GetCounter("Scheduler/QueueSize", false))
+ , EventsSent(counters->GetCounter("Scheduler/EventsSent", true))
+ , EventsDropped(counters->GetCounter("Scheduler/EventsDropped", true))
+ , EventsAdded(counters->GetCounter("Scheduler/EventsAdded", true))
+ , Iterations(counters->GetCounter("Scheduler/Iterations", true))
+ , Sleeps(counters->GetCounter("Scheduler/Sleeps", true))
+ , ElapsedMicrosec(counters->GetCounter("Scheduler/ElapsedMicrosec", true))
+ { }
+ };
+
TBasicSchedulerThread::TBasicSchedulerThread(const TSchedulerConfig& config)
: Config(config)
- , MonCounters(Config.MonCounters ? new TMonCounters(Config.MonCounters) : nullptr)
+ , MonCounters(Config.MonCounters ? new TMonCounters(Config.MonCounters) : nullptr)
, ActorSystem(nullptr)
, CurrentTimestamp(nullptr)
- , CurrentMonotonic(nullptr)
+ , CurrentMonotonic(nullptr)
, TotalReaders(0)
, StopFlag(false)
, ScheduleMap(3600)
@@ -55,45 +55,45 @@ namespace NActors {
#endif
::SetCurrentThreadName("Scheduler");
- ui64 currentMonotonic = RelaxedLoad(CurrentMonotonic);
- ui64 throttledMonotonic = currentMonotonic;
+ ui64 currentMonotonic = RelaxedLoad(CurrentMonotonic);
+ ui64 throttledMonotonic = currentMonotonic;
- ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold);
+ ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold);
TAutoPtr<TMomentMap> activeSec;
NHPTimer::STime hpprev = GetCycleCountFast();
- ui64 nextTimestamp = TInstant::Now().MicroSeconds();
- ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
-
+ ui64 nextTimestamp = TInstant::Now().MicroSeconds();
+ ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+
while (!AtomicLoad(&StopFlag)) {
{
- const ui64 delta = nextMonotonic - throttledMonotonic;
- const ui64 elapsedDelta = nextMonotonic - currentMonotonic;
- const ui64 threshold = Max(Min(Config.ProgressThreshold, 2 * elapsedDelta), ui64(1));
-
- throttledMonotonic = (delta > threshold) ? throttledMonotonic + threshold : nextMonotonic;
-
- if (MonCounters) {
- *MonCounters->TimeDelayMs = (nextMonotonic - throttledMonotonic) / 1000;
- }
- }
- AtomicStore(CurrentTimestamp, nextTimestamp);
- AtomicStore(CurrentMonotonic, nextMonotonic);
- currentMonotonic = nextMonotonic;
-
- if (MonCounters) {
- ++*MonCounters->Iterations;
+ const ui64 delta = nextMonotonic - throttledMonotonic;
+ const ui64 elapsedDelta = nextMonotonic - currentMonotonic;
+ const ui64 threshold = Max(Min(Config.ProgressThreshold, 2 * elapsedDelta), ui64(1));
+
+ throttledMonotonic = (delta > threshold) ? throttledMonotonic + threshold : nextMonotonic;
+
+ if (MonCounters) {
+ *MonCounters->TimeDelayMs = (nextMonotonic - throttledMonotonic) / 1000;
+ }
}
-
+ AtomicStore(CurrentTimestamp, nextTimestamp);
+ AtomicStore(CurrentMonotonic, nextMonotonic);
+ currentMonotonic = nextMonotonic;
+
+ if (MonCounters) {
+ ++*MonCounters->Iterations;
+ }
+
bool somethingDone = false;
// first step - send everything triggered on schedule
- ui64 eventsSent = 0;
- ui64 eventsDropped = 0;
+ ui64 eventsSent = 0;
+ ui64 eventsDropped = 0;
for (;;) {
while (!!activeSec && !activeSec->empty()) {
TMomentMap::iterator it = activeSec->begin();
- if (it->first <= throttledMonotonic) {
+ if (it->first <= throttledMonotonic) {
if (NSchedulerQueue::TQueueType* q = it->second.Get()) {
while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) {
somethingDone = true;
@@ -102,16 +102,16 @@ namespace NActors {
ISchedulerCookie* cookie = x->Cookie;
// TODO: lazy send with backoff queue to not hang over contended mailboxes
if (cookie) {
- if (cookie->Detach()) {
+ if (cookie->Detach()) {
ActorSystem->Send(ev);
- ++eventsSent;
- } else {
+ ++eventsSent;
+ } else {
delete ev;
- ++eventsDropped;
- }
+ ++eventsDropped;
+ }
} else {
ActorSystem->Send(ev);
- ++eventsSent;
+ ++eventsSent;
}
}
}
@@ -120,7 +120,7 @@ namespace NActors {
break;
}
- if (activeTick <= throttledMonotonic) {
+ if (activeTick <= throttledMonotonic) {
Y_VERIFY_DEBUG(!activeSec || activeSec->empty());
activeSec.Destroy();
activeTick += IntrasecondThreshold;
@@ -138,7 +138,7 @@ namespace NActors {
// second step - collect everything from queues
- ui64 eventsAdded = 0;
+ ui64 eventsAdded = 0;
for (ui32 i = 0; i != TotalReaders; ++i) {
while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) {
somethingDone = true;
@@ -165,57 +165,57 @@ namespace NActors {
queue.Reset(new NSchedulerQueue::TQueueType());
queue->Writer.Push(instant, ev, cookie);
}
-
- ++eventsAdded;
+
+ ++eventsAdded;
}
}
NHPTimer::STime hpnow = GetCycleCountFast();
-
- if (MonCounters) {
- *MonCounters->QueueSize -= eventsSent + eventsDropped;
- *MonCounters->QueueSize += eventsAdded;
- *MonCounters->EventsSent += eventsSent;
- *MonCounters->EventsDropped += eventsDropped;
- *MonCounters->EventsAdded += eventsAdded;
- *MonCounters->ElapsedMicrosec += NHPTimer::GetSeconds(hpnow - hpprev) * 1000000;
- }
-
- hpprev = hpnow;
- nextTimestamp = TInstant::Now().MicroSeconds();
- nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
-
+
+ if (MonCounters) {
+ *MonCounters->QueueSize -= eventsSent + eventsDropped;
+ *MonCounters->QueueSize += eventsAdded;
+ *MonCounters->EventsSent += eventsSent;
+ *MonCounters->EventsDropped += eventsDropped;
+ *MonCounters->EventsAdded += eventsAdded;
+ *MonCounters->ElapsedMicrosec += NHPTimer::GetSeconds(hpnow - hpprev) * 1000000;
+ }
+
+ hpprev = hpnow;
+ nextTimestamp = TInstant::Now().MicroSeconds();
+ nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+
// ok complete, if nothing left - sleep
if (!somethingDone) {
- const ui64 nextInstant = AlignDown<ui64>(throttledMonotonic + Config.ResolutionMicroseconds, Config.ResolutionMicroseconds);
- if (nextMonotonic >= nextInstant) // already in next time-slice
+ const ui64 nextInstant = AlignDown<ui64>(throttledMonotonic + Config.ResolutionMicroseconds, Config.ResolutionMicroseconds);
+ if (nextMonotonic >= nextInstant) // already in next time-slice
continue;
- const ui64 delta = nextInstant - nextMonotonic;
+ const ui64 delta = nextInstant - nextMonotonic;
if (delta < Config.SpinThreshold) // not so much time left, just spin
continue;
- if (MonCounters) {
- ++*MonCounters->Sleeps;
- }
-
+ if (MonCounters) {
+ ++*MonCounters->Sleeps;
+ }
+
NanoSleep(delta * 1000); // ok, looks like we should sleep a bit.
-
- // Don't count sleep in elapsed microseconds
+
+ // Don't count sleep in elapsed microseconds
hpprev = GetCycleCountFast();
- nextTimestamp = TInstant::Now().MicroSeconds();
- nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+ nextTimestamp = TInstant::Now().MicroSeconds();
+ nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
}
}
// ok, die!
}
- void TBasicSchedulerThread::Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) {
+ void TBasicSchedulerThread::Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) {
ActorSystem = actorSystem;
CurrentTimestamp = currentTimestamp;
- CurrentMonotonic = currentMonotonic;
- *CurrentTimestamp = TInstant::Now().MicroSeconds();
- *CurrentMonotonic = GetMonotonicMicroSeconds();
+ CurrentMonotonic = currentMonotonic;
+ *CurrentTimestamp = TInstant::Now().MicroSeconds();
+ *CurrentMonotonic = GetMonotonicMicroSeconds();
}
void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) {
@@ -225,16 +225,16 @@ namespace NActors {
Copy(readers, readers + scheduleReadersCount, Readers.Get());
}
- void TBasicSchedulerThread::PrepareStart() {
- // Called after actor system is initialized, but before executor threads
- // are started, giving us a chance to update current timestamp with a
- // more recent value, taking initialization time into account. This is
- // safe to do, since scheduler thread is not started yet, so no other
- // threads are updating time concurrently.
- AtomicStore(CurrentTimestamp, TInstant::Now().MicroSeconds());
- AtomicStore(CurrentMonotonic, Max(RelaxedLoad(CurrentMonotonic), GetMonotonicMicroSeconds()));
- }
-
+ void TBasicSchedulerThread::PrepareStart() {
+ // Called after actor system is initialized, but before executor threads
+ // are started, giving us a chance to update current timestamp with a
+ // more recent value, taking initialization time into account. This is
+ // safe to do, since scheduler thread is not started yet, so no other
+ // threads are updating time concurrently.
+ AtomicStore(CurrentTimestamp, TInstant::Now().MicroSeconds());
+ AtomicStore(CurrentMonotonic, Max(RelaxedLoad(CurrentMonotonic), GetMonotonicMicroSeconds()));
+ }
+
void TBasicSchedulerThread::Start() {
MainCycle.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TBasicSchedulerThread::CycleFunc, this)));
}
diff --git a/library/cpp/actors/core/scheduler_basic.h b/library/cpp/actors/core/scheduler_basic.h
index 2ccde39235..89ef8323f5 100644
--- a/library/cpp/actors/core/scheduler_basic.h
+++ b/library/cpp/actors/core/scheduler_basic.h
@@ -1,7 +1,7 @@
#pragma once
#include "actorsystem.h"
-#include "monotonic.h"
+#include "monotonic.h"
#include "scheduler_queue.h"
#include <library/cpp/actors/util/queue_chunk.h>
#include <library/cpp/threading/future/legacy_future.h>
@@ -9,17 +9,17 @@
#include <util/generic/map.h>
namespace NActors {
-
+
class TBasicSchedulerThread: public ISchedulerThread {
// TODO: replace with NUMA-local threads and per-thread schedules
const TSchedulerConfig Config;
- struct TMonCounters;
- const THolder<TMonCounters> MonCounters;
-
+ struct TMonCounters;
+ const THolder<TMonCounters> MonCounters;
+
TActorSystem* ActorSystem;
volatile ui64* CurrentTimestamp;
- volatile ui64* CurrentMonotonic;
+ volatile ui64* CurrentMonotonic;
ui32 TotalReaders;
TArrayHolder<NSchedulerQueue::TReader*> Readers;
@@ -44,7 +44,7 @@ namespace NActors {
void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override;
void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override;
- void PrepareStart() override;
+ void PrepareStart() override;
void Start() override;
void PrepareStop() override;
void Stop() override;
@@ -55,10 +55,10 @@ namespace NActors {
virtual ~TMockSchedulerThread() override {
}
- void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override {
+ void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override {
Y_UNUSED(actorSystem);
- *currentTimestamp = TInstant::Now().MicroSeconds();
- *currentMonotonic = GetMonotonicMicroSeconds();
+ *currentTimestamp = TInstant::Now().MicroSeconds();
+ *currentMonotonic = GetMonotonicMicroSeconds();
}
void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override {
diff --git a/library/cpp/actors/core/scheduler_queue.h b/library/cpp/actors/core/scheduler_queue.h
index 3b8fac28f0..51b597be1f 100644
--- a/library/cpp/actors/core/scheduler_queue.h
+++ b/library/cpp/actors/core/scheduler_queue.h
@@ -76,10 +76,10 @@ namespace NActors {
}
void Push(ui64 instantMicrosends, IEventHandle* ev, ISchedulerCookie* cookie) {
- if (Y_UNLIKELY(instantMicrosends == 0)) {
- // Protect against Pop() getting stuck forever
- instantMicrosends = 1;
- }
+ if (Y_UNLIKELY(instantMicrosends == 0)) {
+ // Protect against Pop() getting stuck forever
+ instantMicrosends = 1;
+ }
if (WritePosition != TChunk::EntriesCount) {
volatile TEntry& entry = WriteTo->Entries[WritePosition];
entry.Cookie = cookie;
diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make
index 880a9d00db..25fc0ce902 100644
--- a/library/cpp/actors/core/ya.make
+++ b/library/cpp/actors/core/ya.make
@@ -81,7 +81,7 @@ SRCS(
memory_tracker.h
mon.h
mon_stats.h
- monotonic.cpp
+ monotonic.cpp
monotonic.h
worker_context.cpp
worker_context.h
diff --git a/library/cpp/actors/dnsresolver/dnsresolver.cpp b/library/cpp/actors/dnsresolver/dnsresolver.cpp
index 6329bb0083..791360bd82 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver.cpp
@@ -1,475 +1,475 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/core/hfunc.h>
-#include <library/cpp/threading/queue/mpsc_htswap.h>
-#include <util/network/pair.h>
-#include <util/network/socket.h>
-#include <util/string/builder.h>
-#include <util/system/thread.h>
-
-#include <ares.h>
-
-#include <atomic>
-
-namespace NActors {
-namespace NDnsResolver {
-
- class TAresLibraryInitBase {
- protected:
- TAresLibraryInitBase() noexcept {
- int status = ares_library_init(ARES_LIB_INIT_ALL);
- Y_VERIFY(status == ARES_SUCCESS, "Unexpected failure to initialize c-ares library");
- }
-
- ~TAresLibraryInitBase() noexcept {
- ares_library_cleanup();
- }
- };
-
- class TCallbackQueueBase {
- protected:
- TCallbackQueueBase() noexcept {
- int err = SocketPair(Sockets, false, true);
- Y_VERIFY(err == 0, "Unexpected failure to create a socket pair");
- SetNonBlock(Sockets[0]);
- SetNonBlock(Sockets[1]);
- }
-
- ~TCallbackQueueBase() noexcept {
- closesocket(Sockets[0]);
- closesocket(Sockets[1]);
- }
-
- protected:
- using TCallback = std::function<void()>;
- using TCallbackQueue = NThreading::THTSwapQueue<TCallback>;
-
- void PushCallback(TCallback callback) {
- Y_VERIFY(callback, "Cannot push an empty callback");
- CallbackQueue.Push(std::move(callback)); // this is a lockfree queue
-
- // Wake up worker thread on the first activation
- if (Activations.fetch_add(1, std::memory_order_acq_rel) == 0) {
- char ch = 'x';
- ssize_t ret;
-#ifdef _win_
- ret = send(SignalSock(), &ch, 1, 0);
- if (ret == -1) {
- Y_VERIFY(WSAGetLastError() == WSAEWOULDBLOCK, "Unexpected send error");
- return;
- }
-#else
- do {
- ret = send(SignalSock(), &ch, 1, 0);
- } while (ret == -1 && errno == EINTR);
- if (ret == -1) {
- Y_VERIFY(errno == EAGAIN || errno == EWOULDBLOCK, "Unexpected send error");
- return;
- }
-#endif
- Y_VERIFY(ret == 1, "Unexpected send result");
- }
- }
-
- void RunCallbacks() noexcept {
- char ch[32];
- ssize_t ret;
- bool signalled = false;
- for (;;) {
- ret = recv(WaitSock(), ch, sizeof(ch), 0);
- if (ret > 0) {
- signalled = true;
- }
- if (ret == sizeof(ch)) {
- continue;
- }
- if (ret != -1) {
- break;
- }
-#ifdef _win_
- if (WSAGetLastError() == WSAEWOULDBLOCK) {
- break;
- }
- Y_FAIL("Unexpected recv error");
-#else
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- break;
- }
- Y_VERIFY(errno == EINTR, "Unexpected recv error");
-#endif
- }
-
- if (signalled) {
- // There's exactly one write to SignalSock while Activations != 0
- // It's impossible to get signalled while Activations == 0
- // We must set Activations = 0 to receive new signals
- size_t count = Activations.exchange(0, std::memory_order_acq_rel);
- Y_VERIFY(count != 0);
-
- // N.B. due to the way HTSwap works we may not be able to pop
- // all callbacks on this activation, however we expect a new
- // delayed activation to happen at a later time.
- while (auto callback = CallbackQueue.Pop()) {
- callback();
- }
- }
- }
-
- SOCKET SignalSock() {
- return Sockets[0];
- }
-
- SOCKET WaitSock() {
- return Sockets[1];
- }
-
- private:
- SOCKET Sockets[2];
- TCallbackQueue CallbackQueue;
- std::atomic<size_t> Activations{ 0 };
- };
-
- class TSimpleDnsResolver
- : public TActor<TSimpleDnsResolver>
- , private TAresLibraryInitBase
- , private TCallbackQueueBase
- {
- public:
- TSimpleDnsResolver(TSimpleDnsResolverOptions options) noexcept
- : TActor(&TThis::StateWork)
- , Options(std::move(options))
- , WorkerThread(&TThis::WorkerThreadStart, this)
- {
- InitAres();
-
- WorkerThread.Start();
- }
-
- ~TSimpleDnsResolver() noexcept override {
- if (!Stopped) {
- PushCallback([this] {
- // Mark as stopped first
- Stopped = true;
-
- // Cancel all current ares requests (will not send replies)
- ares_cancel(AresChannel);
- });
-
- WorkerThread.Join();
- }
-
- StopAres();
- }
-
- static constexpr EActivityType ActorActivityType() {
- return DNS_RESOLVER;
- }
-
- private:
- void InitAres() noexcept {
- struct ares_options options;
- memset(&options, 0, sizeof(options));
- int optmask = 0;
-
- options.flags = ARES_FLAG_STAYOPEN;
- optmask |= ARES_OPT_FLAGS;
-
- options.sock_state_cb = &TThis::SockStateCallback;
- options.sock_state_cb_data = this;
- optmask |= ARES_OPT_SOCK_STATE_CB;
-
- options.timeout = Options.Timeout.MilliSeconds();
- if (options.timeout > 0) {
- optmask |= ARES_OPT_TIMEOUTMS;
- }
-
- options.tries = Options.Attempts;
- if (options.tries > 0) {
- optmask |= ARES_OPT_TRIES;
- }
-
- int err = ares_init_options(&AresChannel, &options, optmask);
- Y_VERIFY(err == 0, "Unexpected failure to initialize c-ares channel");
-
- if (Options.Servers) {
- TStringBuilder csv;
- for (const TString& server : Options.Servers) {
- if (csv) {
- csv << ',';
- }
- csv << server;
- }
- err = ares_set_servers_ports_csv(AresChannel, csv.c_str());
- Y_VERIFY(err == 0, "Unexpected failure to set a list of dns servers: %s", ares_strerror(err));
- }
- }
-
- void StopAres() noexcept {
- // Destroy the ares channel
- ares_destroy(AresChannel);
- AresChannel = nullptr;
- }
-
- private:
- STRICT_STFUNC(StateWork, {
- hFunc(TEvents::TEvPoison, Handle);
- hFunc(TEvDns::TEvGetHostByName, Handle);
- hFunc(TEvDns::TEvGetAddr, Handle);
- })
-
- void Handle(TEvents::TEvPoison::TPtr&) {
- Y_VERIFY(!Stopped);
-
- PushCallback([this] {
- // Cancel all current ares requests (will send notifications)
- ares_cancel(AresChannel);
-
- // Mark as stopped last
- Stopped = true;
- });
-
- WorkerThread.Join();
- PassAway();
- }
-
- private:
- enum class ERequestType {
- GetHostByName,
- GetAddr,
- };
-
- struct TRequestContext : public TThrRefBase {
- using TPtr = TIntrusivePtr<TRequestContext>;
-
- TThis* Self;
- TActorSystem* ActorSystem;
- TActorId SelfId;
- TActorId Sender;
- ui64 Cookie;
- ERequestType Type;
-
- TRequestContext(TThis* self, TActorSystem* as, TActorId selfId, TActorId sender, ui64 cookie, ERequestType type)
- : Self(self)
- , ActorSystem(as)
- , SelfId(selfId)
- , Sender(sender)
- , Cookie(cookie)
- , Type(type)
- { }
- };
-
- private:
- void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
- auto* msg = ev->Get();
- auto reqCtx = MakeIntrusive<TRequestContext>(
- this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetHostByName);
- PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
- StartGetHostByName(std::move(reqCtx), std::move(name), family);
- });
- }
-
- void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
- auto* msg = ev->Get();
- auto reqCtx = MakeIntrusive<TRequestContext>(
- this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetAddr);
- PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
- StartGetHostByName(std::move(reqCtx), std::move(name), family);
- });
- }
-
- void StartGetHostByName(TRequestContext::TPtr reqCtx, TString name, int family) noexcept {
- reqCtx->Ref();
- ares_gethostbyname(AresChannel, name.c_str(), family,
- &TThis::GetHostByNameAresCallback, reqCtx.Get());
- }
-
- private:
- static void GetHostByNameAresCallback(void* arg, int status, int timeouts, struct hostent* info) {
- Y_UNUSED(timeouts);
- TRequestContext::TPtr reqCtx(static_cast<TRequestContext*>(arg));
- reqCtx->UnRef();
-
- if (reqCtx->Self->Stopped) {
- // Don't send any replies after destruction
- return;
- }
-
- switch (reqCtx->Type) {
- case ERequestType::GetHostByName: {
- auto result = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- if (status == 0) {
- switch (info->h_addrtype) {
- case AF_INET: {
- for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
- result->AddrsV4.emplace_back(*(struct in_addr*)(info->h_addr_list[i]));
- }
- break;
- }
- case AF_INET6: {
- for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
- result->AddrsV6.emplace_back(*(struct in6_addr*)(info->h_addr_list[i]));
- }
- break;
- }
- default:
- Y_FAIL("unknown address family in ares callback");
- }
- } else {
- result->ErrorText = ares_strerror(status);
- }
- result->Status = status;
-
- reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
- break;
- }
-
- case ERequestType::GetAddr: {
- auto result = MakeHolder<TEvDns::TEvGetAddrResult>();
- if (status == 0 && Y_UNLIKELY(info->h_addr_list[0] == nullptr)) {
- status = ARES_ENODATA;
- }
- if (status == 0) {
- switch (info->h_addrtype) {
- case AF_INET: {
- result->Addr = *(struct in_addr*)(info->h_addr_list[0]);
- break;
- }
- case AF_INET6: {
- result->Addr = *(struct in6_addr*)(info->h_addr_list[0]);
- break;
- }
- default:
- Y_FAIL("unknown address family in ares callback");
- }
- } else {
- result->ErrorText = ares_strerror(status);
- }
- result->Status = status;
-
- reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
- break;
- }
- }
- }
-
- private:
- static void SockStateCallback(void* data, ares_socket_t socket_fd, int readable, int writable) {
- static_cast<TThis*>(data)->DoSockStateCallback(socket_fd, readable, writable);
- }
-
- void DoSockStateCallback(ares_socket_t socket_fd, int readable, int writable) noexcept {
- int events = (readable ? (POLLRDNORM | POLLIN) : 0) | (writable ? (POLLWRNORM | POLLOUT) : 0);
- if (events == 0) {
- AresSockStates.erase(socket_fd);
- } else {
- AresSockStates[socket_fd].NeededEvents = events;
- }
- }
-
- private:
- static void* WorkerThreadStart(void* arg) noexcept {
- static_cast<TSimpleDnsResolver*>(arg)->WorkerThreadLoop();
- return nullptr;
- }
-
- void WorkerThreadLoop() noexcept {
- TThread::SetCurrentThreadName("DnsResolver");
-
- TVector<struct pollfd> fds;
- while (!Stopped) {
- fds.clear();
- fds.reserve(1 + AresSockStates.size());
- {
- auto& entry = fds.emplace_back();
- entry.fd = WaitSock();
- entry.events = POLLRDNORM | POLLIN;
- }
- for (auto& kv : AresSockStates) {
- auto& entry = fds.emplace_back();
- entry.fd = kv.first;
- entry.events = kv.second.NeededEvents;
- }
-
- int timeout = -1;
- struct timeval tv;
- if (ares_timeout(AresChannel, nullptr, &tv)) {
- timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
- }
-
- int ret = poll(fds.data(), fds.size(), timeout);
- if (ret == -1) {
- if (errno == EINTR) {
- continue;
- }
- // we cannot handle failures, run callbacks and pretend everything is ok
- RunCallbacks();
- if (Stopped) {
- break;
- }
- ret = 0;
- }
-
- bool ares_called = false;
- if (ret > 0) {
- for (size_t i = 0; i < fds.size(); ++i) {
- auto& entry = fds[i];
-
- // Handle WaitSock activation and run callbacks
- if (i == 0) {
- if (entry.revents & (POLLRDNORM | POLLIN)) {
- RunCallbacks();
- if (Stopped) {
- break;
- }
- }
- continue;
- }
-
- // All other sockets belong to ares
- if (entry.revents == 0) {
- continue;
- }
- // Previous invocation of aress_process_fd might have removed some sockets
- if (Y_UNLIKELY(!AresSockStates.contains(entry.fd))) {
- continue;
- }
- ares_process_fd(
- AresChannel,
- entry.revents & (POLLRDNORM | POLLIN) ? entry.fd : ARES_SOCKET_BAD,
- entry.revents & (POLLWRNORM | POLLOUT) ? entry.fd : ARES_SOCKET_BAD);
- ares_called = true;
- }
-
- if (Stopped) {
- break;
- }
- }
-
- if (!ares_called) {
- // Let ares handle timeouts
- ares_process_fd(AresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
- }
- }
- }
-
- private:
- struct TSockState {
- short NeededEvents = 0; // poll events
- };
-
- private:
- TSimpleDnsResolverOptions Options;
- TThread WorkerThread;
-
- ares_channel AresChannel;
- THashMap<SOCKET, TSockState> AresSockStates;
-
- bool Stopped = false;
- };
-
- IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) {
- return new TSimpleDnsResolver(std::move(options));
- }
-
-} // namespace NDnsResolver
-} // namespace NActors
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/threading/queue/mpsc_htswap.h>
+#include <util/network/pair.h>
+#include <util/network/socket.h>
+#include <util/string/builder.h>
+#include <util/system/thread.h>
+
+#include <ares.h>
+
+#include <atomic>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TAresLibraryInitBase {
+ protected:
+ TAresLibraryInitBase() noexcept {
+ int status = ares_library_init(ARES_LIB_INIT_ALL);
+ Y_VERIFY(status == ARES_SUCCESS, "Unexpected failure to initialize c-ares library");
+ }
+
+ ~TAresLibraryInitBase() noexcept {
+ ares_library_cleanup();
+ }
+ };
+
+ class TCallbackQueueBase {
+ protected:
+ TCallbackQueueBase() noexcept {
+ int err = SocketPair(Sockets, false, true);
+ Y_VERIFY(err == 0, "Unexpected failure to create a socket pair");
+ SetNonBlock(Sockets[0]);
+ SetNonBlock(Sockets[1]);
+ }
+
+ ~TCallbackQueueBase() noexcept {
+ closesocket(Sockets[0]);
+ closesocket(Sockets[1]);
+ }
+
+ protected:
+ using TCallback = std::function<void()>;
+ using TCallbackQueue = NThreading::THTSwapQueue<TCallback>;
+
+ void PushCallback(TCallback callback) {
+ Y_VERIFY(callback, "Cannot push an empty callback");
+ CallbackQueue.Push(std::move(callback)); // this is a lockfree queue
+
+ // Wake up worker thread on the first activation
+ if (Activations.fetch_add(1, std::memory_order_acq_rel) == 0) {
+ char ch = 'x';
+ ssize_t ret;
+#ifdef _win_
+ ret = send(SignalSock(), &ch, 1, 0);
+ if (ret == -1) {
+ Y_VERIFY(WSAGetLastError() == WSAEWOULDBLOCK, "Unexpected send error");
+ return;
+ }
+#else
+ do {
+ ret = send(SignalSock(), &ch, 1, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ Y_VERIFY(errno == EAGAIN || errno == EWOULDBLOCK, "Unexpected send error");
+ return;
+ }
+#endif
+ Y_VERIFY(ret == 1, "Unexpected send result");
+ }
+ }
+
+ void RunCallbacks() noexcept {
+ char ch[32];
+ ssize_t ret;
+ bool signalled = false;
+ for (;;) {
+ ret = recv(WaitSock(), ch, sizeof(ch), 0);
+ if (ret > 0) {
+ signalled = true;
+ }
+ if (ret == sizeof(ch)) {
+ continue;
+ }
+ if (ret != -1) {
+ break;
+ }
+#ifdef _win_
+ if (WSAGetLastError() == WSAEWOULDBLOCK) {
+ break;
+ }
+ Y_FAIL("Unexpected recv error");
+#else
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ break;
+ }
+ Y_VERIFY(errno == EINTR, "Unexpected recv error");
+#endif
+ }
+
+ if (signalled) {
+ // There's exactly one write to SignalSock while Activations != 0
+ // It's impossible to get signalled while Activations == 0
+ // We must set Activations = 0 to receive new signals
+ size_t count = Activations.exchange(0, std::memory_order_acq_rel);
+ Y_VERIFY(count != 0);
+
+ // N.B. due to the way HTSwap works we may not be able to pop
+ // all callbacks on this activation, however we expect a new
+ // delayed activation to happen at a later time.
+ while (auto callback = CallbackQueue.Pop()) {
+ callback();
+ }
+ }
+ }
+
+ SOCKET SignalSock() {
+ return Sockets[0];
+ }
+
+ SOCKET WaitSock() {
+ return Sockets[1];
+ }
+
+ private:
+ SOCKET Sockets[2];
+ TCallbackQueue CallbackQueue;
+ std::atomic<size_t> Activations{ 0 };
+ };
+
+ class TSimpleDnsResolver
+ : public TActor<TSimpleDnsResolver>
+ , private TAresLibraryInitBase
+ , private TCallbackQueueBase
+ {
+ public:
+ TSimpleDnsResolver(TSimpleDnsResolverOptions options) noexcept
+ : TActor(&TThis::StateWork)
+ , Options(std::move(options))
+ , WorkerThread(&TThis::WorkerThreadStart, this)
+ {
+ InitAres();
+
+ WorkerThread.Start();
+ }
+
+ ~TSimpleDnsResolver() noexcept override {
+ if (!Stopped) {
+ PushCallback([this] {
+ // Mark as stopped first
+ Stopped = true;
+
+ // Cancel all current ares requests (will not send replies)
+ ares_cancel(AresChannel);
+ });
+
+ WorkerThread.Join();
+ }
+
+ StopAres();
+ }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ void InitAres() noexcept {
+ struct ares_options options;
+ memset(&options, 0, sizeof(options));
+ int optmask = 0;
+
+ options.flags = ARES_FLAG_STAYOPEN;
+ optmask |= ARES_OPT_FLAGS;
+
+ options.sock_state_cb = &TThis::SockStateCallback;
+ options.sock_state_cb_data = this;
+ optmask |= ARES_OPT_SOCK_STATE_CB;
+
+ options.timeout = Options.Timeout.MilliSeconds();
+ if (options.timeout > 0) {
+ optmask |= ARES_OPT_TIMEOUTMS;
+ }
+
+ options.tries = Options.Attempts;
+ if (options.tries > 0) {
+ optmask |= ARES_OPT_TRIES;
+ }
+
+ int err = ares_init_options(&AresChannel, &options, optmask);
+ Y_VERIFY(err == 0, "Unexpected failure to initialize c-ares channel");
+
+ if (Options.Servers) {
+ TStringBuilder csv;
+ for (const TString& server : Options.Servers) {
+ if (csv) {
+ csv << ',';
+ }
+ csv << server;
+ }
+ err = ares_set_servers_ports_csv(AresChannel, csv.c_str());
+ Y_VERIFY(err == 0, "Unexpected failure to set a list of dns servers: %s", ares_strerror(err));
+ }
+ }
+
+ void StopAres() noexcept {
+ // Destroy the ares channel
+ ares_destroy(AresChannel);
+ AresChannel = nullptr;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvDns::TEvGetAddr, Handle);
+ })
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ Y_VERIFY(!Stopped);
+
+ PushCallback([this] {
+ // Cancel all current ares requests (will send notifications)
+ ares_cancel(AresChannel);
+
+ // Mark as stopped last
+ Stopped = true;
+ });
+
+ WorkerThread.Join();
+ PassAway();
+ }
+
+ private:
+ enum class ERequestType {
+ GetHostByName,
+ GetAddr,
+ };
+
+ struct TRequestContext : public TThrRefBase {
+ using TPtr = TIntrusivePtr<TRequestContext>;
+
+ TThis* Self;
+ TActorSystem* ActorSystem;
+ TActorId SelfId;
+ TActorId Sender;
+ ui64 Cookie;
+ ERequestType Type;
+
+ TRequestContext(TThis* self, TActorSystem* as, TActorId selfId, TActorId sender, ui64 cookie, ERequestType type)
+ : Self(self)
+ , ActorSystem(as)
+ , SelfId(selfId)
+ , Sender(sender)
+ , Cookie(cookie)
+ , Type(type)
+ { }
+ };
+
+ private:
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto* msg = ev->Get();
+ auto reqCtx = MakeIntrusive<TRequestContext>(
+ this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetHostByName);
+ PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
+ StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ });
+ }
+
+ void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
+ auto* msg = ev->Get();
+ auto reqCtx = MakeIntrusive<TRequestContext>(
+ this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetAddr);
+ PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
+ StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ });
+ }
+
+ void StartGetHostByName(TRequestContext::TPtr reqCtx, TString name, int family) noexcept {
+ reqCtx->Ref();
+ ares_gethostbyname(AresChannel, name.c_str(), family,
+ &TThis::GetHostByNameAresCallback, reqCtx.Get());
+ }
+
+ private:
+ static void GetHostByNameAresCallback(void* arg, int status, int timeouts, struct hostent* info) {
+ Y_UNUSED(timeouts);
+ TRequestContext::TPtr reqCtx(static_cast<TRequestContext*>(arg));
+ reqCtx->UnRef();
+
+ if (reqCtx->Self->Stopped) {
+ // Don't send any replies after destruction
+ return;
+ }
+
+ switch (reqCtx->Type) {
+ case ERequestType::GetHostByName: {
+ auto result = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ if (status == 0) {
+ switch (info->h_addrtype) {
+ case AF_INET: {
+ for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
+ result->AddrsV4.emplace_back(*(struct in_addr*)(info->h_addr_list[i]));
+ }
+ break;
+ }
+ case AF_INET6: {
+ for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
+ result->AddrsV6.emplace_back(*(struct in6_addr*)(info->h_addr_list[i]));
+ }
+ break;
+ }
+ default:
+ Y_FAIL("unknown address family in ares callback");
+ }
+ } else {
+ result->ErrorText = ares_strerror(status);
+ }
+ result->Status = status;
+
+ reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
+ break;
+ }
+
+ case ERequestType::GetAddr: {
+ auto result = MakeHolder<TEvDns::TEvGetAddrResult>();
+ if (status == 0 && Y_UNLIKELY(info->h_addr_list[0] == nullptr)) {
+ status = ARES_ENODATA;
+ }
+ if (status == 0) {
+ switch (info->h_addrtype) {
+ case AF_INET: {
+ result->Addr = *(struct in_addr*)(info->h_addr_list[0]);
+ break;
+ }
+ case AF_INET6: {
+ result->Addr = *(struct in6_addr*)(info->h_addr_list[0]);
+ break;
+ }
+ default:
+ Y_FAIL("unknown address family in ares callback");
+ }
+ } else {
+ result->ErrorText = ares_strerror(status);
+ }
+ result->Status = status;
+
+ reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
+ break;
+ }
+ }
+ }
+
+ private:
+ static void SockStateCallback(void* data, ares_socket_t socket_fd, int readable, int writable) {
+ static_cast<TThis*>(data)->DoSockStateCallback(socket_fd, readable, writable);
+ }
+
+ void DoSockStateCallback(ares_socket_t socket_fd, int readable, int writable) noexcept {
+ int events = (readable ? (POLLRDNORM | POLLIN) : 0) | (writable ? (POLLWRNORM | POLLOUT) : 0);
+ if (events == 0) {
+ AresSockStates.erase(socket_fd);
+ } else {
+ AresSockStates[socket_fd].NeededEvents = events;
+ }
+ }
+
+ private:
+ static void* WorkerThreadStart(void* arg) noexcept {
+ static_cast<TSimpleDnsResolver*>(arg)->WorkerThreadLoop();
+ return nullptr;
+ }
+
+ void WorkerThreadLoop() noexcept {
+ TThread::SetCurrentThreadName("DnsResolver");
+
+ TVector<struct pollfd> fds;
+ while (!Stopped) {
+ fds.clear();
+ fds.reserve(1 + AresSockStates.size());
+ {
+ auto& entry = fds.emplace_back();
+ entry.fd = WaitSock();
+ entry.events = POLLRDNORM | POLLIN;
+ }
+ for (auto& kv : AresSockStates) {
+ auto& entry = fds.emplace_back();
+ entry.fd = kv.first;
+ entry.events = kv.second.NeededEvents;
+ }
+
+ int timeout = -1;
+ struct timeval tv;
+ if (ares_timeout(AresChannel, nullptr, &tv)) {
+ timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ }
+
+ int ret = poll(fds.data(), fds.size(), timeout);
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ // we cannot handle failures, run callbacks and pretend everything is ok
+ RunCallbacks();
+ if (Stopped) {
+ break;
+ }
+ ret = 0;
+ }
+
+ bool ares_called = false;
+ if (ret > 0) {
+ for (size_t i = 0; i < fds.size(); ++i) {
+ auto& entry = fds[i];
+
+ // Handle WaitSock activation and run callbacks
+ if (i == 0) {
+ if (entry.revents & (POLLRDNORM | POLLIN)) {
+ RunCallbacks();
+ if (Stopped) {
+ break;
+ }
+ }
+ continue;
+ }
+
+ // All other sockets belong to ares
+ if (entry.revents == 0) {
+ continue;
+ }
+ // Previous invocation of aress_process_fd might have removed some sockets
+ if (Y_UNLIKELY(!AresSockStates.contains(entry.fd))) {
+ continue;
+ }
+ ares_process_fd(
+ AresChannel,
+ entry.revents & (POLLRDNORM | POLLIN) ? entry.fd : ARES_SOCKET_BAD,
+ entry.revents & (POLLWRNORM | POLLOUT) ? entry.fd : ARES_SOCKET_BAD);
+ ares_called = true;
+ }
+
+ if (Stopped) {
+ break;
+ }
+ }
+
+ if (!ares_called) {
+ // Let ares handle timeouts
+ ares_process_fd(AresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ }
+ }
+ }
+
+ private:
+ struct TSockState {
+ short NeededEvents = 0; // poll events
+ };
+
+ private:
+ TSimpleDnsResolverOptions Options;
+ TThread WorkerThread;
+
+ ares_channel AresChannel;
+ THashMap<SOCKET, TSockState> AresSockStates;
+
+ bool Stopped = false;
+ };
+
+ IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) {
+ return new TSimpleDnsResolver(std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver.h b/library/cpp/actors/dnsresolver/dnsresolver.h
index 88fc74df7d..6aa28641fc 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver.h
+++ b/library/cpp/actors/dnsresolver/dnsresolver.h
@@ -1,128 +1,128 @@
-#pragma once
-
-#include <library/cpp/actors/core/actor.h>
-#include <library/cpp/actors/core/events.h>
-#include <library/cpp/actors/core/event_local.h>
-#include <library/cpp/monlib/dynamic_counters/counters.h>
-#include <util/network/address.h>
-#include <variant>
-
-namespace NActors {
-namespace NDnsResolver {
-
- struct TEvDns {
- enum EEv {
- EvGetHostByName = EventSpaceBegin(TEvents::ES_DNS),
- EvGetHostByNameResult,
- EvGetAddr,
- EvGetAddrResult,
- };
-
- /**
- * TEvGetHostByName returns the result of ares_gethostbyname
- */
- struct TEvGetHostByName : public TEventLocal<TEvGetHostByName, EvGetHostByName> {
- TString Name;
- int Family;
-
- explicit TEvGetHostByName(TString name, int family = AF_UNSPEC)
- : Name(std::move(name))
- , Family(family)
- { }
- };
-
- struct TEvGetHostByNameResult : public TEventLocal<TEvGetHostByNameResult, EvGetHostByNameResult> {
- TVector<struct in_addr> AddrsV4;
- TVector<struct in6_addr> AddrsV6;
- TString ErrorText;
- int Status = 0;
- };
-
- /**
- * TEvGetAddr returns a single address for a given hostname
- */
- struct TEvGetAddr : public TEventLocal<TEvGetAddr, EvGetAddr> {
- TString Name;
- int Family;
-
- explicit TEvGetAddr(TString name, int family = AF_UNSPEC)
- : Name(std::move(name))
- , Family(family)
- { }
- };
-
- struct TEvGetAddrResult : public TEventLocal<TEvGetAddrResult, EvGetAddrResult> {
- // N.B. "using" here doesn't work with Visual Studio compiler
- typedef struct in6_addr TIPv6Addr;
- typedef struct in_addr TIPv4Addr;
-
- std::variant<std::monostate, TIPv6Addr, TIPv4Addr> Addr;
- TString ErrorText;
- int Status = 0;
-
- bool IsV6() const {
- return std::holds_alternative<TIPv6Addr>(Addr);
- }
-
- bool IsV4() const {
- return std::holds_alternative<TIPv4Addr>(Addr);
- }
-
- const TIPv6Addr& GetAddrV6() const {
- const TIPv6Addr* p = std::get_if<TIPv6Addr>(&Addr);
- Y_VERIFY(p, "Result is not an ipv6 address");
- return *p;
- }
-
- const TIPv4Addr& GetAddrV4() const {
- const TIPv4Addr* p = std::get_if<TIPv4Addr>(&Addr);
- Y_VERIFY(p, "Result is not an ipv4 address");
- return *p;
- }
- };
- };
-
- struct TSimpleDnsResolverOptions {
- // Initial per-server timeout, grows exponentially with each retry
- TDuration Timeout = TDuration::Seconds(1);
- // Number of attempts per-server
- int Attempts = 2;
- // Optional list of custom dns servers (ip.v4[:port], ip::v6 or [ip::v6]:port format)
- TVector<TString> Servers;
- };
-
- IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options = TSimpleDnsResolverOptions());
-
- struct TCachingDnsResolverOptions {
- // Soft expire time specifies delay before name is refreshed in background
- TDuration SoftNegativeExpireTime = TDuration::Seconds(1);
- TDuration SoftPositiveExpireTime = TDuration::Seconds(10);
- // Hard expire time specifies delay before the last result is forgotten
- TDuration HardNegativeExpireTime = TDuration::Seconds(10);
- TDuration HardPositiveExpireTime = TDuration::Hours(2);
- // Allow these request families
- bool AllowIPv6 = true;
- bool AllowIPv4 = true;
- // Optional counters
- NMonitoring::TDynamicCounterPtr MonCounters = nullptr;
- };
-
- IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options = TCachingDnsResolverOptions());
-
- struct TOnDemandDnsResolverOptions
- : public TSimpleDnsResolverOptions
- , public TCachingDnsResolverOptions
- {
- };
-
- IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options = TOnDemandDnsResolverOptions());
-
- /**
- * Returns actor id of a globally registered dns resolver
- */
- inline TActorId MakeDnsResolverActorId() {
- return TActorId(0, TStringBuf("dnsresolver"));
- }
-
-} // namespace NDnsResolver
-} // namespace NActors
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/event_local.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <util/network/address.h>
+#include <variant>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ struct TEvDns {
+ enum EEv {
+ EvGetHostByName = EventSpaceBegin(TEvents::ES_DNS),
+ EvGetHostByNameResult,
+ EvGetAddr,
+ EvGetAddrResult,
+ };
+
+ /**
+ * TEvGetHostByName returns the result of ares_gethostbyname
+ */
+ struct TEvGetHostByName : public TEventLocal<TEvGetHostByName, EvGetHostByName> {
+ TString Name;
+ int Family;
+
+ explicit TEvGetHostByName(TString name, int family = AF_UNSPEC)
+ : Name(std::move(name))
+ , Family(family)
+ { }
+ };
+
+ struct TEvGetHostByNameResult : public TEventLocal<TEvGetHostByNameResult, EvGetHostByNameResult> {
+ TVector<struct in_addr> AddrsV4;
+ TVector<struct in6_addr> AddrsV6;
+ TString ErrorText;
+ int Status = 0;
+ };
+
+ /**
+ * TEvGetAddr returns a single address for a given hostname
+ */
+ struct TEvGetAddr : public TEventLocal<TEvGetAddr, EvGetAddr> {
+ TString Name;
+ int Family;
+
+ explicit TEvGetAddr(TString name, int family = AF_UNSPEC)
+ : Name(std::move(name))
+ , Family(family)
+ { }
+ };
+
+ struct TEvGetAddrResult : public TEventLocal<TEvGetAddrResult, EvGetAddrResult> {
+ // N.B. "using" here doesn't work with Visual Studio compiler
+ typedef struct in6_addr TIPv6Addr;
+ typedef struct in_addr TIPv4Addr;
+
+ std::variant<std::monostate, TIPv6Addr, TIPv4Addr> Addr;
+ TString ErrorText;
+ int Status = 0;
+
+ bool IsV6() const {
+ return std::holds_alternative<TIPv6Addr>(Addr);
+ }
+
+ bool IsV4() const {
+ return std::holds_alternative<TIPv4Addr>(Addr);
+ }
+
+ const TIPv6Addr& GetAddrV6() const {
+ const TIPv6Addr* p = std::get_if<TIPv6Addr>(&Addr);
+ Y_VERIFY(p, "Result is not an ipv6 address");
+ return *p;
+ }
+
+ const TIPv4Addr& GetAddrV4() const {
+ const TIPv4Addr* p = std::get_if<TIPv4Addr>(&Addr);
+ Y_VERIFY(p, "Result is not an ipv4 address");
+ return *p;
+ }
+ };
+ };
+
+ struct TSimpleDnsResolverOptions {
+ // Initial per-server timeout, grows exponentially with each retry
+ TDuration Timeout = TDuration::Seconds(1);
+ // Number of attempts per-server
+ int Attempts = 2;
+ // Optional list of custom dns servers (ip.v4[:port], ip::v6 or [ip::v6]:port format)
+ TVector<TString> Servers;
+ };
+
+ IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options = TSimpleDnsResolverOptions());
+
+ struct TCachingDnsResolverOptions {
+ // Soft expire time specifies delay before name is refreshed in background
+ TDuration SoftNegativeExpireTime = TDuration::Seconds(1);
+ TDuration SoftPositiveExpireTime = TDuration::Seconds(10);
+ // Hard expire time specifies delay before the last result is forgotten
+ TDuration HardNegativeExpireTime = TDuration::Seconds(10);
+ TDuration HardPositiveExpireTime = TDuration::Hours(2);
+ // Allow these request families
+ bool AllowIPv6 = true;
+ bool AllowIPv4 = true;
+ // Optional counters
+ NMonitoring::TDynamicCounterPtr MonCounters = nullptr;
+ };
+
+ IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options = TCachingDnsResolverOptions());
+
+ struct TOnDemandDnsResolverOptions
+ : public TSimpleDnsResolverOptions
+ , public TCachingDnsResolverOptions
+ {
+ };
+
+ IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options = TOnDemandDnsResolverOptions());
+
+ /**
+ * Returns actor id of a globally registered dns resolver
+ */
+ inline TActorId MakeDnsResolverActorId() {
+ return TActorId(0, TStringBuf("dnsresolver"));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
index 02760f4c27..a1688854c4 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
@@ -1,730 +1,730 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/core/hfunc.h>
-#include <util/generic/intrlist.h>
-
-#include <ares.h>
-
-#include <queue>
-
-namespace NActors {
-namespace NDnsResolver {
-
- class TCachingDnsResolver : public TActor<TCachingDnsResolver> {
- public:
- struct TMonCounters {
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV4;
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV6;
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV4;
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV6;
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV4;
- NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV6;
-
- NMonitoring::TDynamicCounters::TCounterPtr IncomingInFlight;
- NMonitoring::TDynamicCounters::TCounterPtr IncomingErrors;
- NMonitoring::TDynamicCounters::TCounterPtr IncomingTotal;
-
- NMonitoring::TDynamicCounters::TCounterPtr CacheSize;
- NMonitoring::TDynamicCounters::TCounterPtr CacheHits;
- NMonitoring::TDynamicCounters::TCounterPtr CacheMisses;
-
- TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
- : OutgoingInFlightV4(counters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false))
- , OutgoingInFlightV6(counters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false))
- , OutgoingErrorsV4(counters->GetCounter("DnsResolver/Outgoing/Errors/V4", true))
- , OutgoingErrorsV6(counters->GetCounter("DnsResolver/Outgoing/Errors/V6", true))
- , OutgoingTotalV4(counters->GetCounter("DnsResolver/Outgoing/Total/V4", true))
- , OutgoingTotalV6(counters->GetCounter("DnsResolver/Outgoing/Total/V6", true))
- , IncomingInFlight(counters->GetCounter("DnsResolver/Incoming/InFlight", false))
- , IncomingErrors(counters->GetCounter("DnsResolver/Incoming/Errors", true))
- , IncomingTotal(counters->GetCounter("DnsResolver/Incoming/Total", true))
- , CacheSize(counters->GetCounter("DnsResolver/Cache/Size", false))
- , CacheHits(counters->GetCounter("DnsResolver/Cache/Hits", true))
- , CacheMisses(counters->GetCounter("DnsResolver/Cache/Misses", true))
- { }
- };
-
- public:
- TCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options)
- : TActor(&TThis::StateWork)
- , Upstream(upstream)
- , Options(std::move(options))
- , MonCounters(Options.MonCounters ? new TMonCounters(Options.MonCounters) : nullptr)
- { }
-
- static constexpr EActivityType ActorActivityType() {
- return DNS_RESOLVER;
- }
-
- private:
- STRICT_STFUNC(StateWork, {
- hFunc(TEvents::TEvPoison, Handle);
- hFunc(TEvDns::TEvGetHostByName, Handle);
- hFunc(TEvDns::TEvGetAddr, Handle);
- hFunc(TEvDns::TEvGetHostByNameResult, Handle);
- hFunc(TEvents::TEvUndelivered, Handle);
- });
-
- void Handle(TEvents::TEvPoison::TPtr&) {
- DropPending(ARES_ECANCELLED);
- PassAway();
- }
-
- void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
- auto req = MakeHolder<TIncomingRequest>();
- req->Type = EIncomingRequestType::GetHostByName;
- req->Sender = ev->Sender;
- req->Cookie = ev->Cookie;
- req->Name = std::move(ev->Get()->Name);
- req->Family = ev->Get()->Family;
- EnqueueRequest(std::move(req));
- }
-
- void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
- auto req = MakeHolder<TIncomingRequest>();
- req->Type = EIncomingRequestType::GetAddr;
- req->Sender = ev->Sender;
- req->Cookie = ev->Cookie;
- req->Name = std::move(ev->Get()->Name);
- req->Family = ev->Get()->Family;
- EnqueueRequest(std::move(req));
- }
-
- void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) {
- auto waitingIt = WaitingRequests.find(ev->Cookie);
- Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected reply, reqId=%" PRIu64, ev->Cookie);
- auto waitingInfo = waitingIt->second;
- WaitingRequests.erase(waitingIt);
-
- switch (waitingInfo.Family) {
- case AF_INET6:
- if (ev->Get()->Status) {
- ProcessErrorV6(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
- } else {
- ProcessAddrsV6(waitingInfo.Position, std::move(ev->Get()->AddrsV6));
- }
- break;
-
- case AF_INET:
- if (ev->Get()->Status) {
- ProcessErrorV4(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
- } else {
- ProcessAddrsV4(waitingInfo.Position, std::move(ev->Get()->AddrsV4));
- }
- break;
-
- default:
- Y_FAIL("Unexpected request family %d", waitingInfo.Family);
- }
- }
-
- void Handle(TEvents::TEvUndelivered::TPtr& ev) {
- switch (ev->Get()->SourceType) {
- case TEvDns::TEvGetHostByName::EventType: {
- auto waitingIt = WaitingRequests.find(ev->Cookie);
- Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected TEvUndelivered, reqId=%" PRIu64, ev->Cookie);
- auto waitingInfo = waitingIt->second;
- WaitingRequests.erase(waitingIt);
-
- switch (waitingInfo.Family) {
- case AF_INET6:
- ProcessErrorV6(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
- break;
- case AF_INET:
- ProcessErrorV4(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
- break;
- default:
- Y_FAIL("Unexpected request family %d", waitingInfo.Family);
- }
-
- break;
- }
-
- default:
- Y_FAIL("Unexpected TEvUndelievered, type=%" PRIu32, ev->Get()->SourceType);
- }
- }
-
- private:
- enum EIncomingRequestType {
- GetHostByName,
- GetAddr,
- };
-
- struct TIncomingRequest : public TIntrusiveListItem<TIncomingRequest> {
- EIncomingRequestType Type;
- TActorId Sender;
- ui64 Cookie;
- TString Name;
- int Family;
- };
-
- using TIncomingRequestList = TIntrusiveListWithAutoDelete<TIncomingRequest, TDelete>;
-
- void EnqueueRequest(THolder<TIncomingRequest> req) {
- if (MonCounters) {
- ++*MonCounters->IncomingTotal;
- }
-
- CleanupExpired(TActivationContext::Now());
-
- switch (req->Family) {
- case AF_UNSPEC:
- if (Options.AllowIPv6) {
- EnqueueRequestIPv6(std::move(req));
- return;
- }
- if (Options.AllowIPv4) {
- EnqueueRequestIPv4(std::move(req));
- return;
- }
- break;
-
- case AF_INET6:
- if (Options.AllowIPv6) {
- EnqueueRequestIPv6(std::move(req));
- return;
- }
- break;
-
- case AF_INET:
- if (Options.AllowIPv4) {
- EnqueueRequestIPv4(std::move(req));
- return;
- }
- break;
- }
-
- ReplyWithError(std::move(req), ARES_EBADFAMILY);
- }
-
- void EnqueueRequestIPv6(THolder<TIncomingRequest> req) {
- auto now = TActivationContext::Now();
-
- auto& fullState = NameToState[req->Name];
- if (MonCounters) {
- *MonCounters->CacheSize = NameToState.size();
- }
-
- auto& state = fullState.StateIPv6;
- EnsureRequest(state, req->Name, AF_INET6, now);
-
- if (state.IsHardExpired(now)) {
- Y_VERIFY(state.Waiting);
- if (MonCounters) {
- ++*MonCounters->CacheMisses;
- }
- // We need to wait for ipv6 reply, schedule ipv4 request in parallel if needed
- if (Options.AllowIPv4) {
- EnsureRequest(fullState.StateIPv4, req->Name, AF_INET, now);
- }
- state.WaitingRequests.PushBack(req.Release());
- return;
- }
-
- // We want to retry AF_UNSPEC with IPv4 in some cases
- if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
- EnqueueRequestIPv4(std::move(req));
- return;
- }
-
- if (MonCounters) {
- ++*MonCounters->CacheHits;
- }
-
- if (state.Status != 0) {
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- } else {
- ReplyWithAddrs(std::move(req), fullState.AddrsIPv6);
- }
- }
-
- void EnqueueRequestIPv4(THolder<TIncomingRequest> req, bool isCacheMiss = false) {
- auto now = TActivationContext::Now();
-
- auto& fullState = NameToState[req->Name];
- if (MonCounters) {
- *MonCounters->CacheSize = NameToState.size();
- }
-
- auto& state = fullState.StateIPv4;
- EnsureRequest(state, req->Name, AF_INET, now);
-
- if (state.IsHardExpired(now)) {
- Y_VERIFY(state.Waiting);
- if (MonCounters && !isCacheMiss) {
- ++*MonCounters->CacheMisses;
- }
- state.WaitingRequests.PushBack(req.Release());
- return;
- }
-
- if (MonCounters && !isCacheMiss) {
- ++*MonCounters->CacheHits;
- }
-
- if (state.Status != 0) {
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- } else {
- ReplyWithAddrs(std::move(req), fullState.AddrsIPv4);
- }
- }
-
- private:
- struct TFamilyState {
- TIncomingRequestList WaitingRequests;
- TInstant SoftDeadline;
- TInstant HardDeadline;
- TInstant NextSoftDeadline;
- TInstant NextHardDeadline;
- TString ErrorText;
- int Status = -1; // never requested before
- bool InSoftHeap = false;
- bool InHardHeap = false;
- bool Waiting = false;
-
- bool Needed() const {
- return InSoftHeap || InHardHeap || Waiting;
- }
-
- bool RetryUnspec() const {
- return (
- Status == ARES_ENODATA ||
- Status == ARES_EBADRESP ||
- Status == ARES_ETIMEOUT);
- }
-
- bool ServerReplied() const {
- return ServerReplied(Status);
- }
-
- bool IsSoftExpired(TInstant now) const {
- return !InSoftHeap || NextSoftDeadline < now;
- }
-
- bool IsHardExpired(TInstant now) const {
- return !InHardHeap || NextHardDeadline < now;
- }
-
- static bool ServerReplied(int status) {
- return (
- status == ARES_SUCCESS ||
- status == ARES_ENODATA ||
- status == ARES_ENOTFOUND);
- }
- };
-
- struct TState {
- TFamilyState StateIPv6;
- TFamilyState StateIPv4;
- TVector<struct in6_addr> AddrsIPv6;
- TVector<struct in_addr> AddrsIPv4;
-
- bool Needed() const {
- return StateIPv6.Needed() || StateIPv4.Needed();
- }
- };
-
- using TNameToState = THashMap<TString, TState>;
-
- template<const TFamilyState TState::* StateToFamily,
- const TInstant TFamilyState::* FamilyToDeadline>
- struct THeapCompare {
- // returns true when b < a
- bool operator()(TNameToState::iterator a, TNameToState::iterator b) const {
- const TState& aState = a->second;
- const TState& bState = b->second;
- const TFamilyState& aFamily = aState.*StateToFamily;
- const TFamilyState& bFamily = bState.*StateToFamily;
- const TInstant& aDeadline = aFamily.*FamilyToDeadline;
- const TInstant& bDeadline = bFamily.*FamilyToDeadline;
- return bDeadline < aDeadline;
- }
- };
-
- template<const TFamilyState TState::* StateToFamily,
- const TInstant TFamilyState::* FamilyToDeadline>
- using TStateHeap = std::priority_queue<
- TNameToState::iterator,
- std::vector<TNameToState::iterator>,
- THeapCompare<StateToFamily, FamilyToDeadline>
- >;
-
- struct TWaitingInfo {
- TNameToState::iterator Position;
- int Family;
- };
-
- private:
- void EnsureRequest(TFamilyState& state, const TString& name, int family, TInstant now) {
- if (state.Waiting) {
- return; // request is already pending
- }
-
- if (!state.IsSoftExpired(now) && !state.IsHardExpired(now)) {
- return; // response is not expired yet
- }
-
- if (MonCounters) {
- switch (family) {
- case AF_INET6:
- ++*MonCounters->OutgoingInFlightV6;
- ++*MonCounters->OutgoingTotalV6;
- break;
- case AF_INET:
- ++*MonCounters->OutgoingInFlightV4;
- ++*MonCounters->OutgoingTotalV4;
- break;
- }
- }
-
- ui64 reqId = ++LastRequestId;
- auto& req = WaitingRequests[reqId];
- req.Position = NameToState.find(name);
- req.Family = family;
- Y_VERIFY(req.Position != NameToState.end());
-
- Send(Upstream, new TEvDns::TEvGetHostByName(name, family), IEventHandle::FlagTrackDelivery, reqId);
- state.Waiting = true;
- }
-
- template<TFamilyState TState::* StateToFamily,
- TInstant TFamilyState::* FamilyToDeadline,
- TInstant TFamilyState::* FamilyToNextDeadline,
- bool TFamilyState::* FamilyToFlag,
- class THeap>
- void PushToHeap(THeap& heap, TNameToState::iterator it, TInstant newDeadline) {
- auto& family = it->second.*StateToFamily;
- TInstant& deadline = family.*FamilyToDeadline;
- TInstant& nextDeadline = family.*FamilyToNextDeadline;
- bool& flag = family.*FamilyToFlag;
- nextDeadline = newDeadline;
- if (!flag) {
- deadline = newDeadline;
- heap.push(it);
- flag = true;
- }
- }
-
- void PushSoftV6(TNameToState::iterator it, TInstant newDeadline) {
- PushToHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, it, newDeadline);
- }
-
- void PushHardV6(TNameToState::iterator it, TInstant newDeadline) {
- PushToHeap<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, it, newDeadline);
- }
-
- void PushSoftV4(TNameToState::iterator it, TInstant newDeadline) {
- PushToHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, it, newDeadline);
- }
-
- void PushHardV4(TNameToState::iterator it, TInstant newDeadline) {
- PushToHeap<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, it, newDeadline);
- }
-
- void ProcessErrorV6(TNameToState::iterator it, int status, TString errorText) {
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV6;
- ++*MonCounters->OutgoingErrorsV6;
- }
-
- auto& state = it->second.StateIPv6;
- Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
- state.Waiting = false;
-
- // When we have a cached positive reply, don't overwrite it with spurious errors
- const bool serverReplied = TFamilyState::ServerReplied(status);
- if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
- PushSoftV6(it, now + Options.SoftNegativeExpireTime);
- if (state.Status == ARES_SUCCESS) {
- SendAddrsV6(it);
- } else {
- SendErrorsV6(it, now);
- }
- return;
- }
-
- state.Status = status;
- state.ErrorText = std::move(errorText);
- PushSoftV6(it, now + Options.SoftNegativeExpireTime);
- if (serverReplied) {
- // Server actually replied, so keep it cached for longer
- PushHardV6(it, now + Options.HardPositiveExpireTime);
- } else {
- PushHardV6(it, now + Options.HardNegativeExpireTime);
- }
-
- SendErrorsV6(it, now);
- }
-
- void SendErrorsV6(TNameToState::iterator it, TInstant now) {
- bool cleaned = false;
- auto& state = it->second.StateIPv6;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
- if (!cleaned) {
- CleanupExpired(now);
- cleaned = true;
- }
- EnqueueRequestIPv4(std::move(req), /* isCacheMiss */ true);
- } else {
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- }
- }
- }
-
- void ProcessErrorV4(TNameToState::iterator it, int status, TString errorText) {
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV4;
- ++*MonCounters->OutgoingErrorsV4;
- }
-
- auto& state = it->second.StateIPv4;
- Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
- state.Waiting = false;
-
- // When we have a cached positive reply, don't overwrite it with spurious errors
- const bool serverReplied = TFamilyState::ServerReplied(status);
- if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
- PushSoftV4(it, now + Options.SoftNegativeExpireTime);
- if (state.Status == ARES_SUCCESS) {
- SendAddrsV4(it);
- } else {
- SendErrorsV4(it);
- }
- return;
- }
-
- state.Status = status;
- state.ErrorText = std::move(errorText);
- PushSoftV4(it, now + Options.SoftNegativeExpireTime);
- if (serverReplied) {
- // Server actually replied, so keep it cached for longer
- PushHardV4(it, now + Options.HardPositiveExpireTime);
- } else {
- PushHardV4(it, now + Options.HardNegativeExpireTime);
- }
-
- SendErrorsV4(it);
- }
-
- void SendErrorsV4(TNameToState::iterator it) {
- auto& state = it->second.StateIPv4;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- ReplyWithError(std::move(req), state.Status, state.ErrorText);
- }
- }
-
- void ProcessAddrsV6(TNameToState::iterator it, TVector<struct in6_addr> addrs) {
- if (Y_UNLIKELY(addrs.empty())) {
- // Probably unnecessary: we don't want to deal with empty address lists
- return ProcessErrorV6(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
- }
-
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV6;
- }
-
- auto& state = it->second.StateIPv6;
- Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
- state.Waiting = false;
-
- state.Status = ARES_SUCCESS;
- it->second.AddrsIPv6 = std::move(addrs);
- PushSoftV6(it, now + Options.SoftPositiveExpireTime);
- PushHardV6(it, now + Options.HardPositiveExpireTime);
-
- SendAddrsV6(it);
- }
-
- void SendAddrsV6(TNameToState::iterator it) {
- auto& state = it->second.StateIPv6;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- ReplyWithAddrs(std::move(req), it->second.AddrsIPv6);
- }
- }
-
- void ProcessAddrsV4(TNameToState::iterator it, TVector<struct in_addr> addrs) {
- if (Y_UNLIKELY(addrs.empty())) {
- // Probably unnecessary: we don't want to deal with empty address lists
- return ProcessErrorV4(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
- }
-
- auto now = TActivationContext::Now();
- if (MonCounters) {
- --*MonCounters->OutgoingInFlightV4;
- }
-
- auto& state = it->second.StateIPv4;
- Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
- state.Waiting = false;
-
- state.Status = ARES_SUCCESS;
- it->second.AddrsIPv4 = std::move(addrs);
- PushSoftV4(it, now + Options.SoftPositiveExpireTime);
- PushHardV4(it, now + Options.HardPositiveExpireTime);
-
- SendAddrsV4(it);
- }
-
- void SendAddrsV4(TNameToState::iterator it) {
- auto& state = it->second.StateIPv4;
- while (state.WaitingRequests) {
- THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
- ReplyWithAddrs(std::move(req), it->second.AddrsIPv4);
- }
- }
-
- private:
- template<TFamilyState TState::*StateToFamily,
- TInstant TFamilyState::* FamilyToDeadline,
- TInstant TFamilyState::* FamilyToNextDeadline,
- bool TFamilyState::* FamilyToFlag>
- void DoCleanupExpired(TStateHeap<StateToFamily, FamilyToDeadline>& heap, TInstant now) {
- while (!heap.empty()) {
- auto it = heap.top();
- auto& family = it->second.*StateToFamily;
- TInstant& deadline = family.*FamilyToDeadline;
- if (now <= deadline) {
- break;
- }
-
- bool& flag = family.*FamilyToFlag;
- Y_VERIFY(flag);
- heap.pop();
- flag = false;
-
- TInstant& nextDeadline = family.*FamilyToNextDeadline;
- if (now < nextDeadline) {
- deadline = nextDeadline;
- heap.push(it);
- flag = true;
- continue;
- }
-
- // Remove unnecessary items
- if (!it->second.Needed()) {
- NameToState.erase(it);
- if (MonCounters) {
- *MonCounters->CacheSize = NameToState.size();
- }
- }
- }
- }
-
- void CleanupExpired(TInstant now) {
- DoCleanupExpired<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, now);
- DoCleanupExpired<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, now);
- DoCleanupExpired<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, now);
- DoCleanupExpired<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, now);
- }
-
- template<class TEvent>
- void SendError(TActorId replyTo, ui64 cookie, int status, const TString& errorText) {
- auto reply = MakeHolder<TEvent>();
- reply->Status = status;
- reply->ErrorText = errorText;
- this->Send(replyTo, reply.Release(), 0, cookie);
- }
-
- void ReplyWithError(THolder<TIncomingRequest> req, int status, const TString& errorText) {
- if (MonCounters) {
- ++*MonCounters->IncomingErrors;
- }
- switch (req->Type) {
- case EIncomingRequestType::GetHostByName: {
- SendError<TEvDns::TEvGetHostByNameResult>(req->Sender, req->Cookie, status, errorText);
- break;
- }
- case EIncomingRequestType::GetAddr: {
- SendError<TEvDns::TEvGetAddrResult>(req->Sender, req->Cookie, status, errorText);
- break;
- }
- }
- }
-
- void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs) {
- switch (req->Type) {
- case EIncomingRequestType::GetHostByName: {
- auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- reply->AddrsV6 = addrs;
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- case EIncomingRequestType::GetAddr: {
- Y_VERIFY(!addrs.empty());
- auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
- reply->Addr = addrs.front();
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- }
- }
-
- void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in_addr>& addrs) {
- switch (req->Type) {
- case EIncomingRequestType::GetHostByName: {
- auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- reply->AddrsV4 = addrs;
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- case EIncomingRequestType::GetAddr: {
- Y_VERIFY(!addrs.empty());
- auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
- reply->Addr = addrs.front();
- Send(req->Sender, reply.Release(), 0, req->Cookie);
- break;
- }
- }
- }
-
- void ReplyWithError(THolder<TIncomingRequest> req, int status) {
- ReplyWithError(std::move(req), status, ares_strerror(status));
- }
-
- void DropPending(TIncomingRequestList& list, int status, const TString& errorText) {
- while (list) {
- THolder<TIncomingRequest> req(list.PopFront());
- ReplyWithError(std::move(req), status, errorText);
- }
- }
-
- void DropPending(int status, const TString& errorText) {
- for (auto& [name, state] : NameToState) {
- DropPending(state.StateIPv6.WaitingRequests, status, errorText);
- DropPending(state.StateIPv4.WaitingRequests, status, errorText);
- }
- }
-
- void DropPending(int status) {
- DropPending(status, ares_strerror(status));
- }
-
- private:
- const TActorId Upstream;
- const TCachingDnsResolverOptions Options;
- const THolder<TMonCounters> MonCounters;
-
- TNameToState NameToState;
- TStateHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline> SoftHeapIPv6;
- TStateHeap<&TState::StateIPv6, &TFamilyState::HardDeadline> HardHeapIPv6;
- TStateHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline> SoftHeapIPv4;
- TStateHeap<&TState::StateIPv4, &TFamilyState::HardDeadline> HardHeapIPv4;
-
- THashMap<ui64, TWaitingInfo> WaitingRequests;
- ui64 LastRequestId = 0;
- };
-
- IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options) {
- return new TCachingDnsResolver(upstream, std::move(options));
- }
-
-} // namespace NDnsResolver
-} // namespace NActors
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <util/generic/intrlist.h>
+
+#include <ares.h>
+
+#include <queue>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TCachingDnsResolver : public TActor<TCachingDnsResolver> {
+ public:
+ struct TMonCounters {
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV6;
+
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingInFlight;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingErrors;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingTotal;
+
+ NMonitoring::TDynamicCounters::TCounterPtr CacheSize;
+ NMonitoring::TDynamicCounters::TCounterPtr CacheHits;
+ NMonitoring::TDynamicCounters::TCounterPtr CacheMisses;
+
+ TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
+ : OutgoingInFlightV4(counters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false))
+ , OutgoingInFlightV6(counters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false))
+ , OutgoingErrorsV4(counters->GetCounter("DnsResolver/Outgoing/Errors/V4", true))
+ , OutgoingErrorsV6(counters->GetCounter("DnsResolver/Outgoing/Errors/V6", true))
+ , OutgoingTotalV4(counters->GetCounter("DnsResolver/Outgoing/Total/V4", true))
+ , OutgoingTotalV6(counters->GetCounter("DnsResolver/Outgoing/Total/V6", true))
+ , IncomingInFlight(counters->GetCounter("DnsResolver/Incoming/InFlight", false))
+ , IncomingErrors(counters->GetCounter("DnsResolver/Incoming/Errors", true))
+ , IncomingTotal(counters->GetCounter("DnsResolver/Incoming/Total", true))
+ , CacheSize(counters->GetCounter("DnsResolver/Cache/Size", false))
+ , CacheHits(counters->GetCounter("DnsResolver/Cache/Hits", true))
+ , CacheMisses(counters->GetCounter("DnsResolver/Cache/Misses", true))
+ { }
+ };
+
+ public:
+ TCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options)
+ : TActor(&TThis::StateWork)
+ , Upstream(upstream)
+ , Options(std::move(options))
+ , MonCounters(Options.MonCounters ? new TMonCounters(Options.MonCounters) : nullptr)
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvDns::TEvGetAddr, Handle);
+ hFunc(TEvDns::TEvGetHostByNameResult, Handle);
+ hFunc(TEvents::TEvUndelivered, Handle);
+ });
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ DropPending(ARES_ECANCELLED);
+ PassAway();
+ }
+
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto req = MakeHolder<TIncomingRequest>();
+ req->Type = EIncomingRequestType::GetHostByName;
+ req->Sender = ev->Sender;
+ req->Cookie = ev->Cookie;
+ req->Name = std::move(ev->Get()->Name);
+ req->Family = ev->Get()->Family;
+ EnqueueRequest(std::move(req));
+ }
+
+ void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
+ auto req = MakeHolder<TIncomingRequest>();
+ req->Type = EIncomingRequestType::GetAddr;
+ req->Sender = ev->Sender;
+ req->Cookie = ev->Cookie;
+ req->Name = std::move(ev->Get()->Name);
+ req->Family = ev->Get()->Family;
+ EnqueueRequest(std::move(req));
+ }
+
+ void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) {
+ auto waitingIt = WaitingRequests.find(ev->Cookie);
+ Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected reply, reqId=%" PRIu64, ev->Cookie);
+ auto waitingInfo = waitingIt->second;
+ WaitingRequests.erase(waitingIt);
+
+ switch (waitingInfo.Family) {
+ case AF_INET6:
+ if (ev->Get()->Status) {
+ ProcessErrorV6(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
+ } else {
+ ProcessAddrsV6(waitingInfo.Position, std::move(ev->Get()->AddrsV6));
+ }
+ break;
+
+ case AF_INET:
+ if (ev->Get()->Status) {
+ ProcessErrorV4(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
+ } else {
+ ProcessAddrsV4(waitingInfo.Position, std::move(ev->Get()->AddrsV4));
+ }
+ break;
+
+ default:
+ Y_FAIL("Unexpected request family %d", waitingInfo.Family);
+ }
+ }
+
+ void Handle(TEvents::TEvUndelivered::TPtr& ev) {
+ switch (ev->Get()->SourceType) {
+ case TEvDns::TEvGetHostByName::EventType: {
+ auto waitingIt = WaitingRequests.find(ev->Cookie);
+ Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected TEvUndelivered, reqId=%" PRIu64, ev->Cookie);
+ auto waitingInfo = waitingIt->second;
+ WaitingRequests.erase(waitingIt);
+
+ switch (waitingInfo.Family) {
+ case AF_INET6:
+ ProcessErrorV6(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
+ break;
+ case AF_INET:
+ ProcessErrorV4(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
+ break;
+ default:
+ Y_FAIL("Unexpected request family %d", waitingInfo.Family);
+ }
+
+ break;
+ }
+
+ default:
+ Y_FAIL("Unexpected TEvUndelievered, type=%" PRIu32, ev->Get()->SourceType);
+ }
+ }
+
+ private:
+ enum EIncomingRequestType {
+ GetHostByName,
+ GetAddr,
+ };
+
+ struct TIncomingRequest : public TIntrusiveListItem<TIncomingRequest> {
+ EIncomingRequestType Type;
+ TActorId Sender;
+ ui64 Cookie;
+ TString Name;
+ int Family;
+ };
+
+ using TIncomingRequestList = TIntrusiveListWithAutoDelete<TIncomingRequest, TDelete>;
+
+ void EnqueueRequest(THolder<TIncomingRequest> req) {
+ if (MonCounters) {
+ ++*MonCounters->IncomingTotal;
+ }
+
+ CleanupExpired(TActivationContext::Now());
+
+ switch (req->Family) {
+ case AF_UNSPEC:
+ if (Options.AllowIPv6) {
+ EnqueueRequestIPv6(std::move(req));
+ return;
+ }
+ if (Options.AllowIPv4) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+ break;
+
+ case AF_INET6:
+ if (Options.AllowIPv6) {
+ EnqueueRequestIPv6(std::move(req));
+ return;
+ }
+ break;
+
+ case AF_INET:
+ if (Options.AllowIPv4) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+ break;
+ }
+
+ ReplyWithError(std::move(req), ARES_EBADFAMILY);
+ }
+
+ void EnqueueRequestIPv6(THolder<TIncomingRequest> req) {
+ auto now = TActivationContext::Now();
+
+ auto& fullState = NameToState[req->Name];
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+
+ auto& state = fullState.StateIPv6;
+ EnsureRequest(state, req->Name, AF_INET6, now);
+
+ if (state.IsHardExpired(now)) {
+ Y_VERIFY(state.Waiting);
+ if (MonCounters) {
+ ++*MonCounters->CacheMisses;
+ }
+ // We need to wait for ipv6 reply, schedule ipv4 request in parallel if needed
+ if (Options.AllowIPv4) {
+ EnsureRequest(fullState.StateIPv4, req->Name, AF_INET, now);
+ }
+ state.WaitingRequests.PushBack(req.Release());
+ return;
+ }
+
+ // We want to retry AF_UNSPEC with IPv4 in some cases
+ if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+
+ if (MonCounters) {
+ ++*MonCounters->CacheHits;
+ }
+
+ if (state.Status != 0) {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ } else {
+ ReplyWithAddrs(std::move(req), fullState.AddrsIPv6);
+ }
+ }
+
+ void EnqueueRequestIPv4(THolder<TIncomingRequest> req, bool isCacheMiss = false) {
+ auto now = TActivationContext::Now();
+
+ auto& fullState = NameToState[req->Name];
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+
+ auto& state = fullState.StateIPv4;
+ EnsureRequest(state, req->Name, AF_INET, now);
+
+ if (state.IsHardExpired(now)) {
+ Y_VERIFY(state.Waiting);
+ if (MonCounters && !isCacheMiss) {
+ ++*MonCounters->CacheMisses;
+ }
+ state.WaitingRequests.PushBack(req.Release());
+ return;
+ }
+
+ if (MonCounters && !isCacheMiss) {
+ ++*MonCounters->CacheHits;
+ }
+
+ if (state.Status != 0) {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ } else {
+ ReplyWithAddrs(std::move(req), fullState.AddrsIPv4);
+ }
+ }
+
+ private:
+ struct TFamilyState {
+ TIncomingRequestList WaitingRequests;
+ TInstant SoftDeadline;
+ TInstant HardDeadline;
+ TInstant NextSoftDeadline;
+ TInstant NextHardDeadline;
+ TString ErrorText;
+ int Status = -1; // never requested before
+ bool InSoftHeap = false;
+ bool InHardHeap = false;
+ bool Waiting = false;
+
+ bool Needed() const {
+ return InSoftHeap || InHardHeap || Waiting;
+ }
+
+ bool RetryUnspec() const {
+ return (
+ Status == ARES_ENODATA ||
+ Status == ARES_EBADRESP ||
+ Status == ARES_ETIMEOUT);
+ }
+
+ bool ServerReplied() const {
+ return ServerReplied(Status);
+ }
+
+ bool IsSoftExpired(TInstant now) const {
+ return !InSoftHeap || NextSoftDeadline < now;
+ }
+
+ bool IsHardExpired(TInstant now) const {
+ return !InHardHeap || NextHardDeadline < now;
+ }
+
+ static bool ServerReplied(int status) {
+ return (
+ status == ARES_SUCCESS ||
+ status == ARES_ENODATA ||
+ status == ARES_ENOTFOUND);
+ }
+ };
+
+ struct TState {
+ TFamilyState StateIPv6;
+ TFamilyState StateIPv4;
+ TVector<struct in6_addr> AddrsIPv6;
+ TVector<struct in_addr> AddrsIPv4;
+
+ bool Needed() const {
+ return StateIPv6.Needed() || StateIPv4.Needed();
+ }
+ };
+
+ using TNameToState = THashMap<TString, TState>;
+
+ template<const TFamilyState TState::* StateToFamily,
+ const TInstant TFamilyState::* FamilyToDeadline>
+ struct THeapCompare {
+ // returns true when b < a
+ bool operator()(TNameToState::iterator a, TNameToState::iterator b) const {
+ const TState& aState = a->second;
+ const TState& bState = b->second;
+ const TFamilyState& aFamily = aState.*StateToFamily;
+ const TFamilyState& bFamily = bState.*StateToFamily;
+ const TInstant& aDeadline = aFamily.*FamilyToDeadline;
+ const TInstant& bDeadline = bFamily.*FamilyToDeadline;
+ return bDeadline < aDeadline;
+ }
+ };
+
+ template<const TFamilyState TState::* StateToFamily,
+ const TInstant TFamilyState::* FamilyToDeadline>
+ using TStateHeap = std::priority_queue<
+ TNameToState::iterator,
+ std::vector<TNameToState::iterator>,
+ THeapCompare<StateToFamily, FamilyToDeadline>
+ >;
+
+ struct TWaitingInfo {
+ TNameToState::iterator Position;
+ int Family;
+ };
+
+ private:
+ void EnsureRequest(TFamilyState& state, const TString& name, int family, TInstant now) {
+ if (state.Waiting) {
+ return; // request is already pending
+ }
+
+ if (!state.IsSoftExpired(now) && !state.IsHardExpired(now)) {
+ return; // response is not expired yet
+ }
+
+ if (MonCounters) {
+ switch (family) {
+ case AF_INET6:
+ ++*MonCounters->OutgoingInFlightV6;
+ ++*MonCounters->OutgoingTotalV6;
+ break;
+ case AF_INET:
+ ++*MonCounters->OutgoingInFlightV4;
+ ++*MonCounters->OutgoingTotalV4;
+ break;
+ }
+ }
+
+ ui64 reqId = ++LastRequestId;
+ auto& req = WaitingRequests[reqId];
+ req.Position = NameToState.find(name);
+ req.Family = family;
+ Y_VERIFY(req.Position != NameToState.end());
+
+ Send(Upstream, new TEvDns::TEvGetHostByName(name, family), IEventHandle::FlagTrackDelivery, reqId);
+ state.Waiting = true;
+ }
+
+ template<TFamilyState TState::* StateToFamily,
+ TInstant TFamilyState::* FamilyToDeadline,
+ TInstant TFamilyState::* FamilyToNextDeadline,
+ bool TFamilyState::* FamilyToFlag,
+ class THeap>
+ void PushToHeap(THeap& heap, TNameToState::iterator it, TInstant newDeadline) {
+ auto& family = it->second.*StateToFamily;
+ TInstant& deadline = family.*FamilyToDeadline;
+ TInstant& nextDeadline = family.*FamilyToNextDeadline;
+ bool& flag = family.*FamilyToFlag;
+ nextDeadline = newDeadline;
+ if (!flag) {
+ deadline = newDeadline;
+ heap.push(it);
+ flag = true;
+ }
+ }
+
+ void PushSoftV6(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, it, newDeadline);
+ }
+
+ void PushHardV6(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, it, newDeadline);
+ }
+
+ void PushSoftV4(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, it, newDeadline);
+ }
+
+ void PushHardV4(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, it, newDeadline);
+ }
+
+ void ProcessErrorV6(TNameToState::iterator it, int status, TString errorText) {
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV6;
+ ++*MonCounters->OutgoingErrorsV6;
+ }
+
+ auto& state = it->second.StateIPv6;
+ Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
+ state.Waiting = false;
+
+ // When we have a cached positive reply, don't overwrite it with spurious errors
+ const bool serverReplied = TFamilyState::ServerReplied(status);
+ if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
+ PushSoftV6(it, now + Options.SoftNegativeExpireTime);
+ if (state.Status == ARES_SUCCESS) {
+ SendAddrsV6(it);
+ } else {
+ SendErrorsV6(it, now);
+ }
+ return;
+ }
+
+ state.Status = status;
+ state.ErrorText = std::move(errorText);
+ PushSoftV6(it, now + Options.SoftNegativeExpireTime);
+ if (serverReplied) {
+ // Server actually replied, so keep it cached for longer
+ PushHardV6(it, now + Options.HardPositiveExpireTime);
+ } else {
+ PushHardV6(it, now + Options.HardNegativeExpireTime);
+ }
+
+ SendErrorsV6(it, now);
+ }
+
+ void SendErrorsV6(TNameToState::iterator it, TInstant now) {
+ bool cleaned = false;
+ auto& state = it->second.StateIPv6;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
+ if (!cleaned) {
+ CleanupExpired(now);
+ cleaned = true;
+ }
+ EnqueueRequestIPv4(std::move(req), /* isCacheMiss */ true);
+ } else {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ }
+ }
+ }
+
+ void ProcessErrorV4(TNameToState::iterator it, int status, TString errorText) {
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV4;
+ ++*MonCounters->OutgoingErrorsV4;
+ }
+
+ auto& state = it->second.StateIPv4;
+ Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
+ state.Waiting = false;
+
+ // When we have a cached positive reply, don't overwrite it with spurious errors
+ const bool serverReplied = TFamilyState::ServerReplied(status);
+ if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
+ PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ if (state.Status == ARES_SUCCESS) {
+ SendAddrsV4(it);
+ } else {
+ SendErrorsV4(it);
+ }
+ return;
+ }
+
+ state.Status = status;
+ state.ErrorText = std::move(errorText);
+ PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ if (serverReplied) {
+ // Server actually replied, so keep it cached for longer
+ PushHardV4(it, now + Options.HardPositiveExpireTime);
+ } else {
+ PushHardV4(it, now + Options.HardNegativeExpireTime);
+ }
+
+ SendErrorsV4(it);
+ }
+
+ void SendErrorsV4(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv4;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ }
+ }
+
+ void ProcessAddrsV6(TNameToState::iterator it, TVector<struct in6_addr> addrs) {
+ if (Y_UNLIKELY(addrs.empty())) {
+ // Probably unnecessary: we don't want to deal with empty address lists
+ return ProcessErrorV6(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
+ }
+
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV6;
+ }
+
+ auto& state = it->second.StateIPv6;
+ Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
+ state.Waiting = false;
+
+ state.Status = ARES_SUCCESS;
+ it->second.AddrsIPv6 = std::move(addrs);
+ PushSoftV6(it, now + Options.SoftPositiveExpireTime);
+ PushHardV6(it, now + Options.HardPositiveExpireTime);
+
+ SendAddrsV6(it);
+ }
+
+ void SendAddrsV6(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv6;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithAddrs(std::move(req), it->second.AddrsIPv6);
+ }
+ }
+
+ void ProcessAddrsV4(TNameToState::iterator it, TVector<struct in_addr> addrs) {
+ if (Y_UNLIKELY(addrs.empty())) {
+ // Probably unnecessary: we don't want to deal with empty address lists
+ return ProcessErrorV4(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
+ }
+
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV4;
+ }
+
+ auto& state = it->second.StateIPv4;
+ Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
+ state.Waiting = false;
+
+ state.Status = ARES_SUCCESS;
+ it->second.AddrsIPv4 = std::move(addrs);
+ PushSoftV4(it, now + Options.SoftPositiveExpireTime);
+ PushHardV4(it, now + Options.HardPositiveExpireTime);
+
+ SendAddrsV4(it);
+ }
+
+ void SendAddrsV4(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv4;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithAddrs(std::move(req), it->second.AddrsIPv4);
+ }
+ }
+
+ private:
+ template<TFamilyState TState::*StateToFamily,
+ TInstant TFamilyState::* FamilyToDeadline,
+ TInstant TFamilyState::* FamilyToNextDeadline,
+ bool TFamilyState::* FamilyToFlag>
+ void DoCleanupExpired(TStateHeap<StateToFamily, FamilyToDeadline>& heap, TInstant now) {
+ while (!heap.empty()) {
+ auto it = heap.top();
+ auto& family = it->second.*StateToFamily;
+ TInstant& deadline = family.*FamilyToDeadline;
+ if (now <= deadline) {
+ break;
+ }
+
+ bool& flag = family.*FamilyToFlag;
+ Y_VERIFY(flag);
+ heap.pop();
+ flag = false;
+
+ TInstant& nextDeadline = family.*FamilyToNextDeadline;
+ if (now < nextDeadline) {
+ deadline = nextDeadline;
+ heap.push(it);
+ flag = true;
+ continue;
+ }
+
+ // Remove unnecessary items
+ if (!it->second.Needed()) {
+ NameToState.erase(it);
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+ }
+ }
+ }
+
+ void CleanupExpired(TInstant now) {
+ DoCleanupExpired<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, now);
+ DoCleanupExpired<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, now);
+ DoCleanupExpired<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, now);
+ DoCleanupExpired<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, now);
+ }
+
+ template<class TEvent>
+ void SendError(TActorId replyTo, ui64 cookie, int status, const TString& errorText) {
+ auto reply = MakeHolder<TEvent>();
+ reply->Status = status;
+ reply->ErrorText = errorText;
+ this->Send(replyTo, reply.Release(), 0, cookie);
+ }
+
+ void ReplyWithError(THolder<TIncomingRequest> req, int status, const TString& errorText) {
+ if (MonCounters) {
+ ++*MonCounters->IncomingErrors;
+ }
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ SendError<TEvDns::TEvGetHostByNameResult>(req->Sender, req->Cookie, status, errorText);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ SendError<TEvDns::TEvGetAddrResult>(req->Sender, req->Cookie, status, errorText);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs) {
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ reply->AddrsV6 = addrs;
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ Y_VERIFY(!addrs.empty());
+ auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
+ reply->Addr = addrs.front();
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in_addr>& addrs) {
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ reply->AddrsV4 = addrs;
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ Y_VERIFY(!addrs.empty());
+ auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
+ reply->Addr = addrs.front();
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithError(THolder<TIncomingRequest> req, int status) {
+ ReplyWithError(std::move(req), status, ares_strerror(status));
+ }
+
+ void DropPending(TIncomingRequestList& list, int status, const TString& errorText) {
+ while (list) {
+ THolder<TIncomingRequest> req(list.PopFront());
+ ReplyWithError(std::move(req), status, errorText);
+ }
+ }
+
+ void DropPending(int status, const TString& errorText) {
+ for (auto& [name, state] : NameToState) {
+ DropPending(state.StateIPv6.WaitingRequests, status, errorText);
+ DropPending(state.StateIPv4.WaitingRequests, status, errorText);
+ }
+ }
+
+ void DropPending(int status) {
+ DropPending(status, ares_strerror(status));
+ }
+
+ private:
+ const TActorId Upstream;
+ const TCachingDnsResolverOptions Options;
+ const THolder<TMonCounters> MonCounters;
+
+ TNameToState NameToState;
+ TStateHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline> SoftHeapIPv6;
+ TStateHeap<&TState::StateIPv6, &TFamilyState::HardDeadline> HardHeapIPv6;
+ TStateHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline> SoftHeapIPv4;
+ TStateHeap<&TState::StateIPv4, &TFamilyState::HardDeadline> HardHeapIPv4;
+
+ THashMap<ui64, TWaitingInfo> WaitingRequests;
+ ui64 LastRequestId = 0;
+ };
+
+ IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options) {
+ return new TCachingDnsResolver(upstream, std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
index c3b7cb3c77..f63e594d30 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
@@ -1,630 +1,630 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/core/hfunc.h>
-#include <library/cpp/actors/testlib/test_runtime.h>
-#include <library/cpp/testing/unittest/registar.h>
-#include <util/string/builder.h>
-
-#include <ares.h>
-
-using namespace NActors;
-using namespace NActors::NDnsResolver;
-
-// FIXME: use a mock resolver
-Y_UNIT_TEST_SUITE(CachingDnsResolver) {
-
- struct TAddrToString {
- TString operator()(const std::monostate&) const {
- return "<nothing>";
- }
-
- TString operator()(const struct in6_addr& addr) const {
- char dst[INET6_ADDRSTRLEN];
- auto res = ares_inet_ntop(AF_INET6, &addr, dst, INET6_ADDRSTRLEN);
- Y_VERIFY(res, "Cannot convert ipv6 address");
- return dst;
- }
-
- TString operator()(const struct in_addr& addr) const {
- char dst[INET_ADDRSTRLEN];
- auto res = ares_inet_ntop(AF_INET, &addr, dst, INET_ADDRSTRLEN);
- Y_VERIFY(res, "Cannot convert ipv4 address");
- return dst;
- }
- };
-
- TString AddrToString(const std::variant<std::monostate, struct in6_addr, struct in_addr>& v) {
- return std::visit(TAddrToString(), v);
- }
-
- struct TMockReply {
- static constexpr TDuration DefaultDelay = TDuration::MilliSeconds(1);
-
- int Status = 0;
- TDuration Delay;
- TVector<struct in6_addr> AddrsV6;
- TVector<struct in_addr> AddrsV4;
-
- static TMockReply Error(int status, TDuration delay = DefaultDelay) {
- Y_VERIFY(status != 0);
- TMockReply reply;
- reply.Status = status;
- reply.Delay = delay;
- return reply;
- }
-
- static TMockReply Empty(TDuration delay = DefaultDelay) {
- TMockReply reply;
- reply.Delay = delay;
- return reply;
- }
-
- static TMockReply ManyV6(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
- TMockReply reply;
- reply.Delay = delay;
- for (const TString& addr : addrs) {
- void* dst = &reply.AddrsV6.emplace_back();
- int status = ares_inet_pton(AF_INET6, addr.c_str(), dst);
- Y_VERIFY(status == 1, "Invalid ipv6 address: %s", addr.c_str());
- }
- return reply;
- }
-
- static TMockReply ManyV4(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
- TMockReply reply;
- reply.Delay = delay;
- for (const TString& addr : addrs) {
- void* dst = &reply.AddrsV4.emplace_back();
- int status = ares_inet_pton(AF_INET, addr.c_str(), dst);
- Y_VERIFY(status == 1, "Invalid ipv4 address: %s", addr.c_str());
- }
- return reply;
- }
-
- static TMockReply SingleV6(const TString& addr, TDuration delay = DefaultDelay) {
- return ManyV6({ addr }, delay);
- }
-
- static TMockReply SingleV4(const TString& addr, TDuration delay = DefaultDelay) {
- return ManyV4({ addr }, delay);
- }
- };
-
- using TMockDnsCallback = std::function<TMockReply (const TString&, int)>;
-
- class TMockDnsResolver : public TActor<TMockDnsResolver> {
- public:
- TMockDnsResolver(TMockDnsCallback callback)
- : TActor(&TThis::StateWork)
- , Callback(std::move(callback))
- { }
-
- private:
- struct TEvPrivate {
- enum EEv {
- EvScheduled = EventSpaceBegin(TEvents::ES_PRIVATE),
- };
-
- struct TEvScheduled : public TEventLocal<TEvScheduled, EvScheduled> {
- TActorId Sender;
- ui64 Cookie;
- TMockReply Reply;
-
- TEvScheduled(TActorId sender, ui64 cookie, TMockReply reply)
- : Sender(sender)
- , Cookie(cookie)
- , Reply(std::move(reply))
- { }
- };
- };
-
- private:
- STRICT_STFUNC(StateWork, {
- hFunc(TEvents::TEvPoison, Handle);
- hFunc(TEvDns::TEvGetHostByName, Handle);
- hFunc(TEvPrivate::TEvScheduled, Handle);
- });
-
- void Handle(TEvents::TEvPoison::TPtr&) {
- PassAway();
- }
-
- void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
- auto reply = Callback(ev->Get()->Name, ev->Get()->Family);
- if (reply.Delay) {
- Schedule(reply.Delay, new TEvPrivate::TEvScheduled(ev->Sender, ev->Cookie, std::move(reply)));
- } else {
- SendReply(ev->Sender, ev->Cookie, std::move(reply));
- }
- }
-
- void Handle(TEvPrivate::TEvScheduled::TPtr& ev) {
- SendReply(ev->Get()->Sender, ev->Get()->Cookie, std::move(ev->Get()->Reply));
- }
-
- private:
- void SendReply(const TActorId& sender, ui64 cookie, TMockReply&& reply) {
- auto res = MakeHolder<TEvDns::TEvGetHostByNameResult>();
- res->Status = reply.Status;
- if (res->Status != 0) {
- res->ErrorText = ares_strerror(res->Status);
- } else {
- res->AddrsV6 = std::move(reply.AddrsV6);
- res->AddrsV4 = std::move(reply.AddrsV4);
- }
- Send(sender, res.Release(), 0, cookie);
- }
-
- private:
- TMockDnsCallback Callback;
- };
-
- struct TCachingDnsRuntime : public TTestActorRuntimeBase {
- TCachingDnsResolverOptions ResolverOptions;
- TActorId MockResolver;
- TActorId Resolver;
- TActorId Sleeper;
- TString Section_;
-
- NMonitoring::TDynamicCounters::TCounterPtr InFlight6;
- NMonitoring::TDynamicCounters::TCounterPtr InFlight4;
- NMonitoring::TDynamicCounters::TCounterPtr Total6;
- NMonitoring::TDynamicCounters::TCounterPtr Total4;
- NMonitoring::TDynamicCounters::TCounterPtr Misses;
- NMonitoring::TDynamicCounters::TCounterPtr Hits;
-
- THashMap<TString, TMockReply> ReplyV6;
- THashMap<TString, TMockReply> ReplyV4;
-
- TCachingDnsRuntime() {
- SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
- ResolverOptions.MonCounters = new NMonitoring::TDynamicCounters;
-
- ReplyV6["localhost"] = TMockReply::SingleV6("::1");
- ReplyV4["localhost"] = TMockReply::SingleV4("127.0.0.1");
- ReplyV6["yandex.ru"] = TMockReply::SingleV6("2a02:6b8:a::a", TDuration::MilliSeconds(500));
- ReplyV4["yandex.ru"] = TMockReply::SingleV4("77.88.55.77", TDuration::MilliSeconds(250));
- ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ENODATA);
- ReplyV4["router.asus.com"] = TMockReply::SingleV4("192.168.0.1");
- }
-
- void Start(TMockDnsCallback callback) {
- MockResolver = Register(new TMockDnsResolver(std::move(callback)));
- EnableScheduleForActor(MockResolver);
- Resolver = Register(CreateCachingDnsResolver(MockResolver, ResolverOptions));
- Sleeper = AllocateEdgeActor();
-
- InFlight6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false);
- InFlight4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false);
- Total6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V6", true);
- Total4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V4", true);
- Misses = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Misses", true);
- Hits = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Hits", true);
- }
-
- void Start() {
- Start([this](const TString& name, int family) {
- switch (family) {
- case AF_INET6: {
- auto it = ReplyV6.find(name);
- if (it != ReplyV6.end()) {
- return it->second;
- }
- break;
- }
- case AF_INET: {
- auto it = ReplyV4.find(name);
- if (it != ReplyV4.end()) {
- return it->second;
- }
- break;
- }
- }
- return TMockReply::Error(ARES_ENOTFOUND);
- });
- }
-
- void Section(const TString& section) {
- Section_ = section;
- }
-
- void Sleep(TDuration duration) {
- Schedule(new IEventHandle(Sleeper, Sleeper, new TEvents::TEvWakeup), duration);
- GrabEdgeEventRethrow<TEvents::TEvWakeup>(Sleeper);
- }
-
- void WaitNoInFlight() {
- if (*InFlight6 || *InFlight4) {
- TDispatchOptions options;
- options.CustomFinalCondition = [&]() {
- return !*InFlight6 && !*InFlight4;
- };
- DispatchEvents(options);
- UNIT_ASSERT_C(!*InFlight6 && !*InFlight4, "Failed to wait for no inflight in " << Section_);
- }
- }
-
- void SendGetHostByName(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
- Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetHostByName(name, family)), 0, true);
- }
-
- void SendGetAddr(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
- Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetAddr(name, family)), 0, true);
- }
-
- TEvDns::TEvGetHostByNameResult::TPtr WaitGetHostByName(const TActorId& sender) {
- return GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- }
-
- TEvDns::TEvGetAddrResult::TPtr WaitGetAddr(const TActorId& sender) {
- return GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
- }
-
- void ExpectInFlight6(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(InFlight6->Val(), count, Section_);
- }
-
- void ExpectInFlight4(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(InFlight4->Val(), count, Section_);
- }
-
- void ExpectTotal6(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(Total6->Val(), count, Section_);
- }
-
- void ExpectTotal4(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(Total4->Val(), count, Section_);
- }
-
- void Expect6(i64 total, i64 inflight) {
- UNIT_ASSERT_C(
- Total6->Val() == total && InFlight6->Val() == inflight,
- Section_ << ": Expect6(" << total << ", " << inflight << ") "
- << " but got (" << Total6->Val() << ", " << InFlight6->Val() << ")");
- }
-
- void Expect4(i64 total, i64 inflight) {
- UNIT_ASSERT_C(
- Total4->Val() == total && InFlight4->Val() == inflight,
- Section_ << ": Expect4(" << total << ", " << inflight << ") "
- << " got (" << Total4->Val() << ", " << InFlight4->Val() << ")");
- }
-
- void ExpectMisses(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(Misses->Val(), count, Section_);
- }
-
- void ExpectHits(i64 count) {
- UNIT_ASSERT_VALUES_EQUAL_C(Hits->Val(), count, Section_);
- }
-
- void ExpectGetHostByNameError(const TActorId& sender, int status) {
- auto ev = WaitGetHostByName(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
- }
-
- void ExpectGetAddrError(const TActorId& sender, int status) {
- auto ev = WaitGetAddr(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
- }
-
- void ExpectGetHostByNameSuccess(const TActorId& sender, const TString& expected) {
- auto ev = WaitGetHostByName(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
- TStringBuilder result;
- for (const auto& addr : ev->Get()->AddrsV6) {
- if (result) {
- result << ',';
- }
- result << TAddrToString()(addr);
- }
- for (const auto& addr : ev->Get()->AddrsV4) {
- if (result) {
- result << ',';
- }
- result << TAddrToString()(addr);
- }
- UNIT_ASSERT_VALUES_EQUAL_C(TString(result), expected, Section_);
- }
-
- void ExpectGetAddrSuccess(const TActorId& sender, const TString& expected) {
- auto ev = WaitGetAddr(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
- TString result = AddrToString(ev->Get()->Addr);
- UNIT_ASSERT_VALUES_EQUAL_C(result, expected, Section_);
- }
- };
-
- Y_UNIT_TEST(UnusableResolver) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
-
- runtime.Send(new IEventHandle(runtime.MockResolver, { }, new TEvents::TEvPoison), 0, true);
- runtime.SendGetAddr(sender, "foo.ru", AF_UNSPEC);
- runtime.ExpectGetAddrError(sender, ARES_ENOTINITIALIZED);
- }
-
- Y_UNIT_TEST(ResolveCaching) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- // First time resolve, ipv4 and ipv6 sent in parallel, we wait for ipv6 result
- runtime.Section("First time resolve");
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(1, 0);
- runtime.Expect4(1, 0);
- runtime.ExpectMisses(1);
- runtime.ExpectHits(0);
-
- // Second resolve, ipv6 and ipv4 queries result in a cache hit
- runtime.Section("Second resolve, ipv6");
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(1, 0);
- runtime.ExpectHits(1);
- runtime.Section("Second resolve, ipv4");
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect4(1, 0);
- runtime.ExpectHits(2);
-
- // Wait until soft expiration and try ipv4 again
- // Will cause a cache hit, but will start a new ipv4 request in background
- runtime.Section("Retry ipv4 after soft expiration");
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect6(1, 0);
- runtime.Expect4(2, 1);
- runtime.ExpectMisses(1);
- runtime.ExpectHits(3);
- runtime.WaitNoInFlight();
-
- // Wait until soft expiration and try both again
- // Will cause a cache hit, but will start a new ipv6 request in background
- runtime.Section("Retry both after soft expiration");
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(2, 1);
- runtime.Expect4(2, 0);
- runtime.ExpectMisses(1);
- runtime.ExpectHits(4);
- runtime.WaitNoInFlight();
-
- // Wait until hard expiration and try both again
- // Will cause a cache miss and new resolve requests
- runtime.Section("Retry both after hard expiration");
- runtime.Sleep(TDuration::Hours(2));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(3, 0);
- runtime.Expect4(3, 0);
- runtime.ExpectMisses(2);
- runtime.ExpectHits(4);
-
- // Wait half the hard expiration time, must always result in a cache hit
- runtime.Section("Retry both after half hard expiration");
- for (ui64 i = 1; i <= 4; ++i) {
- runtime.Sleep(TDuration::Hours(1));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(3 + i, 1);
- runtime.ExpectHits(4 + i);
- runtime.WaitNoInFlight();
- }
-
- // Change v6 result to a timeout, must keep using cached result until hard expiration
- runtime.Section("Dns keeps timing out");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT);
- for (ui64 i = 1; i <= 4; ++i) {
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.Expect6(7 + i, 1);
- runtime.ExpectHits(8 + i);
- runtime.WaitNoInFlight();
- }
-
- // Change v6 result to nodata, must switch to a v4 result eventually
- runtime.Section("Host changes to being ipv4 only");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENODATA);
- runtime.Sleep(TDuration::Seconds(2));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
- runtime.WaitNoInFlight();
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.Expect6(12, 0);
- runtime.Expect4(4, 0);
- runtime.ExpectMisses(3);
-
- // Change v6 result to nxdomain, must not fall back to a v4 result
- runtime.Section("Host is removed from dns");
- runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND);
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
- runtime.WaitNoInFlight();
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- }
-
- Y_UNIT_TEST(ResolveCachingV4) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.Section("First request");
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.ExpectMisses(1);
-
- runtime.Section("Second request");
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.ExpectHits(1);
-
- runtime.Section("Dns keeps timing out");
- runtime.ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
- runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
- for (ui64 i = 1; i <= 4; ++i) {
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.Expect6(1 + i, 1);
- runtime.Expect4(1 + i, 1);
- runtime.ExpectHits(1 + i);
- runtime.WaitNoInFlight();
- }
-
- runtime.Section("Host is removed from ipv4 dns");
- runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND);
- runtime.Sleep(TDuration::Seconds(15));
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.WaitNoInFlight();
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- }
-
- Y_UNIT_TEST(EventualTimeout) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.ReplyV6["notfound.ru"] = TMockReply::Error(ARES_ENODATA);
- runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND);
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
-
- runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT);
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- runtime.WaitNoInFlight();
-
- bool timeout = false;
- for (ui64 i = 1; i <= 8; ++i) {
- runtime.Sleep(TDuration::Minutes(30));
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- auto ev = runtime.WaitGetAddr(sender);
- if (ev->Get()->Status == ARES_ETIMEOUT && i > 2) {
- timeout = true;
- break;
- }
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ENOTFOUND,
- "Iteration " << i << ": " << ev->Get()->ErrorText);
- }
-
- UNIT_ASSERT_C(timeout, "DnsResolver did not reply with a timeout");
- }
-
- Y_UNIT_TEST(MultipleRequestsAndHosts) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameSuccess(sender, "192.168.0.1");
- runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
- runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a");
- runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
-
- runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- }
-
- Y_UNIT_TEST(DisabledIPv6) {
- TCachingDnsRuntime runtime;
- runtime.ResolverOptions.AllowIPv6 = false;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
-
- runtime.SendGetHostByName(sender, "yandex.ru", AF_INET6);
- runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
- runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
- runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
-
- runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
- runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
-
- runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- }
-
- Y_UNIT_TEST(DisabledIPv4) {
- TCachingDnsRuntime runtime;
- runtime.ResolverOptions.AllowIPv4 = false;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
- runtime.ExpectGetAddrError(sender, ARES_ENODATA);
-
- runtime.SendGetHostByName(sender, "router.asus.com", AF_INET);
- runtime.SendGetAddr(sender, "router.asus.com", AF_INET);
- runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
- runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
-
- runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
- runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
- runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
- runtime.ExpectGetAddrError(sender, ARES_ENODATA);
-
- runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
- runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
- runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
- }
-
- Y_UNIT_TEST(PoisonPill) {
- TCachingDnsRuntime runtime;
- runtime.Initialize();
- runtime.Start();
-
- auto sender = runtime.AllocateEdgeActor();
-
- runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
- runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
- runtime.Send(new IEventHandle(runtime.Resolver, sender, new TEvents::TEvPoison), 0, true);
- runtime.ExpectGetHostByNameError(sender, ARES_ECANCELLED);
- runtime.ExpectGetAddrError(sender, ARES_ECANCELLED);
- }
-
-}
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/builder.h>
+
+#include <ares.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+// FIXME: use a mock resolver
+Y_UNIT_TEST_SUITE(CachingDnsResolver) {
+
+ struct TAddrToString {
+ TString operator()(const std::monostate&) const {
+ return "<nothing>";
+ }
+
+ TString operator()(const struct in6_addr& addr) const {
+ char dst[INET6_ADDRSTRLEN];
+ auto res = ares_inet_ntop(AF_INET6, &addr, dst, INET6_ADDRSTRLEN);
+ Y_VERIFY(res, "Cannot convert ipv6 address");
+ return dst;
+ }
+
+ TString operator()(const struct in_addr& addr) const {
+ char dst[INET_ADDRSTRLEN];
+ auto res = ares_inet_ntop(AF_INET, &addr, dst, INET_ADDRSTRLEN);
+ Y_VERIFY(res, "Cannot convert ipv4 address");
+ return dst;
+ }
+ };
+
+ TString AddrToString(const std::variant<std::monostate, struct in6_addr, struct in_addr>& v) {
+ return std::visit(TAddrToString(), v);
+ }
+
+ struct TMockReply {
+ static constexpr TDuration DefaultDelay = TDuration::MilliSeconds(1);
+
+ int Status = 0;
+ TDuration Delay;
+ TVector<struct in6_addr> AddrsV6;
+ TVector<struct in_addr> AddrsV4;
+
+ static TMockReply Error(int status, TDuration delay = DefaultDelay) {
+ Y_VERIFY(status != 0);
+ TMockReply reply;
+ reply.Status = status;
+ reply.Delay = delay;
+ return reply;
+ }
+
+ static TMockReply Empty(TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ return reply;
+ }
+
+ static TMockReply ManyV6(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ for (const TString& addr : addrs) {
+ void* dst = &reply.AddrsV6.emplace_back();
+ int status = ares_inet_pton(AF_INET6, addr.c_str(), dst);
+ Y_VERIFY(status == 1, "Invalid ipv6 address: %s", addr.c_str());
+ }
+ return reply;
+ }
+
+ static TMockReply ManyV4(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ for (const TString& addr : addrs) {
+ void* dst = &reply.AddrsV4.emplace_back();
+ int status = ares_inet_pton(AF_INET, addr.c_str(), dst);
+ Y_VERIFY(status == 1, "Invalid ipv4 address: %s", addr.c_str());
+ }
+ return reply;
+ }
+
+ static TMockReply SingleV6(const TString& addr, TDuration delay = DefaultDelay) {
+ return ManyV6({ addr }, delay);
+ }
+
+ static TMockReply SingleV4(const TString& addr, TDuration delay = DefaultDelay) {
+ return ManyV4({ addr }, delay);
+ }
+ };
+
+ using TMockDnsCallback = std::function<TMockReply (const TString&, int)>;
+
+ class TMockDnsResolver : public TActor<TMockDnsResolver> {
+ public:
+ TMockDnsResolver(TMockDnsCallback callback)
+ : TActor(&TThis::StateWork)
+ , Callback(std::move(callback))
+ { }
+
+ private:
+ struct TEvPrivate {
+ enum EEv {
+ EvScheduled = EventSpaceBegin(TEvents::ES_PRIVATE),
+ };
+
+ struct TEvScheduled : public TEventLocal<TEvScheduled, EvScheduled> {
+ TActorId Sender;
+ ui64 Cookie;
+ TMockReply Reply;
+
+ TEvScheduled(TActorId sender, ui64 cookie, TMockReply reply)
+ : Sender(sender)
+ , Cookie(cookie)
+ , Reply(std::move(reply))
+ { }
+ };
+ };
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvPrivate::TEvScheduled, Handle);
+ });
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ PassAway();
+ }
+
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto reply = Callback(ev->Get()->Name, ev->Get()->Family);
+ if (reply.Delay) {
+ Schedule(reply.Delay, new TEvPrivate::TEvScheduled(ev->Sender, ev->Cookie, std::move(reply)));
+ } else {
+ SendReply(ev->Sender, ev->Cookie, std::move(reply));
+ }
+ }
+
+ void Handle(TEvPrivate::TEvScheduled::TPtr& ev) {
+ SendReply(ev->Get()->Sender, ev->Get()->Cookie, std::move(ev->Get()->Reply));
+ }
+
+ private:
+ void SendReply(const TActorId& sender, ui64 cookie, TMockReply&& reply) {
+ auto res = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ res->Status = reply.Status;
+ if (res->Status != 0) {
+ res->ErrorText = ares_strerror(res->Status);
+ } else {
+ res->AddrsV6 = std::move(reply.AddrsV6);
+ res->AddrsV4 = std::move(reply.AddrsV4);
+ }
+ Send(sender, res.Release(), 0, cookie);
+ }
+
+ private:
+ TMockDnsCallback Callback;
+ };
+
+ struct TCachingDnsRuntime : public TTestActorRuntimeBase {
+ TCachingDnsResolverOptions ResolverOptions;
+ TActorId MockResolver;
+ TActorId Resolver;
+ TActorId Sleeper;
+ TString Section_;
+
+ NMonitoring::TDynamicCounters::TCounterPtr InFlight6;
+ NMonitoring::TDynamicCounters::TCounterPtr InFlight4;
+ NMonitoring::TDynamicCounters::TCounterPtr Total6;
+ NMonitoring::TDynamicCounters::TCounterPtr Total4;
+ NMonitoring::TDynamicCounters::TCounterPtr Misses;
+ NMonitoring::TDynamicCounters::TCounterPtr Hits;
+
+ THashMap<TString, TMockReply> ReplyV6;
+ THashMap<TString, TMockReply> ReplyV4;
+
+ TCachingDnsRuntime() {
+ SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
+ ResolverOptions.MonCounters = new NMonitoring::TDynamicCounters;
+
+ ReplyV6["localhost"] = TMockReply::SingleV6("::1");
+ ReplyV4["localhost"] = TMockReply::SingleV4("127.0.0.1");
+ ReplyV6["yandex.ru"] = TMockReply::SingleV6("2a02:6b8:a::a", TDuration::MilliSeconds(500));
+ ReplyV4["yandex.ru"] = TMockReply::SingleV4("77.88.55.77", TDuration::MilliSeconds(250));
+ ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ENODATA);
+ ReplyV4["router.asus.com"] = TMockReply::SingleV4("192.168.0.1");
+ }
+
+ void Start(TMockDnsCallback callback) {
+ MockResolver = Register(new TMockDnsResolver(std::move(callback)));
+ EnableScheduleForActor(MockResolver);
+ Resolver = Register(CreateCachingDnsResolver(MockResolver, ResolverOptions));
+ Sleeper = AllocateEdgeActor();
+
+ InFlight6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false);
+ InFlight4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false);
+ Total6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V6", true);
+ Total4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V4", true);
+ Misses = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Misses", true);
+ Hits = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Hits", true);
+ }
+
+ void Start() {
+ Start([this](const TString& name, int family) {
+ switch (family) {
+ case AF_INET6: {
+ auto it = ReplyV6.find(name);
+ if (it != ReplyV6.end()) {
+ return it->second;
+ }
+ break;
+ }
+ case AF_INET: {
+ auto it = ReplyV4.find(name);
+ if (it != ReplyV4.end()) {
+ return it->second;
+ }
+ break;
+ }
+ }
+ return TMockReply::Error(ARES_ENOTFOUND);
+ });
+ }
+
+ void Section(const TString& section) {
+ Section_ = section;
+ }
+
+ void Sleep(TDuration duration) {
+ Schedule(new IEventHandle(Sleeper, Sleeper, new TEvents::TEvWakeup), duration);
+ GrabEdgeEventRethrow<TEvents::TEvWakeup>(Sleeper);
+ }
+
+ void WaitNoInFlight() {
+ if (*InFlight6 || *InFlight4) {
+ TDispatchOptions options;
+ options.CustomFinalCondition = [&]() {
+ return !*InFlight6 && !*InFlight4;
+ };
+ DispatchEvents(options);
+ UNIT_ASSERT_C(!*InFlight6 && !*InFlight4, "Failed to wait for no inflight in " << Section_);
+ }
+ }
+
+ void SendGetHostByName(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
+ Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetHostByName(name, family)), 0, true);
+ }
+
+ void SendGetAddr(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
+ Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetAddr(name, family)), 0, true);
+ }
+
+ TEvDns::TEvGetHostByNameResult::TPtr WaitGetHostByName(const TActorId& sender) {
+ return GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ }
+
+ TEvDns::TEvGetAddrResult::TPtr WaitGetAddr(const TActorId& sender) {
+ return GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
+ }
+
+ void ExpectInFlight6(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(InFlight6->Val(), count, Section_);
+ }
+
+ void ExpectInFlight4(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(InFlight4->Val(), count, Section_);
+ }
+
+ void ExpectTotal6(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Total6->Val(), count, Section_);
+ }
+
+ void ExpectTotal4(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Total4->Val(), count, Section_);
+ }
+
+ void Expect6(i64 total, i64 inflight) {
+ UNIT_ASSERT_C(
+ Total6->Val() == total && InFlight6->Val() == inflight,
+ Section_ << ": Expect6(" << total << ", " << inflight << ") "
+ << " but got (" << Total6->Val() << ", " << InFlight6->Val() << ")");
+ }
+
+ void Expect4(i64 total, i64 inflight) {
+ UNIT_ASSERT_C(
+ Total4->Val() == total && InFlight4->Val() == inflight,
+ Section_ << ": Expect4(" << total << ", " << inflight << ") "
+ << " got (" << Total4->Val() << ", " << InFlight4->Val() << ")");
+ }
+
+ void ExpectMisses(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Misses->Val(), count, Section_);
+ }
+
+ void ExpectHits(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Hits->Val(), count, Section_);
+ }
+
+ void ExpectGetHostByNameError(const TActorId& sender, int status) {
+ auto ev = WaitGetHostByName(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
+ }
+
+ void ExpectGetAddrError(const TActorId& sender, int status) {
+ auto ev = WaitGetAddr(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
+ }
+
+ void ExpectGetHostByNameSuccess(const TActorId& sender, const TString& expected) {
+ auto ev = WaitGetHostByName(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
+ TStringBuilder result;
+ for (const auto& addr : ev->Get()->AddrsV6) {
+ if (result) {
+ result << ',';
+ }
+ result << TAddrToString()(addr);
+ }
+ for (const auto& addr : ev->Get()->AddrsV4) {
+ if (result) {
+ result << ',';
+ }
+ result << TAddrToString()(addr);
+ }
+ UNIT_ASSERT_VALUES_EQUAL_C(TString(result), expected, Section_);
+ }
+
+ void ExpectGetAddrSuccess(const TActorId& sender, const TString& expected) {
+ auto ev = WaitGetAddr(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
+ TString result = AddrToString(ev->Get()->Addr);
+ UNIT_ASSERT_VALUES_EQUAL_C(result, expected, Section_);
+ }
+ };
+
+ Y_UNIT_TEST(UnusableResolver) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+
+ runtime.Send(new IEventHandle(runtime.MockResolver, { }, new TEvents::TEvPoison), 0, true);
+ runtime.SendGetAddr(sender, "foo.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTINITIALIZED);
+ }
+
+ Y_UNIT_TEST(ResolveCaching) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ // First time resolve, ipv4 and ipv6 sent in parallel, we wait for ipv6 result
+ runtime.Section("First time resolve");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(1, 0);
+ runtime.Expect4(1, 0);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(0);
+
+ // Second resolve, ipv6 and ipv4 queries result in a cache hit
+ runtime.Section("Second resolve, ipv6");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(1, 0);
+ runtime.ExpectHits(1);
+ runtime.Section("Second resolve, ipv4");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect4(1, 0);
+ runtime.ExpectHits(2);
+
+ // Wait until soft expiration and try ipv4 again
+ // Will cause a cache hit, but will start a new ipv4 request in background
+ runtime.Section("Retry ipv4 after soft expiration");
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect6(1, 0);
+ runtime.Expect4(2, 1);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(3);
+ runtime.WaitNoInFlight();
+
+ // Wait until soft expiration and try both again
+ // Will cause a cache hit, but will start a new ipv6 request in background
+ runtime.Section("Retry both after soft expiration");
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(2, 1);
+ runtime.Expect4(2, 0);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(4);
+ runtime.WaitNoInFlight();
+
+ // Wait until hard expiration and try both again
+ // Will cause a cache miss and new resolve requests
+ runtime.Section("Retry both after hard expiration");
+ runtime.Sleep(TDuration::Hours(2));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(3, 0);
+ runtime.Expect4(3, 0);
+ runtime.ExpectMisses(2);
+ runtime.ExpectHits(4);
+
+ // Wait half the hard expiration time, must always result in a cache hit
+ runtime.Section("Retry both after half hard expiration");
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Hours(1));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(3 + i, 1);
+ runtime.ExpectHits(4 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ // Change v6 result to a timeout, must keep using cached result until hard expiration
+ runtime.Section("Dns keeps timing out");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(7 + i, 1);
+ runtime.ExpectHits(8 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ // Change v6 result to nodata, must switch to a v4 result eventually
+ runtime.Section("Host changes to being ipv4 only");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENODATA);
+ runtime.Sleep(TDuration::Seconds(2));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect6(12, 0);
+ runtime.Expect4(4, 0);
+ runtime.ExpectMisses(3);
+
+ // Change v6 result to nxdomain, must not fall back to a v4 result
+ runtime.Section("Host is removed from dns");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(ResolveCachingV4) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.Section("First request");
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectMisses(1);
+
+ runtime.Section("Second request");
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectHits(1);
+
+ runtime.Section("Dns keeps timing out");
+ runtime.ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.Expect6(1 + i, 1);
+ runtime.Expect4(1 + i, 1);
+ runtime.ExpectHits(1 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ runtime.Section("Host is removed from ipv4 dns");
+ runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(EventualTimeout) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.ReplyV6["notfound.ru"] = TMockReply::Error(ARES_ENODATA);
+ runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+
+ runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ runtime.WaitNoInFlight();
+
+ bool timeout = false;
+ for (ui64 i = 1; i <= 8; ++i) {
+ runtime.Sleep(TDuration::Minutes(30));
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ auto ev = runtime.WaitGetAddr(sender);
+ if (ev->Get()->Status == ARES_ETIMEOUT && i > 2) {
+ timeout = true;
+ break;
+ }
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ENOTFOUND,
+ "Iteration " << i << ": " << ev->Get()->ErrorText);
+ }
+
+ UNIT_ASSERT_C(timeout, "DnsResolver did not reply with a timeout");
+ }
+
+ Y_UNIT_TEST(MultipleRequestsAndHosts) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "192.168.0.1");
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a");
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(DisabledIPv6) {
+ TCachingDnsRuntime runtime;
+ runtime.ResolverOptions.AllowIPv6 = false;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_INET6);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
+ runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
+ runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(DisabledIPv4) {
+ TCachingDnsRuntime runtime;
+ runtime.ResolverOptions.AllowIPv4 = false;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
+ runtime.ExpectGetAddrError(sender, ARES_ENODATA);
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_INET);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_INET);
+ runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
+ runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
+ runtime.ExpectGetAddrError(sender, ARES_ENODATA);
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(PoisonPill) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.Send(new IEventHandle(runtime.Resolver, sender, new TEvents::TEvPoison), 0, true);
+ runtime.ExpectGetHostByNameError(sender, ARES_ECANCELLED);
+ runtime.ExpectGetAddrError(sender, ARES_ECANCELLED);
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp
index 2025162e95..da3f364601 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp
@@ -1,64 +1,64 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/core/hfunc.h>
-
-namespace NActors {
-namespace NDnsResolver {
-
- class TOnDemandDnsResolver : public TActor<TOnDemandDnsResolver> {
- public:
- TOnDemandDnsResolver(TOnDemandDnsResolverOptions options)
- : TActor(&TThis::StateWork)
- , Options(std::move(options))
- { }
-
- static constexpr EActivityType ActorActivityType() {
- return DNS_RESOLVER;
- }
-
- private:
- STRICT_STFUNC(StateWork, {
- cFunc(TEvents::TEvPoison::EventType, PassAway);
- fFunc(TEvDns::TEvGetHostByName::EventType, Forward);
- fFunc(TEvDns::TEvGetAddr::EventType, Forward);
- });
-
- void Forward(STATEFN_SIG) {
- ev->Rewrite(ev->GetTypeRewrite(), GetUpstream());
- TActivationContext::Send(std::move(ev));
- }
-
- private:
- TActorId GetUpstream() {
- if (Y_UNLIKELY(!CachingResolverId)) {
- if (Y_LIKELY(!SimpleResolverId)) {
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TOnDemandDnsResolver : public TActor<TOnDemandDnsResolver> {
+ public:
+ TOnDemandDnsResolver(TOnDemandDnsResolverOptions options)
+ : TActor(&TThis::StateWork)
+ , Options(std::move(options))
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ cFunc(TEvents::TEvPoison::EventType, PassAway);
+ fFunc(TEvDns::TEvGetHostByName::EventType, Forward);
+ fFunc(TEvDns::TEvGetAddr::EventType, Forward);
+ });
+
+ void Forward(STATEFN_SIG) {
+ ev->Rewrite(ev->GetTypeRewrite(), GetUpstream());
+ TActivationContext::Send(std::move(ev));
+ }
+
+ private:
+ TActorId GetUpstream() {
+ if (Y_UNLIKELY(!CachingResolverId)) {
+ if (Y_LIKELY(!SimpleResolverId)) {
SimpleResolverId = RegisterWithSameMailbox(CreateSimpleDnsResolver(Options));
- }
+ }
CachingResolverId = RegisterWithSameMailbox(CreateCachingDnsResolver(SimpleResolverId, Options));
- }
- return CachingResolverId;
- }
-
- void PassAway() override {
- if (CachingResolverId) {
- Send(CachingResolverId, new TEvents::TEvPoison);
- CachingResolverId = { };
- }
- if (SimpleResolverId) {
- Send(SimpleResolverId, new TEvents::TEvPoison);
- SimpleResolverId = { };
- }
- }
-
- private:
- TOnDemandDnsResolverOptions Options;
- TActorId SimpleResolverId;
- TActorId CachingResolverId;
- };
-
- IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options) {
- return new TOnDemandDnsResolver(std::move(options));
- }
-
-} // namespace NDnsResolver
-} // namespace NActors
+ }
+ return CachingResolverId;
+ }
+
+ void PassAway() override {
+ if (CachingResolverId) {
+ Send(CachingResolverId, new TEvents::TEvPoison);
+ CachingResolverId = { };
+ }
+ if (SimpleResolverId) {
+ Send(SimpleResolverId, new TEvents::TEvPoison);
+ SimpleResolverId = { };
+ }
+ }
+
+ private:
+ TOnDemandDnsResolverOptions Options;
+ TActorId SimpleResolverId;
+ TActorId CachingResolverId;
+ };
+
+ IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options) {
+ return new TOnDemandDnsResolver(std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp
index 2758484552..ee6b4113f0 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp
@@ -1,24 +1,24 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/testlib/test_runtime.h>
-#include <library/cpp/testing/unittest/registar.h>
-
-using namespace NActors;
-using namespace NActors::NDnsResolver;
-
-Y_UNIT_TEST_SUITE(OnDemandDnsResolver) {
-
- Y_UNIT_TEST(ResolveLocalHost) {
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- auto resolver = runtime.Register(CreateOnDemandDnsResolver());
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
- 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
- size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
- UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
- }
-
-}
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+Y_UNIT_TEST_SUITE(OnDemandDnsResolver) {
+
+ Y_UNIT_TEST(ResolveLocalHost) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateOnDemandDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp
index 0c343a805c..86d2ae7a1c 100644
--- a/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp
@@ -1,98 +1,98 @@
-#include "dnsresolver.h"
-
-#include <library/cpp/actors/testlib/test_runtime.h>
-#include <library/cpp/testing/unittest/registar.h>
-#include <util/string/builder.h>
-
-#include <ares.h>
-
-using namespace NActors;
-using namespace NActors::NDnsResolver;
-
-Y_UNIT_TEST_SUITE(DnsResolver) {
-
- struct TSilentUdpServer {
- TInetDgramSocket Socket;
- ui16 Port;
-
- TSilentUdpServer() {
- TSockAddrInet addr("127.0.0.1", 0);
- int err = Socket.Bind(&addr);
- Y_VERIFY(err == 0, "Cannot bind a udp socket");
- Port = addr.GetPort();
- }
- };
-
- Y_UNIT_TEST(ResolveLocalHost) {
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- auto resolver = runtime.Register(CreateSimpleDnsResolver());
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
- 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
- size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
- UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
- }
-
- Y_UNIT_TEST(ResolveYandexRu) {
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- auto resolver = runtime.Register(CreateSimpleDnsResolver());
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)),
- 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
- size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
- UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
- }
-
- Y_UNIT_TEST(GetAddrYandexRu) {
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- auto resolver = runtime.Register(CreateSimpleDnsResolver());
-
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)),
- 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
- UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address");
- }
-
- Y_UNIT_TEST(ResolveTimeout) {
- TSilentUdpServer server;
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- TSimpleDnsResolverOptions options;
- options.Timeout = TDuration::MilliSeconds(250);
- options.Attempts = 2;
- options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
- auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
- 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ETIMEOUT, ev->Get()->ErrorText);
- }
-
- Y_UNIT_TEST(ResolveGracefulStop) {
- TSilentUdpServer server;
- TTestActorRuntimeBase runtime;
- runtime.Initialize();
- auto sender = runtime.AllocateEdgeActor();
- TSimpleDnsResolverOptions options;
- options.Timeout = TDuration::Seconds(5);
- options.Attempts = 5;
- options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
- auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
- runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
- 0, true);
- runtime.Send(new IEventHandle(resolver, sender, new TEvents::TEvPoison), 0, true);
- auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
- UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ECANCELLED, ev->Get()->ErrorText);
- }
-
-}
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/builder.h>
+
+#include <ares.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+Y_UNIT_TEST_SUITE(DnsResolver) {
+
+ struct TSilentUdpServer {
+ TInetDgramSocket Socket;
+ ui16 Port;
+
+ TSilentUdpServer() {
+ TSockAddrInet addr("127.0.0.1", 0);
+ int err = Socket.Bind(&addr);
+ Y_VERIFY(err == 0, "Cannot bind a udp socket");
+ Port = addr.GetPort();
+ }
+ };
+
+ Y_UNIT_TEST(ResolveLocalHost) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+ Y_UNIT_TEST(ResolveYandexRu) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+ Y_UNIT_TEST(GetAddrYandexRu) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address");
+ }
+
+ Y_UNIT_TEST(ResolveTimeout) {
+ TSilentUdpServer server;
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ TSimpleDnsResolverOptions options;
+ options.Timeout = TDuration::MilliSeconds(250);
+ options.Attempts = 2;
+ options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
+ auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ETIMEOUT, ev->Get()->ErrorText);
+ }
+
+ Y_UNIT_TEST(ResolveGracefulStop) {
+ TSilentUdpServer server;
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ TSimpleDnsResolverOptions options;
+ options.Timeout = TDuration::Seconds(5);
+ options.Attempts = 5;
+ options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
+ auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
+ 0, true);
+ runtime.Send(new IEventHandle(resolver, sender, new TEvents::TEvPoison), 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ECANCELLED, ev->Get()->ErrorText);
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/ut/ya.make b/library/cpp/actors/dnsresolver/ut/ya.make
index ad936bdacd..2af5f5f260 100644
--- a/library/cpp/actors/dnsresolver/ut/ya.make
+++ b/library/cpp/actors/dnsresolver/ut/ya.make
@@ -1,20 +1,20 @@
-UNITTEST_FOR(library/cpp/actors/dnsresolver)
-
-OWNER(g:kikimr)
-
-PEERDIR(
- library/cpp/actors/testlib
-)
-
-SRCS(
- dnsresolver_caching_ut.cpp
- dnsresolver_ondemand_ut.cpp
- dnsresolver_ut.cpp
-)
-
-ADDINCL(contrib/libs/c-ares)
-
-TAG(ya:external)
-REQUIREMENTS(network:full)
-
-END()
+UNITTEST_FOR(library/cpp/actors/dnsresolver)
+
+OWNER(g:kikimr)
+
+PEERDIR(
+ library/cpp/actors/testlib
+)
+
+SRCS(
+ dnsresolver_caching_ut.cpp
+ dnsresolver_ondemand_ut.cpp
+ dnsresolver_ut.cpp
+)
+
+ADDINCL(contrib/libs/c-ares)
+
+TAG(ya:external)
+REQUIREMENTS(network:full)
+
+END()
diff --git a/library/cpp/actors/dnsresolver/ya.make b/library/cpp/actors/dnsresolver/ya.make
index 329c56c5b3..7ee69fe4b5 100644
--- a/library/cpp/actors/dnsresolver/ya.make
+++ b/library/cpp/actors/dnsresolver/ya.make
@@ -1,20 +1,20 @@
-LIBRARY()
-
-OWNER(g:kikimr)
-
-SRCS(
- dnsresolver.cpp
- dnsresolver_caching.cpp
- dnsresolver_ondemand.cpp
-)
-
-PEERDIR(
- library/cpp/actors/core
- contrib/libs/c-ares
-)
-
-ADDINCL(contrib/libs/c-ares)
-
-END()
-
-RECURSE_FOR_TESTS(ut)
+LIBRARY()
+
+OWNER(g:kikimr)
+
+SRCS(
+ dnsresolver.cpp
+ dnsresolver_caching.cpp
+ dnsresolver_ondemand.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ contrib/libs/c-ares
+)
+
+ADDINCL(contrib/libs/c-ares)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/actors/interconnect/interconnect.h b/library/cpp/actors/interconnect/interconnect.h
index 225a5243fd..f885377d2d 100644
--- a/library/cpp/actors/interconnect/interconnect.h
+++ b/library/cpp/actors/interconnect/interconnect.h
@@ -133,7 +133,7 @@ namespace NActors {
const TIntrusivePtr<TTableNameserverSetup>& setup,
ui32 poolId = 0);
- /**
+ /**
* Name service which can be paired with external discovery service.
* Copies information from setup on the start (table may be empty).
* Handles TEvNodesInfo to change list of known nodes.
@@ -147,17 +147,17 @@ namespace NActors {
ui32 poolId = 0);
/**
- * Creates an actor that resolves host/port and replies with either:
- *
- * - TEvLocalNodeInfo on success
- * - TEvResolveError on errors
- *
- * Optional defaultAddress may be used as fallback.
- */
- IActor* CreateResolveActor(
- const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
-
+ * Creates an actor that resolves host/port and replies with either:
+ *
+ * - TEvLocalNodeInfo on success
+ * - TEvResolveError on errors
+ *
+ * Optional defaultAddress may be used as fallback.
+ */
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
+
inline IActor* CreateResolveActor(
ui32 nodeId, const TTableNameserverSetup::TNodeInfo& nodeInfo,
const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
@@ -166,14 +166,14 @@ namespace NActors {
replyTo, replyFrom, deadline);
}
- /**
- * Creates an actor that resolves host/port and replies with either:
- *
- * - TEvAddressInfo on success
- * - TEvResolveError on errors
- */
- IActor* CreateResolveActor(
- const TString& host, ui16 port,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
-
+ /**
+ * Creates an actor that resolves host/port and replies with either:
+ *
+ * - TEvAddressInfo on success
+ * - TEvResolveError on errors
+ */
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
+
}
diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp b/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp
index 43419bf70d..18f3f4aed3 100644
--- a/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp
+++ b/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp
@@ -17,7 +17,7 @@ namespace NActors {
return NAMESERVICE;
}
- TInterconnectNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 /*resolvePoolId*/)
+ TInterconnectNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 /*resolvePoolId*/)
: TInterconnectNameserverBase<TInterconnectNameserverTable>(&TInterconnectNameserverTable::StateFunc, setup->StaticNodeTable)
, Config(setup)
{
diff --git a/library/cpp/actors/interconnect/interconnect_resolve.cpp b/library/cpp/actors/interconnect/interconnect_resolve.cpp
index 14296194df..1f0ed84e30 100644
--- a/library/cpp/actors/interconnect/interconnect_resolve.cpp
+++ b/library/cpp/actors/interconnect/interconnect_resolve.cpp
@@ -1,174 +1,174 @@
-#include "interconnect.h"
-#include "interconnect_address.h"
-#include "events_local.h"
-
-#include <library/cpp/actors/core/actor_bootstrapped.h>
-#include <library/cpp/actors/core/hfunc.h>
-#include <library/cpp/actors/dnsresolver/dnsresolver.h>
-
-namespace NActors {
-
- using namespace NActors::NDnsResolver;
-
- class TInterconnectResolveActor : public TActorBootstrapped<TInterconnectResolveActor> {
- public:
- TInterconnectResolveActor(
- const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
- : Host(host)
- , NodeId(nodeId)
- , Port(port)
- , DefaultAddress(defaultAddress)
- , ReplyTo(replyTo)
- , ReplyFrom(replyFrom)
- , Deadline(deadline)
- { }
-
- TInterconnectResolveActor(
- const TString& host, ui16 port,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
- : Host(host)
- , Port(port)
- , ReplyTo(replyTo)
- , ReplyFrom(replyFrom)
- , Deadline(deadline)
- { }
-
- static constexpr EActivityType ActorActivityType() {
- return NAMESERVICE;
- }
-
- void Bootstrap() {
- TMaybe<TString> errorText;
- if (auto addr = ExtractDefaultAddr(errorText)) {
- return SendAddrAndDie(std::move(addr));
- }
-
- if (errorText) {
- SendErrorAndDie(*errorText);
- }
-
- auto now = TActivationContext::Now();
- if (Deadline < now) {
- SendErrorAndDie("Deadline");
- return;
- }
-
- Send(MakeDnsResolverActorId(),
- new TEvDns::TEvGetAddr(Host, AF_UNSPEC),
- IEventHandle::FlagTrackDelivery);
-
- if (Deadline != TInstant::Max()) {
- Schedule(Deadline, new TEvents::TEvWakeup);
- }
-
- Become(&TThis::StateWork);
- }
-
- STRICT_STFUNC(StateWork, {
- sFunc(TEvents::TEvWakeup, HandleTimeout);
- sFunc(TEvents::TEvUndelivered, HandleUndelivered);
- hFunc(TEvDns::TEvGetAddrResult, Handle);
- });
-
- void HandleTimeout() {
- SendErrorAndDie("Deadline");
- }
-
- void HandleUndelivered() {
- SendErrorAndDie("Dns resolver is unavailable");
- }
-
- void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) {
- if (auto addr = ExtractAddr(ev->Get())) {
- return SendAddrAndDie(std::move(addr));
- }
-
- SendErrorAndDie(ev->Get()->ErrorText);
- }
-
- void SendAddrAndDie(NAddr::IRemoteAddrPtr addr) {
- if (NodeId) {
- auto reply = new TEvLocalNodeInfo;
- reply->NodeId = *NodeId;
- reply->Address = std::move(addr);
- TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
- } else {
- auto reply = new TEvAddressInfo;
- reply->Address = std::move(addr);
- TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
- }
- PassAway();
- }
-
- void SendErrorAndDie(const TString& errorText) {
- auto *event = new TEvResolveError;
- event->Explain = errorText;
- TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, event));
- PassAway();
- }
-
- NAddr::IRemoteAddrPtr ExtractAddr(TEvDns::TEvGetAddrResult* msg) {
- if (msg->Status == 0) {
- if (msg->IsV6()) {
- struct sockaddr_in6 sin6;
- Zero(sin6);
- sin6.sin6_family = AF_INET6;
- sin6.sin6_addr = msg->GetAddrV6();
- sin6.sin6_port = HostToInet(Port);
- return MakeHolder<NAddr::TIPv6Addr>(sin6);
- }
-
- if (msg->IsV4()) {
- return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(msg->GetAddrV4().s_addr, Port));
- }
-
- Y_FAIL("Unexpected result address family");
- }
-
- return nullptr;
- }
-
- NAddr::IRemoteAddrPtr ExtractDefaultAddr(TMaybe<TString>& errorText) {
- if (DefaultAddress) {
- NInterconnect::TAddress address(DefaultAddress.data(), Port);
-
- switch (address.GetFamily()) {
- case AF_INET:
- return MakeHolder<NAddr::TIPv4Addr>(*(sockaddr_in*)address.SockAddr());
- case AF_INET6:
- return MakeHolder<NAddr::TIPv6Addr>(*(sockaddr_in6*)address.SockAddr());
- default:
- errorText = "Unsupported default address: " + DefaultAddress;
- break;
- }
- }
-
- return nullptr;
- }
-
- private:
- const TString Host;
- const std::optional<ui32> NodeId;
- const ui16 Port;
- const TString DefaultAddress;
- const TActorId ReplyTo;
- const TActorId ReplyFrom;
- const TInstant Deadline;
- };
-
- IActor* CreateResolveActor(
- const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
- {
- return new TInterconnectResolveActor(host, port, nodeId, defaultAddress, replyTo, replyFrom, deadline);
- }
-
- IActor* CreateResolveActor(
- const TString& host, ui16 port,
- const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
- {
- return new TInterconnectResolveActor(host, port, replyTo, replyFrom, deadline);
- }
-
-} // namespace NActors
+#include "interconnect.h"
+#include "interconnect_address.h"
+#include "events_local.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/dnsresolver/dnsresolver.h>
+
+namespace NActors {
+
+ using namespace NActors::NDnsResolver;
+
+ class TInterconnectResolveActor : public TActorBootstrapped<TInterconnectResolveActor> {
+ public:
+ TInterconnectResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ : Host(host)
+ , NodeId(nodeId)
+ , Port(port)
+ , DefaultAddress(defaultAddress)
+ , ReplyTo(replyTo)
+ , ReplyFrom(replyFrom)
+ , Deadline(deadline)
+ { }
+
+ TInterconnectResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ : Host(host)
+ , Port(port)
+ , ReplyTo(replyTo)
+ , ReplyFrom(replyFrom)
+ , Deadline(deadline)
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return NAMESERVICE;
+ }
+
+ void Bootstrap() {
+ TMaybe<TString> errorText;
+ if (auto addr = ExtractDefaultAddr(errorText)) {
+ return SendAddrAndDie(std::move(addr));
+ }
+
+ if (errorText) {
+ SendErrorAndDie(*errorText);
+ }
+
+ auto now = TActivationContext::Now();
+ if (Deadline < now) {
+ SendErrorAndDie("Deadline");
+ return;
+ }
+
+ Send(MakeDnsResolverActorId(),
+ new TEvDns::TEvGetAddr(Host, AF_UNSPEC),
+ IEventHandle::FlagTrackDelivery);
+
+ if (Deadline != TInstant::Max()) {
+ Schedule(Deadline, new TEvents::TEvWakeup);
+ }
+
+ Become(&TThis::StateWork);
+ }
+
+ STRICT_STFUNC(StateWork, {
+ sFunc(TEvents::TEvWakeup, HandleTimeout);
+ sFunc(TEvents::TEvUndelivered, HandleUndelivered);
+ hFunc(TEvDns::TEvGetAddrResult, Handle);
+ });
+
+ void HandleTimeout() {
+ SendErrorAndDie("Deadline");
+ }
+
+ void HandleUndelivered() {
+ SendErrorAndDie("Dns resolver is unavailable");
+ }
+
+ void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) {
+ if (auto addr = ExtractAddr(ev->Get())) {
+ return SendAddrAndDie(std::move(addr));
+ }
+
+ SendErrorAndDie(ev->Get()->ErrorText);
+ }
+
+ void SendAddrAndDie(NAddr::IRemoteAddrPtr addr) {
+ if (NodeId) {
+ auto reply = new TEvLocalNodeInfo;
+ reply->NodeId = *NodeId;
+ reply->Address = std::move(addr);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ } else {
+ auto reply = new TEvAddressInfo;
+ reply->Address = std::move(addr);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ }
+ PassAway();
+ }
+
+ void SendErrorAndDie(const TString& errorText) {
+ auto *event = new TEvResolveError;
+ event->Explain = errorText;
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, event));
+ PassAway();
+ }
+
+ NAddr::IRemoteAddrPtr ExtractAddr(TEvDns::TEvGetAddrResult* msg) {
+ if (msg->Status == 0) {
+ if (msg->IsV6()) {
+ struct sockaddr_in6 sin6;
+ Zero(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = msg->GetAddrV6();
+ sin6.sin6_port = HostToInet(Port);
+ return MakeHolder<NAddr::TIPv6Addr>(sin6);
+ }
+
+ if (msg->IsV4()) {
+ return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(msg->GetAddrV4().s_addr, Port));
+ }
+
+ Y_FAIL("Unexpected result address family");
+ }
+
+ return nullptr;
+ }
+
+ NAddr::IRemoteAddrPtr ExtractDefaultAddr(TMaybe<TString>& errorText) {
+ if (DefaultAddress) {
+ NInterconnect::TAddress address(DefaultAddress.data(), Port);
+
+ switch (address.GetFamily()) {
+ case AF_INET:
+ return MakeHolder<NAddr::TIPv4Addr>(*(sockaddr_in*)address.SockAddr());
+ case AF_INET6:
+ return MakeHolder<NAddr::TIPv6Addr>(*(sockaddr_in6*)address.SockAddr());
+ default:
+ errorText = "Unsupported default address: " + DefaultAddress;
+ break;
+ }
+ }
+
+ return nullptr;
+ }
+
+ private:
+ const TString Host;
+ const std::optional<ui32> NodeId;
+ const ui16 Port;
+ const TString DefaultAddress;
+ const TActorId ReplyTo;
+ const TActorId ReplyFrom;
+ const TInstant Deadline;
+ };
+
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ {
+ return new TInterconnectResolveActor(host, port, nodeId, defaultAddress, replyTo, replyFrom, deadline);
+ }
+
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ {
+ return new TInterconnectResolveActor(host, port, replyTo, replyFrom, deadline);
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp b/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp
index 7e2d8ccb94..a634fd804b 100644
--- a/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp
+++ b/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp
@@ -43,7 +43,7 @@ namespace NActors {
PassAwayTimestamp = TActivationContext::Now() + TDuration::Seconds(15);
LOG_INFO_IC("ICP01", "ready to work");
- }
+ }
void TInterconnectProxyTCP::Registered(TActorSystem* sys, const TActorId& owner) {
if (!DynamicPtr) {
@@ -53,7 +53,7 @@ namespace NActors {
if (const auto& mon = Common->RegisterMonPage) {
TString path = Sprintf("peer%04" PRIu32, PeerNodeId);
TString title = Sprintf("Peer #%04" PRIu32, PeerNodeId);
- mon(path, title, sys, SelfId());
+ mon(path, title, sys, SelfId());
}
}
@@ -508,14 +508,14 @@ namespace NActors {
switch (ev->GetTypeRewrite()) {
case TEvInterconnect::EvForward:
if (ev->Flags & IEventHandle::FlagSubscribeOnSession) {
- Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
+ Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
}
TActivationContext::Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::Disconnected));
break;
case TEvInterconnect::TEvConnectNode::EventType:
case TEvents::TEvSubscribe::EventType:
- Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
+ Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
break;
case TEvents::TEvUnsubscribe::EventType:
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp
index 2ded7f9f53..8767bd68ce 100644
--- a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp
+++ b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp
@@ -82,8 +82,8 @@ namespace NActors {
IActor::InvokeOtherActor(*Proxy, &TInterconnectProxyTCP::UnregisterSession, this);
ShutdownSocket(std::move(reason));
- for (const auto& kv : Subscribers) {
- Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
+ for (const auto& kv : Subscribers) {
+ Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
}
Proxy->Metrics->SubSubscribersCount(Subscribers.size());
Subscribers.clear();
@@ -186,13 +186,13 @@ namespace NActors {
void TInterconnectSessionTCP::Subscribe(STATEFN_SIG) {
LOG_DEBUG_IC_SESSION("ICS04", "subscribe for session state for %s", ev->Sender.ToString().data());
- const auto [it, inserted] = Subscribers.emplace(ev->Sender, ev->Cookie);
+ const auto [it, inserted] = Subscribers.emplace(ev->Sender, ev->Cookie);
if (inserted) {
Proxy->Metrics->IncSubscribersCount();
- } else {
- it->second = ev->Cookie;
+ } else {
+ it->second = ev->Cookie;
}
- Send(ev->Sender, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, ev->Cookie);
+ Send(ev->Sender, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, ev->Cookie);
}
void TInterconnectSessionTCP::Unsubscribe(STATEFN_SIG) {
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.h b/library/cpp/actors/interconnect/interconnect_tcp_session.h
index 7fc00dbcc5..76357187b0 100644
--- a/library/cpp/actors/interconnect/interconnect_tcp_session.h
+++ b/library/cpp/actors/interconnect/interconnect_tcp_session.h
@@ -477,7 +477,7 @@ namespace NActors {
ui32 SendBufferSize;
ui64 InflightDataAmount = 0;
- std::unordered_map<TActorId, ui64, TActorId::THash> Subscribers;
+ std::unordered_map<TActorId, ui64, TActorId::THash> Subscribers;
// time at which we want to send confirmation packet even if there was no outgoing data
ui64 UnconfirmedBytes = 0;
diff --git a/library/cpp/actors/interconnect/mock/ic_mock.cpp b/library/cpp/actors/interconnect/mock/ic_mock.cpp
index 884503e602..275a02e551 100644
--- a/library/cpp/actors/interconnect/mock/ic_mock.cpp
+++ b/library/cpp/actors/interconnect/mock/ic_mock.cpp
@@ -95,7 +95,7 @@ namespace NActors {
class TProxyMockActor : public TActor<TProxyMockActor> {
class TSessionMockActor : public TActor<TSessionMockActor> {
- std::map<TActorId, ui64> Subscribers;
+ std::map<TActorId, ui64> Subscribers;
TProxyMockActor* const Proxy;
std::deque<std::unique_ptr<IEventHandle>> Queue;
@@ -113,8 +113,8 @@ namespace NActors {
for (auto&& ev : std::exchange(Queue, {})) {
TActivationContext::Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::Disconnected));
}
- for (const auto& kv : Subscribers) {
- Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
+ for (const auto& kv : Subscribers) {
+ Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
}
Y_VERIFY(Proxy->Session == this);
Proxy->Session = nullptr;
@@ -123,7 +123,7 @@ namespace NActors {
void HandleForward(TAutoPtr<IEventHandle> ev) {
if (ev->Flags & IEventHandle::FlagSubscribeOnSession) {
- Subscribe(ev->Sender, ev->Cookie);
+ Subscribe(ev->Sender, ev->Cookie);
}
if (Queue.empty()) {
TActivationContext::Send(new IEventHandle(EvRam, 0, SelfId(), {}, {}, 0));
@@ -140,11 +140,11 @@ namespace NActors {
}
void Handle(TEvInterconnect::TEvConnectNode::TPtr ev) {
- Subscribe(ev->Sender, ev->Cookie);
+ Subscribe(ev->Sender, ev->Cookie);
}
void Handle(TEvents::TEvSubscribe::TPtr ev) {
- Subscribe(ev->Sender, ev->Cookie);
+ Subscribe(ev->Sender, ev->Cookie);
}
void Handle(TEvents::TEvUnsubscribe::TPtr ev) {
@@ -165,9 +165,9 @@ namespace NActors {
)
private:
- void Subscribe(const TActorId& actorId, ui64 cookie) {
- Subscribers[actorId] = cookie;
- Send(actorId, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, cookie);
+ void Subscribe(const TActorId& actorId, ui64 cookie) {
+ Subscribers[actorId] = cookie;
+ Send(actorId, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, cookie);
}
};
diff --git a/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h b/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h
index 2b6d27cd3f..5b3c8f1dcc 100644
--- a/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h
+++ b/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h
@@ -25,7 +25,7 @@ private:
THashMap<ui32, THolder<TNode>> Nodes;
TList<TTrafficInterrupter> interrupters;
NActors::TChannelsConfig ChannelsConfig;
- TPortManager PortManager;
+ TPortManager PortManager;
public:
TTestICCluster(ui32 numNodes = 1, NActors::TChannelsConfig channelsConfig = NActors::TChannelsConfig(),
@@ -38,7 +38,7 @@ public:
THashMap<ui32, THashMap<ui32, ui16>> specificNodePortMap;
for (ui32 i = 1; i <= NumNodes; ++i) {
- nodeToPortMap.emplace(i, PortManager.GetPort());
+ nodeToPortMap.emplace(i, PortManager.GetPort());
}
if (tiSettings) {
@@ -48,7 +48,7 @@ public:
for (auto& item : nodeToPortMap) {
nodeId = item.first;
listenPort = item.second;
- forwardPort = PortManager.GetPort();
+ forwardPort = PortManager.GetPort();
specificNodePortMap[nodeId] = nodeToPortMap;
specificNodePortMap[nodeId].at(nodeId) = forwardPort;
diff --git a/library/cpp/actors/interconnect/ut/lib/node.h b/library/cpp/actors/interconnect/ut/lib/node.h
index ff30b1445e..12087fbe32 100644
--- a/library/cpp/actors/interconnect/ut/lib/node.h
+++ b/library/cpp/actors/interconnect/ut/lib/node.h
@@ -4,7 +4,7 @@
#include <library/cpp/actors/core/executor_pool_basic.h>
#include <library/cpp/actors/core/scheduler_basic.h>
#include <library/cpp/actors/core/mailbox.h>
-#include <library/cpp/actors/dnsresolver/dnsresolver.h>
+#include <library/cpp/actors/dnsresolver/dnsresolver.h>
#include <library/cpp/actors/interconnect/interconnect_tcp_server.h>
#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
@@ -91,7 +91,7 @@ public:
for (ui32 i = 1; i <= numNodes; ++i) {
names->StaticNodeTable[i] = TTableNameserverSetup::TNodeInfo(address, address, nodeToPort.at(i));
}
- setup.LocalServices.emplace_back(
+ setup.LocalServices.emplace_back(
NDnsResolver::MakeDnsResolverActorId(),
TActorSetupCmd(
NDnsResolver::CreateOnDemandDnsResolver(),
@@ -111,7 +111,7 @@ public:
}
~TNode() {
- ActorSystem->Stop();
+ ActorSystem->Stop();
}
bool Send(const TActorId& recipient, IEventBase* ev) {
diff --git a/library/cpp/actors/interconnect/ya.make b/library/cpp/actors/interconnect/ya.make
index 60d29b0fc0..01a57c3aa2 100644
--- a/library/cpp/actors/interconnect/ya.make
+++ b/library/cpp/actors/interconnect/ya.make
@@ -33,7 +33,7 @@ SRCS(
interconnect_nameserver_table.cpp
interconnect_proxy_wrapper.cpp
interconnect_proxy_wrapper.h
- interconnect_resolve.cpp
+ interconnect_resolve.cpp
interconnect_stream.cpp
interconnect_stream.h
interconnect_tcp_input_session.cpp
@@ -76,7 +76,7 @@ PEERDIR(
contrib/libs/openssl
library/cpp/actors/core
library/cpp/actors/dnscachelib
- library/cpp/actors/dnsresolver
+ library/cpp/actors/dnsresolver
library/cpp/actors/helpers
library/cpp/actors/prof
library/cpp/actors/protos
diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp
index 6fa25b9965..cf93742d21 100644
--- a/library/cpp/actors/testlib/test_runtime.cpp
+++ b/library/cpp/actors/testlib/test_runtime.cpp
@@ -58,7 +58,7 @@ namespace NActors {
TTestActorRuntimeBase::TNodeDataBase::TNodeDataBase() {
ActorSystemTimestamp = nullptr;
- ActorSystemMonotonic = nullptr;
+ ActorSystemMonotonic = nullptr;
}
void TTestActorRuntimeBase::TNodeDataBase::Stop() {
@@ -210,10 +210,10 @@ namespace NActors {
return Scheduled.empty();
}
- TInstant TEventMailBox::GetFirstScheduleDeadline() const {
- return Scheduled.begin()->Deadline;
- }
-
+ TInstant TEventMailBox::GetFirstScheduleDeadline() const {
+ return Scheduled.begin()->Deadline;
+ }
+
ui64 TEventMailBox::GetSentEventCount() const {
return Sent.size();
}
@@ -245,7 +245,7 @@ namespace NActors {
void Prepare(TActorSystem *actorSystem, volatile ui64 *currentTimestamp, volatile ui64 *currentMonotonic) override {
Y_UNUSED(actorSystem);
Node->ActorSystemTimestamp = currentTimestamp;
- Node->ActorSystemMonotonic = currentMonotonic;
+ Node->ActorSystemMonotonic = currentMonotonic;
}
void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override {
@@ -299,8 +299,8 @@ namespace NActors {
void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override {
DoSchedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, workerId);
- }
-
+ }
+
void Schedule(TDuration delay, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override {
TInstant deadline = Runtime->GetTimeProvider()->Now() + delay;
DoSchedule(deadline, ev, cookie, workerId);
@@ -467,7 +467,7 @@ namespace NActors {
, LocalId(0)
, DispatchCyclesCount(0)
, DispatchedEventsCount(0)
- , NeedMonitoring(false)
+ , NeedMonitoring(false)
, RandomProvider(CreateDeterministicRandomProvider(DefaultRandomSeed))
, TimeProvider(new TTimeProvider(*this))
, ShouldContinue()
@@ -490,7 +490,7 @@ namespace NActors {
node->LogSettings = new NActors::NLog::TSettings(loggerActorId, 410 /* NKikimrServices::LOGGER */,
NActors::NLog::PRI_WARN, NActors::NLog::PRI_WARN, 0);
node->LogSettings->SetAllowDrop(false);
- node->LogSettings->SetThrottleDelay(TDuration::Zero());
+ node->LogSettings->SetThrottleDelay(TDuration::Zero());
node->DynamicCounters = new NMonitoring::TDynamicCounters;
InitNodeImpl(node, nodeIndex);
@@ -572,9 +572,9 @@ namespace NActors {
bool TTestActorRuntimeBase::NopFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline) {
Y_UNUSED(runtime);
- Y_UNUSED(delay);
+ Y_UNUSED(delay);
Y_UNUSED(event);
- Y_UNUSED(deadline);
+ Y_UNUSED(deadline);
return true;
}
@@ -843,14 +843,14 @@ namespace NActors {
}
ui32 TTestActorRuntimeBase::InterconnectPoolId() const {
- if (UseRealThreads && NSan::TSanIsOn()) {
- // Interconnect coroutines may move across threads
- // Use a special single-threaded pool to avoid that
- return 4;
- }
- return 0;
- }
-
+ if (UseRealThreads && NSan::TSanIsOn()) {
+ // Interconnect coroutines may move across threads
+ // Use a special single-threaded pool to avoid that
+ return 4;
+ }
+ return 0;
+ }
+
TString TTestActorRuntimeBase::GetTempDir() {
if (!TmpDir)
TmpDir.Reset(new TTempDir());
@@ -967,7 +967,7 @@ namespace NActors {
Y_VERIFY(nodeIndex < NodeCount);
TActorId edgeActor = Register(new TEdgeActor(this), nodeIndex);
EdgeActors.insert(edgeActor);
- EdgeActorByMailbox[TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint())] = edgeActor;
+ EdgeActorByMailbox[TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint())] = edgeActor;
return edgeActor;
}
@@ -1161,15 +1161,15 @@ namespace NActors {
if (mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
bool isEdgeMailbox = false;
- if (EdgeActorByMailbox.FindPtr(TEventMailboxId(mbox.first.NodeId, mbox.first.Hint))) {
- isEdgeMailbox = true;
- TEventsList events;
- mbox.second->Capture(events);
- for (auto& ev : events) {
- TInverseGuard<TMutex> inverseGuard(Mutex);
- ObserverFunc(*this, ev);
+ if (EdgeActorByMailbox.FindPtr(TEventMailboxId(mbox.first.NodeId, mbox.first.Hint))) {
+ isEdgeMailbox = true;
+ TEventsList events;
+ mbox.second->Capture(events);
+ for (auto& ev : events) {
+ TInverseGuard<TMutex> inverseGuard(Mutex);
+ ObserverFunc(*this, ev);
}
- mbox.second->PushFront(events);
+ mbox.second->PushFront(events);
}
if (!isEdgeMailbox) {
@@ -1246,8 +1246,8 @@ namespace NActors {
}
}
- if (localContext.FinalEventFound) {
- return true;
+ if (localContext.FinalEventFound) {
+ return true;
}
if (!localContext.FoundNonEmptyMailboxes.empty())
@@ -1287,8 +1287,8 @@ namespace NActors {
inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval;
bool isEmpty = true;
TMaybe<TInstant> nearestMailboxDeadline;
- TVector<TIntrusivePtr<TEventMailBox>> nextScheduleMboxes;
- TMaybe<TInstant> nextScheduleDeadline;
+ TVector<TIntrusivePtr<TEventMailBox>> nextScheduleMboxes;
+ TMaybe<TInstant> nextScheduleDeadline;
for (auto& mbox : currentMailboxes) {
if (!mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
if (!nearestMailboxDeadline.Defined() || *nearestMailboxDeadline.Get() > mbox.second->GetInactiveUntil()) {
@@ -1301,29 +1301,29 @@ namespace NActors {
if (mbox.second->IsScheduledEmpty())
continue;
- auto firstScheduleDeadline = mbox.second->GetFirstScheduleDeadline();
- if (!nextScheduleDeadline || firstScheduleDeadline < *nextScheduleDeadline) {
- nextScheduleMboxes.clear();
- nextScheduleMboxes.emplace_back(mbox.second);
- nextScheduleDeadline = firstScheduleDeadline;
- } else if (firstScheduleDeadline == *nextScheduleDeadline) {
- nextScheduleMboxes.emplace_back(mbox.second);
- }
- }
-
- for (const auto& nextScheduleMbox : nextScheduleMboxes) {
+ auto firstScheduleDeadline = mbox.second->GetFirstScheduleDeadline();
+ if (!nextScheduleDeadline || firstScheduleDeadline < *nextScheduleDeadline) {
+ nextScheduleMboxes.clear();
+ nextScheduleMboxes.emplace_back(mbox.second);
+ nextScheduleDeadline = firstScheduleDeadline;
+ } else if (firstScheduleDeadline == *nextScheduleDeadline) {
+ nextScheduleMboxes.emplace_back(mbox.second);
+ }
+ }
+
+ for (const auto& nextScheduleMbox : nextScheduleMboxes) {
TEventsList selectedEvents;
TScheduledEventsList capturedScheduledEvents;
- nextScheduleMbox->CaptureScheduled(capturedScheduledEvents);
+ nextScheduleMbox->CaptureScheduled(capturedScheduledEvents);
ScheduledEventsSelectorFunc(*this, capturedScheduledEvents, selectedEvents);
- nextScheduleMbox->PushScheduled(capturedScheduledEvents);
+ nextScheduleMbox->PushScheduled(capturedScheduledEvents);
for (auto& event : selectedEvents) {
if (verbose && (BlockedOutput.find(event->Sender) == BlockedOutput.end())) {
Cerr << "Selected scheduled event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
PrintEvent(event, this);
}
- nextScheduleMbox->Send(event);
+ nextScheduleMbox->Send(event);
isEmpty = false;
}
}
@@ -1371,10 +1371,10 @@ namespace NActors {
while (context) {
for (const auto& finalEvent : context->Options->FinalEvents) {
if (finalEvent.EventCheck(ev)) {
- auto& freq = context->FinalEventFrequency[&finalEvent];
- if (++freq >= finalEvent.RequiredCount) {
- context->FinalEventFound = true;
- }
+ auto& freq = context->FinalEventFrequency[&finalEvent];
+ if (++freq >= finalEvent.RequiredCount) {
+ context->FinalEventFound = true;
+ }
}
}
@@ -1424,15 +1424,15 @@ namespace NActors {
void TTestActorRuntimeBase::WaitForEdgeEvents(TEventFilter filter, const TSet<TActorId>& edgeFilter, TDuration simTimeout) {
TGuard<TMutex> guard(Mutex);
ui32 dispatchCount = 0;
- if (!edgeFilter.empty()) {
- for (auto edgeActor : edgeFilter) {
+ if (!edgeFilter.empty()) {
+ for (auto edgeActor : edgeFilter) {
Y_VERIFY(EdgeActors.contains(edgeActor), "%s is not an edge actor", ToString(edgeActor).data());
- }
- }
+ }
+ }
const TSet<TActorId>& edgeActors = edgeFilter.empty() ? EdgeActors : edgeFilter;
- TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + simTimeout;
+ TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + simTimeout;
for (;;) {
- for (auto edgeActor : edgeActors) {
+ for (auto edgeActor : edgeActors) {
TEventsList events;
auto& mbox = GetMailbox(edgeActor.NodeId(), edgeActor.Hint());
bool foundEvent = false;
@@ -1451,7 +1451,7 @@ namespace NActors {
++dispatchCount;
{
- if (!DispatchEventsInternal(TDispatchOptions(), deadline)) {
+ if (!DispatchEventsInternal(TDispatchOptions(), deadline)) {
return; // Timed out; event was not found
}
}
@@ -1522,8 +1522,8 @@ namespace NActors {
return node->DynamicCounters;
}
- void TTestActorRuntimeBase::SetupMonitoring() {
- NeedMonitoring = true;
+ void TTestActorRuntimeBase::SetupMonitoring() {
+ NeedMonitoring = true;
}
void TTestActorRuntimeBase::SendInternal(IEventHandle* ev, ui32 nodeIndex, bool viaActorSystem) {
@@ -1612,13 +1612,13 @@ namespace NActors {
setup->NodeId = FirstNodeId + nodeIndex;
if (UseRealThreads) {
- setup->ExecutorsCount = 5;
- setup->Executors.Reset(new TAutoPtr<IExecutorPool>[5]);
+ setup->ExecutorsCount = 5;
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[5]);
setup->Executors[0].Reset(new TBasicExecutorPool(0, 2, 20));
setup->Executors[1].Reset(new TBasicExecutorPool(1, 2, 20));
setup->Executors[2].Reset(new TIOExecutorPool(2, 1));
setup->Executors[3].Reset(new TBasicExecutorPool(3, 2, 20));
- setup->Executors[4].Reset(new TBasicExecutorPool(4, 1, 20));
+ setup->Executors[4].Reset(new TBasicExecutorPool(4, 1, 20));
setup->Scheduler.Reset(new TBasicSchedulerThread(TSchedulerConfig(512, 100)));
} else {
setup->ExecutorsCount = 1;
@@ -1652,14 +1652,14 @@ namespace NActors {
common->MonCounters = interconnectCounters;
common->TechnicalSelfHostName = "::1";
- if (!UseRealThreads) {
+ if (!UseRealThreads) {
common->Settings.DeadPeer = TDuration::Max();
common->Settings.CloseOnIdle = TDuration::Max();
common->Settings.PingPeriod = TDuration::Max();
common->Settings.ForceConfirmPeriod = TDuration::Max();
common->Settings.Handshake = TDuration::Max();
- }
-
+ }
+
common->ClusterUUID = ClusterUUID;
common->AcceptUUID = {ClusterUUID};
@@ -1677,7 +1677,7 @@ namespace NActors {
}
setup->Interconnect.ProxyWrapperFactory = CreateProxyWrapperFactory(common, InterconnectPoolId(), &InterconnectMock);
-
+
if (UseRealInterconnect) {
setup->LocalServices.emplace_back(MakePollerActorId(), NActors::TActorSetupCmd(CreatePollerActor(),
NActors::TMailboxType::Simple, InterconnectPoolId()));
diff --git a/library/cpp/actors/testlib/test_runtime.h b/library/cpp/actors/testlib/test_runtime.h
index 26e3b45c98..387b386df3 100644
--- a/library/cpp/actors/testlib/test_runtime.h
+++ b/library/cpp/actors/testlib/test_runtime.h
@@ -16,7 +16,7 @@
#include <util/datetime/base.h>
#include <util/folder/tempdir.h>
#include <util/generic/deque.h>
-#include <util/generic/hash.h>
+#include <util/generic/hash.h>
#include <util/generic/noncopyable.h>
#include <util/generic/ptr.h>
#include <util/generic/queue.h>
@@ -62,12 +62,12 @@ namespace NActors {
return (NodeId == other.NodeId) && (Hint == other.Hint);
}
- struct THash {
- ui64 operator()(const TEventMailboxId& mboxId) const noexcept {
- return mboxId.NodeId * 31ULL + mboxId.Hint;
- }
- };
-
+ struct THash {
+ ui64 operator()(const TEventMailboxId& mboxId) const noexcept {
+ return mboxId.NodeId * 31ULL + mboxId.Hint;
+ }
+ };
+
ui32 NodeId;
ui32 Hint;
};
@@ -150,7 +150,7 @@ namespace NActors {
TInstant GetInactiveUntil() const;
void Schedule(const TScheduledEventQueueItem& item);
bool IsScheduledEmpty() const;
- TInstant GetFirstScheduleDeadline() const;
+ TInstant GetFirstScheduleDeadline() const;
ui64 GetSentEventCount() const;
private:
@@ -164,7 +164,7 @@ namespace NActors {
#endif
};
- typedef THashMap<TEventMailboxId, TIntrusivePtr<TEventMailBox>, TEventMailboxId::THash> TEventMailBoxList;
+ typedef THashMap<TEventMailboxId, TIntrusivePtr<TEventMailBox>, TEventMailboxId::THash> TEventMailBoxList;
class TEmptyEventQueueException : public yexception {
public:
@@ -237,7 +237,7 @@ namespace NActors {
ui32 GetNodeId(ui32 index = 0) const;
ui32 GetNodeCount() const;
ui64 AllocateLocalId();
- ui32 InterconnectPoolId() const;
+ ui32 InterconnectPoolId() const;
TString GetTempDir();
TActorId Register(IActor* actor, ui32 nodeIndex = 0, ui32 poolId = 0,
TMailboxType::EType mailboxType = TMailboxType::Simple, ui64 revolvingCounter = 0,
@@ -268,7 +268,7 @@ namespace NActors {
void EnableScheduleForActor(const TActorId& actorId, bool allow = true);
bool IsScheduleForActorEnabled(const TActorId& actorId) const;
TIntrusivePtr<NMonitoring::TDynamicCounters> GetDynamicCounters(ui32 nodeIndex = 0);
- void SetupMonitoring();
+ void SetupMonitoring();
template<typename T>
void AppendToLogSettings(NLog::EComponent minVal, NLog::EComponent maxVal, T func) {
@@ -303,7 +303,7 @@ namespace NActors {
}
return false;
- }, {}, simTimeout);
+ }, {}, simTimeout);
if (simTimeout == TDuration::Max())
Y_VERIFY(handle);
@@ -315,44 +315,44 @@ namespace NActors {
}
}
- template<class TEvent>
- typename TEvent::TPtr GrabEdgeEventIf(
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventIf(
const TSet<TActorId>& edgeFilter,
- const std::function<bool(const typename TEvent::TPtr&)>& predicate,
- TDuration simTimeout = TDuration::Max())
- {
- typename TEvent::TPtr handle;
- const ui32 eventType = TEvent::EventType;
+ const std::function<bool(const typename TEvent::TPtr&)>& predicate,
+ TDuration simTimeout = TDuration::Max())
+ {
+ typename TEvent::TPtr handle;
+ const ui32 eventType = TEvent::EventType;
WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) {
- Y_UNUSED(runtime);
- if (event->GetTypeRewrite() != eventType)
- return false;
-
- typename TEvent::TPtr* typedEvent = reinterpret_cast<typename TEvent::TPtr*>(&event);
- if (predicate(*typedEvent)) {
- handle = *typedEvent;
- return true;
- }
-
- return false;
- }, edgeFilter, simTimeout);
-
- if (simTimeout == TDuration::Max())
- Y_VERIFY(handle);
-
- return handle;
- }
-
- template<class TEvent>
- typename TEvent::TPtr GrabEdgeEventIf(
+ Y_UNUSED(runtime);
+ if (event->GetTypeRewrite() != eventType)
+ return false;
+
+ typename TEvent::TPtr* typedEvent = reinterpret_cast<typename TEvent::TPtr*>(&event);
+ if (predicate(*typedEvent)) {
+ handle = *typedEvent;
+ return true;
+ }
+
+ return false;
+ }, edgeFilter, simTimeout);
+
+ if (simTimeout == TDuration::Max())
+ Y_VERIFY(handle);
+
+ return handle;
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventIf(
const TActorId& edgeActor,
- const std::function<bool(const typename TEvent::TPtr&)>& predicate,
- TDuration simTimeout = TDuration::Max())
- {
+ const std::function<bool(const typename TEvent::TPtr&)>& predicate,
+ TDuration simTimeout = TDuration::Max())
+ {
TSet<TActorId> edgeFilter{edgeActor};
- return GrabEdgeEventIf<TEvent>(edgeFilter, predicate, simTimeout);
- }
-
+ return GrabEdgeEventIf<TEvent>(edgeFilter, predicate, simTimeout);
+ }
+
template <typename TEvent>
TEvent* GrabEdgeEvent(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; };
@@ -367,17 +367,17 @@ namespace NActors {
return THolder(handle ? handle->Release<TEvent>().Release() : nullptr);
}
- template<class TEvent>
+ template<class TEvent>
typename TEvent::TPtr GrabEdgeEvent(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) {
- return GrabEdgeEventIf<TEvent>(edgeFilter, [](const typename TEvent::TPtr&) { return true; }, simTimeout);
- }
-
- template<class TEvent>
+ return GrabEdgeEventIf<TEvent>(edgeFilter, [](const typename TEvent::TPtr&) { return true; }, simTimeout);
+ }
+
+ template<class TEvent>
typename TEvent::TPtr GrabEdgeEvent(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) {
TSet<TActorId> edgeFilter{edgeActor};
- return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
- }
-
+ return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
+ }
+
// replace with std::variant<>
template <typename... TEvents>
std::tuple<TEvents*...> GrabEdgeEvents(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
@@ -388,7 +388,7 @@ namespace NActors {
return false;
handle = event;
return true;
- }, {}, simTimeout);
+ }, {}, simTimeout);
if (simTimeout == TDuration::Max())
Y_VERIFY(handle);
if (handle) {
@@ -408,24 +408,24 @@ namespace NActors {
}
}
- template<class TEvent>
+ template<class TEvent>
typename TEvent::TPtr GrabEdgeEventRethrow(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) {
- try {
- return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
- } catch (...) {
- ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
- }
- }
-
- template<class TEvent>
+ try {
+ return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ template<class TEvent>
typename TEvent::TPtr GrabEdgeEventRethrow(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) {
- try {
- return GrabEdgeEvent<TEvent>(edgeActor, simTimeout);
- } catch (...) {
- ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
- }
- }
-
+ try {
+ return GrabEdgeEvent<TEvent>(edgeActor, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
template <typename... TEvents>
static TString TypeNames() {
static TString names[] = { TypeName<TEvents>()... };
@@ -530,7 +530,7 @@ namespace NActors {
ui64 DispatcherRandomSeed;
TIntrusivePtr<IRandomProvider> DispatcherRandomProvider;
TAutoPtr<TLogBackend> LogBackend;
- bool NeedMonitoring;
+ bool NeedMonitoring;
TIntrusivePtr<IRandomProvider> RandomProvider;
TIntrusivePtr<ITimeProvider> TimeProvider;
@@ -558,7 +558,7 @@ namespace NActors {
TIntrusivePtr<NActors::NLog::TSettings> LogSettings;
TIntrusivePtr<NInterconnect::TPollerThreads> Poller;
volatile ui64* ActorSystemTimestamp;
- volatile ui64* ActorSystemMonotonic;
+ volatile ui64* ActorSystemMonotonic;
TVector<std::pair<TActorId, TActorSetupCmd> > LocalServices;
TMap<TActorId, IActor*> LocalServicesActors;
TMap<IActor*, TActorId> ActorToActorId;
@@ -607,7 +607,7 @@ namespace NActors {
TMap<const TDispatchOptions::TFinalEventCondition*, ui32> FinalEventFrequency;
TSet<TEventMailboxId> FoundNonEmptyMailboxes;
- bool FinalEventFound = false;
+ bool FinalEventFound = false;
};
TProgramShouldContinue ShouldContinue;
diff --git a/library/cpp/actors/util/unordered_cache.h b/library/cpp/actors/util/unordered_cache.h
index 76f036c0cf..6b1b4f838a 100644
--- a/library/cpp/actors/util/unordered_cache.h
+++ b/library/cpp/actors/util/unordered_cache.h
@@ -3,126 +3,126 @@
#include "defs.h"
#include "queue_chunk.h"
-template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>>
+template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>>
class TUnorderedCache : TNonCopyable {
static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
public:
- static constexpr ui32 Concurrency = ConcurrencyFactor * 4;
+ static constexpr ui32 Concurrency = ConcurrencyFactor * 4;
private:
- struct TReadSlot {
- TChunk* volatile ReadFrom;
- volatile ui32 ReadPosition;
- char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
- };
-
- struct TWriteSlot {
- TChunk* volatile WriteTo;
- volatile ui32 WritePosition;
- char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
- };
-
- static_assert(sizeof(TReadSlot) == 64, "expect sizeof(TReadSlot) == 64");
- static_assert(sizeof(TWriteSlot) == 64, "expect sizeof(TWriteSlot) == 64");
-
-private:
- TReadSlot ReadSlots[Concurrency];
- TWriteSlot WriteSlots[Concurrency];
-
+ struct TReadSlot {
+ TChunk* volatile ReadFrom;
+ volatile ui32 ReadPosition;
+ char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
+ };
+
+ struct TWriteSlot {
+ TChunk* volatile WriteTo;
+ volatile ui32 WritePosition;
+ char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
+ };
+
+ static_assert(sizeof(TReadSlot) == 64, "expect sizeof(TReadSlot) == 64");
+ static_assert(sizeof(TWriteSlot) == 64, "expect sizeof(TWriteSlot) == 64");
+
+private:
+ TReadSlot ReadSlots[Concurrency];
+ TWriteSlot WriteSlots[Concurrency];
+
static_assert(sizeof(TChunk*) == sizeof(TAtomic), "expect sizeof(TChunk*) == sizeof(TAtomic)");
-private:
- struct TLockedWriter {
- TWriteSlot* Slot;
- TChunk* WriteTo;
-
- TLockedWriter()
- : Slot(nullptr)
- , WriteTo(nullptr)
- { }
-
- TLockedWriter(TWriteSlot* slot, TChunk* writeTo)
- : Slot(slot)
- , WriteTo(writeTo)
- { }
-
- ~TLockedWriter() noexcept {
- Drop();
- }
-
- void Drop() {
- if (Slot) {
- AtomicStore(&Slot->WriteTo, WriteTo);
- Slot = nullptr;
- }
- }
-
- TLockedWriter(const TLockedWriter&) = delete;
- TLockedWriter& operator=(const TLockedWriter&) = delete;
-
- TLockedWriter(TLockedWriter&& rhs)
- : Slot(rhs.Slot)
- , WriteTo(rhs.WriteTo)
- {
- rhs.Slot = nullptr;
- }
-
- TLockedWriter& operator=(TLockedWriter&& rhs) {
- if (Y_LIKELY(this != &rhs)) {
- Drop();
- Slot = rhs.Slot;
- WriteTo = rhs.WriteTo;
- rhs.Slot = nullptr;
- }
- return *this;
- }
- };
-
-private:
- TLockedWriter LockWriter(ui64 writerRotation) {
- ui32 cycle = 0;
+private:
+ struct TLockedWriter {
+ TWriteSlot* Slot;
+ TChunk* WriteTo;
+
+ TLockedWriter()
+ : Slot(nullptr)
+ , WriteTo(nullptr)
+ { }
+
+ TLockedWriter(TWriteSlot* slot, TChunk* writeTo)
+ : Slot(slot)
+ , WriteTo(writeTo)
+ { }
+
+ ~TLockedWriter() noexcept {
+ Drop();
+ }
+
+ void Drop() {
+ if (Slot) {
+ AtomicStore(&Slot->WriteTo, WriteTo);
+ Slot = nullptr;
+ }
+ }
+
+ TLockedWriter(const TLockedWriter&) = delete;
+ TLockedWriter& operator=(const TLockedWriter&) = delete;
+
+ TLockedWriter(TLockedWriter&& rhs)
+ : Slot(rhs.Slot)
+ , WriteTo(rhs.WriteTo)
+ {
+ rhs.Slot = nullptr;
+ }
+
+ TLockedWriter& operator=(TLockedWriter&& rhs) {
+ if (Y_LIKELY(this != &rhs)) {
+ Drop();
+ Slot = rhs.Slot;
+ WriteTo = rhs.WriteTo;
+ rhs.Slot = nullptr;
+ }
+ return *this;
+ }
+ };
+
+private:
+ TLockedWriter LockWriter(ui64 writerRotation) {
+ ui32 cycle = 0;
for (;;) {
- TWriteSlot* slot = &WriteSlots[writerRotation % Concurrency];
- if (AtomicLoad(&slot->WriteTo) != nullptr) {
- if (TChunk* writeTo = AtomicSwap(&slot->WriteTo, nullptr)) {
- return TLockedWriter(slot, writeTo);
+ TWriteSlot* slot = &WriteSlots[writerRotation % Concurrency];
+ if (AtomicLoad(&slot->WriteTo) != nullptr) {
+ if (TChunk* writeTo = AtomicSwap(&slot->WriteTo, nullptr)) {
+ return TLockedWriter(slot, writeTo);
}
}
- ++writerRotation;
-
- // Do a spinlock pause after a full cycle
- if (++cycle == Concurrency) {
- SpinLockPause();
- cycle = 0;
- }
- }
+ ++writerRotation;
+
+ // Do a spinlock pause after a full cycle
+ if (++cycle == Concurrency) {
+ SpinLockPause();
+ cycle = 0;
+ }
+ }
}
- void WriteOne(TLockedWriter& lock, T x) {
+ void WriteOne(TLockedWriter& lock, T x) {
Y_VERIFY_DEBUG(x != 0);
- const ui32 pos = AtomicLoad(&lock.Slot->WritePosition);
+ const ui32 pos = AtomicLoad(&lock.Slot->WritePosition);
if (pos != TChunk::EntriesCount) {
- AtomicStore(&lock.Slot->WritePosition, pos + 1);
- AtomicStore(&lock.WriteTo->Entries[pos], x);
+ AtomicStore(&lock.Slot->WritePosition, pos + 1);
+ AtomicStore(&lock.WriteTo->Entries[pos], x);
} else {
- TChunk* next = new TChunk();
+ TChunk* next = new TChunk();
AtomicStore(&next->Entries[0], x);
- AtomicStore(&lock.Slot->WritePosition, 1u);
- AtomicStore(&lock.WriteTo->Next, next);
- lock.WriteTo = next;
+ AtomicStore(&lock.Slot->WritePosition, 1u);
+ AtomicStore(&lock.WriteTo->Next, next);
+ lock.WriteTo = next;
}
}
public:
- TUnorderedCache() {
- for (ui32 i = 0; i < Concurrency; ++i) {
- ReadSlots[i].ReadFrom = new TChunk();
- ReadSlots[i].ReadPosition = 0;
+ TUnorderedCache() {
+ for (ui32 i = 0; i < Concurrency; ++i) {
+ ReadSlots[i].ReadFrom = new TChunk();
+ ReadSlots[i].ReadPosition = 0;
- WriteSlots[i].WriteTo = ReadSlots[i].ReadFrom;
- WriteSlots[i].WritePosition = 0;
+ WriteSlots[i].WriteTo = ReadSlots[i].ReadFrom;
+ WriteSlots[i].WritePosition = 0;
}
}
@@ -130,44 +130,44 @@ public:
Y_VERIFY(!Pop(0));
for (ui64 i = 0; i < Concurrency; ++i) {
- if (ReadSlots[i].ReadFrom) {
- delete ReadSlots[i].ReadFrom;
- ReadSlots[i].ReadFrom = nullptr;
+ if (ReadSlots[i].ReadFrom) {
+ delete ReadSlots[i].ReadFrom;
+ ReadSlots[i].ReadFrom = nullptr;
}
- WriteSlots[i].WriteTo = nullptr;
+ WriteSlots[i].WriteTo = nullptr;
}
}
- T Pop(ui64 readerRotation) noexcept {
+ T Pop(ui64 readerRotation) noexcept {
ui64 readerIndex = readerRotation;
const ui64 endIndex = readerIndex + Concurrency;
for (; readerIndex != endIndex; ++readerIndex) {
- TReadSlot* slot = &ReadSlots[readerIndex % Concurrency];
- if (AtomicLoad(&slot->ReadFrom) != nullptr) {
- if (TChunk* readFrom = AtomicSwap(&slot->ReadFrom, nullptr)) {
- const ui32 pos = AtomicLoad(&slot->ReadPosition);
+ TReadSlot* slot = &ReadSlots[readerIndex % Concurrency];
+ if (AtomicLoad(&slot->ReadFrom) != nullptr) {
+ if (TChunk* readFrom = AtomicSwap(&slot->ReadFrom, nullptr)) {
+ const ui32 pos = AtomicLoad(&slot->ReadPosition);
if (pos != TChunk::EntriesCount) {
if (T ret = AtomicLoad(&readFrom->Entries[pos])) {
- AtomicStore(&slot->ReadPosition, pos + 1);
- AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
- return ret; // found, return
+ AtomicStore(&slot->ReadPosition, pos + 1);
+ AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
+ return ret; // found, return
} else {
- AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
+ AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
}
} else if (TChunk* next = AtomicLoad(&readFrom->Next)) {
if (T ret = AtomicLoad(&next->Entries[0])) {
- AtomicStore(&slot->ReadPosition, 1u);
- AtomicStore(&slot->ReadFrom, next); // release lock with next chunk
+ AtomicStore(&slot->ReadPosition, 1u);
+ AtomicStore(&slot->ReadFrom, next); // release lock with next chunk
delete readFrom;
return ret;
} else {
- AtomicStore(&slot->ReadPosition, 0u);
- AtomicStore(&slot->ReadFrom, next); // release lock with new chunk
+ AtomicStore(&slot->ReadPosition, 0u);
+ AtomicStore(&slot->ReadFrom, next); // release lock with new chunk
delete readFrom;
}
} else {
- // nothing in old chunk and no next chunk, just release lock with old chunk
- AtomicStore(&slot->ReadFrom, readFrom);
+ // nothing in old chunk and no next chunk, just release lock with old chunk
+ AtomicStore(&slot->ReadFrom, readFrom);
}
}
}
@@ -177,20 +177,20 @@ public:
}
void Push(T x, ui64 writerRotation) {
- TLockedWriter lock = LockWriter(writerRotation);
- WriteOne(lock, x);
+ TLockedWriter lock = LockWriter(writerRotation);
+ WriteOne(lock, x);
}
void PushBulk(T* x, ui32 xcount, ui64 writerRotation) {
- for (;;) {
- // Fill no more then one queue chunk per round
+ for (;;) {
+ // Fill no more then one queue chunk per round
const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount);
- {
- TLockedWriter lock = LockWriter(writerRotation++);
- for (T* end = x + xround; x != end; ++x)
- WriteOne(lock, *x);
- }
+ {
+ TLockedWriter lock = LockWriter(writerRotation++);
+ for (T* end = x + xround; x != end; ++x)
+ WriteOne(lock, *x);
+ }
if (xcount <= TChunk::EntriesCount)
break;
diff --git a/library/cpp/actors/util/unordered_cache_ut.cpp b/library/cpp/actors/util/unordered_cache_ut.cpp
index 37865f2f91..8f15f9c3d5 100644
--- a/library/cpp/actors/util/unordered_cache_ut.cpp
+++ b/library/cpp/actors/util/unordered_cache_ut.cpp
@@ -1,138 +1,138 @@
-#include "unordered_cache.h"
-
-#include <library/cpp/testing/unittest/registar.h>
-#include <util/random/random.h>
-#include <util/system/hp_timer.h>
-#include <util/system/sanitizers.h>
-#include <util/system/thread.h>
-
-Y_UNIT_TEST_SUITE(UnorderedCache) {
-
- void DoOnePushOnePop(ui64 count) {
- TUnorderedCache<ui64> queue;
-
- ui64 readRotation = 0;
- ui64 writeRotation = 0;
-
- auto popped = queue.Pop(readRotation++);
- UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
-
- for (ui64 i = 0; i < count; ++i) {
- queue.Push(i + 1, writeRotation++);
- popped = queue.Pop(readRotation++);
- UNIT_ASSERT_VALUES_EQUAL(popped, i + 1);
-
- popped = queue.Pop(readRotation++);
- UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
- }
- }
-
- Y_UNIT_TEST(OnePushOnePop) {
- DoOnePushOnePop(1);
- }
-
- Y_UNIT_TEST(OnePushOnePop_Repeat1M) {
- DoOnePushOnePop(1000000);
- }
-
- /**
- * Simplified thread spawning for testing
- */
- class TWorkerThread : public ISimpleThread {
- private:
- std::function<void()> Func;
- double Time = 0.0;
-
- public:
- TWorkerThread(std::function<void()> func)
- : Func(std::move(func))
- { }
-
- double GetTime() const {
- return Time;
- }
-
- static THolder<TWorkerThread> Spawn(std::function<void()> func) {
- THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func));
- thread->Start();
- return thread;
- }
-
- private:
- void* ThreadProc() noexcept override {
- THPTimer timer;
- Func();
- Time = timer.Passed();
- return nullptr;
- }
- };
-
- void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) {
- // Concurrency factor 4 is up to 16 threads
- TUnorderedCache<ui64, 512, 4> queue;
-
- auto workerFunc = [&](size_t threadIndex) {
- ui64 readRotation = 0;
- ui64 writeRotation = 0;
- ui64 readsDone = 0;
- ui64 writesDone = 0;
- for (;;) {
- bool canRead = readsDone < writesDone;
- bool canWrite = writesDone < perThreadCount;
- if (!canRead && !canWrite) {
- break;
- }
- if (canRead && canWrite) {
- // Randomly choose between read and write
- if (RandomNumber<ui64>(2)) {
- canRead = false;
- } else {
- canWrite = false;
- }
- }
- if (canRead) {
- ui64 popped = queue.Pop(readRotation++);
- if (popped) {
- ++readsDone;
- }
- }
- if (canWrite) {
- queue.Push(1 + writesDone * threads + threadIndex, writeRotation++);
- ++writesDone;
- }
- }
- };
-
- TVector<THolder<TWorkerThread>> workers(threads);
- for (size_t i = 0; i < threads; ++i) {
- workers[i] = TWorkerThread::Spawn([workerFunc, i]() {
- workerFunc(i);
- });
- }
-
- double maxTime = 0;
- for (size_t i = 0; i < threads; ++i) {
- workers[i]->Join();
- maxTime = Max(maxTime, workers[i]->GetTime());
- }
-
- auto popped = queue.Pop(0);
- UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
-
- Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl;
- }
-
- void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) {
- for (size_t i = 0; i < 3; ++i) {
- DoConcurrentPushPop(threads, perThreadCount);
- }
- }
-
- static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000);
-
- Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); }
- Y_UNIT_TEST(ConcurrentPushPop_2threads) { DoConcurrentPushPop_3times(2, PER_THREAD_COUNT); }
- Y_UNIT_TEST(ConcurrentPushPop_4threads) { DoConcurrentPushPop_3times(4, PER_THREAD_COUNT); }
- Y_UNIT_TEST(ConcurrentPushPop_8threads) { DoConcurrentPushPop_3times(8, PER_THREAD_COUNT); }
- Y_UNIT_TEST(ConcurrentPushPop_16threads) { DoConcurrentPushPop_3times(16, PER_THREAD_COUNT); }
-}
+#include "unordered_cache.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+#include <util/system/hp_timer.h>
+#include <util/system/sanitizers.h>
+#include <util/system/thread.h>
+
+Y_UNIT_TEST_SUITE(UnorderedCache) {
+
+ void DoOnePushOnePop(ui64 count) {
+ TUnorderedCache<ui64> queue;
+
+ ui64 readRotation = 0;
+ ui64 writeRotation = 0;
+
+ auto popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+
+ for (ui64 i = 0; i < count; ++i) {
+ queue.Push(i + 1, writeRotation++);
+ popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, i + 1);
+
+ popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+ }
+ }
+
+ Y_UNIT_TEST(OnePushOnePop) {
+ DoOnePushOnePop(1);
+ }
+
+ Y_UNIT_TEST(OnePushOnePop_Repeat1M) {
+ DoOnePushOnePop(1000000);
+ }
+
+ /**
+ * Simplified thread spawning for testing
+ */
+ class TWorkerThread : public ISimpleThread {
+ private:
+ std::function<void()> Func;
+ double Time = 0.0;
+
+ public:
+ TWorkerThread(std::function<void()> func)
+ : Func(std::move(func))
+ { }
+
+ double GetTime() const {
+ return Time;
+ }
+
+ static THolder<TWorkerThread> Spawn(std::function<void()> func) {
+ THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func));
+ thread->Start();
+ return thread;
+ }
+
+ private:
+ void* ThreadProc() noexcept override {
+ THPTimer timer;
+ Func();
+ Time = timer.Passed();
+ return nullptr;
+ }
+ };
+
+ void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) {
+ // Concurrency factor 4 is up to 16 threads
+ TUnorderedCache<ui64, 512, 4> queue;
+
+ auto workerFunc = [&](size_t threadIndex) {
+ ui64 readRotation = 0;
+ ui64 writeRotation = 0;
+ ui64 readsDone = 0;
+ ui64 writesDone = 0;
+ for (;;) {
+ bool canRead = readsDone < writesDone;
+ bool canWrite = writesDone < perThreadCount;
+ if (!canRead && !canWrite) {
+ break;
+ }
+ if (canRead && canWrite) {
+ // Randomly choose between read and write
+ if (RandomNumber<ui64>(2)) {
+ canRead = false;
+ } else {
+ canWrite = false;
+ }
+ }
+ if (canRead) {
+ ui64 popped = queue.Pop(readRotation++);
+ if (popped) {
+ ++readsDone;
+ }
+ }
+ if (canWrite) {
+ queue.Push(1 + writesDone * threads + threadIndex, writeRotation++);
+ ++writesDone;
+ }
+ }
+ };
+
+ TVector<THolder<TWorkerThread>> workers(threads);
+ for (size_t i = 0; i < threads; ++i) {
+ workers[i] = TWorkerThread::Spawn([workerFunc, i]() {
+ workerFunc(i);
+ });
+ }
+
+ double maxTime = 0;
+ for (size_t i = 0; i < threads; ++i) {
+ workers[i]->Join();
+ maxTime = Max(maxTime, workers[i]->GetTime());
+ }
+
+ auto popped = queue.Pop(0);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+
+ Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl;
+ }
+
+ void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) {
+ for (size_t i = 0; i < 3; ++i) {
+ DoConcurrentPushPop(threads, perThreadCount);
+ }
+ }
+
+ static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000);
+
+ Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_2threads) { DoConcurrentPushPop_3times(2, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_4threads) { DoConcurrentPushPop_3times(4, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_8threads) { DoConcurrentPushPop_3times(8, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_16threads) { DoConcurrentPushPop_3times(16, PER_THREAD_COUNT); }
+}
diff --git a/library/cpp/actors/util/ut/ya.make b/library/cpp/actors/util/ut/ya.make
index 3b08b77984..5546525c3a 100644
--- a/library/cpp/actors/util/ut/ya.make
+++ b/library/cpp/actors/util/ut/ya.make
@@ -12,7 +12,7 @@ OWNER(
SRCS(
rope_ut.cpp
- unordered_cache_ut.cpp
+ unordered_cache_ut.cpp
)
END()
diff --git a/library/cpp/actors/ya.make b/library/cpp/actors/ya.make
index 737c7fbc18..7d7eb1fa85 100644
--- a/library/cpp/actors/ya.make
+++ b/library/cpp/actors/ya.make
@@ -3,7 +3,7 @@ RECURSE_FOR_TESTS(ut)
RECURSE(
log_backend
core
- dnsresolver
+ dnsresolver
examples
memory_log
helpers
diff --git a/library/cpp/execprofile/profile.cpp b/library/cpp/execprofile/profile.cpp
index d05de20203..be1fc21670 100644
--- a/library/cpp/execprofile/profile.cpp
+++ b/library/cpp/execprofile/profile.cpp
@@ -188,11 +188,11 @@ private:
#endif
#elif defined _darwin_
#if defined _64_
-#if defined(_arm_)
- return (void*)(*mctx)->__ss.__pc;
-#else
+#if defined(_arm_)
+ return (void*)(*mctx)->__ss.__pc;
+#else
return (void*)(*mctx)->__ss.__rip;
-#endif
+#endif
#else
#if defined(__IOS__)
return (void*)(*mctx)->__ss.__pc;
diff --git a/library/cpp/grpc/client/grpc_client_low.cpp b/library/cpp/grpc/client/grpc_client_low.cpp
index 73cc908ef8..bba83aee02 100644
--- a/library/cpp/grpc/client/grpc_client_low.cpp
+++ b/library/cpp/grpc/client/grpc_client_low.cpp
@@ -193,214 +193,214 @@ static void PullEvents(grpc::CompletionQueue* cq) {
}
}
-class TGRpcClientLow::TContextImpl final
- : public std::enable_shared_from_this<TContextImpl>
- , public IQueueClientContext
-{
- friend class TGRpcClientLow;
-
- using TCallback = std::function<void()>;
- using TContextPtr = std::shared_ptr<TContextImpl>;
-
-public:
+class TGRpcClientLow::TContextImpl final
+ : public std::enable_shared_from_this<TContextImpl>
+ , public IQueueClientContext
+{
+ friend class TGRpcClientLow;
+
+ using TCallback = std::function<void()>;
+ using TContextPtr = std::shared_ptr<TContextImpl>;
+
+public:
~TContextImpl() override {
- Y_VERIFY(CountChildren() == 0,
- "Destructor called with non-empty children");
-
- if (Parent) {
- Parent->ForgetContext(this);
- } else if (Y_LIKELY(Owner)) {
- Owner->ForgetContext(this);
- }
- }
-
- /**
- * Helper for locking child pointer from a parent container
- */
- static TContextPtr LockChildPtr(TContextImpl* ptr) {
- if (ptr) {
- // N.B. it is safe to do as long as it's done under a mutex and
- // pointer is among valid children. When that's the case we
- // know that TContextImpl destructor has not finished yet, so
- // the object is valid. The lock() method may return nullptr
- // though, if the object is being destructed right now.
- return ptr->weak_from_this().lock();
- } else {
- return nullptr;
- }
- }
-
- void ForgetContext(TContextImpl* child) {
- std::unique_lock<std::mutex> guard(Mutex);
-
- auto removed = RemoveChild(child);
- Y_VERIFY(removed, "Unexpected ForgetContext(%p)", child);
- }
-
- IQueueClientContextPtr CreateContext() override {
- auto self = shared_from_this();
- auto child = std::make_shared<TContextImpl>();
-
- {
- std::unique_lock<std::mutex> guard(Mutex);
-
- AddChild(child.get());
-
- // It's now safe to initialize parent and owner
- child->Parent = std::move(self);
- child->Owner = Owner;
+ Y_VERIFY(CountChildren() == 0,
+ "Destructor called with non-empty children");
+
+ if (Parent) {
+ Parent->ForgetContext(this);
+ } else if (Y_LIKELY(Owner)) {
+ Owner->ForgetContext(this);
+ }
+ }
+
+ /**
+ * Helper for locking child pointer from a parent container
+ */
+ static TContextPtr LockChildPtr(TContextImpl* ptr) {
+ if (ptr) {
+ // N.B. it is safe to do as long as it's done under a mutex and
+ // pointer is among valid children. When that's the case we
+ // know that TContextImpl destructor has not finished yet, so
+ // the object is valid. The lock() method may return nullptr
+ // though, if the object is being destructed right now.
+ return ptr->weak_from_this().lock();
+ } else {
+ return nullptr;
+ }
+ }
+
+ void ForgetContext(TContextImpl* child) {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ auto removed = RemoveChild(child);
+ Y_VERIFY(removed, "Unexpected ForgetContext(%p)", child);
+ }
+
+ IQueueClientContextPtr CreateContext() override {
+ auto self = shared_from_this();
+ auto child = std::make_shared<TContextImpl>();
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ AddChild(child.get());
+
+ // It's now safe to initialize parent and owner
+ child->Parent = std::move(self);
+ child->Owner = Owner;
child->CQ = CQ;
-
- // Propagate cancellation to a child context
- if (Cancelled.load(std::memory_order_relaxed)) {
- child->Cancelled.store(true, std::memory_order_relaxed);
- }
- }
-
- return child;
- }
-
- grpc::CompletionQueue* CompletionQueue() override {
- Y_VERIFY(Owner, "Uninitialized context");
+
+ // Propagate cancellation to a child context
+ if (Cancelled.load(std::memory_order_relaxed)) {
+ child->Cancelled.store(true, std::memory_order_relaxed);
+ }
+ }
+
+ return child;
+ }
+
+ grpc::CompletionQueue* CompletionQueue() override {
+ Y_VERIFY(Owner, "Uninitialized context");
return CQ;
- }
-
- bool IsCancelled() const override {
- return Cancelled.load(std::memory_order_acquire);
- }
-
- bool Cancel() override {
- TStackVec<TCallback, 1> callbacks;
- TStackVec<TContextPtr, 2> children;
-
- {
- std::unique_lock<std::mutex> guard(Mutex);
-
- if (Cancelled.load(std::memory_order_relaxed)) {
- // Already cancelled in another thread
- return false;
- }
-
- callbacks.reserve(Callbacks.size());
- children.reserve(CountChildren());
-
- for (auto& callback : Callbacks) {
- callbacks.emplace_back().swap(callback);
- }
- Callbacks.clear();
-
- // Collect all children we need to cancel
- // N.B. we don't clear children links (cleared by destructors)
- // N.B. some children may be stuck in destructors at the moment
- for (TContextImpl* ptr : InlineChildren) {
- if (auto child = LockChildPtr(ptr)) {
- children.emplace_back(std::move(child));
- }
- }
- for (auto* ptr : Children) {
- if (auto child = LockChildPtr(ptr)) {
- children.emplace_back(std::move(child));
- }
- }
-
- Cancelled.store(true, std::memory_order_release);
- }
-
- // Call directly subscribed callbacks
- if (callbacks) {
- RunCallbacksNoExcept(callbacks);
- }
-
- // Cancel all children
- for (auto& child : children) {
- child->Cancel();
- child.reset();
- }
-
- return true;
- }
-
- void SubscribeCancel(TCallback callback) override {
- Y_VERIFY(callback, "SubscribeCancel called with an empty callback");
-
- {
- std::unique_lock<std::mutex> guard(Mutex);
-
- if (!Cancelled.load(std::memory_order_relaxed)) {
- Callbacks.emplace_back().swap(callback);
- return;
- }
- }
-
- // Already cancelled, run immediately
- callback();
- }
-
-private:
- void AddChild(TContextImpl* child) {
- for (TContextImpl*& slot : InlineChildren) {
- if (!slot) {
- slot = child;
- return;
- }
- }
-
- Children.insert(child);
- }
-
- bool RemoveChild(TContextImpl* child) {
- for (TContextImpl*& slot : InlineChildren) {
- if (slot == child) {
- slot = nullptr;
- return true;
- }
- }
-
- return Children.erase(child);
- }
-
- size_t CountChildren() {
- size_t count = 0;
-
- for (TContextImpl* ptr : InlineChildren) {
- if (ptr) {
- ++count;
- }
- }
-
- return count + Children.size();
- }
-
- template<class TCallbacks>
- static void RunCallbacksNoExcept(TCallbacks& callbacks) noexcept {
- for (auto& callback : callbacks) {
- if (callback) {
- callback();
- callback = nullptr;
- }
- }
- }
-
-private:
- // We want a simple lock here, without extra memory allocations
- std::mutex Mutex;
-
- // These fields are initialized on successful registration
- TContextPtr Parent;
- TGRpcClientLow* Owner = nullptr;
+ }
+
+ bool IsCancelled() const override {
+ return Cancelled.load(std::memory_order_acquire);
+ }
+
+ bool Cancel() override {
+ TStackVec<TCallback, 1> callbacks;
+ TStackVec<TContextPtr, 2> children;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ if (Cancelled.load(std::memory_order_relaxed)) {
+ // Already cancelled in another thread
+ return false;
+ }
+
+ callbacks.reserve(Callbacks.size());
+ children.reserve(CountChildren());
+
+ for (auto& callback : Callbacks) {
+ callbacks.emplace_back().swap(callback);
+ }
+ Callbacks.clear();
+
+ // Collect all children we need to cancel
+ // N.B. we don't clear children links (cleared by destructors)
+ // N.B. some children may be stuck in destructors at the moment
+ for (TContextImpl* ptr : InlineChildren) {
+ if (auto child = LockChildPtr(ptr)) {
+ children.emplace_back(std::move(child));
+ }
+ }
+ for (auto* ptr : Children) {
+ if (auto child = LockChildPtr(ptr)) {
+ children.emplace_back(std::move(child));
+ }
+ }
+
+ Cancelled.store(true, std::memory_order_release);
+ }
+
+ // Call directly subscribed callbacks
+ if (callbacks) {
+ RunCallbacksNoExcept(callbacks);
+ }
+
+ // Cancel all children
+ for (auto& child : children) {
+ child->Cancel();
+ child.reset();
+ }
+
+ return true;
+ }
+
+ void SubscribeCancel(TCallback callback) override {
+ Y_VERIFY(callback, "SubscribeCancel called with an empty callback");
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ if (!Cancelled.load(std::memory_order_relaxed)) {
+ Callbacks.emplace_back().swap(callback);
+ return;
+ }
+ }
+
+ // Already cancelled, run immediately
+ callback();
+ }
+
+private:
+ void AddChild(TContextImpl* child) {
+ for (TContextImpl*& slot : InlineChildren) {
+ if (!slot) {
+ slot = child;
+ return;
+ }
+ }
+
+ Children.insert(child);
+ }
+
+ bool RemoveChild(TContextImpl* child) {
+ for (TContextImpl*& slot : InlineChildren) {
+ if (slot == child) {
+ slot = nullptr;
+ return true;
+ }
+ }
+
+ return Children.erase(child);
+ }
+
+ size_t CountChildren() {
+ size_t count = 0;
+
+ for (TContextImpl* ptr : InlineChildren) {
+ if (ptr) {
+ ++count;
+ }
+ }
+
+ return count + Children.size();
+ }
+
+ template<class TCallbacks>
+ static void RunCallbacksNoExcept(TCallbacks& callbacks) noexcept {
+ for (auto& callback : callbacks) {
+ if (callback) {
+ callback();
+ callback = nullptr;
+ }
+ }
+ }
+
+private:
+ // We want a simple lock here, without extra memory allocations
+ std::mutex Mutex;
+
+ // These fields are initialized on successful registration
+ TContextPtr Parent;
+ TGRpcClientLow* Owner = nullptr;
grpc::CompletionQueue* CQ = nullptr;
-
- // Some children are stored inline, others are in a set
- std::array<TContextImpl*, 2> InlineChildren{ { nullptr, nullptr } };
+
+ // Some children are stored inline, others are in a set
+ std::array<TContextImpl*, 2> InlineChildren{ { nullptr, nullptr } };
std::unordered_set<TContextImpl*> Children;
-
- // Single callback is stored without extra allocations
- TStackVec<TCallback, 1> Callbacks;
-
- // Atomic flag for a faster IsCancelled() implementation
- std::atomic<bool> Cancelled;
-};
-
+
+ // Single callback is stored without extra allocations
+ TStackVec<TCallback, 1> Callbacks;
+
+ // Atomic flag for a faster IsCancelled() implementation
+ std::atomic<bool> Cancelled;
+};
+
TGRpcClientLow::TGRpcClientLow(size_t numWorkerThread, bool useCompletionQueuePerThread)
: UseCompletionQueuePerThread_(useCompletionQueuePerThread)
{
@@ -408,7 +408,7 @@ TGRpcClientLow::TGRpcClientLow(size_t numWorkerThread, bool useCompletionQueuePe
}
void TGRpcClientLow::Init(size_t numWorkerThread) {
- SetCqState(WORKING);
+ SetCqState(WORKING);
if (UseCompletionQueuePerThread_) {
for (size_t i = 0; i < numWorkerThread; i++) {
CQS_.push_back(std::make_unique<grpc::CompletionQueue>());
@@ -428,7 +428,7 @@ void TGRpcClientLow::Init(size_t numWorkerThread) {
}
}
-void TGRpcClientLow::AddWorkerThreadForTest() {
+void TGRpcClientLow::AddWorkerThreadForTest() {
if (UseCompletionQueuePerThread_) {
CQS_.push_back(std::make_unique<grpc::CompletionQueue>());
auto* cq = CQS_.back().get();
@@ -441,75 +441,75 @@ void TGRpcClientLow::AddWorkerThreadForTest() {
PullEvents(cq);
}).Release());
}
-}
-
-TGRpcClientLow::~TGRpcClientLow() {
- StopInternal(true);
- WaitInternal();
-}
-
-void TGRpcClientLow::Stop(bool wait) {
- StopInternal(false);
-
- if (wait) {
- WaitInternal();
+}
+
+TGRpcClientLow::~TGRpcClientLow() {
+ StopInternal(true);
+ WaitInternal();
+}
+
+void TGRpcClientLow::Stop(bool wait) {
+ StopInternal(false);
+
+ if (wait) {
+ WaitInternal();
}
}
-void TGRpcClientLow::StopInternal(bool silent) {
- bool shutdown;
-
- TVector<TContextImpl::TContextPtr> cancelQueue;
-
+void TGRpcClientLow::StopInternal(bool silent) {
+ bool shutdown;
+
+ TVector<TContextImpl::TContextPtr> cancelQueue;
+
{
std::unique_lock<std::mutex> guard(Mtx_);
- auto allowStateChange = [&]() {
- switch (GetCqState()) {
- case WORKING:
- return true;
- case STOP_SILENT:
- return !silent;
- case STOP_EXPLICIT:
- return false;
- }
-
- Y_UNREACHABLE();
- };
-
- if (!allowStateChange()) {
- // Completion queue is already stopping
- return;
- }
-
- SetCqState(silent ? STOP_SILENT : STOP_EXPLICIT);
-
+ auto allowStateChange = [&]() {
+ switch (GetCqState()) {
+ case WORKING:
+ return true;
+ case STOP_SILENT:
+ return !silent;
+ case STOP_EXPLICIT:
+ return false;
+ }
+
+ Y_UNREACHABLE();
+ };
+
+ if (!allowStateChange()) {
+ // Completion queue is already stopping
+ return;
+ }
+
+ SetCqState(silent ? STOP_SILENT : STOP_EXPLICIT);
+
if (!silent && !Contexts_.empty()) {
- cancelQueue.reserve(Contexts_.size());
- for (auto* ptr : Contexts_) {
- // N.B. some contexts may be stuck in destructors
- if (auto context = TContextImpl::LockChildPtr(ptr)) {
- cancelQueue.emplace_back(std::move(context));
- }
- }
- }
-
+ cancelQueue.reserve(Contexts_.size());
+ for (auto* ptr : Contexts_) {
+ // N.B. some contexts may be stuck in destructors
+ if (auto context = TContextImpl::LockChildPtr(ptr)) {
+ cancelQueue.emplace_back(std::move(context));
+ }
+ }
+ }
+
shutdown = Contexts_.empty();
- }
-
- for (auto& context : cancelQueue) {
- context->Cancel();
- context.reset();
- }
-
- if (shutdown) {
+ }
+
+ for (auto& context : cancelQueue) {
+ context->Cancel();
+ context.reset();
+ }
+
+ if (shutdown) {
for (auto& cq : CQS_) {
cq->Shutdown();
}
}
-}
-
-void TGRpcClientLow::WaitInternal() {
+}
+
+void TGRpcClientLow::WaitInternal() {
std::unique_lock<std::mutex> guard(JoinMutex_);
for (auto& ti : WorkerThreads_) {
@@ -517,7 +517,7 @@ void TGRpcClientLow::WaitInternal() {
}
}
-void TGRpcClientLow::WaitIdle() {
+void TGRpcClientLow::WaitIdle() {
std::unique_lock<std::mutex> guard(Mtx_);
while (!Contexts_.empty()) {
@@ -525,7 +525,7 @@ void TGRpcClientLow::WaitIdle() {
}
}
-std::shared_ptr<IQueueClientContext> TGRpcClientLow::CreateContext() {
+std::shared_ptr<IQueueClientContext> TGRpcClientLow::CreateContext() {
std::unique_lock<std::mutex> guard(Mtx_);
auto allowCreateContext = [&]() {
@@ -535,15 +535,15 @@ std::shared_ptr<IQueueClientContext> TGRpcClientLow::CreateContext() {
case STOP_SILENT:
case STOP_EXPLICIT:
return false;
- }
-
+ }
+
Y_UNREACHABLE();
};
if (!allowCreateContext()) {
// New context creation is forbidden
return nullptr;
- }
+ }
auto context = std::make_shared<TContextImpl>();
Contexts_.insert(context.get());
@@ -554,32 +554,32 @@ std::shared_ptr<IQueueClientContext> TGRpcClientLow::CreateContext() {
context->CQ = CQS_[0].get();
}
return context;
-}
-
-void TGRpcClientLow::ForgetContext(TContextImpl* context) {
- bool shutdown = false;
-
+}
+
+void TGRpcClientLow::ForgetContext(TContextImpl* context) {
+ bool shutdown = false;
+
{
std::unique_lock<std::mutex> guard(Mtx_);
- if (!Contexts_.erase(context)) {
- Y_FAIL("Unexpected ForgetContext(%p)", context);
- }
-
- if (Contexts_.empty()) {
- if (IsStopping()) {
- shutdown = true;
- }
-
+ if (!Contexts_.erase(context)) {
+ Y_FAIL("Unexpected ForgetContext(%p)", context);
+ }
+
+ if (Contexts_.empty()) {
+ if (IsStopping()) {
+ shutdown = true;
+ }
+
ContextsEmpty_.notify_all();
- }
- }
-
- if (shutdown) {
- // This was the last context, shutdown CQ
+ }
+ }
+
+ if (shutdown) {
+ // This was the last context, shutdown CQ
for (auto& cq : CQS_) {
cq->Shutdown();
- }
+ }
}
}
diff --git a/library/cpp/grpc/client/grpc_client_low.h b/library/cpp/grpc/client/grpc_client_low.h
index ab0a0627be..5d0983f804 100644
--- a/library/cpp/grpc/client/grpc_client_low.h
+++ b/library/cpp/grpc/client/grpc_client_low.h
@@ -52,125 +52,125 @@ public:
virtual void Destroy() = 0;
};
-// Implementation of IQueueClientEvent that reduces allocations
-template<class TSelf>
-class TQueueClientFixedEvent : private IQueueClientEvent {
- using TCallback = void (TSelf::*)(bool);
-
-public:
- TQueueClientFixedEvent(TSelf* self, TCallback callback)
- : Self(self)
- , Callback(callback)
- { }
-
- IQueueClientEvent* Prepare() {
- Self->Ref();
- return this;
- }
-
-private:
- bool Execute(bool ok) override {
- ((*Self).*Callback)(ok);
- return false;
- }
-
- void Destroy() override {
- Self->UnRef();
- }
-
-private:
- TSelf* const Self;
- TCallback const Callback;
-};
-
-class IQueueClientContext;
-using IQueueClientContextPtr = std::shared_ptr<IQueueClientContext>;
-
-// Provider of IQueueClientContext instances
-class IQueueClientContextProvider {
-public:
- virtual ~IQueueClientContextProvider() = default;
-
- virtual IQueueClientContextPtr CreateContext() = 0;
-};
-
-// Activity context for a low-level client
-class IQueueClientContext : public IQueueClientContextProvider {
-public:
- virtual ~IQueueClientContext() = default;
-
- //! Returns CompletionQueue associated with the client
- virtual grpc::CompletionQueue* CompletionQueue() = 0;
-
- //! Returns true if context has been cancelled
- virtual bool IsCancelled() const = 0;
-
- //! Tries to cancel context, calling all registered callbacks
- virtual bool Cancel() = 0;
-
- //! Subscribes callback to cancellation
- //
- // Note there's no way to unsubscribe, if subscription is temporary
- // make sure you create a new context with CreateContext and release
- // it as soon as it's no longer needed.
- virtual void SubscribeCancel(std::function<void()> callback) = 0;
-
- //! Subscribes callback to cancellation
- //
- // This alias is for compatibility with older code.
- void SubscribeStop(std::function<void()> callback) {
- SubscribeCancel(std::move(callback));
- }
-};
-
+// Implementation of IQueueClientEvent that reduces allocations
+template<class TSelf>
+class TQueueClientFixedEvent : private IQueueClientEvent {
+ using TCallback = void (TSelf::*)(bool);
+
+public:
+ TQueueClientFixedEvent(TSelf* self, TCallback callback)
+ : Self(self)
+ , Callback(callback)
+ { }
+
+ IQueueClientEvent* Prepare() {
+ Self->Ref();
+ return this;
+ }
+
+private:
+ bool Execute(bool ok) override {
+ ((*Self).*Callback)(ok);
+ return false;
+ }
+
+ void Destroy() override {
+ Self->UnRef();
+ }
+
+private:
+ TSelf* const Self;
+ TCallback const Callback;
+};
+
+class IQueueClientContext;
+using IQueueClientContextPtr = std::shared_ptr<IQueueClientContext>;
+
+// Provider of IQueueClientContext instances
+class IQueueClientContextProvider {
+public:
+ virtual ~IQueueClientContextProvider() = default;
+
+ virtual IQueueClientContextPtr CreateContext() = 0;
+};
+
+// Activity context for a low-level client
+class IQueueClientContext : public IQueueClientContextProvider {
+public:
+ virtual ~IQueueClientContext() = default;
+
+ //! Returns CompletionQueue associated with the client
+ virtual grpc::CompletionQueue* CompletionQueue() = 0;
+
+ //! Returns true if context has been cancelled
+ virtual bool IsCancelled() const = 0;
+
+ //! Tries to cancel context, calling all registered callbacks
+ virtual bool Cancel() = 0;
+
+ //! Subscribes callback to cancellation
+ //
+ // Note there's no way to unsubscribe, if subscription is temporary
+ // make sure you create a new context with CreateContext and release
+ // it as soon as it's no longer needed.
+ virtual void SubscribeCancel(std::function<void()> callback) = 0;
+
+ //! Subscribes callback to cancellation
+ //
+ // This alias is for compatibility with older code.
+ void SubscribeStop(std::function<void()> callback) {
+ SubscribeCancel(std::move(callback));
+ }
+};
+
// Represents grpc status and error message string
struct TGrpcStatus {
- TString Msg;
+ TString Msg;
TString Details;
- int GRpcStatusCode;
- bool InternalError;
-
- TGrpcStatus()
- : GRpcStatusCode(grpc::StatusCode::OK)
- , InternalError(false)
- { }
-
- TGrpcStatus(TString msg, int statusCode, bool internalError)
- : Msg(std::move(msg))
- , GRpcStatusCode(statusCode)
- , InternalError(internalError)
- { }
-
+ int GRpcStatusCode;
+ bool InternalError;
+
+ TGrpcStatus()
+ : GRpcStatusCode(grpc::StatusCode::OK)
+ , InternalError(false)
+ { }
+
+ TGrpcStatus(TString msg, int statusCode, bool internalError)
+ : Msg(std::move(msg))
+ , GRpcStatusCode(statusCode)
+ , InternalError(internalError)
+ { }
+
TGrpcStatus(grpc::StatusCode status, TString msg, TString details = {})
- : Msg(std::move(msg))
+ : Msg(std::move(msg))
, Details(std::move(details))
- , GRpcStatusCode(status)
- , InternalError(false)
- { }
-
- TGrpcStatus(const grpc::Status& status)
+ , GRpcStatusCode(status)
+ , InternalError(false)
+ { }
+
+ TGrpcStatus(const grpc::Status& status)
: TGrpcStatus(status.error_code(), TString(status.error_message()), TString(status.error_details()))
- { }
-
- TGrpcStatus& operator=(const grpc::Status& status) {
- Msg = TString(status.error_message());
+ { }
+
+ TGrpcStatus& operator=(const grpc::Status& status) {
+ Msg = TString(status.error_message());
Details = TString(status.error_details());
- GRpcStatusCode = status.error_code();
- InternalError = false;
- return *this;
- }
-
- static TGrpcStatus Internal(TString msg) {
- return { std::move(msg), -1, true };
- }
-
- bool Ok() const {
- return !InternalError && GRpcStatusCode == grpc::StatusCode::OK;
- }
+ GRpcStatusCode = status.error_code();
+ InternalError = false;
+ return *this;
+ }
+
+ static TGrpcStatus Internal(TString msg) {
+ return { std::move(msg), -1, true };
+ }
+
+ bool Ok() const {
+ return !InternalError && GRpcStatusCode == grpc::StatusCode::OK;
+ }
};
bool inline IsGRpcStatusGood(const TGrpcStatus& status) {
- return status.Ok();
+ return status.Ok();
}
// Response callback type - this callback will be called when request is finished
@@ -241,9 +241,9 @@ public:
{ }
~TSimpleRequestProcessor() {
- if (!Replied_ && Callback_) {
- Callback_(TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
- Callback_ = nullptr; // free resources as early as possible
+ if (!Replied_ && Callback_) {
+ Callback_(TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
}
}
@@ -251,53 +251,53 @@ public:
{
std::unique_lock<std::mutex> guard(Mutex_);
LocalContext.reset();
- }
- TGrpcStatus status;
- if (ok) {
+ }
+ TGrpcStatus status;
+ if (ok) {
status = Status;
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
}
Replied_ = true;
Callback_(std::move(status), std::move(Reply_));
- Callback_ = nullptr; // free resources as early as possible
+ Callback_ = nullptr; // free resources as early as possible
return false;
}
void Destroy() override {
- UnRef();
+ UnRef();
}
private:
- IQueueClientEvent* FinishedEvent() {
- Ref();
- return this;
+ IQueueClientEvent* FinishedEvent() {
+ Ref();
+ return this;
}
void Start(TStub& stub, TAsyncRequest asyncRequest, const TRequest& request, IQueueClientContextProvider* provider) {
- auto context = provider->CreateContext();
- if (!context) {
- Replied_ = true;
- Callback_(TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
- Callback_ = nullptr;
- return;
- }
+ auto context = provider->CreateContext();
+ if (!context) {
+ Replied_ = true;
+ Callback_(TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
+ Callback_ = nullptr;
+ return;
+ }
{
std::unique_lock<std::mutex> guard(Mutex_);
LocalContext = context;
Reader_ = (stub.*asyncRequest)(&Context, request, context->CompletionQueue());
Reader_->Finish(&Reply_, &Status, FinishedEvent());
- }
- context->SubscribeStop([self = TPtr(this)] {
- self->Stop();
- });
- }
-
- void Stop() {
+ }
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Stop();
+ });
+ }
+
+ void Stop() {
Context.TryCancel();
- }
-
- TResponseCallback<TResponse> Callback_;
+ }
+
+ TResponseCallback<TResponse> Callback_;
TResponse Reply_;
std::mutex Mutex_;
TAsyncReaderPtr Reader_;
@@ -387,49 +387,49 @@ private:
template<class TResponse>
class IStreamRequestReadProcessor : public TThrRefBase {
-public:
+public:
using TPtr = TIntrusivePtr<IStreamRequestReadProcessor>;
- using TReadCallback = std::function<void(TGrpcStatus&&)>;
-
- /**
- * Asynchronously cancel the request
- */
- virtual void Cancel() = 0;
-
- /**
+ using TReadCallback = std::function<void(TGrpcStatus&&)>;
+
+ /**
+ * Asynchronously cancel the request
+ */
+ virtual void Cancel() = 0;
+
+ /**
* Scheduled initial server metadata read from the stream
*/
virtual void ReadInitialMetadata(std::unordered_multimap<TString, TString>* metadata, TReadCallback callback) = 0;
/**
- * Scheduled response read from the stream
- * Callback will be called with the status if it failed
- * Only one Read or Finish call may be active at a time
- */
- virtual void Read(TResponse* response, TReadCallback callback) = 0;
-
- /**
- * Stop reading and gracefully finish the stream
- * Only one Read or Finish call may be active at a time
- */
- virtual void Finish(TReadCallback callback) = 0;
-
- /**
- * Additional callback to be called when stream has finished
- */
- virtual void AddFinishedCallback(TReadCallback callback) = 0;
-};
-
+ * Scheduled response read from the stream
+ * Callback will be called with the status if it failed
+ * Only one Read or Finish call may be active at a time
+ */
+ virtual void Read(TResponse* response, TReadCallback callback) = 0;
+
+ /**
+ * Stop reading and gracefully finish the stream
+ * Only one Read or Finish call may be active at a time
+ */
+ virtual void Finish(TReadCallback callback) = 0;
+
+ /**
+ * Additional callback to be called when stream has finished
+ */
+ virtual void AddFinishedCallback(TReadCallback callback) = 0;
+};
+
template<class TRequest, class TResponse>
class IStreamRequestReadWriteProcessor : public IStreamRequestReadProcessor<TResponse> {
public:
using TPtr = TIntrusivePtr<IStreamRequestReadWriteProcessor>;
- using TWriteCallback = std::function<void(TGrpcStatus&&)>;
+ using TWriteCallback = std::function<void(TGrpcStatus&&)>;
/**
* Scheduled request write to the stream
*/
- virtual void Write(TRequest&& request, TWriteCallback callback = { }) = 0;
+ virtual void Write(TRequest&& request, TWriteCallback callback = { }) = 0;
};
class TGRpcKeepAliveSocketMutator;
@@ -548,7 +548,7 @@ public:
{
std::unique_lock<std::mutex> guard(Mutex);
Cancelled = true;
- if (Started && !ReadFinished) {
+ if (Started && !ReadFinished) {
if (!ReadActive) {
ReadFinished = true;
}
@@ -640,31 +640,31 @@ public:
callback(std::move(status));
}
-
- void AddFinishedCallback(TReadCallback callback) override {
- Y_VERIFY(callback, "Unexpected empty callback");
-
- TGrpcStatus status;
-
+
+ void AddFinishedCallback(TReadCallback callback) override {
+ Y_VERIFY(callback, "Unexpected empty callback");
+
+ TGrpcStatus status;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- if (!Finished) {
- FinishedCallbacks.emplace_back().swap(callback);
- return;
- }
-
- if (FinishedOk) {
- status = Status;
- } else if (Cancelled) {
- status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
- }
-
- callback(std::move(status));
- }
-
+ if (!Finished) {
+ FinishedCallbacks.emplace_back().swap(callback);
+ return;
+ }
+
+ if (FinishedOk) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
private:
void Start(TStub& stub, const TRequest& request, TAsyncRequest asyncRequest, IQueueClientContextProvider* provider) {
auto context = provider->CreateContext();
@@ -727,8 +727,8 @@ private:
{
std::unique_lock<std::mutex> guard(Mutex);
- Started = true;
- if (!ok || Cancelled) {
+ Started = true;
+ if (!ok || Cancelled) {
ReadFinished = true;
Stream->Finish(&Status, OnFinishedTag.Prepare());
return;
@@ -743,7 +743,7 @@ private:
void OnFinished(bool ok) {
TGrpcStatus status;
std::vector<TReadCallback> finishedCallbacks;
- TReaderCallback startCallback;
+ TReaderCallback startCallback;
TReadCallback readCallback;
TReadCallback finishCallback;
@@ -756,19 +756,19 @@ private:
if (ok) {
status = Status;
- } else if (Cancelled) {
- status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
} else {
status = TGrpcStatus::Internal("Unexpected error");
}
- finishedCallbacks.swap(FinishedCallbacks);
-
- if (Callback) {
- Y_VERIFY(!ReadActive);
- startCallback = std::move(Callback);
- Callback = nullptr;
- } else if (ReadActive) {
+ finishedCallbacks.swap(FinishedCallbacks);
+
+ if (Callback) {
+ Y_VERIFY(!ReadActive);
+ startCallback = std::move(Callback);
+ Callback = nullptr;
+ } else if (ReadActive) {
if (ReadCallback) {
readCallback = std::move(ReadCallback);
ReadCallback = nullptr;
@@ -780,18 +780,18 @@ private:
}
}
- for (auto& finishedCallback : finishedCallbacks) {
- auto statusCopy = status;
- finishedCallback(std::move(statusCopy));
- }
-
- if (startCallback) {
- if (status.Ok()) {
- status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
- }
- startCallback(std::move(status), nullptr);
- } else if (readCallback) {
+ for (auto& finishedCallback : finishedCallbacks) {
+ auto statusCopy = status;
+ finishedCallback(std::move(statusCopy));
+ }
+
+ if (startCallback) {
if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
+ }
+ startCallback(std::move(status), nullptr);
+ } else if (readCallback) {
+ if (status.Ok()) {
status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
}
readCallback(std::move(status));
@@ -812,7 +812,7 @@ private:
TReadCallback FinishCallback;
std::vector<TReadCallback> FinishedCallbacks;
std::unordered_multimap<TString, TString>* InitialMetadata = nullptr;
- bool Started = false;
+ bool Started = false;
bool HasInitialMetadata = false;
bool ReadActive = false;
bool ReadFinished = false;
@@ -821,72 +821,72 @@ private:
bool FinishedOk = false;
};
-template<class TRequest, class TResponse>
+template<class TRequest, class TResponse>
using TStreamConnectedCallback = std::function<void(TGrpcStatus&&, typename IStreamRequestReadWriteProcessor<TRequest, TResponse>::TPtr)>;
-
-template<class TStub, class TRequest, class TResponse>
+
+template<class TStub, class TRequest, class TResponse>
class TStreamRequestReadWriteProcessor
: public IStreamRequestReadWriteProcessor<TRequest, TResponse>
, public TGRpcRequestProcessorCommon {
-public:
+public:
using TSelf = TStreamRequestReadWriteProcessor;
using TBase = IStreamRequestReadWriteProcessor<TRequest, TResponse>;
- using TPtr = TIntrusivePtr<TSelf>;
- using TConnectedCallback = TStreamConnectedCallback<TRequest, TResponse>;
- using TReadCallback = typename TBase::TReadCallback;
- using TWriteCallback = typename TBase::TWriteCallback;
- using TAsyncReaderWriterPtr = std::unique_ptr<grpc::ClientAsyncReaderWriter<TRequest, TResponse>>;
- using TAsyncRequest = TAsyncReaderWriterPtr (TStub::*)(grpc::ClientContext*, grpc::CompletionQueue*, void*);
-
+ using TPtr = TIntrusivePtr<TSelf>;
+ using TConnectedCallback = TStreamConnectedCallback<TRequest, TResponse>;
+ using TReadCallback = typename TBase::TReadCallback;
+ using TWriteCallback = typename TBase::TWriteCallback;
+ using TAsyncReaderWriterPtr = std::unique_ptr<grpc::ClientAsyncReaderWriter<TRequest, TResponse>>;
+ using TAsyncRequest = TAsyncReaderWriterPtr (TStub::*)(grpc::ClientContext*, grpc::CompletionQueue*, void*);
+
explicit TStreamRequestReadWriteProcessor(TConnectedCallback&& callback)
- : ConnectedCallback(std::move(callback))
- {
- Y_VERIFY(ConnectedCallback, "Missing connected callback");
- }
-
- void Cancel() override {
- Context.TryCancel();
-
+ : ConnectedCallback(std::move(callback))
+ {
+ Y_VERIFY(ConnectedCallback, "Missing connected callback");
+ }
+
+ void Cancel() override {
+ Context.TryCancel();
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Cancelled = true;
- if (Started && !(ReadFinished && WriteFinished)) {
- if (!ReadActive) {
- ReadFinished = true;
- }
- if (!WriteActive) {
- WriteFinished = true;
- }
- if (ReadFinished && WriteFinished) {
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- }
- }
- }
- }
-
- void Write(TRequest&& request, TWriteCallback callback) override {
- TGrpcStatus status;
-
+ Cancelled = true;
+ if (Started && !(ReadFinished && WriteFinished)) {
+ if (!ReadActive) {
+ ReadFinished = true;
+ }
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (ReadFinished && WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ }
+ }
+
+ void Write(TRequest&& request, TWriteCallback callback) override {
+ TGrpcStatus status;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- if (Cancelled || ReadFinished || WriteFinished) {
- status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
- } else if (WriteActive) {
- auto& item = WriteQueue.emplace_back();
- item.Callback.swap(callback);
- item.Request.Swap(&request);
- } else {
- WriteActive = true;
- WriteCallback.swap(callback);
- Stream->Write(request, OnWriteDoneTag.Prepare());
- }
- }
-
- if (!status.Ok() && callback) {
- callback(std::move(status));
- }
- }
-
+ if (Cancelled || ReadFinished || WriteFinished) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
+ } else if (WriteActive) {
+ auto& item = WriteQueue.emplace_back();
+ item.Callback.swap(callback);
+ item.Request.Swap(&request);
+ } else {
+ WriteActive = true;
+ WriteCallback.swap(callback);
+ Stream->Write(request, OnWriteDoneTag.Prepare());
+ }
+ }
+
+ if (!status.Ok() && callback) {
+ callback(std::move(status));
+ }
+ }
+
void ReadInitialMetadata(std::unordered_multimap<TString, TString>* metadata, TReadCallback callback) override {
TGrpcStatus status;
@@ -916,321 +916,321 @@ public:
callback(std::move(status));
}
- void Read(TResponse* message, TReadCallback callback) override {
- TGrpcStatus status;
-
+ void Read(TResponse* message, TReadCallback callback) override {
+ TGrpcStatus status;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
- if (!Finished) {
- ReadActive = true;
- ReadCallback = std::move(callback);
- if (!ReadFinished) {
- Stream->Read(message, OnReadDoneTag.Prepare());
- }
- return;
- }
- if (FinishedOk) {
- status = Status;
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
- }
-
- if (status.Ok()) {
- status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
- }
-
- callback(std::move(status));
- }
-
- void Finish(TReadCallback callback) override {
- TGrpcStatus status;
-
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ ReadCallback = std::move(callback);
+ if (!ReadFinished) {
+ Stream->Read(message, OnReadDoneTag.Prepare());
+ }
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+
+ callback(std::move(status));
+ }
+
+ void Finish(TReadCallback callback) override {
+ TGrpcStatus status;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
- if (!Finished) {
- ReadActive = true;
- FinishCallback = std::move(callback);
- if (!ReadFinished) {
- ReadFinished = true;
- if (!WriteActive) {
- WriteFinished = true;
- }
- if (WriteFinished) {
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- }
- }
- return;
- }
- if (FinishedOk) {
- status = Status;
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
- }
-
- callback(std::move(status));
- }
-
- void AddFinishedCallback(TReadCallback callback) override {
- Y_VERIFY(callback, "Unexpected empty callback");
-
- TGrpcStatus status;
-
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ FinishCallback = std::move(callback);
+ if (!ReadFinished) {
+ ReadFinished = true;
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+ void AddFinishedCallback(TReadCallback callback) override {
+ Y_VERIFY(callback, "Unexpected empty callback");
+
+ TGrpcStatus status;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- if (!Finished) {
- FinishedCallbacks.emplace_back().swap(callback);
- return;
- }
-
- if (FinishedOk) {
- status = Status;
- } else if (Cancelled) {
- status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
- }
-
- callback(std::move(status));
- }
-
-private:
- template<typename> friend class TServiceConnection;
-
- void Start(TStub& stub, TAsyncRequest asyncRequest, IQueueClientContextProvider* provider) {
- auto context = provider->CreateContext();
- if (!context) {
- auto callback = std::move(ConnectedCallback);
- TGrpcStatus status(grpc::StatusCode::CANCELLED, "Client is shutting down");
- callback(std::move(status), nullptr);
- return;
- }
-
+ if (!Finished) {
+ FinishedCallbacks.emplace_back().swap(callback);
+ return;
+ }
+
+ if (FinishedOk) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+private:
+ template<typename> friend class TServiceConnection;
+
+ void Start(TStub& stub, TAsyncRequest asyncRequest, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ auto callback = std::move(ConnectedCallback);
+ TGrpcStatus status(grpc::StatusCode::CANCELLED, "Client is shutting down");
+ callback(std::move(status), nullptr);
+ return;
+ }
+
{
std::unique_lock<std::mutex> guard(Mutex);
- LocalContext = context;
- Stream = (stub.*asyncRequest)(&Context, context->CompletionQueue(), OnConnectedTag.Prepare());
- }
-
- context->SubscribeStop([self = TPtr(this)] {
- self->Cancel();
- });
- }
-
-private:
- void OnConnected(bool ok) {
- TConnectedCallback callback;
-
+ LocalContext = context;
+ Stream = (stub.*asyncRequest)(&Context, context->CompletionQueue(), OnConnectedTag.Prepare());
+ }
+
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Cancel();
+ });
+ }
+
+private:
+ void OnConnected(bool ok) {
+ TConnectedCallback callback;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Started = true;
- if (!ok || Cancelled) {
- ReadFinished = true;
- WriteFinished = true;
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- return;
- }
-
- callback = std::move(ConnectedCallback);
- ConnectedCallback = nullptr;
- }
-
- callback({ }, typename TBase::TPtr(this));
- }
-
- void OnReadDone(bool ok) {
- TGrpcStatus status;
- TReadCallback callback;
+ Started = true;
+ if (!ok || Cancelled) {
+ ReadFinished = true;
+ WriteFinished = true;
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ return;
+ }
+
+ callback = std::move(ConnectedCallback);
+ ConnectedCallback = nullptr;
+ }
+
+ callback({ }, typename TBase::TPtr(this));
+ }
+
+ void OnReadDone(bool ok) {
+ TGrpcStatus status;
+ TReadCallback callback;
std::unordered_multimap<TString, TString>* initialMetadata = nullptr;
-
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Y_VERIFY(ReadActive, "Unexpected Read done callback");
- Y_VERIFY(!ReadFinished, "Unexpected ReadFinished flag");
-
- if (!ok || Cancelled || WriteFinished) {
- ReadFinished = true;
- if (!WriteActive) {
- WriteFinished = true;
- }
- if (WriteFinished) {
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- }
- if (!ok) {
- // Keep ReadActive=true, so callback is called
- // after the call is finished with an error
- return;
- }
- }
-
- callback = std::move(ReadCallback);
- ReadCallback = nullptr;
- ReadActive = false;
+ Y_VERIFY(ReadActive, "Unexpected Read done callback");
+ Y_VERIFY(!ReadFinished, "Unexpected ReadFinished flag");
+
+ if (!ok || Cancelled || WriteFinished) {
+ ReadFinished = true;
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ if (!ok) {
+ // Keep ReadActive=true, so callback is called
+ // after the call is finished with an error
+ return;
+ }
+ }
+
+ callback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ ReadActive = false;
initialMetadata = InitialMetadata;
InitialMetadata = nullptr;
HasInitialMetadata = true;
- }
-
+ }
+
if (initialMetadata) {
GetInitialMetadata(initialMetadata);
}
- callback(std::move(status));
- }
-
- void OnWriteDone(bool ok) {
- TWriteCallback okCallback;
-
+ callback(std::move(status));
+ }
+
+ void OnWriteDone(bool ok) {
+ TWriteCallback okCallback;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Y_VERIFY(WriteActive, "Unexpected Write done callback");
- Y_VERIFY(!WriteFinished, "Unexpected WriteFinished flag");
-
- if (ok) {
- okCallback.swap(WriteCallback);
- } else if (WriteCallback) {
- // Put callback back on the queue until OnFinished
- auto& item = WriteQueue.emplace_front();
- item.Callback.swap(WriteCallback);
- }
-
- if (!ok || Cancelled) {
- WriteActive = false;
- WriteFinished = true;
- if (!ReadActive) {
- ReadFinished = true;
- }
- if (ReadFinished) {
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- }
+ Y_VERIFY(WriteActive, "Unexpected Write done callback");
+ Y_VERIFY(!WriteFinished, "Unexpected WriteFinished flag");
+
+ if (ok) {
+ okCallback.swap(WriteCallback);
+ } else if (WriteCallback) {
+ // Put callback back on the queue until OnFinished
+ auto& item = WriteQueue.emplace_front();
+ item.Callback.swap(WriteCallback);
+ }
+
+ if (!ok || Cancelled) {
+ WriteActive = false;
+ WriteFinished = true;
+ if (!ReadActive) {
+ ReadFinished = true;
+ }
+ if (ReadFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
} else if (!WriteQueue.empty()) {
- WriteCallback.swap(WriteQueue.front().Callback);
- Stream->Write(WriteQueue.front().Request, OnWriteDoneTag.Prepare());
- WriteQueue.pop_front();
- } else {
- WriteActive = false;
- if (ReadFinished) {
- WriteFinished = true;
- Stream->Finish(&Status, OnFinishedTag.Prepare());
- }
- }
- }
-
- if (okCallback) {
- okCallback(TGrpcStatus());
- }
- }
-
- void OnFinished(bool ok) {
- TGrpcStatus status;
+ WriteCallback.swap(WriteQueue.front().Callback);
+ Stream->Write(WriteQueue.front().Request, OnWriteDoneTag.Prepare());
+ WriteQueue.pop_front();
+ } else {
+ WriteActive = false;
+ if (ReadFinished) {
+ WriteFinished = true;
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ }
+
+ if (okCallback) {
+ okCallback(TGrpcStatus());
+ }
+ }
+
+ void OnFinished(bool ok) {
+ TGrpcStatus status;
std::deque<TWriteItem> writesDropped;
std::vector<TReadCallback> finishedCallbacks;
- TConnectedCallback connectedCallback;
- TReadCallback readCallback;
- TReadCallback finishCallback;
-
+ TConnectedCallback connectedCallback;
+ TReadCallback readCallback;
+ TReadCallback finishCallback;
+
{
std::unique_lock<std::mutex> guard(Mutex);
- Finished = true;
- FinishedOk = ok;
- LocalContext.reset();
-
- if (ok) {
- status = Status;
- } else if (Cancelled) {
- status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
- } else {
- status = TGrpcStatus::Internal("Unexpected error");
- }
-
- writesDropped.swap(WriteQueue);
- finishedCallbacks.swap(FinishedCallbacks);
-
- if (ConnectedCallback) {
- Y_VERIFY(!ReadActive);
- connectedCallback = std::move(ConnectedCallback);
- ConnectedCallback = nullptr;
- } else if (ReadActive) {
- if (ReadCallback) {
- readCallback = std::move(ReadCallback);
- ReadCallback = nullptr;
- } else {
- finishCallback = std::move(FinishCallback);
- FinishCallback = nullptr;
- }
- ReadActive = false;
- }
- }
-
- for (auto& item : writesDropped) {
- if (item.Callback) {
- TGrpcStatus writeStatus = status;
- if (writeStatus.Ok()) {
- writeStatus = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
- }
- item.Callback(std::move(writeStatus));
- }
- }
-
- for (auto& finishedCallback : finishedCallbacks) {
- TGrpcStatus statusCopy = status;
- finishedCallback(std::move(statusCopy));
- }
-
- if (connectedCallback) {
- if (status.Ok()) {
- status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
- }
- connectedCallback(std::move(status), nullptr);
- } else if (readCallback) {
- if (status.Ok()) {
- status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
- }
- readCallback(std::move(status));
- } else if (finishCallback) {
- finishCallback(std::move(status));
- }
- }
-
-private:
- struct TWriteItem {
- TWriteCallback Callback;
- TRequest Request;
- };
-
-private:
- using TFixedEvent = TQueueClientFixedEvent<TSelf>;
-
- TFixedEvent OnConnectedTag = { this, &TSelf::OnConnected };
- TFixedEvent OnReadDoneTag = { this, &TSelf::OnReadDone };
- TFixedEvent OnWriteDoneTag = { this, &TSelf::OnWriteDone };
- TFixedEvent OnFinishedTag = { this, &TSelf::OnFinished };
-
-private:
+ Finished = true;
+ FinishedOk = ok;
+ LocalContext.reset();
+
+ if (ok) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+
+ writesDropped.swap(WriteQueue);
+ finishedCallbacks.swap(FinishedCallbacks);
+
+ if (ConnectedCallback) {
+ Y_VERIFY(!ReadActive);
+ connectedCallback = std::move(ConnectedCallback);
+ ConnectedCallback = nullptr;
+ } else if (ReadActive) {
+ if (ReadCallback) {
+ readCallback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ } else {
+ finishCallback = std::move(FinishCallback);
+ FinishCallback = nullptr;
+ }
+ ReadActive = false;
+ }
+ }
+
+ for (auto& item : writesDropped) {
+ if (item.Callback) {
+ TGrpcStatus writeStatus = status;
+ if (writeStatus.Ok()) {
+ writeStatus = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
+ }
+ item.Callback(std::move(writeStatus));
+ }
+ }
+
+ for (auto& finishedCallback : finishedCallbacks) {
+ TGrpcStatus statusCopy = status;
+ finishedCallback(std::move(statusCopy));
+ }
+
+ if (connectedCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
+ }
+ connectedCallback(std::move(status), nullptr);
+ } else if (readCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+ readCallback(std::move(status));
+ } else if (finishCallback) {
+ finishCallback(std::move(status));
+ }
+ }
+
+private:
+ struct TWriteItem {
+ TWriteCallback Callback;
+ TRequest Request;
+ };
+
+private:
+ using TFixedEvent = TQueueClientFixedEvent<TSelf>;
+
+ TFixedEvent OnConnectedTag = { this, &TSelf::OnConnected };
+ TFixedEvent OnReadDoneTag = { this, &TSelf::OnReadDone };
+ TFixedEvent OnWriteDoneTag = { this, &TSelf::OnWriteDone };
+ TFixedEvent OnFinishedTag = { this, &TSelf::OnFinished };
+
+private:
std::mutex Mutex;
- TAsyncReaderWriterPtr Stream;
- TConnectedCallback ConnectedCallback;
- TReadCallback ReadCallback;
- TReadCallback FinishCallback;
+ TAsyncReaderWriterPtr Stream;
+ TConnectedCallback ConnectedCallback;
+ TReadCallback ReadCallback;
+ TReadCallback FinishCallback;
std::vector<TReadCallback> FinishedCallbacks;
std::deque<TWriteItem> WriteQueue;
- TWriteCallback WriteCallback;
+ TWriteCallback WriteCallback;
std::unordered_multimap<TString, TString>* InitialMetadata = nullptr;
- bool Started = false;
+ bool Started = false;
bool HasInitialMetadata = false;
- bool ReadActive = false;
- bool ReadFinished = false;
- bool WriteActive = false;
- bool WriteFinished = false;
- bool Finished = false;
- bool Cancelled = false;
- bool FinishedOk = false;
-};
-
+ bool ReadActive = false;
+ bool ReadFinished = false;
+ bool WriteActive = false;
+ bool WriteFinished = false;
+ bool Finished = false;
+ bool Cancelled = false;
+ bool FinishedOk = false;
+};
+
class TGRpcClientLow;
template<typename TGRpcService>
@@ -1245,9 +1245,9 @@ public:
template<typename TRequest, typename TResponse>
void DoRequest(const TRequest& request,
TResponseCallback<TResponse> callback,
- typename TSimpleRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ typename TSimpleRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
const TCallMeta& metas = { },
- IQueueClientContextProvider* provider = nullptr)
+ IQueueClientContextProvider* provider = nullptr)
{
auto processor = MakeIntrusive<TSimpleRequestProcessor<TStub, TRequest, TResponse>>(std::move(callback));
processor->ApplyMeta(metas);
@@ -1282,31 +1282,31 @@ public:
processor->ApplyMeta(metas);
processor->Start(*Stub_, std::move(asyncRequest), provider ? provider : Provider_);
}
-
+
/*
* Start streaming response reading (one request, many responses)
*/
- template<typename TRequest, typename TResponse>
+ template<typename TRequest, typename TResponse>
void DoStreamRequest(const TRequest& request,
TStreamReaderCallback<TResponse> callback,
typename TStreamRequestReadProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
- const TCallMeta& metas = { },
- IQueueClientContextProvider* provider = nullptr)
- {
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
auto processor = MakeIntrusive<TStreamRequestReadProcessor<TStub, TRequest, TResponse>>(std::move(callback));
- processor->ApplyMeta(metas);
+ processor->ApplyMeta(metas);
processor->Start(*Stub_, request, std::move(asyncRequest), provider ? provider : Provider_);
- }
-
+ }
+
private:
TServiceConnection(std::shared_ptr<grpc::ChannelInterface> ci,
- IQueueClientContextProvider* provider)
+ IQueueClientContextProvider* provider)
: Stub_(TGRpcService::NewStub(ci))
- , Provider_(provider)
- {
- Y_VERIFY(Provider_, "Connection does not have a queue provider");
- }
-
+ , Provider_(provider)
+ {
+ Y_VERIFY(Provider_, "Connection does not have a queue provider");
+ }
+
TServiceConnection(TStubsHolder& holder,
IQueueClientContextProvider* provider)
: Stub_(holder.GetOrCreateStub<TStub>())
@@ -1316,47 +1316,47 @@ private:
}
std::shared_ptr<TStub> Stub_;
- IQueueClientContextProvider* Provider_;
+ IQueueClientContextProvider* Provider_;
};
class TGRpcClientLow
: public IQueueClientContextProvider
{
- class TContextImpl;
- friend class TContextImpl;
-
- enum ECqState : TAtomicBase {
- WORKING = 0,
- STOP_SILENT = 1,
- STOP_EXPLICIT = 2,
- };
-
+ class TContextImpl;
+ friend class TContextImpl;
+
+ enum ECqState : TAtomicBase {
+ WORKING = 0,
+ STOP_SILENT = 1,
+ STOP_EXPLICIT = 2,
+ };
+
public:
explicit TGRpcClientLow(size_t numWorkerThread = DEFAULT_NUM_THREADS, bool useCompletionQueuePerThread = false);
~TGRpcClientLow();
- // Tries to stop all currently running requests (via their stop callbacks)
- // Will shutdown CQ and drain events once all requests have finished
- // No new requests may be started after this call
- void Stop(bool wait = false);
-
- // Waits until all currently running requests finish execution
- void WaitIdle();
-
- inline bool IsStopping() const {
- switch (GetCqState()) {
- case WORKING:
- return false;
- case STOP_SILENT:
- case STOP_EXPLICIT:
- return true;
- }
-
- Y_UNREACHABLE();
- }
-
- IQueueClientContextPtr CreateContext() override;
-
+ // Tries to stop all currently running requests (via their stop callbacks)
+ // Will shutdown CQ and drain events once all requests have finished
+ // No new requests may be started after this call
+ void Stop(bool wait = false);
+
+ // Waits until all currently running requests finish execution
+ void WaitIdle();
+
+ inline bool IsStopping() const {
+ switch (GetCqState()) {
+ case WORKING:
+ return false;
+ case STOP_SILENT:
+ case STOP_EXPLICIT:
+ return true;
+ }
+
+ Y_UNREACHABLE();
+ }
+
+ IQueueClientContextPtr CreateContext() override;
+
template<typename TGRpcService>
std::unique_ptr<TServiceConnection<TGRpcService>> CreateGRpcServiceConnection(const TGRpcClientConfig& config) {
return std::unique_ptr<TServiceConnection<TGRpcService>>(new TServiceConnection<TGRpcService>(CreateChannelInterface(config), this));
@@ -1367,32 +1367,32 @@ public:
return std::unique_ptr<TServiceConnection<TGRpcService>>(new TServiceConnection<TGRpcService>(holder, this));
}
- // Tests only, not thread-safe
- void AddWorkerThreadForTest();
-
+ // Tests only, not thread-safe
+ void AddWorkerThreadForTest();
+
private:
using IThreadRef = std::unique_ptr<IThreadFactory::IThread>;
using CompletionQueueRef = std::unique_ptr<grpc::CompletionQueue>;
void Init(size_t numWorkerThread);
- inline ECqState GetCqState() const { return (ECqState) AtomicGet(CqState_); }
- inline void SetCqState(ECqState state) { AtomicSet(CqState_, state); }
-
- void StopInternal(bool silent);
- void WaitInternal();
-
- void ForgetContext(TContextImpl* context);
-
-private:
+ inline ECqState GetCqState() const { return (ECqState) AtomicGet(CqState_); }
+ inline void SetCqState(ECqState state) { AtomicSet(CqState_, state); }
+
+ void StopInternal(bool silent);
+ void WaitInternal();
+
+ void ForgetContext(TContextImpl* context);
+
+private:
bool UseCompletionQueuePerThread_;
std::vector<CompletionQueueRef> CQS_;
std::vector<IThreadRef> WorkerThreads_;
- TAtomic CqState_ = -1;
-
+ TAtomic CqState_ = -1;
+
std::mutex Mtx_;
std::condition_variable ContextsEmpty_;
std::unordered_set<TContextImpl*> Contexts_;
-
+
std::mutex JoinMutex_;
};
diff --git a/library/cpp/grpc/client/grpc_common.h b/library/cpp/grpc/client/grpc_common.h
index ffcdafe045..65f74cda2f 100644
--- a/library/cpp/grpc/client/grpc_common.h
+++ b/library/cpp/grpc/client/grpc_common.h
@@ -24,8 +24,8 @@ struct TGRpcClientConfig {
ui64 MemQuota = 0;
std::unordered_map<TString, TString> StringChannelParams;
std::unordered_map<TString, int> IntChannelParams;
- TString LoadBalancingPolicy = { };
- TString SslTargetNameOverride = { };
+ TString LoadBalancingPolicy = { };
+ TString SslTargetNameOverride = { };
TGRpcClientConfig() = default;
TGRpcClientConfig(const TGRpcClientConfig&) = default;
@@ -68,12 +68,12 @@ inline std::shared_ptr<grpc::ChannelInterface> CreateChannelInterface(const TGRp
if (mutator) {
args.SetSocketMutator(mutator);
}
- if (!config.LoadBalancingPolicy.empty()) {
- args.SetLoadBalancingPolicyName(config.LoadBalancingPolicy);
- }
- if (!config.SslTargetNameOverride.empty()) {
- args.SetSslTargetNameOverride(config.SslTargetNameOverride);
- }
+ if (!config.LoadBalancingPolicy.empty()) {
+ args.SetLoadBalancingPolicyName(config.LoadBalancingPolicy);
+ }
+ if (!config.SslTargetNameOverride.empty()) {
+ args.SetSslTargetNameOverride(config.SslTargetNameOverride);
+ }
if (config.EnableSsl || config.SslCaCert) {
return grpc::CreateCustomChannel(config.Locator, grpc::SslCredentials(grpc::SslCredentialsOptions{config.SslCaCert, "", ""}), args);
} else {
diff --git a/library/cpp/grpc/server/grpc_counters.h b/library/cpp/grpc/server/grpc_counters.h
index 0b6c36c84c..e86299cbd9 100644
--- a/library/cpp/grpc/server/grpc_counters.h
+++ b/library/cpp/grpc/server/grpc_counters.h
@@ -83,13 +83,13 @@ public:
}
void CountRequestBytes(ui32 requestSize) override {
- *RequestBytes += requestSize;
- }
-
+ *RequestBytes += requestSize;
+ }
+
void CountResponseBytes(ui32 responseSize) override {
- *ResponseBytes += responseSize;
- }
-
+ *ResponseBytes += responseSize;
+ }
+
void StartProcessing(ui32 requestSize) override {
TotalCounter->Inc();
InflyCounter->Inc();
diff --git a/library/cpp/grpc/server/grpc_request.h b/library/cpp/grpc/server/grpc_request.h
index 5bd8d3902b..1fcd8b6655 100644
--- a/library/cpp/grpc/server/grpc_request.h
+++ b/library/cpp/grpc/server/grpc_request.h
@@ -117,24 +117,24 @@ public:
return TString(this->Context.peer());
}
- bool SslServer() const override {
- return Server_->SslServer();
- }
-
+ bool SslServer() const override {
+ return Server_->SslServer();
+ }
+
void Run() {
- // Start request unless server is shutting down
- if (auto guard = Server_->ProtectShutdown()) {
- Ref(); //For grpc c runtime
- this->Context.AsyncNotifyWhenDone(OnFinishTag.Prepare());
- if (RequestCallback_) {
- (this->Service->*RequestCallback_)
- (&this->Context, Request_,
- reinterpret_cast<grpc::ServerAsyncResponseWriter<TOut>*>(Writer_.Get()), this->CQ, this->CQ, GetGRpcTag());
- } else {
- (this->Service->*StreamRequestCallback_)
- (&this->Context, Request_,
- reinterpret_cast<grpc::ServerAsyncWriter<TOut>*>(StreamWriter_.Get()), this->CQ, this->CQ, GetGRpcTag());
- }
+ // Start request unless server is shutting down
+ if (auto guard = Server_->ProtectShutdown()) {
+ Ref(); //For grpc c runtime
+ this->Context.AsyncNotifyWhenDone(OnFinishTag.Prepare());
+ if (RequestCallback_) {
+ (this->Service->*RequestCallback_)
+ (&this->Context, Request_,
+ reinterpret_cast<grpc::ServerAsyncResponseWriter<TOut>*>(Writer_.Get()), this->CQ, this->CQ, GetGRpcTag());
+ } else {
+ (this->Service->*StreamRequestCallback_)
+ (&this->Context, Request_,
+ reinterpret_cast<grpc::ServerAsyncWriter<TOut>*>(StreamWriter_.Get()), this->CQ, this->CQ, GetGRpcTag());
+ }
}
}
@@ -148,10 +148,10 @@ public:
}
void DestroyRequest() override {
- if (RequestRegistered_) {
- Server_->DeregisterRequestCtx(this);
- RequestRegistered_ = false;
- }
+ if (RequestRegistered_) {
+ Server_->DeregisterRequestCtx(this);
+ RequestRegistered_ = false;
+ }
UnRef();
}
@@ -346,15 +346,15 @@ private:
ok ? "true" : "false", makeRequestString().data(), this->Context.peer().c_str());
if (this->Context.c_call() == nullptr) {
- Y_VERIFY(!ok);
+ Y_VERIFY(!ok);
// One ref by OnFinishTag, grpc will not call this tag if no request received
UnRef();
- } else if (!(RequestRegistered_ = Server_->RegisterRequestCtx(this))) {
- // Request cannot be registered due to shutdown
- // It's unsafe to continue, so drop this request without processing
+ } else if (!(RequestRegistered_ = Server_->RegisterRequestCtx(this))) {
+ // Request cannot be registered due to shutdown
+ // It's unsafe to continue, so drop this request without processing
GRPC_LOG_DEBUG(Logger_, "[%p] dropping request Name# %s due to shutdown", this, Name_);
- this->Context.TryCancel();
- return false;
+ this->Context.TryCancel();
+ return false;
}
Clone(); // TODO: Request pool?
@@ -501,7 +501,7 @@ private:
ui32 ResponseStatus = 0;
THPTimer RequestTimer;
TAuthState AuthState_ = 0;
- bool RequestRegistered_ = false;
+ bool RequestRegistered_ = false;
using TFixedEvent = TQueueFixedEvent<TGRpcRequestImpl>;
TFixedEvent OnFinishTag = { this, &TGRpcRequestImpl::OnFinish };
diff --git a/library/cpp/grpc/server/grpc_request_base.h b/library/cpp/grpc/server/grpc_request_base.h
index fcfce1c181..dc293ec01a 100644
--- a/library/cpp/grpc/server/grpc_request_base.h
+++ b/library/cpp/grpc/server/grpc_request_base.h
@@ -108,9 +108,9 @@ public:
//! Returns peer address
virtual TString GetPeer() const = 0;
-
- //! Returns true if server is using ssl
- virtual bool SslServer() const = 0;
+
+ //! Returns true if server is using ssl
+ virtual bool SslServer() const = 0;
};
} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_server.cpp b/library/cpp/grpc/server/grpc_server.cpp
index 7437b7a8f5..9bc8305390 100644
--- a/library/cpp/grpc/server/grpc_server.cpp
+++ b/library/cpp/grpc/server/grpc_server.cpp
@@ -77,7 +77,7 @@ void TGRpcServer::Start() {
builder.SetMaxReceiveMessageSize(Options_.MaxMessageSize);
builder.SetMaxSendMessageSize(Options_.MaxMessageSize);
for (IGRpcServicePtr service : Services_) {
- service->SetServerOptions(Options_);
+ service->SetServerOptions(Options_);
builder.RegisterService(service->GetService());
service->SetGlobalLimiterHandle(&Limiter_);
}
@@ -192,14 +192,14 @@ void TGRpcServer::Stop() {
}
for (ui64 attempt = 0; ; ++attempt) {
- bool unsafe = false;
+ bool unsafe = false;
size_t infly = 0;
for (auto& service : Services_) {
- unsafe |= service->IsUnsafeToShutdown();
- infly += service->RequestsInProgress();
+ unsafe |= service->IsUnsafeToShutdown();
+ infly += service->RequestsInProgress();
}
- if (!unsafe && !infly)
+ if (!unsafe && !infly)
break;
auto spent = (TInstant::Now() - now).SecondsFloat();
@@ -208,7 +208,7 @@ void TGRpcServer::Stop() {
Cerr << "GRpc shutdown warning: left infly: " << infly << ", spent: " << spent << " sec" << Endl;
}
- if (!unsafe && spent > Options_.GRpcShutdownDeadline.SecondsFloat())
+ if (!unsafe && spent > Options_.GRpcShutdownDeadline.SecondsFloat())
break;
Sleep(TDuration::MilliSeconds(10));
}
diff --git a/library/cpp/grpc/server/grpc_server.h b/library/cpp/grpc/server/grpc_server.h
index d6814a90a0..59ed364bc9 100644
--- a/library/cpp/grpc/server/grpc_server.h
+++ b/library/cpp/grpc/server/grpc_server.h
@@ -167,77 +167,77 @@ public:
virtual void StopService() noexcept = 0;
virtual void InitService(grpc::ServerCompletionQueue* cq, TLoggerPtr logger) = 0;
virtual void SetGlobalLimiterHandle(TGlobalLimiter* limiter) = 0;
- virtual bool IsUnsafeToShutdown() const = 0;
- virtual size_t RequestsInProgress() const = 0;
-
- /**
- * Called before service is added to the server builder. This allows
- * service to inspect server options and initialize accordingly.
- */
- virtual void SetServerOptions(const TServerOptions& options) = 0;
+ virtual bool IsUnsafeToShutdown() const = 0;
+ virtual size_t RequestsInProgress() const = 0;
+
+ /**
+ * Called before service is added to the server builder. This allows
+ * service to inspect server options and initialize accordingly.
+ */
+ virtual void SetServerOptions(const TServerOptions& options) = 0;
};
template<typename T>
class TGrpcServiceBase: public IGRpcService {
public:
- class TShutdownGuard {
- using TOwner = TGrpcServiceBase<T>;
- friend class TGrpcServiceBase<T>;
-
- public:
- TShutdownGuard()
- : Owner(nullptr)
- { }
-
- ~TShutdownGuard() {
- Release();
- }
-
- TShutdownGuard(TShutdownGuard&& other)
- : Owner(other.Owner)
- {
- other.Owner = nullptr;
- }
-
- TShutdownGuard& operator=(TShutdownGuard&& other) {
- if (Y_LIKELY(this != &other)) {
- Release();
- Owner = other.Owner;
- other.Owner = nullptr;
- }
- return *this;
- }
-
- explicit operator bool() const {
- return bool(Owner);
- }
-
- void Release() {
- if (Owner) {
- AtomicDecrement(Owner->GuardCount_);
- Owner = nullptr;
- }
- }
-
- TShutdownGuard(const TShutdownGuard&) = delete;
- TShutdownGuard& operator=(const TShutdownGuard&) = delete;
-
- private:
- explicit TShutdownGuard(TOwner* owner)
- : Owner(owner)
- { }
-
- private:
- TOwner* Owner;
- };
-
-public:
+ class TShutdownGuard {
+ using TOwner = TGrpcServiceBase<T>;
+ friend class TGrpcServiceBase<T>;
+
+ public:
+ TShutdownGuard()
+ : Owner(nullptr)
+ { }
+
+ ~TShutdownGuard() {
+ Release();
+ }
+
+ TShutdownGuard(TShutdownGuard&& other)
+ : Owner(other.Owner)
+ {
+ other.Owner = nullptr;
+ }
+
+ TShutdownGuard& operator=(TShutdownGuard&& other) {
+ if (Y_LIKELY(this != &other)) {
+ Release();
+ Owner = other.Owner;
+ other.Owner = nullptr;
+ }
+ return *this;
+ }
+
+ explicit operator bool() const {
+ return bool(Owner);
+ }
+
+ void Release() {
+ if (Owner) {
+ AtomicDecrement(Owner->GuardCount_);
+ Owner = nullptr;
+ }
+ }
+
+ TShutdownGuard(const TShutdownGuard&) = delete;
+ TShutdownGuard& operator=(const TShutdownGuard&) = delete;
+
+ private:
+ explicit TShutdownGuard(TOwner* owner)
+ : Owner(owner)
+ { }
+
+ private:
+ TOwner* Owner;
+ };
+
+public:
using TCurrentGRpcService = T;
void StopService() noexcept override {
with_lock(Lock_) {
- AtomicSet(ShuttingDown_, 1);
-
+ AtomicSet(ShuttingDown_, 1);
+
// Send TryCansel to event (can be send after finishing).
// Actual dtors will be called from grpc thread, so deadlock impossible
for (auto* request : Requests_) {
@@ -246,21 +246,21 @@ public:
}
}
- TShutdownGuard ProtectShutdown() noexcept {
- AtomicIncrement(GuardCount_);
- if (IsShuttingDown()) {
- AtomicDecrement(GuardCount_);
- return { };
- }
-
- return TShutdownGuard(this);
- };
-
- bool IsUnsafeToShutdown() const override {
- return AtomicGet(GuardCount_) > 0;
- }
-
- size_t RequestsInProgress() const override {
+ TShutdownGuard ProtectShutdown() noexcept {
+ AtomicIncrement(GuardCount_);
+ if (IsShuttingDown()) {
+ AtomicDecrement(GuardCount_);
+ return { };
+ }
+
+ return TShutdownGuard(this);
+ };
+
+ bool IsUnsafeToShutdown() const override {
+ return AtomicGet(GuardCount_) > 0;
+ }
+
+ size_t RequestsInProgress() const override {
size_t c = 0;
with_lock(Lock_) {
c = Requests_.size();
@@ -268,9 +268,9 @@ public:
return c;
}
- void SetServerOptions(const TServerOptions& options) override {
- SslServer_ = bool(options.SslData);
- NeedAuth_ = options.UseAuth;
+ void SetServerOptions(const TServerOptions& options) override {
+ SslServer_ = bool(options.SslData);
+ NeedAuth_ = options.UseAuth;
}
void SetGlobalLimiterHandle(TGlobalLimiter* /*limiter*/) override {}
@@ -280,32 +280,32 @@ public:
return AtomicGet(ShuttingDown_);
}
- bool SslServer() const {
- return SslServer_;
- }
-
+ bool SslServer() const {
+ return SslServer_;
+ }
+
bool NeedAuth() const {
return NeedAuth_;
}
- bool RegisterRequestCtx(ICancelableContext* req) {
+ bool RegisterRequestCtx(ICancelableContext* req) {
with_lock(Lock_) {
- auto r = Requests_.emplace(req);
- Y_VERIFY(r.second, "Ctx already registered");
-
- if (IsShuttingDown()) {
- // Server is already shutting down
- Requests_.erase(r.first);
- return false;
- }
+ auto r = Requests_.emplace(req);
+ Y_VERIFY(r.second, "Ctx already registered");
+
+ if (IsShuttingDown()) {
+ // Server is already shutting down
+ Requests_.erase(r.first);
+ return false;
+ }
}
-
- return true;
+
+ return true;
}
void DeregisterRequestCtx(ICancelableContext* req) {
with_lock(Lock_) {
- Y_VERIFY(Requests_.erase(req), "Ctx is not registered");
+ Y_VERIFY(Requests_.erase(req), "Ctx is not registered");
}
}
@@ -313,15 +313,15 @@ protected:
using TGrpcAsyncService = typename TCurrentGRpcService::AsyncService;
TGrpcAsyncService Service_;
- TGrpcAsyncService* GetService() override {
+ TGrpcAsyncService* GetService() override {
return &Service_;
}
private:
TAtomic ShuttingDown_ = 0;
- TAtomic GuardCount_ = 0;
+ TAtomic GuardCount_ = 0;
- bool SslServer_ = false;
+ bool SslServer_ = false;
bool NeedAuth_ = false;
THashSet<ICancelableContext*> Requests_;
diff --git a/library/cpp/lfalloc/lf_allocX64.h b/library/cpp/lfalloc/lf_allocX64.h
index fd2a906d6f..408fefbdc6 100644
--- a/library/cpp/lfalloc/lf_allocX64.h
+++ b/library/cpp/lfalloc/lf_allocX64.h
@@ -889,15 +889,15 @@ static void* SlowLFAlloc(int nSizeIdx, int blockSize, EDefrag defrag) {
IncrementCounter(CT_SLOW_ALLOC_CNT, 1);
TLFLockHolder ls;
- for (;;) {
- bool locked = ls.TryLock(&LFGlobalLock);
+ for (;;) {
+ bool locked = ls.TryLock(&LFGlobalLock);
void* res = LFAllocFromCurrentChunk(nSizeIdx, blockSize, 1);
if (res) {
return res; // might happen when other thread allocated new current chunk
}
- if (locked) {
- break;
- }
+ if (locked) {
+ break;
+ }
}
for (;;) {
uintptr_t nChunk;
diff --git a/library/cpp/terminate_handler/segv_handler.cpp b/library/cpp/terminate_handler/segv_handler.cpp
index f24ece4125..c5127496cd 100644
--- a/library/cpp/terminate_handler/segv_handler.cpp
+++ b/library/cpp/terminate_handler/segv_handler.cpp
@@ -16,7 +16,7 @@
static void SegvHandler(int sig) {
Y_UNUSED(sig);
const char msg[] = "Got SEGV\n";
- Y_UNUSED(write(STDERR_FILENO, msg, sizeof(msg)));
+ Y_UNUSED(write(STDERR_FILENO, msg, sizeof(msg)));
//PrintBackTrace();
sig_t r = signal(SIGSEGV, SIG_DFL);
if (r == SIG_ERR) {
diff --git a/library/cpp/threading/future/core/future-inl.h b/library/cpp/threading/future/core/future-inl.h
index 5fd4296a93..506c77d4c8 100644
--- a/library/cpp/threading/future/core/future-inl.h
+++ b/library/cpp/threading/future/core/future-inl.h
@@ -619,8 +619,8 @@ namespace NThreading {
template <typename T>
template <typename F>
- inline TFuture<TFutureType<TFutureCallResult<F, T>>> TFuture<T>::Apply(F&& func) const {
- auto promise = NewPromise<TFutureType<TFutureCallResult<F, T>>>();
+ inline TFuture<TFutureType<TFutureCallResult<F, T>>> TFuture<T>::Apply(F&& func) const {
+ auto promise = NewPromise<TFutureType<TFutureCallResult<F, T>>>();
Subscribe([promise, func = std::forward<F>(func)](const TFuture<T>& future) mutable {
NImpl::SetValue(promise, [&]() { return func(future); });
});
@@ -718,8 +718,8 @@ namespace NThreading {
template <typename F>
- inline TFuture<TFutureType<TFutureCallResult<F, void>>> TFuture<void>::Apply(F&& func) const {
- auto promise = NewPromise<TFutureType<TFutureCallResult<F, void>>>();
+ inline TFuture<TFutureType<TFutureCallResult<F, void>>> TFuture<void>::Apply(F&& func) const {
+ auto promise = NewPromise<TFutureType<TFutureCallResult<F, void>>>();
Subscribe([promise, func = std::forward<F>(func)](const TFuture<void>& future) mutable {
NImpl::SetValue(promise, [&]() { return func(future); });
});
diff --git a/library/cpp/threading/future/core/future.h b/library/cpp/threading/future/core/future.h
index 2e82bb953e..00dc245d9a 100644
--- a/library/cpp/threading/future/core/future.h
+++ b/library/cpp/threading/future/core/future.h
@@ -47,20 +47,20 @@ namespace NThreading {
struct TFutureType<TFuture<T>> {
using TType = typename TFutureType<T>::TType;
};
-
- template <typename F, typename T>
- struct TFutureCallResult {
- // NOTE: separate class for msvc compatibility
- using TType = decltype(std::declval<F&>()(std::declval<const TFuture<T>&>()));
- };
+
+ template <typename F, typename T>
+ struct TFutureCallResult {
+ // NOTE: separate class for msvc compatibility
+ using TType = decltype(std::declval<F&>()(std::declval<const TFuture<T>&>()));
+ };
}
template <typename F>
using TFutureType = typename NImpl::TFutureType<F>::TType;
- template <typename F, typename T>
- using TFutureCallResult = typename NImpl::TFutureCallResult<F, T>::TType;
-
+ template <typename F, typename T>
+ using TFutureCallResult = typename NImpl::TFutureCallResult<F, T>::TType;
+
//! Type of the future/promise state identifier
class TFutureStateId;
@@ -109,7 +109,7 @@ namespace NThreading {
const TFuture<T>& NoexceptSubscribe(F&& callback) const noexcept;
template <typename F>
- TFuture<TFutureType<TFutureCallResult<F, T>>> Apply(F&& func) const;
+ TFuture<TFutureType<TFutureCallResult<F, T>>> Apply(F&& func) const;
TFuture<void> IgnoreResult() const;
@@ -164,7 +164,7 @@ namespace NThreading {
const TFuture<void>& NoexceptSubscribe(F&& callback) const noexcept;
template <typename F>
- TFuture<TFutureType<TFutureCallResult<F, void>>> Apply(F&& func) const;
+ TFuture<TFutureType<TFutureCallResult<F, void>>> Apply(F&& func) const;
template <typename R>
TFuture<R> Return(const R& value) const;
diff --git a/library/cpp/threading/future/future_ut.cpp b/library/cpp/threading/future/future_ut.cpp
index 05950a568d..377154e867 100644
--- a/library/cpp/threading/future/future_ut.cpp
+++ b/library/cpp/threading/future/future_ut.cpp
@@ -168,7 +168,7 @@ namespace {
TTestCallback callback(123);
TFuture<int> future = promise.GetFuture()
- .Apply([&](const auto& theFuture) { return callback.Func(theFuture); });
+ .Apply([&](const auto& theFuture) { return callback.Func(theFuture); });
promise.SetValue(456);
UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
@@ -180,7 +180,7 @@ namespace {
TTestCallback callback(123);
TFuture<void> future = promise.GetFuture()
- .Apply([&](const auto& theFuture) { return callback.VoidFunc(theFuture); });
+ .Apply([&](const auto& theFuture) { return callback.VoidFunc(theFuture); });
promise.SetValue(456);
UNIT_ASSERT(future.HasValue());
@@ -191,7 +191,7 @@ namespace {
TTestCallback callback(123);
TFuture<int> future = promise.GetFuture()
- .Apply([&](const auto& theFuture) { return callback.FutureFunc(theFuture); });
+ .Apply([&](const auto& theFuture) { return callback.FutureFunc(theFuture); });
promise.SetValue(456);
UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
@@ -203,7 +203,7 @@ namespace {
TTestCallback callback(123);
TFuture<void> future = promise.GetFuture()
- .Apply([&](const auto& theFuture) { return callback.FutureVoidFunc(theFuture); });
+ .Apply([&](const auto& theFuture) { return callback.FutureVoidFunc(theFuture); });
promise.SetValue(456);
UNIT_ASSERT(!future.HasValue());
diff --git a/library/cpp/threading/skip_list/skiplist_ut.cpp b/library/cpp/threading/skip_list/skiplist_ut.cpp
index 52fcffda66..f1f075c04c 100644
--- a/library/cpp/threading/skip_list/skiplist_ut.cpp
+++ b/library/cpp/threading/skip_list/skiplist_ut.cpp
@@ -38,148 +38,148 @@ namespace NThreading {
Y_UNIT_TEST_SUITE(TSkipListTest) {
Y_UNIT_TEST(ShouldBeEmptyAfterCreation) {
TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TSkipList<int> list(pool);
- UNIT_ASSERT_EQUAL(list.GetSize(), 0);
- }
+ UNIT_ASSERT_EQUAL(list.GetSize(), 0);
+ }
Y_UNIT_TEST(ShouldAllowInsertion) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(12345678));
- UNIT_ASSERT_EQUAL(list.GetSize(), 1);
- }
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ }
Y_UNIT_TEST(ShouldNotAllowDuplicates) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(12345678));
- UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
- UNIT_ASSERT(!list.Insert(12345678));
- UNIT_ASSERT_EQUAL(list.GetSize(), 1);
- }
+ UNIT_ASSERT(!list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ }
Y_UNIT_TEST(ShouldContainInsertedItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(12345678));
- UNIT_ASSERT(list.Contains(12345678));
- }
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT(list.Contains(12345678));
+ }
Y_UNIT_TEST(ShouldNotContainNotInsertedItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(12345678));
- UNIT_ASSERT(!list.Contains(87654321));
- }
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT(!list.Contains(87654321));
+ }
Y_UNIT_TEST(ShouldIterateAllItems) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
-
- for (int i = 8; i > 0; --i) {
- UNIT_ASSERT(list.Insert(i));
- }
-
- TSkipList<int>::TIterator it = list.SeekToFirst();
- for (int i = 1; i <= 8; ++i) {
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), i);
- it.Next();
- }
- UNIT_ASSERT(!it.IsValid());
- }
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToFirst();
+ for (int i = 1; i <= 8; ++i) {
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), i);
+ it.Next();
+ }
+ UNIT_ASSERT(!it.IsValid());
+ }
Y_UNIT_TEST(ShouldIterateAllItemsInReverseDirection) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
-
- for (int i = 8; i > 0; --i) {
- UNIT_ASSERT(list.Insert(i));
- }
-
- TSkipList<int>::TIterator it = list.SeekToLast();
- for (int i = 8; i > 0; --i) {
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), i);
- it.Prev();
- }
- UNIT_ASSERT(!it.IsValid());
- }
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToLast();
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), i);
+ it.Prev();
+ }
+ UNIT_ASSERT(!it.IsValid());
+ }
Y_UNIT_TEST(ShouldSeekToFirstItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- for (int i = 1; i < 10; ++i) {
- UNIT_ASSERT(list.Insert(i));
- }
+ for (int i = 1; i < 10; ++i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
- TSkipList<int>::TIterator it = list.SeekToFirst();
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), 1);
- }
+ TSkipList<int>::TIterator it = list.SeekToFirst();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 1);
+ }
Y_UNIT_TEST(ShouldSeekToLastItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- for (int i = 1; i < 10; ++i) {
- UNIT_ASSERT(list.Insert(i));
- }
+ for (int i = 1; i < 10; ++i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
- TSkipList<int>::TIterator it = list.SeekToLast();
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), 9);
- }
+ TSkipList<int>::TIterator it = list.SeekToLast();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 9);
+ }
Y_UNIT_TEST(ShouldSeekToExistingItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT(list.Insert(12345678));
- TSkipList<int>::TIterator it = list.SeekTo(12345678);
- UNIT_ASSERT(it.IsValid());
- }
+ TSkipList<int>::TIterator it = list.SeekTo(12345678);
+ UNIT_ASSERT(it.IsValid());
+ }
Y_UNIT_TEST(ShouldSeekAfterMissedItem) {
- TMemoryPool pool(1024);
- TSkipList<int> list(pool);
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
- UNIT_ASSERT(list.Insert(100));
- UNIT_ASSERT(list.Insert(300));
+ UNIT_ASSERT(list.Insert(100));
+ UNIT_ASSERT(list.Insert(300));
- TSkipList<int>::TIterator it = list.SeekTo(200);
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), 300);
+ TSkipList<int>::TIterator it = list.SeekTo(200);
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 300);
- it.Prev();
- UNIT_ASSERT(it.IsValid());
- UNIT_ASSERT_EQUAL(it.GetValue(), 100);
- }
+ it.Prev();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 100);
+ }
Y_UNIT_TEST(ShouldCallDtorsOfNonPodTypes) {
- UNIT_ASSERT(!TTypeTraits<TTestObject>::IsPod);
- UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
+ UNIT_ASSERT(!TTypeTraits<TTestObject>::IsPod);
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
- {
- TMemoryPool pool(1024);
- TSkipList<TTestObject> list(pool);
+ {
+ TMemoryPool pool(1024);
+ TSkipList<TTestObject> list(pool);
- UNIT_ASSERT(list.Insert(TTestObject(1)));
- UNIT_ASSERT(list.Insert(TTestObject(2)));
-
- UNIT_ASSERT_EQUAL(TTestObject::Count, 2);
- }
+ UNIT_ASSERT(list.Insert(TTestObject(1)));
+ UNIT_ASSERT(list.Insert(TTestObject(2)));
- UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
- }
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 2);
+ }
+
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
+ }
}
}