diff options
author | ddoarn <ddoarn@yandex-team.ru> | 2022-02-10 16:49:52 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:52 +0300 |
commit | 0783fe3f48d91a3b741ce2ea32b11fbfc1637e7e (patch) | |
tree | 6d6a79d83e5003eaf4d45cac346113c1137cb886 /library | |
parent | 9541fc30d6f0877db9ff199a16f7fc2505d46a5c (diff) | |
download | ydb-0783fe3f48d91a3b741ce2ea32b11fbfc1637e7e.tar.gz |
Restoring authorship annotation for <ddoarn@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library')
96 files changed, 6081 insertions, 6081 deletions
diff --git a/library/cpp/actors/core/actor.cpp b/library/cpp/actors/core/actor.cpp index 6f9ba6a42b..b9f1eb1b9d 100644 --- a/library/cpp/actors/core/actor.cpp +++ b/library/cpp/actors/core/actor.cpp @@ -1,16 +1,16 @@ -#include "actor.h" -#include "executor_thread.h" -#include "mailbox.h" +#include "actor.h" +#include "executor_thread.h" +#include "mailbox.h" #include <library/cpp/actors/util/datetime.h> - -namespace NActors { - Y_POD_THREAD(TActivationContext*) - TlsActivationContext((TActivationContext*)nullptr); - + +namespace NActors { + Y_POD_THREAD(TActivationContext*) + TlsActivationContext((TActivationContext*)nullptr); + bool TActorContext::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const { return Send(new IEventHandle(recipient, SelfID, ev, flags, cookie, nullptr, std::move(traceId))); - } - + } + bool TActorContext::Send(TAutoPtr<IEventHandle> ev) const { return ExecutorThread.Send(ev); } @@ -26,13 +26,13 @@ namespace NActors { } bool IActor::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const noexcept { - return SelfActorId.Send(recipient, ev, flags, cookie, std::move(traceId)); - } - - bool TActivationContext::Send(TAutoPtr<IEventHandle> ev) { - return TlsActivationContext->ExecutorThread.Send(ev); - } - + return SelfActorId.Send(recipient, ev, flags, cookie, std::move(traceId)); + } + + bool TActivationContext::Send(TAutoPtr<IEventHandle> ev) { + return TlsActivationContext->ExecutorThread.Send(ev); + } + void TActivationContext::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie); } @@ -46,9 +46,9 @@ namespace NActors { } bool TActorIdentity::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const { - return TActivationContext::Send(new IEventHandle(recipient, *this, ev, flags, cookie, nullptr, std::move(traceId))); - } - + return TActivationContext::Send(new IEventHandle(recipient, *this, ev, flags, cookie, nullptr, std::move(traceId))); + } + void TActorIdentity::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const { return TActivationContext::Schedule(deadline, new IEventHandle(*this, {}, ev), cookie); } @@ -62,31 +62,31 @@ namespace NActors { } TActorId TActivationContext::RegisterWithSameMailbox(IActor* actor, TActorId parentId) { - Y_VERIFY_DEBUG(parentId); - auto& ctx = *TlsActivationContext; - return ctx.ExecutorThread.RegisterActor(actor, &ctx.Mailbox, parentId.Hint(), parentId); - } - + Y_VERIFY_DEBUG(parentId); + auto& ctx = *TlsActivationContext; + return ctx.ExecutorThread.RegisterActor(actor, &ctx.Mailbox, parentId.Hint(), parentId); + } + TActorId TActorContext::RegisterWithSameMailbox(IActor* actor) const { - return ExecutorThread.RegisterActor(actor, &Mailbox, SelfID.Hint(), SelfID); - } - + return ExecutorThread.RegisterActor(actor, &Mailbox, SelfID.Hint(), SelfID); + } + TActorId IActor::RegisterWithSameMailbox(IActor* actor) const noexcept { - return TlsActivationContext->ExecutorThread.RegisterActor(actor, &TlsActivationContext->Mailbox, SelfActorId.Hint(), SelfActorId); - } - + return TlsActivationContext->ExecutorThread.RegisterActor(actor, &TlsActivationContext->Mailbox, SelfActorId.Hint(), SelfActorId); + } + TActorId TActivationContext::Register(IActor* actor, TActorId parentId, TMailboxType::EType mailboxType, ui32 poolId) { - return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, parentId); - } - + return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, parentId); + } + TActorId TActivationContext::InterconnectProxy(ui32 destinationNodeId) { - return TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(destinationNodeId); - } - - TActorSystem* TActivationContext::ActorSystem() { - return TlsActivationContext->ExecutorThread.ActorSystem; - } - + return TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(destinationNodeId); + } + + TActorSystem* TActivationContext::ActorSystem() { + return TlsActivationContext->ExecutorThread.ActorSystem; + } + i64 TActivationContext::GetCurrentEventTicks() { return GetCycleCountFast() - TlsActivationContext->EventStart; } @@ -96,13 +96,13 @@ namespace NActors { } TActorId TActorContext::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const { - return ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfID); - } - + return ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfID); + } + TActorId IActor::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const noexcept { - return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfActorId); - } - + return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfActorId); + } + void TActorContext::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const { ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie); } @@ -111,10 +111,10 @@ namespace NActors { ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie); } - void TActorContext::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const { + void TActorContext::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const { ExecutorThread.Schedule(delta, new IEventHandle(SelfID, TActorId(), ev), cookie); - } - + } + void IActor::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept { TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie); } @@ -125,20 +125,20 @@ namespace NActors { void IActor::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const noexcept { TlsActivationContext->ExecutorThread.Schedule(delta, new IEventHandle(SelfActorId, TActorId(), ev), cookie); - } - - TInstant TActivationContext::Now() { - return TlsActivationContext->ExecutorThread.ActorSystem->Timestamp(); - } - + } + + TInstant TActivationContext::Now() { + return TlsActivationContext->ExecutorThread.ActorSystem->Timestamp(); + } + TMonotonic TActivationContext::Monotonic() { return TlsActivationContext->ExecutorThread.ActorSystem->Monotonic(); } TInstant TActorContext::Now() const { return ExecutorThread.ActorSystem->Timestamp(); - } - + } + TMonotonic TActorContext::Monotonic() const { return ExecutorThread.ActorSystem->Monotonic(); } @@ -147,26 +147,26 @@ namespace NActors { return ExecutorThread.ActorSystem->LoggerSettings(); } - std::pair<ui32, ui32> TActorContext::CountMailboxEvents(ui32 maxTraverse) const { - return Mailbox.CountMailboxEvents(SelfID.LocalId(), maxTraverse); - } - - std::pair<ui32, ui32> IActor::CountMailboxEvents(ui32 maxTraverse) const { - return TlsActivationContext->Mailbox.CountMailboxEvents(SelfActorId.LocalId(), maxTraverse); - } - - void IActor::Die(const TActorContext& ctx) { - if (ctx.SelfID) - Y_VERIFY(ctx.SelfID == SelfActorId); - PassAway(); - } - - void IActor::PassAway() { - auto& cx = *TlsActivationContext; - cx.ExecutorThread.UnregisterActor(&cx.Mailbox, SelfActorId.LocalId()); - } - - double IActor::GetElapsedTicksAsSeconds() const { - return NHPTimer::GetSeconds(ElapsedTicks); - } -} + std::pair<ui32, ui32> TActorContext::CountMailboxEvents(ui32 maxTraverse) const { + return Mailbox.CountMailboxEvents(SelfID.LocalId(), maxTraverse); + } + + std::pair<ui32, ui32> IActor::CountMailboxEvents(ui32 maxTraverse) const { + return TlsActivationContext->Mailbox.CountMailboxEvents(SelfActorId.LocalId(), maxTraverse); + } + + void IActor::Die(const TActorContext& ctx) { + if (ctx.SelfID) + Y_VERIFY(ctx.SelfID == SelfActorId); + PassAway(); + } + + void IActor::PassAway() { + auto& cx = *TlsActivationContext; + cx.ExecutorThread.UnregisterActor(&cx.Mailbox, SelfActorId.LocalId()); + } + + double IActor::GetElapsedTicksAsSeconds() const { + return NHPTimer::GetSeconds(ElapsedTicks); + } +} diff --git a/library/cpp/actors/core/actor.h b/library/cpp/actors/core/actor.h index ed29bd14b9..a790101c34 100644 --- a/library/cpp/actors/core/actor.h +++ b/library/cpp/actors/core/actor.h @@ -1,41 +1,41 @@ -#pragma once - -#include "event.h" +#pragma once + +#include "event.h" #include "monotonic.h" -#include <util/system/tls.h> +#include <util/system/tls.h> #include <library/cpp/actors/util/local_process_key.h> - -namespace NActors { + +namespace NActors { class TActorSystem; - class TMailboxTable; - struct TMailboxHeader; - - class TExecutorThread; - class IActor; - class ISchedulerCookie; - - namespace NLog { - struct TSettings; + class TMailboxTable; + struct TMailboxHeader; + + class TExecutorThread; + class IActor; + class ISchedulerCookie; + + namespace NLog { + struct TSettings; } + + struct TActorContext; - struct TActorContext; - - struct TActivationContext { - public: - TMailboxHeader& Mailbox; - TExecutorThread& ExecutorThread; + struct TActivationContext { + public: + TMailboxHeader& Mailbox; + TExecutorThread& ExecutorThread; const NHPTimer::STime EventStart; - - protected: + + protected: explicit TActivationContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart) - : Mailbox(mailbox) - , ExecutorThread(executorThread) + : Mailbox(mailbox) + , ExecutorThread(executorThread) , EventStart(eventStart) - { - } - - public: - static bool Send(TAutoPtr<IEventHandle> ev); + { + } + + public: + static bool Send(TAutoPtr<IEventHandle> ev); /** * Schedule one-shot event that will be send at given time point in the future. @@ -63,40 +63,40 @@ namespace NActors { * @param cookie cookie that will be piggybacked with event */ static void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - - static TInstant Now(); + + static TInstant Now(); static TMonotonic Monotonic(); NLog::TSettings* LoggerSettings() const; - - // register new actor in ActorSystem on new fresh mailbox. + + // register new actor in ActorSystem on new fresh mailbox. static TActorId Register(IActor* actor, TActorId parentId = TActorId(), TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()); - + // Register new actor in ActorSystem on same _mailbox_ as current actor. // There is one thread per mailbox to execute actor, which mean // no _cpu core scalability_ for such actors. // This method of registration can be usefull if multiple actors share // some memory. static TActorId RegisterWithSameMailbox(IActor* actor, TActorId parentId); - - static const TActorContext& AsActorContext(); + + static const TActorContext& AsActorContext(); static TActorContext ActorContextFor(TActorId id); - + static TActorId InterconnectProxy(ui32 nodeid); - static TActorSystem* ActorSystem(); + static TActorSystem* ActorSystem(); static i64 GetCurrentEventTicks(); static double GetCurrentEventTicksAsSeconds(); - }; - - struct TActorContext: public TActivationContext { + }; + + struct TActorContext: public TActivationContext { const TActorId SelfID; - + explicit TActorContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart, const TActorId& selfID) : TActivationContext(mailbox, executorThread, eventStart) - , SelfID(selfID) - { - } - + , SelfID(selfID) + { + } + bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; template <typename TEvent> bool Send(const TActorId& recipient, THolder<TEvent> ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { @@ -132,47 +132,47 @@ namespace NActors { * @param ev the event to send * @param cookie cookie that will be piggybacked with event */ - void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; + void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; TActorContext MakeFor(const TActorId& otherId) const { return TActorContext(Mailbox, ExecutorThread, EventStart, otherId); - } - - // register new actor in ActorSystem on new fresh mailbox. + } + + // register new actor in ActorSystem on new fresh mailbox. TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const; - + // Register new actor in ActorSystem on same _mailbox_ as current actor. // There is one thread per mailbox to execute actor, which mean // no _cpu core scalability_ for such actors. // This method of registration can be usefull if multiple actors share // some memory. TActorId RegisterWithSameMailbox(IActor* actor) const; - - std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; - }; - - extern Y_POD_THREAD(TActivationContext*) TlsActivationContext; - + + std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; + }; + + extern Y_POD_THREAD(TActivationContext*) TlsActivationContext; + struct TActorIdentity: public TActorId { explicit TActorIdentity(TActorId actorId) : TActorId(actorId) - { - } - + { + } + void operator=(TActorId actorId) { - *this = TActorIdentity(actorId); - } - + *this = TActorIdentity(actorId); + } + bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - }; - + }; + class IActor; class IActorOps : TNonCopyable { - public: + public: virtual void Describe(IOutputStream&) const noexcept = 0; virtual bool Send(const TActorId& recipient, IEventBase*, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept = 0; @@ -211,24 +211,24 @@ namespace NActors { class IActor : protected IActorOps { public: - typedef void (IActor::*TReceiveFunc)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx); - - private: - TReceiveFunc StateFunc; - TActorIdentity SelfActorId; - i64 ElapsedTicks; - ui64 HandledEvents; + typedef void (IActor::*TReceiveFunc)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx); + + private: + TReceiveFunc StateFunc; + TActorIdentity SelfActorId; + i64 ElapsedTicks; + ui64 HandledEvents; friend void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); friend class TDecorator; - - public: + + public: /// @sa services.proto NKikimrServices::TActivity::EType - enum EActorActivity { - OTHER = 0, - ACTOR_SYSTEM = 1, - ACTORLIB_COMMON = 2, - ACTORLIB_STATS = 3, + enum EActorActivity { + OTHER = 0, + ACTOR_SYSTEM = 1, + ACTORLIB_COMMON = 2, + ACTORLIB_STATS = 3, LOG_ACTOR = 4, INTERCONNECT_PROXY_TCP = 12, INTERCONNECT_SESSION_TCP = 13, @@ -246,64 +246,64 @@ namespace NActors { NAMESERVICE = 450, DNS_RESOLVER = 481, INTERCONNECT_PROXY_WRAPPER = 546, - }; + }; using EActivityType = EActorActivity; ui32 ActivityType; - protected: + protected: IActor(TReceiveFunc stateFunc, ui32 activityType = OTHER) - : StateFunc(stateFunc) + : StateFunc(stateFunc) , SelfActorId(TActorId()) - , ElapsedTicks(0) - , HandledEvents(0) - , ActivityType(activityType) - { - } - - public: - virtual ~IActor() { - } // must not be called for registered actors, see Die method instead - - protected: - virtual void Die(const TActorContext& ctx); // would unregister actor so call exactly once and only from inside of message processing - virtual void PassAway(); - - public: - template <typename T> - void Become(T stateFunc) { - StateFunc = static_cast<TReceiveFunc>(stateFunc); - } - + , ElapsedTicks(0) + , HandledEvents(0) + , ActivityType(activityType) + { + } + + public: + virtual ~IActor() { + } // must not be called for registered actors, see Die method instead + + protected: + virtual void Die(const TActorContext& ctx); // would unregister actor so call exactly once and only from inside of message processing + virtual void PassAway(); + + public: + template <typename T> + void Become(T stateFunc) { + StateFunc = static_cast<TReceiveFunc>(stateFunc); + } + template <typename T, typename... TArgs> void Become(T stateFunc, const TActorContext& ctx, TArgs&&... args) { - StateFunc = static_cast<TReceiveFunc>(stateFunc); + StateFunc = static_cast<TReceiveFunc>(stateFunc); ctx.Schedule(std::forward<TArgs>(args)...); - } - + } + template <typename T, typename... TArgs> void Become(T stateFunc, TArgs&&... args) { - StateFunc = static_cast<TReceiveFunc>(stateFunc); + StateFunc = static_cast<TReceiveFunc>(stateFunc); Schedule(std::forward<TArgs>(args)...); - } - - protected: + } + + protected: void SetActivityType(ui32 activityType) { - ActivityType = activityType; - } - - public: - TReceiveFunc CurrentStateFunc() const { - return StateFunc; - } - - // NOTE: exceptions must not escape state function but if an exception hasn't be caught - // by the actor then we want to crash an see the stack - void Receive(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) { - (this->*StateFunc)(ev, ctx); - HandledEvents++; - } - + ActivityType = activityType; + } + + public: + TReceiveFunc CurrentStateFunc() const { + return StateFunc; + } + + // NOTE: exceptions must not escape state function but if an exception hasn't be caught + // by the actor then we want to crash an see the stack + void Receive(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) { + (this->*StateFunc)(ev, ctx); + HandledEvents++; + } + // must be called to wrap any call trasitions from one actor to another template<typename TActor, typename TMethod, typename... TArgs> static decltype((std::declval<TActor>().*std::declval<TMethod>())(std::declval<TArgs>()...)) @@ -326,29 +326,29 @@ namespace NActors { virtual void Registered(TActorSystem* sys, const TActorId& owner); virtual TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) { - Y_UNUSED(self); - Y_UNUSED(parentId); - return TAutoPtr<IEventHandle>(); - } - - i64 GetElapsedTicks() const { - return ElapsedTicks; - } - double GetElapsedTicksAsSeconds() const; - void AddElapsedTicks(i64 ticks) { - ElapsedTicks += ticks; - } + Y_UNUSED(self); + Y_UNUSED(parentId); + return TAutoPtr<IEventHandle>(); + } + + i64 GetElapsedTicks() const { + return ElapsedTicks; + } + double GetElapsedTicksAsSeconds() const; + void AddElapsedTicks(i64 ticks) { + ElapsedTicks += ticks; + } auto GetActivityType() const { - return ActivityType; - } - ui64 GetHandledEvents() const { - return HandledEvents; - } - TActorIdentity SelfId() const { - return SelfActorId; - } - - protected: + return ActivityType; + } + ui64 GetHandledEvents() const { + return HandledEvents; + } + TActorIdentity SelfId() const { + return SelfActorId; + } + + protected: void Describe(IOutputStream&) const noexcept override; bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept final; template <typename TEvent> @@ -364,25 +364,25 @@ 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(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final; - - // register new actor in ActorSystem on new fresh mailbox. + + // register new actor in ActorSystem on new fresh mailbox. TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept final; - + // Register new actor in ActorSystem on same _mailbox_ as current actor. // There is one thread per mailbox to execute actor, which mean // no _cpu core scalability_ for such actors. // This method of registration can be usefull if multiple actors share // some memory. TActorId RegisterWithSameMailbox(IActor* actor) const noexcept final; - - std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; + + std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; private: void ChangeSelfId(TActorId actorId) { SelfActorId = actorId; } - }; - + }; + struct TActorActivityTag {}; inline size_t GetActivityTypeCount() { @@ -417,10 +417,10 @@ namespace NActors { } } - protected: + protected: //* Comment this function to find unmarked activities - static constexpr IActor::EActivityType ActorActivityType() { - return EActorActivity::OTHER; + static constexpr IActor::EActivityType ActorActivityType() { + return EActorActivity::OTHER; } //*/ // static constexpr char ActorName[] = "UNNAMED"; @@ -428,17 +428,17 @@ namespace NActors { TActor(void (TDerived::*func)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx), ui32 activityType = GetActivityTypeIndex()) : IActor(static_cast<TReceiveFunc>(func), activityType) { } - - public: - typedef TDerived TThis; - }; - + + public: + typedef TDerived TThis; + }; + #define STFUNC_SIG TAutoPtr< ::NActors::IEventHandle>&ev, const ::NActors::TActorContext &ctx #define STATEFN_SIG TAutoPtr<::NActors::IEventHandle>& ev -#define STFUNC(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& ctx) -#define STATEFN(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& ) - +#define STFUNC(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& ctx) +#define STATEFN(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& ) + #define STRICT_STFUNC(NAME, HANDLERS) \ void NAME(STFUNC_SIG) { \ Y_UNUSED(ctx); \ @@ -449,15 +449,15 @@ namespace NActors { } \ } - inline const TActorContext& TActivationContext::AsActorContext() { - TActivationContext* tls = TlsActivationContext; - return *static_cast<TActorContext*>(tls); - } - + inline const TActorContext& TActivationContext::AsActorContext() { + TActivationContext* tls = TlsActivationContext; + return *static_cast<TActorContext*>(tls); + } + inline TActorContext TActivationContext::ActorContextFor(TActorId id) { - auto& tls = *TlsActivationContext; + auto& tls = *TlsActivationContext; return TActorContext(tls.Mailbox, tls.ExecutorThread, tls.EventStart, id); - } + } class TDecorator : public IActor { protected: @@ -515,16 +515,16 @@ namespace NActors { return true; } }; -} - -template <> -inline void Out<NActors::TActorIdentity>(IOutputStream& o, const NActors::TActorIdentity& x) { - return x.Out(o); -} - -template <> -struct THash<NActors::TActorIdentity> { - inline ui64 operator()(const NActors::TActorIdentity& x) const { - return x.Hash(); - } -}; +} + +template <> +inline void Out<NActors::TActorIdentity>(IOutputStream& o, const NActors::TActorIdentity& x) { + return x.Out(o); +} + +template <> +struct THash<NActors::TActorIdentity> { + inline ui64 operator()(const NActors::TActorIdentity& x) const { + return x.Hash(); + } +}; diff --git a/library/cpp/actors/core/actor_bootstrapped.h b/library/cpp/actors/core/actor_bootstrapped.h index a37887c939..90ab0168a2 100644 --- a/library/cpp/actors/core/actor_bootstrapped.h +++ b/library/cpp/actors/core/actor_bootstrapped.h @@ -1,19 +1,19 @@ -#pragma once - -#include "actor.h" -#include "events.h" - -namespace NActors { +#pragma once + +#include "actor.h" +#include "events.h" + +namespace NActors { template<typename T> struct dependent_false : std::false_type {}; template<typename TDerived> class TActorBootstrapped : public TActor<TDerived> { - protected: + protected: TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override { return new IEventHandle(TEvents::TSystem::Bootstrap, 0, self, parentId, {}, 0); - } - - STFUNC(StateBootstrap) { + } + + STFUNC(StateBootstrap) { Y_VERIFY(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap, "Unexpected bootstrap message"); using T = decltype(&TDerived::Bootstrap); TDerived& self = static_cast<TDerived&>(*this); @@ -27,11 +27,11 @@ namespace NActors { self.Bootstrap(ev->Sender); } else { static_assert(dependent_false<TDerived>::value, "No correct Bootstrap() signature"); - } + } } - TActorBootstrapped() - : TActor<TDerived>(&TDerived::StateBootstrap) + TActorBootstrapped() + : TActor<TDerived>(&TDerived::StateBootstrap) {} - }; + }; } diff --git a/library/cpp/actors/core/actor_coroutine.cpp b/library/cpp/actors/core/actor_coroutine.cpp index 0ab4d2b24d..538cdac971 100644 --- a/library/cpp/actors/core/actor_coroutine.cpp +++ b/library/cpp/actors/core/actor_coroutine.cpp @@ -5,17 +5,17 @@ #include <util/system/type_name.h> namespace NActors { - static constexpr size_t StackOverflowGap = 4096; - static char GoodStack[StackOverflowGap]; - - static struct TInitGoodStack { - TInitGoodStack() { - // fill stack with some pseudo-random pattern - for (size_t k = 0; k < StackOverflowGap; ++k) { - GoodStack[k] = k + k * 91; - } + static constexpr size_t StackOverflowGap = 4096; + static char GoodStack[StackOverflowGap]; + + static struct TInitGoodStack { + TInitGoodStack() { + // fill stack with some pseudo-random pattern + for (size_t k = 0; k < StackOverflowGap; ++k) { + GoodStack[k] = k + k * 91; + } } - } initGoodStack; + } initGoodStack; TActorCoroImpl::TActorCoroImpl(size_t stackSize, bool allowUnhandledPoisonPill, bool allowUnhandledDtor) : Stack(stackSize) @@ -25,15 +25,15 @@ namespace NActors { , FiberContext(FiberClosure) { #ifndef NDEBUG - char* p; + char* p; #if STACK_GROW_DOWN - p = Stack.Begin(); + p = Stack.Begin(); #else - p = Stack.End() - StackOverflowGap; + p = Stack.End() - StackOverflowGap; #endif - memcpy(p, GoodStack, StackOverflowGap); + memcpy(p, GoodStack, StackOverflowGap); #endif - } + } TActorCoroImpl::~TActorCoroImpl() { if (!Finished && !NSan::TSanIsOn()) { // only resume when we have bootstrapped and Run() was entered and not yet finished; in other case simply terminate @@ -53,11 +53,11 @@ namespace NActors { 0, cookie)); } - // ensure we have no unprocessed event and return back to actor system to receive one - Y_VERIFY(!PendingEvent); - ReturnToActorSystem(); + // ensure we have no unprocessed event and return back to actor system to receive one + Y_VERIFY(!PendingEvent); + ReturnToActorSystem(); - // obtain pending event and ensure we've got one + // obtain pending event and ensure we've got one while (THolder<IEventHandle> event = std::exchange(PendingEvent, {})) { if (event->GetTypeRewrite() != TEvents::TSystem::CoroTimeout) { // special handling for poison pill -- we throw exception @@ -72,17 +72,17 @@ namespace NActors { } else { ReturnToActorSystem(); // drop this event and wait for the next one } - } + } Y_FAIL("no pending event"); } const TActorContext& TActorCoroImpl::GetActorContext() const { Y_VERIFY(ActorContext); return *ActorContext; - } + } bool TActorCoroImpl::ProcessEvent(THolder<IEventHandle> ev) { - Y_VERIFY(!PendingEvent); + Y_VERIFY(!PendingEvent); if (!SelfActorId) { // process bootstrap message, extract actor ids Y_VERIFY(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap); SelfActorId = ev->Recipient; @@ -104,40 +104,40 @@ namespace NActors { ActorContext = nullptr; return Finished; - } + } void TActorCoroImpl::Resume() { - // save caller context for a later return - Y_VERIFY(!ActorSystemContext); + // save caller context for a later return + Y_VERIFY(!ActorSystemContext); TExceptionSafeContext actorSystemContext; - ActorSystemContext = &actorSystemContext; + ActorSystemContext = &actorSystemContext; - // go to actor coroutine + // go to actor coroutine BeforeResume(); ActorSystemContext->SwitchTo(&FiberContext); // check for stack overflow #ifndef NDEBUG - const char* p; + const char* p; #if STACK_GROW_DOWN - p = Stack.Begin(); + p = Stack.Begin(); #else - p = Stack.End() - StackOverflowGap; + p = Stack.End() - StackOverflowGap; #endif - Y_VERIFY_DEBUG(memcmp(p, GoodStack, StackOverflowGap) == 0); + Y_VERIFY_DEBUG(memcmp(p, GoodStack, StackOverflowGap) == 0); #endif } void TActorCoroImpl::DoRun() { - try { + try { if (ActorContext) { // ActorContext may be nullptr here if the destructor was invoked before bootstrapping Y_VERIFY(!PendingEvent); Run(); } - } catch (const TPoisonPillException& /*ex*/) { - if (!AllowUnhandledPoisonPill) { - Y_FAIL("unhandled TPoisonPillException"); - } + } catch (const TPoisonPillException& /*ex*/) { + if (!AllowUnhandledPoisonPill) { + Y_FAIL("unhandled TPoisonPillException"); + } } catch (const TDtorException& /*ex*/) { if (!AllowUnhandledDtor) { Y_FAIL("unhandled TDtorException"); @@ -147,19 +147,19 @@ namespace NActors { } catch (...) { Y_FAIL("unhandled exception of type not derived from std::exception"); } - Finished = true; - ReturnToActorSystem(); + Finished = true; + ReturnToActorSystem(); } void TActorCoroImpl::ReturnToActorSystem() { TExceptionSafeContext* returnContext = std::exchange(ActorSystemContext, nullptr); - Y_VERIFY(returnContext); - FiberContext.SwitchTo(returnContext); + Y_VERIFY(returnContext); + FiberContext.SwitchTo(returnContext); if (!PendingEvent) { // we have returned from the actor system and it kindly asks us to terminate the coroutine as it is being // stopped throw TDtorException(); } - } + } } diff --git a/library/cpp/actors/core/actor_coroutine.h b/library/cpp/actors/core/actor_coroutine.h index 6bcb768eaf..2f61e5db8b 100644 --- a/library/cpp/actors/core/actor_coroutine.h +++ b/library/cpp/actors/core/actor_coroutine.h @@ -12,13 +12,13 @@ namespace NActors { class TActorCoro; class TActorCoroImpl : public ITrampoLine { - TMappedAllocation Stack; - bool AllowUnhandledPoisonPill; + TMappedAllocation Stack; + bool AllowUnhandledPoisonPill; bool AllowUnhandledDtor; - TContClosure FiberClosure; + TContClosure FiberClosure; TExceptionSafeContext FiberContext; TExceptionSafeContext* ActorSystemContext = nullptr; - THolder<IEventHandle> PendingEvent; + THolder<IEventHandle> PendingEvent; bool Finished = false; ui64 WaitCookie = 0; TActorContext *ActorContext = nullptr; @@ -27,83 +27,83 @@ namespace NActors { TActorIdentity SelfActorId = TActorIdentity(TActorId()); TActorId ParentActorId; - private: - template <typename TFirstEvent, typename... TOtherEvents> - struct TIsOneOf: public TIsOneOf<TOtherEvents...> { - bool operator()(IEventHandle& ev) const { - return ev.GetTypeRewrite() == TFirstEvent::EventType || TIsOneOf<TOtherEvents...>()(ev); - } - }; - - template <typename TSingleEvent> - struct TIsOneOf<TSingleEvent> { - bool operator()(IEventHandle& ev) const { - return ev.GetTypeRewrite() == TSingleEvent::EventType; - } - }; + private: + template <typename TFirstEvent, typename... TOtherEvents> + struct TIsOneOf: public TIsOneOf<TOtherEvents...> { + bool operator()(IEventHandle& ev) const { + return ev.GetTypeRewrite() == TFirstEvent::EventType || TIsOneOf<TOtherEvents...>()(ev); + } + }; + + template <typename TSingleEvent> + struct TIsOneOf<TSingleEvent> { + bool operator()(IEventHandle& ev) const { + return ev.GetTypeRewrite() == TSingleEvent::EventType; + } + }; struct TEvCoroTimeout : TEventLocal<TEvCoroTimeout, TEvents::TSystem::CoroTimeout> {}; protected: struct TPoisonPillException : yexception {}; struct TDtorException : yexception {}; - - public: + + public: TActorCoroImpl(size_t stackSize, bool allowUnhandledPoisonPill = false, bool allowUnhandledDtor = false); // specify stackSize explicitly for each actor; don't forget about overflow control gap virtual ~TActorCoroImpl(); - virtual void Run() = 0; + virtual void Run() = 0; virtual void BeforeResume() {} - // Handle all events that are not expected in wait loops. - virtual void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> ev) = 0; + // Handle all events that are not expected in wait loops. + virtual void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> ev) = 0; - // Release execution ownership and wait for some event to arrive. When PoisonPill event is received, then - // TPoisonPillException is thrown. + // Release execution ownership and wait for some event to arrive. When PoisonPill event is received, then + // TPoisonPillException is thrown. THolder<IEventHandle> WaitForEvent(TInstant deadline = TInstant::Max()); - // Wait for specific event set by filter functor. Function returns first event that matches filter. On any other - // kind of event ProcessUnexpectedEvent() is called. - // - // Example: WaitForSpecificEvent([](IEventHandle& ev) { return ev.Cookie == 42; }); - template <typename TFunc> + // Wait for specific event set by filter functor. Function returns first event that matches filter. On any other + // kind of event ProcessUnexpectedEvent() is called. + // + // Example: WaitForSpecificEvent([](IEventHandle& ev) { return ev.Cookie == 42; }); + template <typename TFunc> THolder<IEventHandle> WaitForSpecificEvent(TFunc&& filter, TInstant deadline = TInstant::Max()) { - for (;;) { + for (;;) { if (THolder<IEventHandle> event = WaitForEvent(deadline); !event) { return nullptr; } else if (filter(*event)) { - return event; - } else { - ProcessUnexpectedEvent(event); - } + return event; + } else { + ProcessUnexpectedEvent(event); + } } } - // Wait for specific event or set of events. Function returns first event that matches enlisted type. On any other - // kind of event ProcessUnexpectedEvent() is called. - // - // Example: WaitForSpecificEvent<TEvReadResult, TEvFinished>(); - template <typename TFirstEvent, typename TSecondEvent, typename... TOtherEvents> + // Wait for specific event or set of events. Function returns first event that matches enlisted type. On any other + // kind of event ProcessUnexpectedEvent() is called. + // + // Example: WaitForSpecificEvent<TEvReadResult, TEvFinished>(); + template <typename TFirstEvent, typename TSecondEvent, typename... TOtherEvents> THolder<IEventHandle> WaitForSpecificEvent(TInstant deadline = TInstant::Max()) { - TIsOneOf<TFirstEvent, TSecondEvent, TOtherEvents...> filter; + TIsOneOf<TFirstEvent, TSecondEvent, TOtherEvents...> filter; return WaitForSpecificEvent(filter, deadline); - } + } - // Wait for single specific event. - template <typename TEventType> + // Wait for single specific event. + template <typename TEventType> THolder<typename TEventType::THandle> WaitForSpecificEvent(TInstant deadline = TInstant::Max()) { - auto filter = [](IEventHandle& ev) { - return ev.GetTypeRewrite() == TEventType::EventType; - }; + auto filter = [](IEventHandle& ev) { + return ev.GetTypeRewrite() == TEventType::EventType; + }; THolder<IEventHandle> event = WaitForSpecificEvent(filter, deadline); return THolder<typename TEventType::THandle>(static_cast<typename TEventType::THandle*>(event ? event.Release() : nullptr)); - } + } protected: // Actor System compatibility section - const TActorContext& GetActorContext() const; + const TActorContext& GetActorContext() const; TActorSystem *GetActorSystem() const { return GetActorContext().ExecutorThread.ActorSystem; } TInstant Now() const { return GetActorContext().Now(); } @@ -138,17 +138,17 @@ namespace NActors { return GetActorContext().RegisterWithSameMailbox(actor); } - private: + private: friend class TActorCoro; bool ProcessEvent(THolder<IEventHandle> ev); private: - /* Resume() function goes to actor coroutine context and continues (or starts) to execute it until actor finishes + /* Resume() function goes to actor coroutine context and continues (or starts) to execute it until actor finishes * his job or it is blocked on WaitForEvent. Then the function returns. */ void Resume(); - void ReturnToActorSystem(); + void ReturnToActorSystem(); void DoRun() override final; - }; + }; class TActorCoro : public IActor { THolder<TActorCoroImpl> Impl; diff --git a/library/cpp/actors/core/actor_coroutine_ut.cpp b/library/cpp/actors/core/actor_coroutine_ut.cpp index 951512b877..715d44be4f 100644 --- a/library/cpp/actors/core/actor_coroutine_ut.cpp +++ b/library/cpp/actors/core/actor_coroutine_ut.cpp @@ -19,16 +19,16 @@ Y_UNIT_TEST_SUITE(ActorCoro) { Enough }; - struct TEvRequest: public TEventLocal<TEvRequest, Request> { + struct TEvRequest: public TEventLocal<TEvRequest, Request> { }; - struct TEvResponse: public TEventLocal<TEvResponse, Response> { + struct TEvResponse: public TEventLocal<TEvResponse, Response> { }; - struct TEvEnough: public TEventLocal<TEvEnough, Enough> { + struct TEvEnough: public TEventLocal<TEvEnough, Enough> { }; - class TBasicResponderActor: public TActorBootstrapped<TBasicResponderActor> { + class TBasicResponderActor: public TActorBootstrapped<TBasicResponderActor> { TDeque<TActorId> RespondTo; public: @@ -73,8 +73,8 @@ Y_UNIT_TEST_SUITE(ActorCoro) { , DoneEvent(doneEvent) , ItemsProcessed(itemsProcessed) , Finish(false) - { - } + { + } void Run() override { TActorId child = GetActorContext().Register(new TBasicResponderActor); @@ -101,7 +101,7 @@ Y_UNIT_TEST_SUITE(ActorCoro) { } }; - void Check(THolder<IEventBase> && message) { + void Check(THolder<IEventBase> && message) { THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>(); setup->NodeId = 0; setup->ExecutorsCount = 1; diff --git a/library/cpp/actors/core/actorid.cpp b/library/cpp/actors/core/actorid.cpp index ccda035eac..6f2a816fc1 100644 --- a/library/cpp/actors/core/actorid.cpp +++ b/library/cpp/actors/core/actorid.cpp @@ -1,34 +1,34 @@ -#include "actorid.h" -#include <util/string/builder.h> +#include "actorid.h" +#include <util/string/builder.h> #include <util/string/cast.h> - -namespace NActors { + +namespace NActors { void TActorId::Out(IOutputStream& o) const { - o << "[" << NodeId() << ":" << LocalId() << ":" << Hint() << "]"; - } - + o << "[" << NodeId() << ":" << LocalId() << ":" << Hint() << "]"; + } + TString TActorId::ToString() const { - TString x; - TStringOutput o(x); - Out(o); - return x; - } - + TString x; + TStringOutput o(x); + Out(o); + return x; + } + bool TActorId::Parse(const char* buf, ui32 sz) { - if (sz < 4 || buf[0] != '[' || buf[sz - 1] != ']') - return false; - - size_t semicolons[2]; - TStringBuf str(buf, sz); - semicolons[0] = str.find(':', 1); - if (semicolons[0] == TStringBuf::npos) - return false; - semicolons[1] = str.find(':', semicolons[0] + 1); - if (semicolons[1] == TStringBuf::npos) - return false; + if (sz < 4 || buf[0] != '[' || buf[sz - 1] != ']') + return false; + + size_t semicolons[2]; + TStringBuf str(buf, sz); + semicolons[0] = str.find(':', 1); + if (semicolons[0] == TStringBuf::npos) + return false; + semicolons[1] = str.find(':', semicolons[0] + 1); + if (semicolons[1] == TStringBuf::npos) + return false; - bool success = TryFromString(buf + 1, semicolons[0] - 1, Raw.N.NodeId) && TryFromString(buf + semicolons[0] + 1, semicolons[1] - semicolons[0] - 1, Raw.N.LocalId) && TryFromString(buf + semicolons[1] + 1, sz - semicolons[1] - 2, Raw.N.Hint); + bool success = TryFromString(buf + 1, semicolons[0] - 1, Raw.N.NodeId) && TryFromString(buf + semicolons[0] + 1, semicolons[1] - semicolons[0] - 1, Raw.N.LocalId) && TryFromString(buf + semicolons[1] + 1, sz - semicolons[1] - 2, Raw.N.Hint); - return success; - } -} + return success; + } +} diff --git a/library/cpp/actors/core/actorid.h b/library/cpp/actors/core/actorid.h index d972b1a0ff..7d3ac61808 100644 --- a/library/cpp/actors/core/actorid.h +++ b/library/cpp/actors/core/actorid.h @@ -1,16 +1,16 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include <util/stream/output.h> // for IOutputStream #include <util/generic/hash.h> - -namespace NActors { - // used as global uniq address of actor - // also could be used to transport service id (12 byte strings placed in hint-localid) - // highest 1 bit of node - mark of service id - // next 11 bits of node-id - pool id - // next 20 bits - node id itself - + +namespace NActors { + // used as global uniq address of actor + // also could be used to transport service id (12 byte strings placed in hint-localid) + // highest 1 bit of node - mark of service id + // next 11 bits of node-id - pool id + // next 20 bits - node id itself + struct TActorId { static constexpr ui32 MaxServiceIDLength = 12; static constexpr ui32 MaxPoolID = 0x000007FF; @@ -19,174 +19,174 @@ namespace NActors { static constexpr ui32 PoolIndexMask = MaxPoolID << PoolIndexShift; static constexpr ui32 ServiceMask = 0x80000000; static constexpr ui32 NodeIdMask = MaxNodeId; - - private: - union { - struct { - ui64 LocalId; - ui32 Hint; - ui32 NodeId; - } N; - - struct { - ui64 X1; - ui64 X2; - } X; - - ui8 Buf[16]; - } Raw; - - public: + + private: + union { + struct { + ui64 LocalId; + ui32 Hint; + ui32 NodeId; + } N; + + struct { + ui64 X1; + ui64 X2; + } X; + + ui8 Buf[16]; + } Raw; + + public: TActorId() noexcept { - Raw.X.X1 = 0; - Raw.X.X2 = 0; - } - + Raw.X.X1 = 0; + Raw.X.X2 = 0; + } + explicit TActorId(ui32 nodeId, ui32 poolId, ui64 localId, ui32 hint) noexcept { - Y_VERIFY_DEBUG(poolId <= MaxPoolID); - Raw.N.LocalId = localId; - Raw.N.Hint = hint; - Raw.N.NodeId = nodeId | (poolId << PoolIndexShift); - } - + Y_VERIFY_DEBUG(poolId <= MaxPoolID); + Raw.N.LocalId = localId; + Raw.N.Hint = hint; + Raw.N.NodeId = nodeId | (poolId << PoolIndexShift); + } + explicit TActorId(ui32 nodeId, const TStringBuf& x) noexcept { - Y_VERIFY(x.size() <= MaxServiceIDLength, "service id is too long"); - Raw.N.LocalId = 0; - Raw.N.Hint = 0; - Raw.N.NodeId = nodeId | ServiceMask; - memcpy(Raw.Buf, x.data(), x.size()); - } - + Y_VERIFY(x.size() <= MaxServiceIDLength, "service id is too long"); + Raw.N.LocalId = 0; + Raw.N.Hint = 0; + Raw.N.NodeId = nodeId | ServiceMask; + memcpy(Raw.Buf, x.data(), x.size()); + } + explicit TActorId(ui64 x1, ui64 x2) noexcept { - Raw.X.X1 = x1; - Raw.X.X2 = x2; - } - - explicit operator bool() const noexcept { - return Raw.X.X1 != 0 || Raw.X.X2 != 0; - } - + Raw.X.X1 = x1; + Raw.X.X2 = x2; + } + + explicit operator bool() const noexcept { + return Raw.X.X1 != 0 || Raw.X.X2 != 0; + } + ui64 LocalId() const noexcept { - return Raw.N.LocalId; - } - + return Raw.N.LocalId; + } + ui32 Hint() const noexcept { - return Raw.N.Hint; - } - + return Raw.N.Hint; + } + ui32 NodeId() const noexcept { - return Raw.N.NodeId & NodeIdMask; - } - + return Raw.N.NodeId & NodeIdMask; + } + bool IsService() const noexcept { - return (Raw.N.NodeId & ServiceMask); - } - + return (Raw.N.NodeId & ServiceMask); + } + TStringBuf ServiceId() const noexcept { - Y_VERIFY_DEBUG(IsService()); - return TStringBuf((const char*)Raw.Buf, MaxServiceIDLength); - } - + Y_VERIFY_DEBUG(IsService()); + return TStringBuf((const char*)Raw.Buf, MaxServiceIDLength); + } + static ui32 PoolIndex(ui32 nodeid) noexcept { - return ((nodeid & PoolIndexMask) >> PoolIndexShift); - } - + return ((nodeid & PoolIndexMask) >> PoolIndexShift); + } + ui32 PoolID() const noexcept { - return PoolIndex(Raw.N.NodeId); - } - + return PoolIndex(Raw.N.NodeId); + } + ui64 RawX1() const noexcept { - return Raw.X.X1; - } - + return Raw.X.X1; + } + ui64 RawX2() const noexcept { - return Raw.X.X2; - } - + return Raw.X.X2; + } + bool operator<(const TActorId& x) const noexcept { - const ui64 s1 = Raw.X.X1; - const ui64 s2 = Raw.X.X2; - const ui64 x1 = x.Raw.X.X1; - const ui64 x2 = x.Raw.X.X2; - - return (s1 != x1) ? (s1 < x1) : (s2 < x2); - } - + const ui64 s1 = Raw.X.X1; + const ui64 s2 = Raw.X.X2; + const ui64 x1 = x.Raw.X.X1; + const ui64 x2 = x.Raw.X.X2; + + return (s1 != x1) ? (s1 < x1) : (s2 < x2); + } + bool operator!=(const TActorId& x) const noexcept { - return Raw.X.X1 != x.Raw.X.X1 || Raw.X.X2 != x.Raw.X.X2; - } - + return Raw.X.X1 != x.Raw.X.X1 || Raw.X.X2 != x.Raw.X.X2; + } + bool operator==(const TActorId& x) const noexcept { - return !(x != *this); - } - - ui64 Hash() const noexcept { - const ui32* x = (const ui32*)Raw.Buf; - - const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; - const ui64 x2 = x[1] * 0x179CA10C9242235Dull; - const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; - const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; - - const ui64 z1 = x1 + x2; - const ui64 z2 = x3 + x4; - - const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; - - return (sum >> 32) | (sum << 32); - } - - ui32 Hash32() const noexcept { - const ui32* x = (const ui32*)Raw.Buf; - - const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; - const ui64 x2 = x[1] * 0x179CA10C9242235Dull; - const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; - const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; - - const ui64 z1 = x1 + x2; - const ui64 z2 = x3 + x4; - - const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; - - return sum >> 32; - } - - struct THash { + return !(x != *this); + } + + ui64 Hash() const noexcept { + const ui32* x = (const ui32*)Raw.Buf; + + const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; + const ui64 x2 = x[1] * 0x179CA10C9242235Dull; + const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; + const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; + + const ui64 z1 = x1 + x2; + const ui64 z2 = x3 + x4; + + const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; + + return (sum >> 32) | (sum << 32); + } + + ui32 Hash32() const noexcept { + const ui32* x = (const ui32*)Raw.Buf; + + const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; + const ui64 x2 = x[1] * 0x179CA10C9242235Dull; + const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; + const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; + + const ui64 z1 = x1 + x2; + const ui64 z2 = x3 + x4; + + const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; + + return sum >> 32; + } + + struct THash { ui64 operator()(const TActorId& actorId) const noexcept { return actorId.Hash(); - } - }; - - struct THash32 { + } + }; + + struct THash32 { ui64 operator()(const TActorId& actorId) const noexcept { return actorId.Hash(); - } - }; - - struct TOrderedCmp { + } + }; + + struct TOrderedCmp { bool operator()(const TActorId &left, const TActorId &right) const noexcept { - Y_VERIFY_DEBUG(!left.IsService() && !right.IsService(), "ordered compare works for plain actorids only"); - const ui32 n1 = left.NodeId(); - const ui32 n2 = right.NodeId(); - - return (n1 != n2) ? (n1 < n2) : left.LocalId() < right.LocalId(); - } - }; - - TString ToString() const; + Y_VERIFY_DEBUG(!left.IsService() && !right.IsService(), "ordered compare works for plain actorids only"); + const ui32 n1 = left.NodeId(); + const ui32 n2 = right.NodeId(); + + return (n1 != n2) ? (n1 < n2) : left.LocalId() < right.LocalId(); + } + }; + + TString ToString() const; void Out(IOutputStream& o) const; - bool Parse(const char* buf, ui32 sz); - }; - + bool Parse(const char* buf, ui32 sz); + }; + static_assert(sizeof(TActorId) == 16, "expect sizeof(TActorId) == 16"); static_assert(MaxPools < TActorId::MaxPoolID); // current implementation of united pool has limit MaxPools on pool id -} - -template <> +} + +template <> inline void Out<NActors::TActorId>(IOutputStream& o, const NActors::TActorId& x) { - return x.Out(o); -} + return x.Out(o); +} template <> struct THash<NActors::TActorId> { diff --git a/library/cpp/actors/core/actorsystem.cpp b/library/cpp/actors/core/actorsystem.cpp index c58698a206..3e2060b806 100644 --- a/library/cpp/actors/core/actorsystem.cpp +++ b/library/cpp/actors/core/actorsystem.cpp @@ -1,85 +1,85 @@ -#include "defs.h" -#include "actorsystem.h" +#include "defs.h" +#include "actorsystem.h" #include "callstack.h" #include "cpu_manager.h" -#include "mailbox.h" -#include "events.h" -#include "interconnect.h" -#include "servicemap.h" -#include "scheduler_queue.h" +#include "mailbox.h" +#include "events.h" +#include "interconnect.h" +#include "servicemap.h" +#include "scheduler_queue.h" #include "scheduler_actor.h" #include "log.h" #include "probes.h" #include "ask.h" #include <library/cpp/actors/util/affinity.h> #include <library/cpp/actors/util/datetime.h> -#include <util/generic/hash.h> -#include <util/system/rwlock.h> -#include <util/random/random.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - struct TActorSystem::TServiceMap : TNonCopyable { +#include <util/generic/hash.h> +#include <util/system/rwlock.h> +#include <util/random/random.h> + +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + + struct TActorSystem::TServiceMap : TNonCopyable { NActors::TServiceMap<TActorId, TActorId, TActorId::THash> LocalMap; - TTicketLock Lock; - + TTicketLock Lock; + TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) { - TTicketLock::TGuard guard(&Lock); + TTicketLock::TGuard guard(&Lock); const TActorId old = LocalMap.Update(serviceId, actorId); - return old; - } - + return old; + } + TActorId LookupLocal(const TActorId& x) { - return LocalMap.Find(x); - } - }; - - TActorSystem::TActorSystem(THolder<TActorSystemSetup>& setup, void* appData, - TIntrusivePtr<NLog::TSettings> loggerSettings) - : NodeId(setup->NodeId) + return LocalMap.Find(x); + } + }; + + TActorSystem::TActorSystem(THolder<TActorSystemSetup>& setup, void* appData, + TIntrusivePtr<NLog::TSettings> loggerSettings) + : NodeId(setup->NodeId) , CpuManager(new TCpuManager(setup)) , ExecutorPoolCount(CpuManager->GetExecutorsCount()) - , Scheduler(setup->Scheduler) - , InterconnectCount((ui32)setup->Interconnect.ProxyActors.size()) - , CurrentTimestamp(0) + , Scheduler(setup->Scheduler) + , InterconnectCount((ui32)setup->Interconnect.ProxyActors.size()) + , CurrentTimestamp(0) , CurrentMonotonic(0) - , CurrentIDCounter(RandomNumber<ui64>()) - , SystemSetup(setup.Release()) - , DefSelfID(NodeId, "actorsystem") - , AppData0(appData) - , LoggerSettings0(loggerSettings) - , StartExecuted(false) - , StopExecuted(false) - , CleanupExecuted(false) - { - ServiceMap.Reset(new TServiceMap()); - } - - TActorSystem::~TActorSystem() { - Cleanup(); - } - - bool TActorSystem::Send(TAutoPtr<IEventHandle> ev) const { - if (Y_UNLIKELY(!ev)) - return false; - + , CurrentIDCounter(RandomNumber<ui64>()) + , SystemSetup(setup.Release()) + , DefSelfID(NodeId, "actorsystem") + , AppData0(appData) + , LoggerSettings0(loggerSettings) + , StartExecuted(false) + , StopExecuted(false) + , CleanupExecuted(false) + { + ServiceMap.Reset(new TServiceMap()); + } + + TActorSystem::~TActorSystem() { + Cleanup(); + } + + bool TActorSystem::Send(TAutoPtr<IEventHandle> ev) const { + if (Y_UNLIKELY(!ev)) + return false; + #ifdef USE_ACTOR_CALLSTACK - ev->Callstack.TraceIfEmpty(); + ev->Callstack.TraceIfEmpty(); #endif TActorId recipient = ev->GetRecipientRewrite(); 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()); + + 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()); - recipient = InterconnectProxy(recpNodeId); - ev->Rewrite(TEvInterconnect::EvForward, recipient); + recipient = InterconnectProxy(recpNodeId); + ev->Rewrite(TEvInterconnect::EvForward, recipient); } if (recipient.IsService()) { TActorId target = ServiceMap->LookupLocal(recipient); @@ -100,24 +100,24 @@ namespace NActors { } recipient = target; ev->Rewrite(ev->GetTypeRewrite(), recipient); - } - + } + Y_VERIFY_DEBUG(recipient == ev->GetRecipientRewrite()); - const ui32 recpPool = recipient.PoolID(); - if (recipient && recpPool < ExecutorPoolCount) { + const ui32 recpPool = recipient.PoolID(); + if (recipient && recpPool < ExecutorPoolCount) { if (CpuManager->GetExecutorPool(recpPool)->Send(ev)) { - return true; + return true; } } - - Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown)); - return false; - } - + + Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown)); + return false; + } + bool TActorSystem::Send(const TActorId& recipient, IEventBase* ev, ui32 flags) const { - return this->Send(new IEventHandle(recipient, DefSelfID, ev, flags)); - } - + return this->Send(new IEventHandle(recipient, DefSelfID, ev, flags)); + } + void TActorSystem::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const { Schedule(deadline - Timestamp(), ev, cookie); } @@ -136,15 +136,15 @@ namespace NActors { TTicketLock::TGuard guard(&ScheduleLock); ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - + } + TActorId TActorSystem::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 executorPool, ui64 revolvingCounter, const TActorId& parentId) { - Y_VERIFY(executorPool < ExecutorPoolCount, "executorPool# %" PRIu32 ", ExecutorPoolCount# %" PRIu32, - (ui32)executorPool, (ui32)ExecutorPoolCount); + Y_VERIFY(executorPool < ExecutorPoolCount, "executorPool# %" PRIu32 ", ExecutorPoolCount# %" PRIu32, + (ui32)executorPool, (ui32)ExecutorPoolCount); return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); - } - + } + NThreading::TFuture<THolder<IEventBase>> TActorSystem::AskGeneric(TMaybe<ui32> expectedEventType, TActorId recipient, THolder<IEventBase> event, TDuration timeout) { @@ -154,34 +154,34 @@ namespace NActors { } ui64 TActorSystem::AllocateIDSpace(ui64 count) { - Y_VERIFY_DEBUG(count < Max<ui32>() / 65536); - - static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); - - // get high 32 bits as seconds from epoch - // it could wrap every century, but we don't expect any actor-reference to live this long so such wrap will do no harm + Y_VERIFY_DEBUG(count < Max<ui32>() / 65536); + + static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); + + // get high 32 bits as seconds from epoch + // it could wrap every century, but we don't expect any actor-reference to live this long so such wrap will do no harm const ui64 timeFromEpoch = TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)).Seconds(); - - // get low 32 bits as counter value - ui32 lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); - while (lowPartEnd < count) // if our request crosses 32bit boundary - retry - lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); - - const ui64 lowPart = lowPartEnd - count; - const ui64 ret = (timeFromEpoch << 32) | lowPart; - - return ret; - } - + + // get low 32 bits as counter value + ui32 lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); + while (lowPartEnd < count) // if our request crosses 32bit boundary - retry + lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); + + const ui64 lowPart = lowPartEnd - count; + const ui64 ret = (timeFromEpoch << 32) | lowPart; + + return ret; + } + TActorId TActorSystem::InterconnectProxy(ui32 destinationNode) const { - if (destinationNode < InterconnectCount) - return Interconnect[destinationNode]; + if (destinationNode < InterconnectCount) + return Interconnect[destinationNode]; else if (destinationNode != NodeId) return MakeInterconnectProxyId(destinationNode); - else + else return TActorId(); - } - + } + ui32 TActorSystem::BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>& eventFabric) { // TODO: get rid of this method for (ui32 i = 0; i < InterconnectCount; ++i) { @@ -191,87 +191,87 @@ namespace NActors { } TActorId TActorSystem::LookupLocalService(const TActorId& x) const { - return ServiceMap->LookupLocal(x); - } - + return ServiceMap->LookupLocal(x); + } + TActorId TActorSystem::RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) { // TODO: notify old actor about demotion return ServiceMap->RegisterLocalService(serviceId, actorId); - } - + } + void TActorSystem::GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { CpuManager->GetPoolStats(poolId, poolStats, statsCopy); } - void TActorSystem::Start() { - Y_VERIFY(StartExecuted == false); - StartExecuted = true; - + void TActorSystem::Start() { + Y_VERIFY(StartExecuted == false); + StartExecuted = true; + ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); TVector<NSchedulerQueue::TReader*> scheduleReaders; - scheduleReaders.push_back(&ScheduleQueue->Reader); + scheduleReaders.push_back(&ScheduleQueue->Reader); CpuManager->PrepareStart(scheduleReaders, this); Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic); Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size()); - - // setup interconnect proxies - { - const TInterconnectSetup& setup = SystemSetup->Interconnect; + + // setup interconnect proxies + { + const TInterconnectSetup& setup = SystemSetup->Interconnect; Interconnect.Reset(new TActorId[InterconnectCount + 1]); - for (ui32 i = 0, e = InterconnectCount; i != e; ++i) { - const TActorSetupCmd& x = setup.ProxyActors[i]; - if (x.Actor) { - Interconnect[i] = Register(x.Actor, x.MailboxType, x.PoolId, i); - Y_VERIFY(!!Interconnect[i]); - } - } + for (ui32 i = 0, e = InterconnectCount; i != e; ++i) { + const TActorSetupCmd& x = setup.ProxyActors[i]; + if (x.Actor) { + Interconnect[i] = Register(x.Actor, x.MailboxType, x.PoolId, i); + Y_VERIFY(!!Interconnect[i]); + } + } ProxyWrapperFactory = std::move(SystemSetup->Interconnect.ProxyWrapperFactory); - } - - // setup local services - { - for (ui32 i = 0, e = (ui32)SystemSetup->LocalServices.size(); i != e; ++i) { + } + + // setup local services + { + for (ui32 i = 0, e = (ui32)SystemSetup->LocalServices.size(); i != e; ++i) { const std::pair<TActorId, TActorSetupCmd>& x = SystemSetup->LocalServices[i]; const TActorId xid = Register(x.second.Actor, x.second.MailboxType, x.second.PoolId, i); - Y_VERIFY(!!xid); - if (!!x.first) - RegisterLocalService(x.first, xid); - } - } - - // ok, setup complete, we could destroy setup config - SystemSetup.Destroy(); - + Y_VERIFY(!!xid); + if (!!x.first) + RegisterLocalService(x.first, xid); + } + } + + // ok, setup complete, we could destroy setup config + SystemSetup.Destroy(); + Scheduler->PrepareStart(); CpuManager->Start(); Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic)); - Scheduler->Start(); - } - - void TActorSystem::Stop() { - if (StopExecuted || !StartExecuted) - return; - - StopExecuted = true; - + Scheduler->Start(); + } + + void TActorSystem::Stop() { + if (StopExecuted || !StartExecuted) + return; + + StopExecuted = true; + for (auto&& fn : std::exchange(DeferredPreStop, {})) { fn(); } - Scheduler->PrepareStop(); + Scheduler->PrepareStop(); CpuManager->PrepareStop(); - Scheduler->Stop(); + Scheduler->Stop(); CpuManager->Shutdown(); - } - - void TActorSystem::Cleanup() { - Stop(); - if (CleanupExecuted || !StartExecuted) - return; - CleanupExecuted = true; + } + + void TActorSystem::Cleanup() { + Stop(); + if (CleanupExecuted || !StartExecuted) + return; + CleanupExecuted = true; CpuManager->Cleanup(); - Scheduler.Destroy(); - } - - ui32 TActorSystem::MemProfActivityBase; -} + Scheduler.Destroy(); + } + + ui32 TActorSystem::MemProfActivityBase; +} diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h index 40499d7586..6306ab7ce3 100644 --- a/library/cpp/actors/core/actorsystem.h +++ b/library/cpp/actors/core/actorsystem.h @@ -1,28 +1,28 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include "actor.h" #include "balancer.h" #include "config.h" -#include "event.h" +#include "event.h" #include "log_settings.h" -#include "scheduler_cookie.h" +#include "scheduler_cookie.h" #include "mon_stats.h" #include <library/cpp/threading/future/future.h> #include <library/cpp/actors/util/ticket_lock.h> -#include <util/generic/vector.h> -#include <util/datetime/base.h> +#include <util/generic/vector.h> +#include <util/datetime/base.h> #include <util/system/mutex.h> - -namespace NActors { - class TActorSystem; + +namespace NActors { + class TActorSystem; class TCpuManager; - class IExecutorPool; + class IExecutorPool; struct TWorkerContext; - + inline TActorId MakeInterconnectProxyId(ui32 destNodeId) { char data[12]; memcpy(data, "ICProxy@", 8); @@ -40,32 +40,32 @@ namespace NActors { return nodeId; } - namespace NSchedulerQueue { - class TReader; + namespace NSchedulerQueue { + class TReader; struct TQueueType; - } - - class IExecutorPool : TNonCopyable { - public: - const ui32 PoolId; - - TAtomic ActorRegistrations; - TAtomic DestroyedActors; - - IExecutorPool(ui32 poolId) - : PoolId(poolId) - , ActorRegistrations(0) - , DestroyedActors(0) - { - } - - virtual ~IExecutorPool() { - } - + } + + class IExecutorPool : TNonCopyable { + public: + const ui32 PoolId; + + TAtomic ActorRegistrations; + TAtomic DestroyedActors; + + IExecutorPool(ui32 poolId) + : PoolId(poolId) + , ActorRegistrations(0) + , DestroyedActors(0) + { + } + + virtual ~IExecutorPool() { + } + // for workers virtual ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) = 0; virtual void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) = 0; - + /** * Schedule one-shot event that will be send at given time point in the future. * @@ -96,103 +96,103 @@ namespace NActors { */ virtual void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; - // for actorsystem - virtual bool Send(TAutoPtr<IEventHandle>& ev) = 0; - virtual void ScheduleActivation(ui32 activation) = 0; - virtual void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) = 0; + // for actorsystem + virtual bool Send(TAutoPtr<IEventHandle>& ev) = 0; + virtual void ScheduleActivation(ui32 activation) = 0; + virtual void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) = 0; virtual TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingCounter, const TActorId& parentId) = 0; virtual TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) = 0; - - // lifecycle stuff + + // lifecycle stuff virtual void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) = 0; - virtual void Start() = 0; - virtual void PrepareStop() = 0; - virtual void Shutdown() = 0; - virtual bool Cleanup() = 0; - + virtual void Start() = 0; + virtual void PrepareStop() = 0; + virtual void Shutdown() = 0; + virtual bool Cleanup() = 0; + virtual void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - // TODO: make pure virtual and override everywhere - Y_UNUSED(poolStats); - Y_UNUSED(statsCopy); - } - - virtual TString GetName() const { - return TString(); - } - + // TODO: make pure virtual and override everywhere + Y_UNUSED(poolStats); + Y_UNUSED(statsCopy); + } + + virtual TString GetName() const { + return TString(); + } + virtual ui32 GetThreads() const { return 1; } - // generic - virtual TAffinity* Affinity() const = 0; - + // generic + virtual TAffinity* Affinity() const = 0; + virtual void SetRealTimeMode() const {} - }; + }; - // could be proxy to in-pool schedulers (for NUMA-aware executors) - class ISchedulerThread : TNonCopyable { - public: - virtual ~ISchedulerThread() { - } + // could be proxy to in-pool schedulers (for NUMA-aware executors) + class ISchedulerThread : TNonCopyable { + public: + virtual ~ISchedulerThread() { + } 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 Start() = 0; - virtual void PrepareStop() = 0; - virtual void Stop() = 0; - }; - - struct TActorSetupCmd { - TMailboxType::EType MailboxType; - ui32 PoolId; - IActor* Actor; - - TActorSetupCmd() - : MailboxType(TMailboxType::HTSwap) - , PoolId(0) - , Actor(nullptr) - { - } - - TActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) - : MailboxType(mailboxType) - , PoolId(poolId) - , Actor(actor) - { - } - - void Set(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) { - MailboxType = mailboxType; - PoolId = poolId; - Actor = actor; - } - }; - + virtual void Start() = 0; + virtual void PrepareStop() = 0; + virtual void Stop() = 0; + }; + + struct TActorSetupCmd { + TMailboxType::EType MailboxType; + ui32 PoolId; + IActor* Actor; + + TActorSetupCmd() + : MailboxType(TMailboxType::HTSwap) + , PoolId(0) + , Actor(nullptr) + { + } + + TActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) + : MailboxType(mailboxType) + , PoolId(poolId) + , Actor(actor) + { + } + + void Set(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) { + MailboxType = mailboxType; + PoolId = poolId; + Actor = actor; + } + }; + using TProxyWrapperFactory = std::function<TActorId(TActorSystem*, ui32)>; - struct TInterconnectSetup { + struct TInterconnectSetup { TVector<TActorSetupCmd> ProxyActors; TProxyWrapperFactory ProxyWrapperFactory; - }; - - struct TActorSystemSetup { - ui32 NodeId = 0; - + }; + + struct TActorSystemSetup { + ui32 NodeId = 0; + // Either Executors or CpuManager must be initialized - ui32 ExecutorsCount = 0; - TArrayHolder<TAutoPtr<IExecutorPool>> Executors; + ui32 ExecutorsCount = 0; + TArrayHolder<TAutoPtr<IExecutorPool>> Executors; TAutoPtr<IBalancer> Balancer; // main implementation will be implicitly created if not set TCpuManagerConfig CpuManager; - TAutoPtr<ISchedulerThread> Scheduler; - ui32 MaxActivityType = 5; // for default entries - - TInterconnectSetup Interconnect; - + TAutoPtr<ISchedulerThread> Scheduler; + ui32 MaxActivityType = 5; // for default entries + + TInterconnectSetup Interconnect; + using TLocalServices = TVector<std::pair<TActorId, TActorSetupCmd>>; TLocalServices LocalServices; @@ -207,60 +207,60 @@ namespace NActors { ui32 GetThreads(ui32 poolId) const { return Executors ? Executors[poolId]->GetThreads() : CpuManager.GetThreads(poolId); } - }; - - class TActorSystem : TNonCopyable { - struct TServiceMap; - - public: - const ui32 NodeId; - - private: + }; + + class TActorSystem : TNonCopyable { + struct TServiceMap; + + public: + const ui32 NodeId; + + private: THolder<TCpuManager> CpuManager; - const ui32 ExecutorPoolCount; - - TAutoPtr<ISchedulerThread> Scheduler; - THolder<TServiceMap> ServiceMap; - - const ui32 InterconnectCount; + const ui32 ExecutorPoolCount; + + TAutoPtr<ISchedulerThread> Scheduler; + THolder<TServiceMap> ServiceMap; + + const ui32 InterconnectCount; TArrayHolder<TActorId> Interconnect; - - volatile ui64 CurrentTimestamp; + + volatile ui64 CurrentTimestamp; volatile ui64 CurrentMonotonic; - volatile ui64 CurrentIDCounter; - + volatile ui64 CurrentIDCounter; + THolder<NSchedulerQueue::TQueueType> ScheduleQueue; - mutable TTicketLock ScheduleLock; + mutable TTicketLock ScheduleLock; + + friend class TExecutorThread; - friend class TExecutorThread; - - THolder<TActorSystemSetup> SystemSetup; + THolder<TActorSystemSetup> SystemSetup; TActorId DefSelfID; - void* AppData0; - TIntrusivePtr<NLog::TSettings> LoggerSettings0; + void* AppData0; + TIntrusivePtr<NLog::TSettings> LoggerSettings0; TProxyWrapperFactory ProxyWrapperFactory; TMutex ProxyCreationLock; - - bool StartExecuted; - bool StopExecuted; - bool CleanupExecuted; + + bool StartExecuted; + bool StopExecuted; + bool CleanupExecuted; std::deque<std::function<void()>> DeferredPreStop; - public: - TActorSystem(THolder<TActorSystemSetup>& setup, void* appData = nullptr, - TIntrusivePtr<NLog::TSettings> loggerSettings = TIntrusivePtr<NLog::TSettings>(nullptr)); - ~TActorSystem(); - - void Start(); - void Stop(); - void Cleanup(); - + public: + TActorSystem(THolder<TActorSystemSetup>& setup, void* appData = nullptr, + TIntrusivePtr<NLog::TSettings> loggerSettings = TIntrusivePtr<NLog::TSettings>(nullptr)); + ~TActorSystem(); + + void Start(); + void Stop(); + void Cleanup(); + TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 executorPool = 0, ui64 revolvingCounter = 0, const TActorId& parentId = TActorId()); - - bool Send(TAutoPtr<IEventHandle> ev) const; + + bool Send(TAutoPtr<IEventHandle> ev) const; bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0) const; - + /** * Schedule one-shot event that will be send at given time point in the future. * @@ -321,47 +321,47 @@ namespace NActors { THolder<IEventBase> event, TDuration timeout); - ui64 AllocateIDSpace(ui64 count); - + ui64 AllocateIDSpace(ui64 count); + TActorId InterconnectProxy(ui32 destinationNode) const; ui32 BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>&); - - void UpdateLinkStatus(ui8 status, ui32 destinationNode); - ui8 LinkStatus(ui32 destinationNode); - + + void UpdateLinkStatus(ui8 status, ui32 destinationNode); + ui8 LinkStatus(ui32 destinationNode); + TActorId LookupLocalService(const TActorId& x) const; TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId); ui32 GetMaxActivityType() const { return SystemSetup ? SystemSetup->MaxActivityType : 1; - } - - TInstant Timestamp() const { - return TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)); - } + } + + TInstant Timestamp() const { + return TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)); + } TMonotonic Monotonic() const { return TMonotonic::MicroSeconds(RelaxedLoad(&CurrentMonotonic)); } - template <typename T> - T* AppData() const { - return (T*)AppData0; - } + template <typename T> + T* AppData() const { + return (T*)AppData0; + } - NLog::TSettings* LoggerSettings() const { - return LoggerSettings0.Get(); - } + NLog::TSettings* LoggerSettings() const { + return LoggerSettings0.Get(); + } void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const; - + void DeferPreStop(std::function<void()> fn) { DeferredPreStop.push_back(std::move(fn)); } - /* This is the base for memory profiling tags. + /* This is the base for memory profiling tags. System sets memory profiling tag for debug version of lfalloc. The tag is set as "base_tag + actor_activity_type". */ - static ui32 MemProfActivityBase; - }; -} + static ui32 MemProfActivityBase; + }; +} diff --git a/library/cpp/actors/core/buffer.cpp b/library/cpp/actors/core/buffer.cpp index 48128d76ef..7b7f5f059a 100644 --- a/library/cpp/actors/core/buffer.cpp +++ b/library/cpp/actors/core/buffer.cpp @@ -6,51 +6,51 @@ TBufferBase::TBufferBase(size_t size) noexcept : Size(size) -{ -} +{ +} size_t -TBufferBase::GetSize() const noexcept { - return Size; +TBufferBase::GetSize() const noexcept { + return Size; } -void TBufferBase::SetSize(size_t size) noexcept { - Size = size; +void TBufferBase::SetSize(size_t size) noexcept { + Size = size; } ///////////////////////////////////////////////////////////////////// -template <typename PointerType> +template <typename PointerType> TBufferBaseT<PointerType>::TBufferBaseT(PointerType data, size_t size) noexcept - : TBufferBase(size) - , Data(data) -{ -} + : TBufferBase(size) + , Data(data) +{ +} -template <typename PointerType> +template <typename PointerType> PointerType -TBufferBaseT<PointerType>::GetPointer() const noexcept { - return Data; +TBufferBaseT<PointerType>::GetPointer() const noexcept { + return Data; } -template <typename PointerType> -void TBufferBaseT<PointerType>::Assign(PointerType data, size_t size) noexcept { - Data = data; - Size = size; +template <typename PointerType> +void TBufferBaseT<PointerType>::Assign(PointerType data, size_t size) noexcept { + Data = data; + Size = size; } -template <> -void TBufferBaseT<void*>::Cut(size_t offset) noexcept { - Y_VERIFY_DEBUG(offset <= Size); - Data = static_cast<char*>(Data) + offset; - TBufferBase::Size -= offset; +template <> +void TBufferBaseT<void*>::Cut(size_t offset) noexcept { + Y_VERIFY_DEBUG(offset <= Size); + Data = static_cast<char*>(Data) + offset; + TBufferBase::Size -= offset; } -template <> -void TBufferBaseT<const void*>::Cut(size_t offset) noexcept { - Y_VERIFY_DEBUG(offset <= Size); - Data = static_cast<const char*>(Data) + offset; - TBufferBase::Size -= offset; +template <> +void TBufferBaseT<const void*>::Cut(size_t offset) noexcept { + Y_VERIFY_DEBUG(offset <= Size); + Data = static_cast<const char*>(Data) + offset; + TBufferBase::Size -= offset; } template class TBufferBaseT<void*>; @@ -60,34 +60,34 @@ template class TBufferBaseT<const void*>; TConstBuffer::TConstBuffer(const void* data, size_t size) noexcept : TBufferBaseT<const void*>(data, size) -{ -} +{ +} TConstBuffer::TConstBuffer(const TMutableBuffer& buffer) noexcept : TBufferBaseT<const void*>(buffer.GetPointer(), buffer.GetSize()) -{ -} +{ +} TConstBuffer -TConstBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { - return TConstBuffer(static_cast<const char*>(Data) + offset, std::min(Size - offset, size)); +TConstBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { + return TConstBuffer(static_cast<const char*>(Data) + offset, std::min(Size - offset, size)); } //////////////////////////////////////////////////////////////////////////////// TMutableBuffer::TMutableBuffer(void* data, size_t size) noexcept - : TBufferBaseT<void*>(data, size) -{ -} + : TBufferBaseT<void*>(data, size) +{ +} TMutableBuffer -TMutableBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { - return TMutableBuffer(static_cast<char*>(Data) + offset, std::min(Size - offset, size)); +TMutableBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { + return TMutableBuffer(static_cast<char*>(Data) + offset, std::min(Size - offset, size)); } size_t -TMutableBuffer::CopyFrom(const TConstBuffer& buffer) const noexcept { - const auto size = std::min(Size, buffer.Size); - std::memcpy(Data, buffer.Data, size); - return size; +TMutableBuffer::CopyFrom(const TConstBuffer& buffer) const noexcept { + const auto size = std::min(Size, buffer.Size); + std::memcpy(Data, buffer.Data, size); + return size; } diff --git a/library/cpp/actors/core/buffer.h b/library/cpp/actors/core/buffer.h index 95425046d6..fb8bd563d7 100644 --- a/library/cpp/actors/core/buffer.h +++ b/library/cpp/actors/core/buffer.h @@ -5,7 +5,7 @@ class TConstBuffer; class TMutableBuffer; -class TBufferBase { +class TBufferBase { public: size_t GetSize() const noexcept; @@ -17,8 +17,8 @@ protected: size_t Size; }; -template <typename PointerType> -class TBufferBaseT: public TBufferBase { +template <typename PointerType> +class TBufferBaseT: public TBufferBase { public: PointerType GetPointer() const noexcept; @@ -33,30 +33,30 @@ protected: }; /// Represents constant memory buffer, but do not owns it. -class TConstBuffer: public TBufferBaseT<const void*> { - friend class TMutableBuffer; - +class TConstBuffer: public TBufferBaseT<const void*> { + friend class TMutableBuffer; + public: - TConstBuffer(const TMutableBuffer& buffer) noexcept; + TConstBuffer(const TMutableBuffer& buffer) noexcept; - TConstBuffer(const void* data = nullptr, size_t size = 0U) noexcept; + TConstBuffer(const void* data = nullptr, size_t size = 0U) noexcept; - TConstBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; + TConstBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; }; /// Represents mutable memory buffer, but do not owns it. -class TMutableBuffer: public TBufferBaseT<void*> { - friend class TConstBuffer; - +class TMutableBuffer: public TBufferBaseT<void*> { + friend class TConstBuffer; + public: - TMutableBuffer(void* data = nullptr, size_t size = 0U) noexcept; + TMutableBuffer(void* data = nullptr, size_t size = 0U) noexcept; - TMutableBuffer(const TMutableBuffer& value) noexcept - : TBufferBaseT<void*>(value) - { - } + TMutableBuffer(const TMutableBuffer& value) noexcept + : TBufferBaseT<void*>(value) + { + } - TMutableBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; + TMutableBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; - size_t CopyFrom(const TConstBuffer& buffer) const noexcept; + size_t CopyFrom(const TConstBuffer& buffer) const noexcept; }; diff --git a/library/cpp/actors/core/callstack.cpp b/library/cpp/actors/core/callstack.cpp index 9297c1a079..8a3b1df406 100644 --- a/library/cpp/actors/core/callstack.cpp +++ b/library/cpp/actors/core/callstack.cpp @@ -4,88 +4,88 @@ #ifdef USE_ACTOR_CALLSTACK namespace NActors { - namespace { + namespace { void (*PreviousFormatBackTrace)(IOutputStream*) = 0; - ui32 ActorBackTraceEnableCounter = 0; + ui32 ActorBackTraceEnableCounter = 0; } void ActorFormatBackTrace(IOutputStream* out) { - TStringStream str; - PreviousFormatBackTrace(&str); - str << Endl; - TCallstack::DumpCallstack(str); - *out << str.Str(); - } + TStringStream str; + PreviousFormatBackTrace(&str); + str << Endl; + TCallstack::DumpCallstack(str); + *out << str.Str(); + } - void EnableActorCallstack() { - if (ActorBackTraceEnableCounter == 0) { - Y_VERIFY(PreviousFormatBackTrace == 0); - PreviousFormatBackTrace = SetFormatBackTraceFn(ActorFormatBackTrace); - } + void EnableActorCallstack() { + if (ActorBackTraceEnableCounter == 0) { + Y_VERIFY(PreviousFormatBackTrace == 0); + PreviousFormatBackTrace = SetFormatBackTraceFn(ActorFormatBackTrace); + } - ++ActorBackTraceEnableCounter; + ++ActorBackTraceEnableCounter; } - void DisableActorCallstack() { - --ActorBackTraceEnableCounter; + void DisableActorCallstack() { + --ActorBackTraceEnableCounter; - if (ActorBackTraceEnableCounter == 0) { - Y_VERIFY(PreviousFormatBackTrace); - SetFormatBackTraceFn(PreviousFormatBackTrace); - PreviousFormatBackTrace = 0; - } - } + if (ActorBackTraceEnableCounter == 0) { + Y_VERIFY(PreviousFormatBackTrace); + SetFormatBackTraceFn(PreviousFormatBackTrace); + PreviousFormatBackTrace = 0; + } + } - TCallstack::TCallstack() - : BeginIdx(0) - , Size(0) - , LinesToSkip(0) - { + TCallstack::TCallstack() + : BeginIdx(0) + , Size(0) + , LinesToSkip(0) + { } - void TCallstack::SetLinesToSkip() { - TTrace record; - LinesToSkip = BackTrace(record.Data, TTrace::CAPACITY); - } + void TCallstack::SetLinesToSkip() { + TTrace record; + LinesToSkip = BackTrace(record.Data, TTrace::CAPACITY); + } - void TCallstack::Trace() { - size_t currentIdx = (BeginIdx + Size) % RECORDS; - if (Size == RECORDS) { - ++BeginIdx; - } else { - ++Size; - } - TTrace& record = Record[currentIdx]; - record.Size = BackTrace(record.Data, TTrace::CAPACITY); - record.LinesToSkip = LinesToSkip; - } + void TCallstack::Trace() { + size_t currentIdx = (BeginIdx + Size) % RECORDS; + if (Size == RECORDS) { + ++BeginIdx; + } else { + ++Size; + } + TTrace& record = Record[currentIdx]; + record.Size = BackTrace(record.Data, TTrace::CAPACITY); + record.LinesToSkip = LinesToSkip; + } - void TCallstack::TraceIfEmpty() { - if (Size == 0) { - LinesToSkip = 0; - Trace(); - } + void TCallstack::TraceIfEmpty() { + if (Size == 0) { + LinesToSkip = 0; + Trace(); + } } - TCallstack& TCallstack::GetTlsCallstack() { - return *FastTlsSingleton<TCallstack>(); + TCallstack& TCallstack::GetTlsCallstack() { + return *FastTlsSingleton<TCallstack>(); } - void TCallstack::DumpCallstack(TStringStream& str) { - TCallstack& callstack = GetTlsCallstack(); - for (int i = callstack.Size - 1; i >= 0; --i) { - TTrace& record = callstack.Record[(callstack.BeginIdx + i) % RECORDS]; - str << Endl << "Trace entry " << i << Endl << Endl; - size_t size = record.Size; - if (size > record.LinesToSkip && size < TTrace::CAPACITY) { - size -= record.LinesToSkip; - } - if (size > RECORDS_TO_SKIP) { - FormatBackTrace(&str, &record.Data[RECORDS_TO_SKIP], size - RECORDS_TO_SKIP); - } else { - FormatBackTrace(&str, record.Data, size); - } - str << Endl; + void TCallstack::DumpCallstack(TStringStream& str) { + TCallstack& callstack = GetTlsCallstack(); + for (int i = callstack.Size - 1; i >= 0; --i) { + TTrace& record = callstack.Record[(callstack.BeginIdx + i) % RECORDS]; + str << Endl << "Trace entry " << i << Endl << Endl; + size_t size = record.Size; + if (size > record.LinesToSkip && size < TTrace::CAPACITY) { + size -= record.LinesToSkip; + } + if (size > RECORDS_TO_SKIP) { + FormatBackTrace(&str, &record.Data[RECORDS_TO_SKIP], size - RECORDS_TO_SKIP); + } else { + FormatBackTrace(&str, record.Data, size); + } + str << Endl; } } } diff --git a/library/cpp/actors/core/callstack.h b/library/cpp/actors/core/callstack.h index 176717d2ae..1c45b0468e 100644 --- a/library/cpp/actors/core/callstack.h +++ b/library/cpp/actors/core/callstack.h @@ -5,53 +5,53 @@ #endif #ifdef ENABLE_ACTOR_CALLSTACK -#include "defs.h" -#include <util/system/backtrace.h> -#include <util/stream/str.h> -#include <util/generic/deque.h> -#define USE_ACTOR_CALLSTACK +#include "defs.h" +#include <util/system/backtrace.h> +#include <util/stream/str.h> +#include <util/generic/deque.h> +#define USE_ACTOR_CALLSTACK namespace NActors { - struct TCallstack { - struct TTrace { - static const size_t CAPACITY = 50; - void* Data[CAPACITY]; - size_t Size; - size_t LinesToSkip; - - TTrace() - : Size(0) - , LinesToSkip(0) - { - } - }; - - static const size_t RECORDS = 8; - static const size_t RECORDS_TO_SKIP = 2; - TTrace Record[RECORDS]; - size_t BeginIdx; + struct TCallstack { + struct TTrace { + static const size_t CAPACITY = 50; + void* Data[CAPACITY]; + size_t Size; + size_t LinesToSkip; + + TTrace() + : Size(0) + , LinesToSkip(0) + { + } + }; + + static const size_t RECORDS = 8; + static const size_t RECORDS_TO_SKIP = 2; + TTrace Record[RECORDS]; + size_t BeginIdx; size_t Size; size_t LinesToSkip; - TCallstack(); - void SetLinesToSkip(); - void Trace(); - void TraceIfEmpty(); - static TCallstack& GetTlsCallstack(); - static void DumpCallstack(TStringStream& str); + TCallstack(); + void SetLinesToSkip(); + void Trace(); + void TraceIfEmpty(); + static TCallstack& GetTlsCallstack(); + static void DumpCallstack(TStringStream& str); }; - void EnableActorCallstack(); - void DisableActorCallstack(); + void EnableActorCallstack(); + void DisableActorCallstack(); } #else namespace NActors { - inline void EnableActorCallstack(){}; + inline void EnableActorCallstack(){}; - inline void DisableActorCallstack(){}; + inline void DisableActorCallstack(){}; } diff --git a/library/cpp/actors/core/defs.h b/library/cpp/actors/core/defs.h index 980b7d767b..34ddee397e 100644 --- a/library/cpp/actors/core/defs.h +++ b/library/cpp/actors/core/defs.h @@ -1,18 +1,18 @@ -#pragma once - -// unique tag to fix pragma once gcc glueing: ./library/actorlib/core/defs.h - +#pragma once + +// unique tag to fix pragma once gcc glueing: ./library/actorlib/core/defs.h + #include <library/cpp/actors/util/defs.h> #include <util/generic/hash.h> #include <util/string/printf.h> - + // Enables collection of // event send/receive counts // activation time histograms // event processing time histograms #define ACTORSLIB_COLLECT_EXEC_STATS -namespace NActors { +namespace NActors { using TPoolId = ui8; using TPoolsMask = ui64; static constexpr TPoolId PoolBits = 6; @@ -37,19 +37,19 @@ namespace NActors { using TThreadId = ui64; static constexpr TThreadId UnknownThreadId = ui64(-1); - struct TMailboxType { - enum EType { + struct TMailboxType { + enum EType { Inherited = -1, // inherit mailbox from parent - Simple = 0, // simplest queue under producer lock. fastest in no-contention case - Revolving = 1, // somewhat outdated, tries to be wait-free. replaced by ReadAsFilled - HTSwap = 2, // other simple lf queue, suggested for low-contention case - ReadAsFilled = 3, // wait-free queue, suggested for high-contention or latency critical - TinyReadAsFilled = 4, // same as 3 but with lower overhead - //Inplace; - //Direct; - //Virtual - }; - }; + Simple = 0, // simplest queue under producer lock. fastest in no-contention case + Revolving = 1, // somewhat outdated, tries to be wait-free. replaced by ReadAsFilled + HTSwap = 2, // other simple lf queue, suggested for low-contention case + ReadAsFilled = 3, // wait-free queue, suggested for high-contention or latency critical + TinyReadAsFilled = 4, // same as 3 but with lower overhead + //Inplace; + //Direct; + //Virtual + }; + }; struct TScopeId : std::pair<ui64, ui64> { using TBase = std::pair<ui64, ui64>; @@ -61,9 +61,9 @@ namespace NActors { return Sprintf("<%" PRIu64 ":%" PRIu64 ">", scopeId.first, scopeId.second); } -} - +} + template<> struct hash<NActors::TScopeId> : hash<std::pair<ui64, ui64>> {}; -class TAffinity; +class TAffinity; diff --git a/library/cpp/actors/core/event.cpp b/library/cpp/actors/core/event.cpp index 33f8ce2aaf..2ce75ac717 100644 --- a/library/cpp/actors/core/event.cpp +++ b/library/cpp/actors/core/event.cpp @@ -1,4 +1,4 @@ -#include "event.h" +#include "event.h" #include "event_pb.h" namespace NActors { @@ -7,32 +7,32 @@ namespace NActors { Max<ui64>(), Max<ui64>() }; - TIntrusivePtr<TEventSerializedData> IEventHandle::ReleaseChainBuffer() { - if (Buffer) { - TIntrusivePtr<TEventSerializedData> result; - DoSwap(result, Buffer); - Event.Reset(); - return result; - } - if (Event) { - TAllocChunkSerializer serializer; + TIntrusivePtr<TEventSerializedData> IEventHandle::ReleaseChainBuffer() { + if (Buffer) { + TIntrusivePtr<TEventSerializedData> result; + DoSwap(result, Buffer); + Event.Reset(); + return result; + } + if (Event) { + TAllocChunkSerializer serializer; Event->SerializeToArcadiaStream(&serializer); auto chainBuf = serializer.Release(Event->IsExtendedFormat()); - Event.Reset(); - return chainBuf; - } - return new TEventSerializedData; + Event.Reset(); + return chainBuf; + } + return new TEventSerializedData; } - TIntrusivePtr<TEventSerializedData> IEventHandle::GetChainBuffer() { - if (Buffer) - return Buffer; - if (Event) { - TAllocChunkSerializer serializer; + TIntrusivePtr<TEventSerializedData> IEventHandle::GetChainBuffer() { + if (Buffer) + return Buffer; + if (Event) { + TAllocChunkSerializer serializer; Event->SerializeToArcadiaStream(&serializer); Buffer = serializer.Release(Event->IsExtendedFormat()); - return Buffer; - } - return new TEventSerializedData; + return Buffer; + } + return new TEventSerializedData; } } diff --git a/library/cpp/actors/core/event.h b/library/cpp/actors/core/event.h index 6ff02aaf94..617c67fdb9 100644 --- a/library/cpp/actors/core/event.h +++ b/library/cpp/actors/core/event.h @@ -1,40 +1,40 @@ -#pragma once - -#include "defs.h" -#include "actorid.h" +#pragma once + +#include "defs.h" +#include "actorid.h" #include "callstack.h" #include "event_load.h" - + #include <library/cpp/actors/wilson/wilson_trace.h> #include <util/system/hp_timer.h> #include <util/generic/maybe.h> -namespace NActors { - class TChunkSerializer; - - class ISerializerToStream { - public: +namespace NActors { + class TChunkSerializer; + + class ISerializerToStream { + public: virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0; - }; - - class IEventBase - : TNonCopyable, - public ISerializerToStream { - public: - // actual typing is performed by IEventHandle - - virtual ~IEventBase() { - } - - virtual TString ToStringHeader() const = 0; - virtual TString ToString() const { - return ToStringHeader(); - } - virtual ui32 CalculateSerializedSize() const { - return 0; - } - virtual ui32 Type() const = 0; + }; + + class IEventBase + : TNonCopyable, + public ISerializerToStream { + public: + // actual typing is performed by IEventHandle + + virtual ~IEventBase() { + } + + virtual TString ToStringHeader() const = 0; + virtual TString ToString() const { + return ToStringHeader(); + } + virtual ui32 CalculateSerializedSize() const { + return 0; + } + virtual ui32 Type() const = 0; virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0; virtual bool IsSerializable() const = 0; virtual bool IsExtendedFormat() const { @@ -43,20 +43,20 @@ namespace NActors { virtual ui32 CalculateSerializedSizeCached() const { return CalculateSerializedSize(); } - }; - - // fat handle + }; + + // fat handle class IEventHandle : TNonCopyable { struct TOnNondelivery { TActorId Recipient; - + TOnNondelivery(const TActorId& recipient) - : Recipient(recipient) - { - } - }; - - public: + : Recipient(recipient) + { + } + }; + + public: template <typename TEv> inline TEv* CastAsLocal() const noexcept { auto fits = GetTypeRewrite() == TEv::EventType; @@ -64,256 +64,256 @@ namespace NActors { return fits ? static_cast<TEv*>(Event.Get()) : nullptr; } - template <typename TEventType> - TEventType* Get() { - if (Type != TEventType::EventType) - Y_FAIL("Event type %" PRIu32 " doesn't match the expected type %" PRIu32, Type, TEventType::EventType); - - if (!Event) { + template <typename TEventType> + TEventType* Get() { + if (Type != TEventType::EventType) + Y_FAIL("Event type %" PRIu32 " doesn't match the expected type %" PRIu32, Type, TEventType::EventType); + + if (!Event) { Event.Reset(TEventType::Load(Buffer.Get())); - } - + } + if (Event) { - return static_cast<TEventType*>(Event.Get()); + return static_cast<TEventType*>(Event.Get()); } - + Y_FAIL("Failed to Load() event type %" PRIu32 " class %s", Type, TypeName<TEventType>().data()); - } - - template <typename T> - TAutoPtr<T> Release() { - TAutoPtr<T> x = Get<T>(); + } + + template <typename T> + TAutoPtr<T> Release() { + TAutoPtr<T> x = Get<T>(); Y_UNUSED(Event.Release()); - Buffer.Reset(); - return x; - } - - enum EFlags { - FlagTrackDelivery = 1 << 0, - FlagForwardOnNondelivery = 1 << 1, - FlagSubscribeOnSession = 1 << 2, - FlagUseSubChannel = 1 << 3, + Buffer.Reset(); + return x; + } + + enum EFlags { + FlagTrackDelivery = 1 << 0, + FlagForwardOnNondelivery = 1 << 1, + FlagSubscribeOnSession = 1 << 2, + FlagUseSubChannel = 1 << 3, FlagGenerateUnsureUndelivered = 1 << 4, FlagExtendedFormat = 1 << 5, - }; - - const ui32 Type; - const ui32 Flags; + }; + + const ui32 Type; + const ui32 Flags; const TActorId Recipient; const TActorId Sender; - const ui64 Cookie; + const ui64 Cookie; const TScopeId OriginScopeId = TScopeId::LocallyGenerated; // filled in when the message is received from Interconnect + + // if set, used by ActorSystem/Interconnect to report tracepoints + NWilson::TTraceId TraceId; - // if set, used by ActorSystem/Interconnect to report tracepoints - NWilson::TTraceId TraceId; - - // filled if feeded by interconnect session + // filled if feeded by interconnect session const TActorId InterconnectSession; - + #ifdef ACTORSLIB_COLLECT_EXEC_STATS - ::NHPTimer::STime SendTime; + ::NHPTimer::STime SendTime; #endif - static const size_t ChannelBits = 12; - static const size_t ChannelShift = (sizeof(ui32) << 3) - ChannelBits; + static const size_t ChannelBits = 12; + static const size_t ChannelShift = (sizeof(ui32) << 3) - ChannelBits; #ifdef USE_ACTOR_CALLSTACK - TCallstack Callstack; + TCallstack Callstack; #endif - ui16 GetChannel() const noexcept { - return Flags >> ChannelShift; - } - - ui64 GetSubChannel() const noexcept { - return Flags & FlagUseSubChannel ? Sender.LocalId() : 0ULL; - } - - static ui32 MakeFlags(ui32 channel, ui32 flags) { - Y_VERIFY(channel < (1 << ChannelBits)); - Y_VERIFY(flags < (1 << ChannelShift)); - return (flags | (channel << ChannelShift)); - } - - private: - THolder<IEventBase> Event; - TIntrusivePtr<TEventSerializedData> Buffer; - + ui16 GetChannel() const noexcept { + return Flags >> ChannelShift; + } + + ui64 GetSubChannel() const noexcept { + return Flags & FlagUseSubChannel ? Sender.LocalId() : 0ULL; + } + + static ui32 MakeFlags(ui32 channel, ui32 flags) { + Y_VERIFY(channel < (1 << ChannelBits)); + Y_VERIFY(flags < (1 << ChannelShift)); + return (flags | (channel << ChannelShift)); + } + + private: + THolder<IEventBase> Event; + TIntrusivePtr<TEventSerializedData> Buffer; + TActorId RewriteRecipient; - ui32 RewriteType; - - THolder<TOnNondelivery> OnNondeliveryHolder; // only for local events + ui32 RewriteType; + + THolder<TOnNondelivery> OnNondeliveryHolder; // only for local events - public: + public: void Rewrite(ui32 typeRewrite, TActorId recipientRewrite) { - RewriteRecipient = recipientRewrite; - RewriteType = typeRewrite; - } - - void DropRewrite() { - RewriteRecipient = Recipient; - RewriteType = Type; - } - + RewriteRecipient = recipientRewrite; + RewriteType = typeRewrite; + } + + void DropRewrite() { + RewriteRecipient = Recipient; + RewriteType = Type; + } + const TActorId& GetRecipientRewrite() const { - return RewriteRecipient; - } - - ui32 GetTypeRewrite() const { - return RewriteType; - } - + return RewriteRecipient; + } + + ui32 GetTypeRewrite() const { + return RewriteType; + } + TActorId GetForwardOnNondeliveryRecipient() const { return OnNondeliveryHolder.Get() ? OnNondeliveryHolder->Recipient : TActorId(); - } + } IEventHandle(const TActorId& recipient, const TActorId& sender, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, const TActorId* forwardOnNondelivery = nullptr, NWilson::TTraceId traceId = {}) - : Type(ev->Type()) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) - , TraceId(std::move(traceId)) + : Type(ev->Type()) + , Flags(flags) + , Recipient(recipient) + , Sender(sender) + , Cookie(cookie) + , TraceId(std::move(traceId)) #ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) + , SendTime(0) #endif - , Event(ev) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - if (forwardOnNondelivery) - OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); - } - - IEventHandle(ui32 type, - ui32 flags, + , Event(ev) + , RewriteRecipient(Recipient) + , RewriteType(Type) + { + if (forwardOnNondelivery) + OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); + } + + IEventHandle(ui32 type, + ui32 flags, const TActorId& recipient, const TActorId& sender, - TIntrusivePtr<TEventSerializedData> buffer, - ui64 cookie, + TIntrusivePtr<TEventSerializedData> buffer, + ui64 cookie, const TActorId* forwardOnNondelivery = nullptr, - NWilson::TTraceId traceId = {}) - : Type(type) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) - , TraceId(std::move(traceId)) + NWilson::TTraceId traceId = {}) + : Type(type) + , Flags(flags) + , Recipient(recipient) + , Sender(sender) + , Cookie(cookie) + , TraceId(std::move(traceId)) #ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) + , SendTime(0) #endif - , Buffer(std::move(buffer)) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - if (forwardOnNondelivery) - OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); - } - - // Special ctor for events from interconnect. + , Buffer(std::move(buffer)) + , RewriteRecipient(Recipient) + , RewriteType(Type) + { + if (forwardOnNondelivery) + OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); + } + + // Special ctor for events from interconnect. IEventHandle(const TActorId& session, - ui32 type, - ui32 flags, + ui32 type, + ui32 flags, const TActorId& recipient, const TActorId& sender, - TIntrusivePtr<TEventSerializedData> buffer, - ui64 cookie, + TIntrusivePtr<TEventSerializedData> buffer, + ui64 cookie, TScopeId originScopeId, NWilson::TTraceId traceId) noexcept - : Type(type) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) + : Type(type) + , Flags(flags) + , Recipient(recipient) + , Sender(sender) + , Cookie(cookie) , OriginScopeId(originScopeId) - , TraceId(std::move(traceId)) - , InterconnectSession(session) + , TraceId(std::move(traceId)) + , InterconnectSession(session) #ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) + , SendTime(0) #endif - , Buffer(std::move(buffer)) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - } + , Buffer(std::move(buffer)) + , RewriteRecipient(Recipient) + , RewriteType(Type) + { + } TIntrusivePtr<TEventSerializedData> GetChainBuffer(); TIntrusivePtr<TEventSerializedData> ReleaseChainBuffer(); - + ui32 GetSize() const { - if (Buffer) { + if (Buffer) { return Buffer->GetSize(); } else if (Event) { return Event->CalculateSerializedSize(); } else { return 0; - } + } } - bool HasBuffer() const { - return bool(Buffer); + bool HasBuffer() const { + return bool(Buffer); } - - bool HasEvent() const { - return bool(Event); + + bool HasEvent() const { + return bool(Event); } - - IEventBase* GetBase() { - if (!Event) { - if (!Buffer) - return nullptr; - else - ythrow TWithBackTrace<yexception>() << "don't know how to load the event from buffer"; - } - - return Event.Get(); - } - - TAutoPtr<IEventBase> ReleaseBase() { - TAutoPtr<IEventBase> x = GetBase(); + + IEventBase* GetBase() { + if (!Event) { + if (!Buffer) + return nullptr; + else + ythrow TWithBackTrace<yexception>() << "don't know how to load the event from buffer"; + } + + return Event.Get(); + } + + TAutoPtr<IEventBase> ReleaseBase() { + TAutoPtr<IEventBase> x = GetBase(); Y_UNUSED(Event.Release()); - Buffer.Reset(); - return x; - } + Buffer.Reset(); + return x; + } TAutoPtr<IEventHandle> Forward(const TActorId& dest) { - if (Event) - return new IEventHandle(dest, Sender, Event.Release(), Flags, Cookie, nullptr, std::move(TraceId)); - else - return new IEventHandle(Type, Flags, dest, Sender, Buffer, Cookie, nullptr, std::move(TraceId)); - } - + if (Event) + return new IEventHandle(dest, Sender, Event.Release(), Flags, Cookie, nullptr, std::move(TraceId)); + else + return new IEventHandle(Type, Flags, dest, Sender, Buffer, Cookie, nullptr, std::move(TraceId)); + } + TAutoPtr<IEventHandle> ForwardOnNondelivery(ui32 reason, bool unsure = false); - }; - - template <typename TEventType> - class TEventHandle: public IEventHandle { - TEventHandle(); // we never made instance of TEventHandle - public: - TEventType* Get() { - return IEventHandle::Get<TEventType>(); - } - - TAutoPtr<TEventType> Release() { - return IEventHandle::Release<TEventType>(); - } - }; - - static_assert(sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle), "expect sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle)"); - - template <typename TEventType, ui32 EventType0> - class TEventBase: public IEventBase { - public: - static constexpr ui32 EventType = EventType0; - ui32 Type() const override { - return EventType0; - } - // still abstract - - typedef TEventHandle<TEventType> THandle; - typedef TAutoPtr<THandle> TPtr; - }; - + }; + + template <typename TEventType> + class TEventHandle: public IEventHandle { + TEventHandle(); // we never made instance of TEventHandle + public: + TEventType* Get() { + return IEventHandle::Get<TEventType>(); + } + + TAutoPtr<TEventType> Release() { + return IEventHandle::Release<TEventType>(); + } + }; + + static_assert(sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle), "expect sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle)"); + + template <typename TEventType, ui32 EventType0> + class TEventBase: public IEventBase { + public: + static constexpr ui32 EventType = EventType0; + ui32 Type() const override { + return EventType0; + } + // still abstract + + typedef TEventHandle<TEventType> THandle; + typedef TAutoPtr<THandle> TPtr; + }; + #define DEFINE_SIMPLE_LOCAL_EVENT(eventType, header) \ TString ToStringHeader() const override { \ return TString(header); \ @@ -327,7 +327,7 @@ namespace NActors { bool IsSerializable() const override { \ return false; \ } - + #define DEFINE_SIMPLE_NONLOCAL_EVENT(eventType, header) \ TString ToStringHeader() const override { \ return TString(header); \ @@ -341,4 +341,4 @@ namespace NActors { bool IsSerializable() const override { \ return true; \ } -} +} diff --git a/library/cpp/actors/core/event_load.h b/library/cpp/actors/core/event_load.h index 0dab1dd374..30a2cb50d2 100644 --- a/library/cpp/actors/core/event_load.h +++ b/library/cpp/actors/core/event_load.h @@ -1,5 +1,5 @@ #pragma once - + #include <util/stream/walk.h> #include <util/system/types.h> #include <util/generic/string.h> @@ -7,17 +7,17 @@ #include <library/cpp/actors/wilson/wilson_trace.h> namespace NActors { - class IEventHandle; + class IEventHandle; - struct TConstIoVec { - const void* Data; - size_t Size; - }; + struct TConstIoVec { + const void* Data; + size_t Size; + }; - struct TIoVec { - void* Data; - size_t Size; - }; + struct TIoVec { + void* Data; + size_t Size; + }; class TEventSerializedData : public TThrRefBase @@ -80,14 +80,14 @@ namespace NActors { void Append(TRope&& from) { Rope.Insert(Rope.End(), std::move(from)); - } + } void Append(TString buffer) { if (buffer) { Rope.Insert(Rope.End(), TRope(std::move(buffer))); } - } - }; + } + }; } class TChainBufWalk : public IWalkInput { diff --git a/library/cpp/actors/core/event_local.h b/library/cpp/actors/core/event_local.h index 2845aa94dd..492df07a27 100644 --- a/library/cpp/actors/core/event_local.h +++ b/library/cpp/actors/core/event_local.h @@ -1,74 +1,74 @@ -#pragma once - -#include "event.h" -#include "scheduler_cookie.h" +#pragma once + +#include "event.h" +#include "scheduler_cookie.h" #include "event_load.h" #include <util/system/type_name.h> - -namespace NActors { - template <typename TEv, ui32 TEventType> - class TEventLocal: public TEventBase<TEv, TEventType> { - public: + +namespace NActors { + template <typename TEv, ui32 TEventType> + class TEventLocal: public TEventBase<TEv, TEventType> { + public: TString ToStringHeader() const override { - return TypeName<TEv>(); - } - + return TypeName<TEv>(); + } + bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override { Y_FAIL("Serialization of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType); - } - + } + bool IsSerializable() const override { return false; } - static IEventBase* Load(TEventSerializedData*) { + static IEventBase* Load(TEventSerializedData*) { Y_FAIL("Loading of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType); - } - }; - - template <typename TEv, ui32 TEventType> - class TEventScheduler: public TEventLocal<TEv, TEventType> { - public: - TSchedulerCookieHolder Cookie; - - TEventScheduler(ISchedulerCookie* cookie) - : Cookie(cookie) - { - } - }; - - template <ui32 TEventType> - class TEventSchedulerEv: public TEventScheduler<TEventSchedulerEv<TEventType>, TEventType> { - public: - TEventSchedulerEv(ISchedulerCookie* cookie) - : TEventScheduler<TEventSchedulerEv<TEventType>, TEventType>(cookie) - { - } - }; - - template <typename TEv, ui32 TEventType> + } + }; + + template <typename TEv, ui32 TEventType> + class TEventScheduler: public TEventLocal<TEv, TEventType> { + public: + TSchedulerCookieHolder Cookie; + + TEventScheduler(ISchedulerCookie* cookie) + : Cookie(cookie) + { + } + }; + + template <ui32 TEventType> + class TEventSchedulerEv: public TEventScheduler<TEventSchedulerEv<TEventType>, TEventType> { + public: + TEventSchedulerEv(ISchedulerCookie* cookie) + : TEventScheduler<TEventSchedulerEv<TEventType>, TEventType>(cookie) + { + } + }; + + template <typename TEv, ui32 TEventType> class TEventSimple: public TEventBase<TEv, TEventType> { - public: - TString ToStringHeader() const override { - static TString header(TypeName<TEv>()); - return header; - } - + public: + TString ToStringHeader() const override { + static TString header(TypeName<TEv>()); + return header; + } + bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override { static_assert(sizeof(TEv) == sizeof(TEventSimple<TEv, TEventType>), "Descendant should be an empty class"); return true; - } - + } + bool IsSerializable() const override { return true; } - static IEventBase* Load(NActors::TEventSerializedData*) { - return new TEv(); - } + static IEventBase* Load(NActors::TEventSerializedData*) { + return new TEv(); + } - static IEventBase* Load(const TString&) { - return new TEv(); - } - }; -} + static IEventBase* Load(const TString&) { + return new TEv(); + } + }; +} diff --git a/library/cpp/actors/core/event_pb.cpp b/library/cpp/actors/core/event_pb.cpp index 018ff9ac34..b8f40c28ef 100644 --- a/library/cpp/actors/core/event_pb.cpp +++ b/library/cpp/actors/core/event_pb.cpp @@ -9,43 +9,43 @@ namespace NActors { Iter += *size; } else if (Iter.Valid()) { Iter.AdvanceToNextContiguousBlock(); - } + } TotalByteCount += *size; return *size != 0; - } + } void TRopeStream::BackUp(int count) { Y_VERIFY(count <= TotalByteCount); Iter -= count; TotalByteCount -= count; - } + } bool TRopeStream::Skip(int count) { if (static_cast<size_t>(TotalByteCount + count) > Size) { count = Size - TotalByteCount; - } + } Iter += count; TotalByteCount += count; return static_cast<size_t>(TotalByteCount) != Size; } - TCoroutineChunkSerializer::TCoroutineChunkSerializer() - : TotalSerializedDataSize(0) + TCoroutineChunkSerializer::TCoroutineChunkSerializer() + : TotalSerializedDataSize(0) , Stack(64 * 1024) , SelfClosure{this, TArrayRef(Stack.Begin(), Stack.End())} - , InnerContext(SelfClosure) + , InnerContext(SelfClosure) {} - TCoroutineChunkSerializer::~TCoroutineChunkSerializer() { - CancelFlag = true; + TCoroutineChunkSerializer::~TCoroutineChunkSerializer() { + CancelFlag = true; Resume(); Y_VERIFY(Finished); } - - bool TCoroutineChunkSerializer::AllowsAliasing() const { - return true; - } - + + bool TCoroutineChunkSerializer::AllowsAliasing() const { + return true; + } + bool TCoroutineChunkSerializer::Produce(const void *data, size_t size) { Y_VERIFY(size <= SizeRemain); SizeRemain -= size; @@ -71,11 +71,11 @@ namespace NActors { return true; } - bool TCoroutineChunkSerializer::WriteAliasedRaw(const void* data, int size) { - Y_VERIFY(size >= 0); + bool TCoroutineChunkSerializer::WriteAliasedRaw(const void* data, int size) { + Y_VERIFY(size >= 0); while (size) { if (CancelFlag || AbortFlag) { - return false; + return false; } else if (const size_t bytesToAppend = Min<size_t>(size, SizeRemain)) { if (!Produce(data, bytesToAppend)) { return false; @@ -86,29 +86,29 @@ namespace NActors { InnerContext.SwitchTo(BufFeedContext); } } - return true; + return true; } - bool TCoroutineChunkSerializer::Next(void** data, int* size) { + bool TCoroutineChunkSerializer::Next(void** data, int* size) { if (CancelFlag || AbortFlag) { - return false; + return false; } if (!SizeRemain) { - InnerContext.SwitchTo(BufFeedContext); + InnerContext.SwitchTo(BufFeedContext); if (CancelFlag || AbortFlag) { - return false; + return false; } - } + } Y_VERIFY(SizeRemain); *data = BufferPtr; *size = SizeRemain; BufferPtr += SizeRemain; return Produce(*data, *size); - } - - void TCoroutineChunkSerializer::BackUp(int count) { + } + + void TCoroutineChunkSerializer::BackUp(int count) { if (!count) { - return; + return; } Y_VERIFY(count > 0); Y_VERIFY(NumChunks); @@ -121,13 +121,13 @@ namespace NActors { } BufferPtr -= count; SizeRemain += count; - TotalSerializedDataSize -= count; + TotalSerializedDataSize -= count; } - void TCoroutineChunkSerializer::Resume() { - TContMachineContext feedContext; - BufFeedContext = &feedContext; - feedContext.SwitchTo(&InnerContext); + void TCoroutineChunkSerializer::Resume() { + TContMachineContext feedContext; + BufFeedContext = &feedContext; + feedContext.SwitchTo(&InnerContext); BufFeedContext = nullptr; } @@ -155,14 +155,14 @@ namespace NActors { Resume(); return {Chunks, Chunks + NumChunks}; - } + } void TCoroutineChunkSerializer::SetSerializingEvent(const IEventBase *event) { Y_VERIFY(Event == nullptr); Event = event; - TotalSerializedDataSize = 0; + TotalSerializedDataSize = 0; AbortFlag = false; - } + } void TCoroutineChunkSerializer::Abort() { Y_VERIFY(Event); @@ -170,7 +170,7 @@ namespace NActors { Resume(); } - void TCoroutineChunkSerializer::DoRun() { + void TCoroutineChunkSerializer::DoRun() { while (!CancelFlag) { Y_VERIFY(Event); SerializationSuccess = Event->SerializeToArcadiaStream(this); @@ -178,12 +178,12 @@ namespace NActors { if (!CancelFlag) { // cancel flag may have been received during serialization InnerContext.SwitchTo(BufFeedContext); } - } + } Finished = true; InnerContext.SwitchTo(BufFeedContext); } - bool TAllocChunkSerializer::Next(void** pdata, int* psize) { + bool TAllocChunkSerializer::Next(void** pdata, int* psize) { if (Backup) { // we have some data in backup rope -- move the first chunk from the backup rope to the buffer and return // pointer to the buffer; it is safe to remove 'const' here as we uniquely own this buffer @@ -199,17 +199,17 @@ namespace NActors { *psize = item->GetCapacity(); Buffers->Append(TRope(std::move(item))); } - return true; + return true; } - void TAllocChunkSerializer::BackUp(int count) { + void TAllocChunkSerializer::BackUp(int count) { Backup.Insert(Backup.Begin(), Buffers->EraseBack(count)); - } + } - bool TAllocChunkSerializer::WriteAliasedRaw(const void*, int) { - Y_VERIFY(false); - return false; - } + bool TAllocChunkSerializer::WriteAliasedRaw(const void*, int) { + Y_VERIFY(false); + return false; + } bool TAllocChunkSerializer::WriteRope(const TRope *rope) { Buffers->Append(TRope(*rope)); diff --git a/library/cpp/actors/core/event_pb.h b/library/cpp/actors/core/event_pb.h index d7546b901a..76731cbca9 100644 --- a/library/cpp/actors/core/event_pb.h +++ b/library/cpp/actors/core/event_pb.h @@ -1,6 +1,6 @@ -#pragma once - -#include "event.h" +#pragma once + +#include "event.h" #include "event_load.h" #include <google/protobuf/io/zero_copy_stream.h> @@ -10,19 +10,19 @@ #include <util/system/context.h> #include <util/system/filemap.h> #include <array> - -namespace NActors { + +namespace NActors { class TRopeStream : public NProtoBuf::io::ZeroCopyInputStream { TRope::TConstIterator Iter; const size_t Size; - public: + public: TRopeStream(TRope::TConstIterator iter, size_t size) : Iter(iter) , Size(size) {} - + bool Next(const void** data, int* size) override; void BackUp(int count) override; bool Skip(int count) override; @@ -32,19 +32,19 @@ namespace NActors { private: int64_t TotalByteCount = 0; - }; + }; class TChunkSerializer : public NProtoBuf::io::ZeroCopyOutputStream { - public: + public: TChunkSerializer() = default; virtual ~TChunkSerializer() = default; virtual bool WriteRope(const TRope *rope) = 0; virtual bool WriteString(const TString *s) = 0; - }; + }; class TAllocChunkSerializer final : public TChunkSerializer { - public: + public: bool Next(void** data, int* size) override; void BackUp(int count) override; int64_t ByteCount() const override { @@ -61,29 +61,29 @@ namespace NActors { Buffers->SetExtendedFormat(); } return std::move(Buffers); - } + } - protected: + protected: TIntrusivePtr<TEventSerializedData> Buffers = new TEventSerializedData; TRope Backup; - }; + }; class TCoroutineChunkSerializer final : public TChunkSerializer, protected ITrampoLine { - public: + public: using TChunk = std::pair<const char*, size_t>; - TCoroutineChunkSerializer(); - ~TCoroutineChunkSerializer(); + TCoroutineChunkSerializer(); + ~TCoroutineChunkSerializer(); void SetSerializingEvent(const IEventBase *event); void Abort(); std::pair<TChunk*, TChunk*> FeedBuf(void* data, size_t size); - bool IsComplete() const { + bool IsComplete() const { return !Event; - } - bool IsSuccessfull() const { - return SerializationSuccess; - } + } + bool IsSuccessfull() const { + return SerializationSuccess; + } const IEventBase *GetCurrentEvent() const { return Event; } @@ -99,15 +99,15 @@ namespace NActors { bool WriteRope(const TRope *rope) override; bool WriteString(const TString *s) override; - protected: + protected: void DoRun() override; - void Resume(); + void Resume(); bool Produce(const void *data, size_t size); - i64 TotalSerializedDataSize; - TMappedAllocation Stack; - TContClosure SelfClosure; - TContMachineContext InnerContext; + i64 TotalSerializedDataSize; + TMappedAllocation Stack; + TContClosure SelfClosure; + TContMachineContext InnerContext; TContMachineContext *BufFeedContext = nullptr; char *BufferPtr; size_t SizeRemain; @@ -119,7 +119,7 @@ namespace NActors { bool AbortFlag; bool SerializationSuccess; bool Finished = false; - }; + }; #ifdef ACTORLIB_HUGE_PB_SIZE static const size_t EventMaxByteSize = 140 << 20; // (140MB) @@ -132,11 +132,11 @@ namespace NActors { // a vector of data buffers referenced by record; if filled, then extended serialization mechanism applies TVector<TRope> Payload; - public: + public: using TRecHolder::Record; public: - using ProtoRecordType = TRecord; + using ProtoRecordType = TRecord; TEventPBBase() = default; @@ -150,13 +150,13 @@ namespace NActors { Record = std::move(rec); } - TString ToStringHeader() const override { - return Record.GetTypeName(); - } + TString ToStringHeader() const override { + return Record.GetTypeName(); + } - TString ToString() const override { + TString ToString() const override { return Record.ShortDebugString(); - } + } bool IsSerializable() const override { return true; @@ -213,9 +213,9 @@ namespace NActors { } } - return Record.SerializeToZeroCopyStream(chunker); - } - + return Record.SerializeToZeroCopyStream(chunker); + } + ui32 CalculateSerializedSize() const override { ssize_t result = Record.ByteSize(); if (result >= 0 && Payload) { @@ -227,10 +227,10 @@ namespace NActors { result += rope.GetSize(); } } - return result; + return result; } - static IEventBase* Load(TIntrusivePtr<TEventSerializedData> input) { + static IEventBase* Load(TIntrusivePtr<TEventSerializedData> input) { THolder<TEventPBBase> ev(new TEv()); if (!input->GetSize()) { Y_PROTOBUF_SUPPRESS_NODISCARD ev->Record.ParseFromString(TString()); @@ -270,7 +270,7 @@ namespace NActors { if (!ev->Record.ParseFromZeroCopyStream(&stream)) { Y_FAIL("Failed to parse protobuf event type %" PRIu32 " class %s", TEventType, TypeName(ev->Record).data()); } - } + } ev->CachedByteSize = input->GetSize(); return ev.Release(); } @@ -278,18 +278,18 @@ namespace NActors { size_t GetCachedByteSize() const { if (CachedByteSize == 0) { CachedByteSize = CalculateSerializedSize(); - } - return CachedByteSize; - } + } + return CachedByteSize; + } ui32 CalculateSerializedSizeCached() const override { return GetCachedByteSize(); } - void InvalidateCachedByteSize() { - CachedByteSize = 0; - } - + void InvalidateCachedByteSize() { + CachedByteSize = 0; + } + public: void ReservePayload(size_t size) { Payload.reserve(size); @@ -316,7 +316,7 @@ namespace NActors { } protected: - mutable size_t CachedByteSize = 0; + mutable size_t CachedByteSize = 0; static constexpr char PayloadMarker = 0x07; static constexpr size_t MaxNumberBytes = (sizeof(size_t) * CHAR_BIT + 6) / 7; @@ -367,8 +367,8 @@ namespace NActors { } return res; } - }; - + }; + // Protobuf record not using arena template <typename TRecord> struct TRecordHolder { @@ -490,11 +490,11 @@ namespace NActors { inline TActorId ActorIdFromProto(const NActorsProto::TActorId& actorId) { return TActorId(actorId.GetRawX1(), actorId.GetRawX2()); - } - + } + inline void ActorIdToProto(const TActorId& src, NActorsProto::TActorId* dest) { - Y_VERIFY_DEBUG(dest); - dest->SetRawX1(src.RawX1()); - dest->SetRawX2(src.RawX2()); - } -} + Y_VERIFY_DEBUG(dest); + dest->SetRawX1(src.RawX1()); + dest->SetRawX2(src.RawX2()); + } +} diff --git a/library/cpp/actors/core/events.h b/library/cpp/actors/core/events.h index 702cf50fad..5ff747efee 100644 --- a/library/cpp/actors/core/events.h +++ b/library/cpp/actors/core/events.h @@ -1,99 +1,99 @@ -#pragma once - -#include "event.h" +#pragma once + +#include "event.h" #include "event_pb.h" - + #include <library/cpp/actors/protos/actors.pb.h> #include <util/system/unaligned_mem.h> -namespace NActors { - struct TEvents { - enum EEventSpace { - ES_HELLOWORLD = 0, - ES_SYSTEM = 1, - ES_INTERCONNECT = 2, - ES_INTERCONNECT_MSGBUS = 3, - ES_DNS = 4, - ES_SOCKET_POLLER = 5, - ES_LOGGER = 6, - ES_MON = 7, - ES_INTERCONNECT_TCP = 8, - ES_PROFILER = 9, +namespace NActors { + struct TEvents { + enum EEventSpace { + ES_HELLOWORLD = 0, + ES_SYSTEM = 1, + ES_INTERCONNECT = 2, + ES_INTERCONNECT_MSGBUS = 3, + ES_DNS = 4, + ES_SOCKET_POLLER = 5, + ES_LOGGER = 6, + ES_MON = 7, + ES_INTERCONNECT_TCP = 8, + ES_PROFILER = 9, ES_YF = 10, ES_HTTP = 11, - - ES_USERSPACE = 4096, - - ES_PRIVATE = (1 << 15) - 16, - ES_MAX = (1 << 15), - }; - -#define EventSpaceBegin(eventSpace) (eventSpace << 16u) -#define EventSpaceEnd(eventSpace) ((eventSpace << 16u) + (1u << 16u)) - - struct THelloWorld { - enum { - Start = EventSpaceBegin(ES_HELLOWORLD), - Ping, - Pong, - Blob, - End - }; - - static_assert(End < EventSpaceEnd(ES_HELLOWORLD), "expect End < EventSpaceEnd(ES_HELLOWORLD)"); - }; - - struct TEvPing: public TEventBase<TEvPing, THelloWorld::Ping> { - DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPing, "HelloWorld: Ping"); - }; - - struct TEvPong: public TEventBase<TEvPong, THelloWorld::Pong> { - DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPong, "HelloWorld: Pong"); - }; - - struct TEvBlob: public TEventBase<TEvBlob, THelloWorld::Blob> { - const TString Blob; - - TEvBlob(const TString& blob) noexcept - : Blob(blob) - { - } - - TString ToStringHeader() const noexcept override { - return "THelloWorld::Blob"; - } + + ES_USERSPACE = 4096, + + ES_PRIVATE = (1 << 15) - 16, + ES_MAX = (1 << 15), + }; + +#define EventSpaceBegin(eventSpace) (eventSpace << 16u) +#define EventSpaceEnd(eventSpace) ((eventSpace << 16u) + (1u << 16u)) + + struct THelloWorld { + enum { + Start = EventSpaceBegin(ES_HELLOWORLD), + Ping, + Pong, + Blob, + End + }; + + static_assert(End < EventSpaceEnd(ES_HELLOWORLD), "expect End < EventSpaceEnd(ES_HELLOWORLD)"); + }; + + struct TEvPing: public TEventBase<TEvPing, THelloWorld::Ping> { + DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPing, "HelloWorld: Ping"); + }; + + struct TEvPong: public TEventBase<TEvPong, THelloWorld::Pong> { + DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPong, "HelloWorld: Pong"); + }; + + struct TEvBlob: public TEventBase<TEvBlob, THelloWorld::Blob> { + const TString Blob; + + TEvBlob(const TString& blob) noexcept + : Blob(blob) + { + } + + TString ToStringHeader() const noexcept override { + return "THelloWorld::Blob"; + } bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { return serializer->WriteString(&Blob); - } + } - static IEventBase* Load(TEventSerializedData* bufs) noexcept { + static IEventBase* Load(TEventSerializedData* bufs) noexcept { return new TEvBlob(bufs->GetString()); - } + } bool IsSerializable() const override { return true; } - }; - - struct TSystem { - enum { - Start = EventSpaceBegin(ES_SYSTEM), - Bootstrap, // generic bootstrap event - Wakeup, // generic timeout - Subscribe, // generic subscribe to something - Unsubscribe, // generic unsubscribe from something - Delivered, // event delivered - Undelivered, // event undelivered + }; + + struct TSystem { + enum { + Start = EventSpaceBegin(ES_SYSTEM), + Bootstrap, // generic bootstrap event + Wakeup, // generic timeout + Subscribe, // generic subscribe to something + Unsubscribe, // generic unsubscribe from something + Delivered, // event delivered + Undelivered, // event undelivered Poison, // request actor to shutdown - Completed, // generic async job result event + Completed, // generic async job result event PoisonTaken, // generic Poison taken (reply to PoisonPill event, i.e. died completely) - FlushLog, - CallbackCompletion, - CallbackException, + FlushLog, + CallbackCompletion, + CallbackException, Gone, // Generic notification of actor death - TrackActor, - UntrackActor, + TrackActor, + UntrackActor, InvokeResult, CoroTimeout, InvokeQuery, @@ -102,61 +102,61 @@ namespace NActors { // Compatibility section PoisonPill = Poison, ActorDied = Gone, - }; - - static_assert(End < EventSpaceEnd(ES_SYSTEM), "expect End < EventSpaceEnd(ES_SYSTEM)"); - }; - - struct TEvBootstrap: public TEventBase<TEvBootstrap, TSystem::Bootstrap> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvBootstrap, "System: TEvBootstrap") - }; - + }; + + static_assert(End < EventSpaceEnd(ES_SYSTEM), "expect End < EventSpaceEnd(ES_SYSTEM)"); + }; + + struct TEvBootstrap: public TEventBase<TEvBootstrap, TSystem::Bootstrap> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvBootstrap, "System: TEvBootstrap") + }; + struct TEvPoison : public TEventBase<TEvPoison, TSystem::Poison> { DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPoison, "System: TEvPoison") - }; - - struct TEvWakeup: public TEventBase<TEvWakeup, TSystem::Wakeup> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvWakeup, "System: TEvWakeup") + }; + + struct TEvWakeup: public TEventBase<TEvWakeup, TSystem::Wakeup> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvWakeup, "System: TEvWakeup") TEvWakeup(ui64 tag = 0) : Tag(tag) { } const ui64 Tag = 0; - }; - - struct TEvSubscribe: public TEventBase<TEvSubscribe, TSystem::Subscribe> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSubscribe, "System: TEvSubscribe") - }; - - struct TEvUnsubscribe: public TEventBase<TEvUnsubscribe, TSystem::Unsubscribe> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvUnsubscribe, "System: TEvUnsubscribe") - }; - - struct TEvUndelivered: public TEventBase<TEvUndelivered, TSystem::Undelivered> { - enum EReason { - ReasonUnknown, - ReasonActorUnknown, - Disconnected - }; - const ui32 SourceType; - const EReason Reason; + }; + + struct TEvSubscribe: public TEventBase<TEvSubscribe, TSystem::Subscribe> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvSubscribe, "System: TEvSubscribe") + }; + + struct TEvUnsubscribe: public TEventBase<TEvUnsubscribe, TSystem::Unsubscribe> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvUnsubscribe, "System: TEvUnsubscribe") + }; + + struct TEvUndelivered: public TEventBase<TEvUndelivered, TSystem::Undelivered> { + enum EReason { + ReasonUnknown, + ReasonActorUnknown, + Disconnected + }; + const ui32 SourceType; + const EReason Reason; const bool Unsure; const TString Data; TEvUndelivered(ui32 sourceType, ui32 reason, bool unsure = false) - : SourceType(sourceType) - , Reason(static_cast<EReason>(reason)) + : SourceType(sourceType) + , Reason(static_cast<EReason>(reason)) , Unsure(unsure) , Data(MakeData(sourceType, reason)) {} - - TString ToStringHeader() const override; + + TString ToStringHeader() const override; bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override; - static IEventBase* Load(TEventSerializedData* bufs); + static IEventBase* Load(TEventSerializedData* bufs); bool IsSerializable() const override; - + ui32 CalculateSerializedSize() const override { return 2 * sizeof(ui32); } - static void Out(IOutputStream& o, EReason x); + static void Out(IOutputStream& o, EReason x); private: static TString MakeData(ui32 sourceType, ui32 reason) { @@ -166,57 +166,57 @@ namespace NActors { WriteUnaligned<ui32>(p + 4, reason); return s; } - }; - - struct TEvCompleted: public TEventBase<TEvCompleted, TSystem::Completed> { - const ui32 Id; - const ui32 Status; - TEvCompleted(ui32 id = 0, ui32 status = 0) - : Id(id) - , Status(status) - { - } - - DEFINE_SIMPLE_LOCAL_EVENT(TEvCompleted, "System: TEvCompleted") - }; - - struct TEvPoisonTaken: public TEventBase<TEvPoisonTaken, TSystem::PoisonTaken> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvPoisonTaken, "System: TEvPoisonTaken") - }; - - struct TEvFlushLog: public TEventBase<TEvFlushLog, TSystem::FlushLog> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvFlushLog, "System: TEvFlushLog") - }; - - struct TEvCallbackException: public TEventPB<TEvCallbackException, - NActorsProto::TCallbackException, - TSystem::CallbackException> { + }; + + struct TEvCompleted: public TEventBase<TEvCompleted, TSystem::Completed> { + const ui32 Id; + const ui32 Status; + TEvCompleted(ui32 id = 0, ui32 status = 0) + : Id(id) + , Status(status) + { + } + + DEFINE_SIMPLE_LOCAL_EVENT(TEvCompleted, "System: TEvCompleted") + }; + + struct TEvPoisonTaken: public TEventBase<TEvPoisonTaken, TSystem::PoisonTaken> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvPoisonTaken, "System: TEvPoisonTaken") + }; + + struct TEvFlushLog: public TEventBase<TEvFlushLog, TSystem::FlushLog> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvFlushLog, "System: TEvFlushLog") + }; + + struct TEvCallbackException: public TEventPB<TEvCallbackException, + NActorsProto::TCallbackException, + TSystem::CallbackException> { TEvCallbackException(const TActorId& id, const TString& msg) { ActorIdToProto(id, Record.MutableActorId()); - Record.SetExceptionMessage(msg); - } - }; + Record.SetExceptionMessage(msg); + } + }; - struct TEvCallbackCompletion: public TEventPB<TEvCallbackCompletion, + struct TEvCallbackCompletion: public TEventPB<TEvCallbackCompletion, NActorsProto::TActorId, - TSystem::CallbackCompletion> { + TSystem::CallbackCompletion> { TEvCallbackCompletion(const TActorId& id) { ActorIdToProto(id, &Record); - } - }; - + } + }; + struct TEvGone: public TEventBase<TEvGone, TSystem::Gone> { DEFINE_SIMPLE_LOCAL_EVENT(TEvGone, "System: TEvGone") - }; + }; struct TEvInvokeResult; using TEvPoisonPill = TEvPoison; // Legacy name, deprecated using TEvActorDied = TEvGone; }; -} - -template <> -inline void Out<NActors::TEvents::TEvUndelivered::EReason>(IOutputStream& o, NActors::TEvents::TEvUndelivered::EReason x) { - NActors::TEvents::TEvUndelivered::Out(o, x); -} +} + +template <> +inline void Out<NActors::TEvents::TEvUndelivered::EReason>(IOutputStream& o, NActors::TEvents::TEvUndelivered::EReason x) { + NActors::TEvents::TEvUndelivered::Out(o, x); +} diff --git a/library/cpp/actors/core/events_undelivered.cpp b/library/cpp/actors/core/events_undelivered.cpp index 23deaffd10..6ba2d685ee 100644 --- a/library/cpp/actors/core/events_undelivered.cpp +++ b/library/cpp/actors/core/events_undelivered.cpp @@ -1,54 +1,54 @@ -#include "events.h" +#include "events.h" #include "actorsystem.h" - -namespace NActors { - TString TEvents::TEvUndelivered::ToStringHeader() const { - return "TSystem::Undelivered"; - } - + +namespace NActors { + TString TEvents::TEvUndelivered::ToStringHeader() const { + return "TSystem::Undelivered"; + } + bool TEvents::TEvUndelivered::SerializeToArcadiaStream(TChunkSerializer *serializer) const { Y_VERIFY(!Unsure); // these are local-only events generated by Interconnect return serializer->WriteString(&Data); - } - - void TEvents::TEvUndelivered::Out(IOutputStream& o, EReason x) { - switch (x) { - case ReasonActorUnknown: - o << "ActorUnknown"; - break; - case Disconnected: - o << "Disconnected"; - break; - default: - o << "Undefined"; - break; - } - } - + } + + void TEvents::TEvUndelivered::Out(IOutputStream& o, EReason x) { + switch (x) { + case ReasonActorUnknown: + o << "ActorUnknown"; + break; + case Disconnected: + o << "Disconnected"; + break; + default: + o << "Undefined"; + break; + } + } + bool TEvents::TEvUndelivered::IsSerializable() const { return true; } - IEventBase* TEvents::TEvUndelivered::Load(TEventSerializedData* bufs) { + IEventBase* TEvents::TEvUndelivered::Load(TEventSerializedData* bufs) { TString str = bufs->GetString(); - Y_VERIFY(str.size() == (sizeof(ui32) + sizeof(ui32))); + 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); - return new TEvUndelivered(sourceType, reason); - } - + return new TEvUndelivered(sourceType, reason); + } + TAutoPtr<IEventHandle> IEventHandle::ForwardOnNondelivery(ui32 reason, bool unsure) { if (Flags & FlagForwardOnNondelivery) { - const ui32 updatedFlags = Flags & ~(FlagForwardOnNondelivery | FlagSubscribeOnSession); + const ui32 updatedFlags = Flags & ~(FlagForwardOnNondelivery | FlagSubscribeOnSession); const TActorId recp = OnNondeliveryHolder ? OnNondeliveryHolder->Recipient : TActorId(); - - if (Event) - return new IEventHandle(recp, Sender, Event.Release(), updatedFlags, Cookie, &Recipient, TraceId.Clone()); - else + + if (Event) + return new IEventHandle(recp, Sender, Event.Release(), updatedFlags, Cookie, &Recipient, TraceId.Clone()); + else return new IEventHandle(Type, updatedFlags, recp, Sender, Buffer, Cookie, &Recipient, TraceId.Clone()); - } - + } + if (Flags & FlagTrackDelivery) { const ui32 updatedFlags = Flags & ~(FlagTrackDelivery | FlagSubscribeOnSession | FlagGenerateUnsureUndelivered); return new IEventHandle(Sender, Recipient, new TEvents::TEvUndelivered(Type, reason, unsure), updatedFlags, @@ -56,5 +56,5 @@ namespace NActors { } return nullptr; - } -} + } +} diff --git a/library/cpp/actors/core/executelater.h b/library/cpp/actors/core/executelater.h index e7a13c1005..dd617047d8 100644 --- a/library/cpp/actors/core/executelater.h +++ b/library/cpp/actors/core/executelater.h @@ -5,36 +5,36 @@ #include <utility> namespace NActors { - template <typename TCallback> - class TExecuteLater: public TActorBootstrapped<TExecuteLater<TCallback>> { - public: + template <typename TCallback> + class TExecuteLater: public TActorBootstrapped<TExecuteLater<TCallback>> { + public: static constexpr IActor::EActivityType ActorActivityType() { return IActor::ACTORLIB_COMMON; } - TExecuteLater( + TExecuteLater( TCallback&& callback, IActor::EActivityType activityType, ui32 channel = 0, ui64 cookie = 0, const TActorId& reportCompletionTo = TActorId(), const TActorId& reportExceptionTo = TActorId()) noexcept - : Callback(std::move(callback)) - , Channel(channel) - , Cookie(cookie) - , ReportCompletionTo(reportCompletionTo) - , ReportExceptionTo(reportExceptionTo) - { - this->SetActivityType(activityType); - } + : Callback(std::move(callback)) + , Channel(channel) + , Cookie(cookie) + , ReportCompletionTo(reportCompletionTo) + , ReportExceptionTo(reportExceptionTo) + { + this->SetActivityType(activityType); + } - void Bootstrap(const TActorContext& ctx) noexcept { - try { - { - /* RAII, Callback should be destroyed right before sending + void Bootstrap(const TActorContext& ctx) noexcept { + try { + { + /* RAII, Callback should be destroyed right before sending TEvCallbackCompletion */ - auto local = std::move(Callback); + auto local = std::move(Callback); using T = decltype(local); if constexpr (std::is_invocable_v<T, const TActorContext&>) { @@ -42,46 +42,46 @@ namespace NActors { } else { local(); } - } - - if (ReportCompletionTo) { - ctx.Send(ReportCompletionTo, - new TEvents::TEvCallbackCompletion(ctx.SelfID), - Channel, Cookie); - } - } catch (...) { - if (ReportExceptionTo) { - const TString msg = CurrentExceptionMessage(); - ctx.Send(ReportExceptionTo, - new TEvents::TEvCallbackException(ctx.SelfID, msg), - Channel, Cookie); - } + } + + if (ReportCompletionTo) { + ctx.Send(ReportCompletionTo, + new TEvents::TEvCallbackCompletion(ctx.SelfID), + Channel, Cookie); + } + } catch (...) { + if (ReportExceptionTo) { + const TString msg = CurrentExceptionMessage(); + ctx.Send(ReportExceptionTo, + new TEvents::TEvCallbackException(ctx.SelfID, msg), + Channel, Cookie); + } } - this->Die(ctx); + this->Die(ctx); } - private: - TCallback Callback; - const ui32 Channel; - const ui64 Cookie; + private: + TCallback Callback; + const ui32 Channel; + const ui64 Cookie; const TActorId ReportCompletionTo; const TActorId ReportExceptionTo; - }; + }; - template <typename T> - IActor* CreateExecuteLaterActor( + template <typename T> + IActor* CreateExecuteLaterActor( T&& func, IActor::EActivityType activityType, ui32 channel = 0, ui64 cookie = 0, const TActorId& reportCompletionTo = TActorId(), const TActorId& reportExceptionTo = TActorId()) noexcept { - return new TExecuteLater<T>(std::forward<T>(func), - activityType, - channel, - cookie, - reportCompletionTo, - reportExceptionTo); - } + return new TExecuteLater<T>(std::forward<T>(func), + activityType, + channel, + cookie, + reportCompletionTo, + reportExceptionTo); + } } diff --git a/library/cpp/actors/core/executor_pool_base.cpp b/library/cpp/actors/core/executor_pool_base.cpp index c3b9999168..1e47aa179c 100644 --- a/library/cpp/actors/core/executor_pool_base.cpp +++ b/library/cpp/actors/core/executor_pool_base.cpp @@ -1,21 +1,21 @@ -#include "executor_pool_base.h" -#include "executor_thread.h" -#include "mailbox.h" +#include "executor_pool_base.h" +#include "executor_thread.h" +#include "mailbox.h" #include "probes.h" #include <library/cpp/actors/util/datetime.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - + +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + void DoActorInit(TActorSystem* sys, IActor* actor, const TActorId& self, const TActorId& owner) { actor->SelfActorId = self; actor->Registered(sys, owner); - } + } TExecutorPoolBaseMailboxed::TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType) - : IExecutorPool(poolId) - , ActorSystem(nullptr) - , MailboxTable(new TMailboxTable) + : IExecutorPool(poolId) + , ActorSystem(nullptr) + , MailboxTable(new TMailboxTable) #ifdef ACTORSLIB_COLLECT_EXEC_STATS , Stats(maxActivityType) #endif @@ -23,146 +23,146 @@ namespace NActors { TExecutorPoolBaseMailboxed::~TExecutorPoolBaseMailboxed() { MailboxTable.Destroy(); - } - + } + TExecutorPoolBase::TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType) : TExecutorPoolBaseMailboxed(poolId, maxActivityType) , PoolThreads(threads) , ThreadsAffinity(affinity) {} - TExecutorPoolBase::~TExecutorPoolBase() { - while (Activations.Pop(0)) - ; - } - + TExecutorPoolBase::~TExecutorPoolBase() { + while (Activations.Pop(0)) + ; + } + void TExecutorPoolBaseMailboxed::ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) { Y_UNUSED(workerId); - MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingWriteCounter); - } - + MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingWriteCounter); + } + ui64 TExecutorPoolBaseMailboxed::AllocateID() { - return ActorSystem->AllocateIDSpace(1); - } - + return ActorSystem->AllocateIDSpace(1); + } + bool TExecutorPoolBaseMailboxed::Send(TAutoPtr<IEventHandle>& ev) { - Y_VERIFY_DEBUG(ev->GetRecipientRewrite().PoolID() == PoolId); + Y_VERIFY_DEBUG(ev->GetRecipientRewrite().PoolID() == PoolId); #ifdef ACTORSLIB_COLLECT_EXEC_STATS RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast()); #endif - return MailboxTable->SendTo(ev, this); - } - - void TExecutorPoolBase::ScheduleActivation(ui32 activation) { - ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); - } - + return MailboxTable->SendTo(ev, this); + } + + void TExecutorPoolBase::ScheduleActivation(ui32 activation) { + ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); + } + TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) { NHPTimer::STime hpstart = GetCycleCountFast(); #ifdef ACTORSLIB_COLLECT_EXEC_STATS - ui32 at = actor->GetActivityType(); - if (at >= Stats.MaxActivityType()) - at = 0; - AtomicIncrement(Stats.ActorsAliveByActivity[at]); + ui32 at = actor->GetActivityType(); + if (at >= Stats.MaxActivityType()) + at = 0; + AtomicIncrement(Stats.ActorsAliveByActivity[at]); #endif - AtomicIncrement(ActorRegistrations); + AtomicIncrement(ActorRegistrations); - // first step - find good enough mailbox - ui32 hint = 0; - TMailboxHeader* mailbox = nullptr; + // first step - find good enough mailbox + ui32 hint = 0; + TMailboxHeader* mailbox = nullptr; - if (revolvingWriteCounter == 0) + if (revolvingWriteCounter == 0) revolvingWriteCounter = AtomicIncrement(RegisterRevolvingCounter); - { - ui32 hintBackoff = 0; + { + ui32 hintBackoff = 0; - while (hint == 0) { - hint = MailboxTable->AllocateMailbox(mailboxType, ++revolvingWriteCounter); - mailbox = MailboxTable->Get(hint); + while (hint == 0) { + hint = MailboxTable->AllocateMailbox(mailboxType, ++revolvingWriteCounter); + mailbox = MailboxTable->Get(hint); - if (!mailbox->LockFromFree()) { - MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); - hintBackoff = hint; - hint = 0; - } + if (!mailbox->LockFromFree()) { + MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); + hintBackoff = hint; + hint = 0; + } } - - MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); + + MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); } - const ui64 localActorId = AllocateID(); + const ui64 localActorId = AllocateID(); - // ok, got mailbox - mailbox->AttachActor(localActorId, actor); + // ok, got mailbox + mailbox->AttachActor(localActorId, actor); - // do init + // do init const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint); DoActorInit(ActorSystem, actor, actorId, parentId); - // Once we unlock the mailbox the actor starts running and we cannot use the pointer any more - actor = nullptr; + // Once we unlock the mailbox the actor starts running and we cannot use the pointer any more + actor = nullptr; - switch (mailboxType) { - case TMailboxType::Simple: + switch (mailboxType) { + case TMailboxType::Simple: UnlockFromExecution((TMailboxTable::TSimpleMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::Revolving: + break; + case TMailboxType::Revolving: UnlockFromExecution((TMailboxTable::TRevolvingMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::HTSwap: + break; + case TMailboxType::HTSwap: UnlockFromExecution((TMailboxTable::THTSwapMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::ReadAsFilled: + break; + case TMailboxType::ReadAsFilled: UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::TinyReadAsFilled: + break; + case TMailboxType::TinyReadAsFilled: UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - default: - Y_FAIL(); - } + break; + default: + Y_FAIL(); + } NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; - if (elapsed > 1000000) { - LWPROBE(SlowRegisterNew, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); - } + if (elapsed > 1000000) { + LWPROBE(SlowRegisterNew, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); + } - return actorId; + return actorId; } TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { NHPTimer::STime hpstart = GetCycleCountFast(); #ifdef ACTORSLIB_COLLECT_EXEC_STATS - ui32 at = actor->GetActivityType(); - if (at >= Stats.MaxActivityType()) - at = 0; - AtomicIncrement(Stats.ActorsAliveByActivity[at]); + ui32 at = actor->GetActivityType(); + if (at >= Stats.MaxActivityType()) + at = 0; + AtomicIncrement(Stats.ActorsAliveByActivity[at]); #endif - AtomicIncrement(ActorRegistrations); + AtomicIncrement(ActorRegistrations); - const ui64 localActorId = AllocateID(); - mailbox->AttachActor(localActorId, actor); + const ui64 localActorId = AllocateID(); + mailbox->AttachActor(localActorId, actor); const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint); DoActorInit(ActorSystem, actor, actorId, parentId); NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; - if (elapsed > 1000000) { - LWPROBE(SlowRegisterAdd, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); - } - - return actorId; + if (elapsed > 1000000) { + LWPROBE(SlowRegisterAdd, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); + } + + return actorId; } - TAffinity* TExecutorPoolBase::Affinity() const { - return ThreadsAffinity.Get(); - } + TAffinity* TExecutorPoolBase::Affinity() const { + return ThreadsAffinity.Get(); + } bool TExecutorPoolBaseMailboxed::Cleanup() { - return MailboxTable->Cleanup(); - } + return MailboxTable->Cleanup(); + } ui32 TExecutorPoolBase::GetThreads() const { return PoolThreads; } -} +} diff --git a/library/cpp/actors/core/executor_pool_base.h b/library/cpp/actors/core/executor_pool_base.h index c84ce1af77..1f8c036376 100644 --- a/library/cpp/actors/core/executor_pool_base.h +++ b/library/cpp/actors/core/executor_pool_base.h @@ -1,34 +1,34 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_thread.h" -#include "scheduler_queue.h" +#pragma once + +#include "actorsystem.h" +#include "executor_thread.h" +#include "scheduler_queue.h" #include <library/cpp/actors/util/affinity.h> #include <library/cpp/actors/util/unordered_cache.h> #include <library/cpp/actors/util/threadparkpad.h> - -namespace NActors { + +namespace NActors { class TExecutorPoolBaseMailboxed: public IExecutorPool { - protected: - TActorSystem* ActorSystem; - THolder<TMailboxTable> MailboxTable; + protected: + TActorSystem* ActorSystem; + THolder<TMailboxTable> MailboxTable; #ifdef ACTORSLIB_COLLECT_EXEC_STATS - // Need to have per pool object to collect stats like actor registrations (because - // registrations might be done in threads from other pools) - TExecutorThreadStats Stats; + // Need to have per pool object to collect stats like actor registrations (because + // registrations might be done in threads from other pools) + TExecutorThreadStats Stats; #endif TAtomic RegisterRevolvingCounter = 0; ui64 AllocateID(); - public: + public: TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType); ~TExecutorPoolBaseMailboxed(); void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) override; - bool Send(TAutoPtr<IEventHandle>& ev) override; + bool Send(TAutoPtr<IEventHandle>& ev) override; TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) override; TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) override; - bool Cleanup() override; + bool Cleanup() override; }; - + class TExecutorPoolBase: public TExecutorPoolBaseMailboxed { protected: const ui32 PoolThreads; @@ -41,9 +41,9 @@ namespace NActors { TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType); ~TExecutorPoolBase(); void ScheduleActivation(ui32 activation) override; - TAffinity* Affinity() const override; + TAffinity* Affinity() const override; ui32 GetThreads() const override; - }; + }; void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); -} +} diff --git a/library/cpp/actors/core/executor_pool_basic.cpp b/library/cpp/actors/core/executor_pool_basic.cpp index 4dce16939a..1645ba1910 100644 --- a/library/cpp/actors/core/executor_pool_basic.cpp +++ b/library/cpp/actors/core/executor_pool_basic.cpp @@ -1,43 +1,43 @@ -#include "executor_pool_basic.h" +#include "executor_pool_basic.h" #include "probes.h" -#include "mailbox.h" +#include "mailbox.h" #include <library/cpp/actors/util/affinity.h> #include <library/cpp/actors/util/datetime.h> - + #ifdef _linux_ -#include <pthread.h> +#include <pthread.h> #endif -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - constexpr TDuration TBasicExecutorPool::DEFAULT_TIME_PER_MAILBOX; +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + + constexpr TDuration TBasicExecutorPool::DEFAULT_TIME_PER_MAILBOX; - TBasicExecutorPool::TBasicExecutorPool( + TBasicExecutorPool::TBasicExecutorPool( ui32 poolId, ui32 threads, ui64 spinThreshold, const TString& poolName, - TAffinity* affinity, + TAffinity* affinity, TDuration timePerMailbox, ui32 eventsPerMailbox, int realtimePriority, ui32 maxActivityType) : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) - , SpinThreshold(spinThreshold) - , SpinThresholdCycles(spinThreshold * NHPTimer::GetCyclesPerSecond() * 0.000001) // convert microseconds to cycles - , Threads(new TThreadCtx[threads]) - , PoolName(poolName) - , TimePerMailbox(timePerMailbox) - , EventsPerMailbox(eventsPerMailbox) - , RealtimePriority(realtimePriority) - , ThreadUtilization(0) - , MaxUtilizationCounter(0) - , MaxUtilizationAccumulator(0) + , SpinThreshold(spinThreshold) + , SpinThresholdCycles(spinThreshold * NHPTimer::GetCyclesPerSecond() * 0.000001) // convert microseconds to cycles + , Threads(new TThreadCtx[threads]) + , PoolName(poolName) + , TimePerMailbox(timePerMailbox) + , EventsPerMailbox(eventsPerMailbox) + , RealtimePriority(realtimePriority) + , ThreadUtilization(0) + , MaxUtilizationCounter(0) + , MaxUtilizationAccumulator(0) , ThreadCount(threads) - { - } - + { + } + TBasicExecutorPool::TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg) : TBasicExecutorPool( cfg.PoolId, @@ -52,20 +52,20 @@ namespace NActors { ) {} - TBasicExecutorPool::~TBasicExecutorPool() { - Threads.Destroy(); - } - + TBasicExecutorPool::~TBasicExecutorPool() { + Threads.Destroy(); + } + ui32 TBasicExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { 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 blocked = 0; NHPTimer::STime hpstart = GetCycleCountFast(); - NHPTimer::STime hpnow; - + NHPTimer::STime hpnow; + TThreadCtx& threadCtx = Threads[workerId]; AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_NONE); @@ -82,11 +82,11 @@ namespace NActors { } while (AtomicGet(threadCtx.BlockedFlag) != TThreadCtx::BS_NONE && !AtomicLoad(&StopFlag)); } - const TAtomic x = AtomicDecrement(Semaphore); - - if (x < 0) { -#if defined ACTORSLIB_COLLECT_EXEC_STATS - if (AtomicGetAndIncrement(ThreadUtilization) == 0) { + const TAtomic x = AtomicDecrement(Semaphore); + + 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. @@ -98,67 +98,67 @@ namespace NActors { const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t); if (x < 0 && x + t > 0) AtomicStore(&MaxUtilizationAccumulator, x + t); - } -#endif - + } +#endif + Y_VERIFY(AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_NONE); - - if (SpinThreshold > 0) { - // spin configured period - AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_ACTIVE); + + if (SpinThreshold > 0) { + // spin configured period + AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_ACTIVE); ui64 start = GetCycleCountFast(); - bool doSpin = true; - while (true) { - for (ui32 j = 0; doSpin && j < 12; ++j) { + bool doSpin = true; + while (true) { + for (ui32 j = 0; doSpin && j < 12; ++j) { if (GetCycleCountFast() >= (start + SpinThresholdCycles)) { doSpin = false; break; } - for (ui32 i = 0; i < 12; ++i) { - if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { - SpinLockPause(); - } else { - doSpin = false; - break; - } - } - } - if (!doSpin) { - break; + for (ui32 i = 0; i < 12; ++i) { + if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { + SpinLockPause(); + } else { + doSpin = false; + break; + } + } } + if (!doSpin) { + break; + } if (RelaxedLoad(&StopFlag)) { - break; - } - } - // then - sleep - if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { - if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED, TThreadCtx::WS_ACTIVE)) { - do { + break; + } + } + // then - sleep + if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { + if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED, TThreadCtx::WS_ACTIVE)) { + do { hpnow = GetCycleCountFast(); - elapsed += hpnow - hpstart; - if (threadCtx.Pad.Park()) // interrupted - return 0; + elapsed += hpnow - hpstart; + if (threadCtx.Pad.Park()) // interrupted + return 0; hpstart = GetCycleCountFast(); - parked += hpstart - hpnow; - } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); - } + parked += hpstart - hpnow; + } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); + } } - } else { + } else { AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED); - do { + do { hpnow = GetCycleCountFast(); - elapsed += hpnow - hpstart; - if (threadCtx.Pad.Park()) // interrupted - return 0; + elapsed += hpnow - hpstart; + if (threadCtx.Pad.Park()) // interrupted + return 0; hpstart = GetCycleCountFast(); - parked += hpstart - hpnow; - } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); - } - + parked += hpstart - hpnow; + } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED); + } + Y_VERIFY_DEBUG(AtomicLoad(&StopFlag) || AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_RUNNING); - -#if defined ACTORSLIB_COLLECT_EXEC_STATS - if (AtomicDecrement(ThreadUtilization) == 0) { + +#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 @@ -173,34 +173,34 @@ namespace NActors { const i64 t = GetCycleCountFast(); const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t); if (x > 0 && x - t < 0) - AtomicStore(&MaxUtilizationAccumulator, x); - } -#endif + AtomicStore(&MaxUtilizationAccumulator, x); + } +#endif } else { AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING); - } - - // ok, has work suggested, must dequeue - while (!RelaxedLoad(&StopFlag)) { - if (const ui32 activation = Activations.Pop(++revolvingCounter)) { + } + + // ok, has work suggested, must dequeue + while (!RelaxedLoad(&StopFlag)) { + 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); - } + } if (blocked > 0) { wctx.AddBlockedCycles(blocked); } - return activation; + return activation; } - SpinLockPause(); + SpinLockPause(); } - - // stopping, die! - return 0; - } - + + // stopping, die! + return 0; + } + inline void TBasicExecutorPool::WakeUpLoop() { for (ui32 i = 0;;) { TThreadCtx& threadCtx = Threads[i % PoolThreads]; @@ -226,83 +226,83 @@ namespace NActors { } } - void TBasicExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { - Activations.Push(activation, revolvingCounter); - const TAtomic x = AtomicIncrement(Semaphore); - if (x <= 0) { // we must find someone to wake-up + void TBasicExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { + Activations.Push(activation, revolvingCounter); + const TAtomic x = AtomicIncrement(Semaphore); + if (x <= 0) { // we must find someone to wake-up WakeUpLoop(); - } - } - + } + } + void TBasicExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - poolStats.MaxUtilizationTime = RelaxedLoad(&MaxUtilizationAccumulator) / (i64)(NHPTimer::GetCyclesPerSecond() / 1000); - - statsCopy.resize(PoolThreads + 1); - // Save counters from the pool object - statsCopy[0] = TExecutorThreadStats(); - statsCopy[0].Aggregate(Stats); - // Per-thread stats - for (size_t i = 0; i < PoolThreads; ++i) { - Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]); - } + poolStats.MaxUtilizationTime = RelaxedLoad(&MaxUtilizationAccumulator) / (i64)(NHPTimer::GetCyclesPerSecond() / 1000); + + statsCopy.resize(PoolThreads + 1); + // Save counters from the pool object + statsCopy[0] = TExecutorThreadStats(); + statsCopy[0].Aggregate(Stats); + // Per-thread stats + for (size_t i = 0; i < PoolThreads; ++i) { + Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]); + } } void TBasicExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - TAffinityGuard affinityGuard(Affinity()); - - ActorSystem = actorSystem; - - ScheduleReaders.Reset(new NSchedulerQueue::TReader[PoolThreads]); - ScheduleWriters.Reset(new NSchedulerQueue::TWriter[PoolThreads]); - - for (ui32 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread.Reset( - new TExecutorThread( - i, + TAffinityGuard affinityGuard(Affinity()); + + ActorSystem = actorSystem; + + ScheduleReaders.Reset(new NSchedulerQueue::TReader[PoolThreads]); + ScheduleWriters.Reset(new NSchedulerQueue::TWriter[PoolThreads]); + + for (ui32 i = 0; i != PoolThreads; ++i) { + Threads[i].Thread.Reset( + new TExecutorThread( + i, 0, // CpuId is not used in BASIC pool - actorSystem, - this, - MailboxTable.Get(), - PoolName, - TimePerMailbox, - EventsPerMailbox)); - ScheduleWriters[i].Init(ScheduleReaders[i]); - } - - *scheduleReaders = ScheduleReaders.Get(); - *scheduleSz = PoolThreads; - } - - void TBasicExecutorPool::Start() { - TAffinityGuard affinityGuard(Affinity()); - - ThreadUtilization = 0; + actorSystem, + this, + MailboxTable.Get(), + PoolName, + TimePerMailbox, + EventsPerMailbox)); + ScheduleWriters[i].Init(ScheduleReaders[i]); + } + + *scheduleReaders = ScheduleReaders.Get(); + *scheduleSz = PoolThreads; + } + + void TBasicExecutorPool::Start() { + TAffinityGuard affinityGuard(Affinity()); + + ThreadUtilization = 0; AtomicAdd(MaxUtilizationCounter, -(i64)GetCycleCountFast()); - - for (ui32 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread->Start(); - } - } - - void TBasicExecutorPool::PrepareStop() { - AtomicStore(&StopFlag, true); + + for (ui32 i = 0; i != PoolThreads; ++i) { + Threads[i].Thread->Start(); + } + } + + void TBasicExecutorPool::PrepareStop() { + AtomicStore(&StopFlag, true); for (ui32 i = 0; i != PoolThreads; ++i) { - Threads[i].Pad.Interrupt(); + Threads[i].Pad.Interrupt(); Threads[i].BlockedPad.Interrupt(); } - } - - void TBasicExecutorPool::Shutdown() { - for (ui32 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Join(); - } - + } + + void TBasicExecutorPool::Shutdown() { + for (ui32 i = 0; i != PoolThreads; ++i) + Threads[i].Thread->Join(); + } + void TBasicExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { Y_VERIFY_DEBUG(workerId < PoolThreads); - + Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - + } + void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { Y_VERIFY_DEBUG(workerId < PoolThreads); @@ -320,21 +320,21 @@ namespace NActors { ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); } - void TBasicExecutorPool::SetRealTimeMode() const { -// TODO: musl-libc version of `sched_param` struct is for some reason different from pthread -// version in Ubuntu 12.04 + void TBasicExecutorPool::SetRealTimeMode() const { +// TODO: musl-libc version of `sched_param` struct is for some reason different from pthread +// version in Ubuntu 12.04 #if defined(_linux_) && !defined(_musl_) - if (RealtimePriority != 0) { - pthread_t threadSelf = pthread_self(); - sched_param param = {RealtimePriority}; - if (pthread_setschedparam(threadSelf, SCHED_FIFO, ¶m)) { - Y_FAIL("Cannot set realtime priority"); - } + if (RealtimePriority != 0) { + pthread_t threadSelf = pthread_self(); + sched_param param = {RealtimePriority}; + if (pthread_setschedparam(threadSelf, SCHED_FIFO, ¶m)) { + Y_FAIL("Cannot set realtime priority"); + } } #else - Y_UNUSED(RealtimePriority); + Y_UNUSED(RealtimePriority); #endif - } + } ui32 TBasicExecutorPool::GetThreadCount() const { return AtomicGet(ThreadCount); @@ -428,4 +428,4 @@ namespace NActors { } } } -} +} diff --git a/library/cpp/actors/core/executor_pool_basic.h b/library/cpp/actors/core/executor_pool_basic.h index 023190f7fe..755f679957 100644 --- a/library/cpp/actors/core/executor_pool_basic.h +++ b/library/cpp/actors/core/executor_pool_basic.h @@ -1,37 +1,37 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_thread.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" +#pragma once + +#include "actorsystem.h" +#include "executor_thread.h" +#include "scheduler_queue.h" +#include "executor_pool_base.h" #include <library/cpp/actors/util/unordered_cache.h> #include <library/cpp/actors/util/threadparkpad.h> #include <library/cpp/monlib/dynamic_counters/counters.h> - + #include <util/system/mutex.h> -namespace NActors { - class TBasicExecutorPool: public TExecutorPoolBase { - struct TThreadCtx { - TAutoPtr<TExecutorThread> Thread; - TThreadParkPad Pad; +namespace NActors { + class TBasicExecutorPool: public TExecutorPoolBase { + struct TThreadCtx { + TAutoPtr<TExecutorThread> Thread; + TThreadParkPad Pad; TThreadParkPad BlockedPad; - TAtomic WaitingFlag; + TAtomic WaitingFlag; TAtomic BlockedFlag; - - // different threads must spin/block on different cache-lines. - // we add some padding bytes to enforce this rule + + // different threads must spin/block on different cache-lines. + // we add some padding bytes to enforce this rule static const size_t SizeWithoutPadding = sizeof(TAutoPtr<TExecutorThread>) + 2 * sizeof(TThreadParkPad) + 2 * sizeof(TAtomic); ui8 Padding[64 - SizeWithoutPadding]; static_assert(64 >= SizeWithoutPadding); - - enum EWaitState { - WS_NONE, - WS_ACTIVE, + + enum EWaitState { + WS_NONE, + WS_ACTIVE, WS_BLOCKED, WS_RUNNING - }; - + }; + enum EBlockedState { BS_NONE, BS_BLOCKING, @@ -42,70 +42,70 @@ namespace NActors { : WaitingFlag(WS_NONE) , BlockedFlag(BS_NONE) { - } - }; - - const ui64 SpinThreshold; - const ui64 SpinThresholdCycles; - - TArrayHolder<TThreadCtx> Threads; - - TArrayHolder<NSchedulerQueue::TReader> ScheduleReaders; - TArrayHolder<NSchedulerQueue::TWriter> ScheduleWriters; - - const TString PoolName; - const TDuration TimePerMailbox; - const ui32 EventsPerMailbox; - - const int RealtimePriority; - - TAtomic ThreadUtilization; - TAtomic MaxUtilizationCounter; - TAtomic MaxUtilizationAccumulator; + } + }; + + const ui64 SpinThreshold; + const ui64 SpinThresholdCycles; + + TArrayHolder<TThreadCtx> Threads; + + TArrayHolder<NSchedulerQueue::TReader> ScheduleReaders; + TArrayHolder<NSchedulerQueue::TWriter> ScheduleWriters; + + const TString PoolName; + const TDuration TimePerMailbox; + const ui32 EventsPerMailbox; + + const int RealtimePriority; + + TAtomic ThreadUtilization; + TAtomic MaxUtilizationCounter; + TAtomic MaxUtilizationAccumulator; TAtomic ThreadCount; TMutex ChangeThreadsLock; - public: + public: static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_TIME_PER_MAILBOX; static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX; - - TBasicExecutorPool(ui32 poolId, - ui32 threads, - ui64 spinThreshold, - const TString& poolName = "", - TAffinity* affinity = nullptr, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX, + + TBasicExecutorPool(ui32 poolId, + ui32 threads, + ui64 spinThreshold, + const TString& poolName = "", + TAffinity* affinity = nullptr, + TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, + ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX, int realtimePriority = 0, ui32 maxActivityType = 1); explicit TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg); - ~TBasicExecutorPool(); + ~TBasicExecutorPool(); ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; - + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - + void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; + void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; - + void Start() override; + void PrepareStop() override; + void Shutdown() override; + void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - TString GetName() const override { - return PoolName; - } - - void SetRealTimeMode() const override; + TString GetName() const override { + return PoolName; + } + + void SetRealTimeMode() const override; ui32 GetThreadCount() const; void SetThreadCount(ui32 threads); private: void WakeUpLoop(); - }; -} + }; +} diff --git a/library/cpp/actors/core/executor_pool_basic_ut.cpp b/library/cpp/actors/core/executor_pool_basic_ut.cpp index 76dff693af..42669685be 100644 --- a/library/cpp/actors/core/executor_pool_basic_ut.cpp +++ b/library/cpp/actors/core/executor_pool_basic_ut.cpp @@ -116,8 +116,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { for (size_t testIdx = 0; testIdx < testCount; ++testIdx) { for (size_t i = 0; i < size; ++i) { actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < size; ++i) { + } + for (size_t i = 0; i < size; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } @@ -143,8 +143,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { for (size_t testIdx = 0; testIdx < testCount; ++testIdx) { for (size_t i = 0; i < size; ++i) { actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < size; ++i) { + } + for (size_t i = 0; i < size; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } @@ -184,8 +184,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { for (size_t i = 0; i < size; ++i) { actors[i]->Start(actorIds[i], msgCount); - } - for (size_t i = 0; i < size; ++i) { + } + for (size_t i = 0; i < size; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } @@ -268,8 +268,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { } for (size_t i = 0; i < size; ++i) { actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < size; ++i) { + } + for (size_t i = 0; i < size; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } @@ -312,8 +312,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { } for (size_t i = 0; i < actorsCount; ++i) { actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < actorsCount; ++i) { + } + for (size_t i = 0; i < actorsCount; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } @@ -356,8 +356,8 @@ Y_UNIT_TEST_SUITE(BasicExecutorPool) { } for (size_t i = 0; i < actorsCount; ++i) { actors[i]->Start(actorIds[(i + 1) % actorsCount], msgCount); - } - for (size_t i = 0; i < actorsCount; ++i) { + } + for (size_t i = 0; i < actorsCount; ++i) { actorSystem.Send(actorIds[i], new TEvMsg()); } diff --git a/library/cpp/actors/core/executor_pool_io.cpp b/library/cpp/actors/core/executor_pool_io.cpp index fb557ae6b0..aea38e39e7 100644 --- a/library/cpp/actors/core/executor_pool_io.cpp +++ b/library/cpp/actors/core/executor_pool_io.cpp @@ -1,15 +1,15 @@ -#include "executor_pool_io.h" -#include "mailbox.h" +#include "executor_pool_io.h" +#include "mailbox.h" #include <library/cpp/actors/util/affinity.h> #include <library/cpp/actors/util/datetime.h> - -namespace NActors { + +namespace NActors { TIOExecutorPool::TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName, TAffinity* affinity, ui32 maxActivityType) : TExecutorPoolBase(poolId, threads, affinity, maxActivityType) - , Threads(new TThreadCtx[threads]) - , PoolName(poolName) + , Threads(new TThreadCtx[threads]) + , PoolName(poolName) {} - + TIOExecutorPool::TIOExecutorPool(const TIOExecutorPoolConfig& cfg) : TIOExecutorPool( cfg.PoolId, @@ -20,34 +20,34 @@ namespace NActors { ) {} - TIOExecutorPool::~TIOExecutorPool() { - Threads.Destroy(); - while (ThreadQueue.Pop(0)) - ; - } - + TIOExecutorPool::~TIOExecutorPool() { + Threads.Destroy(); + while (ThreadQueue.Pop(0)) + ; + } + ui32 TIOExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { ui32 workerId = wctx.WorkerId; Y_VERIFY_DEBUG(workerId < PoolThreads); - + NHPTimer::STime elapsed = 0; NHPTimer::STime parked = 0; NHPTimer::STime hpstart = GetCycleCountFast(); NHPTimer::STime hpnow; - const TAtomic x = AtomicDecrement(Semaphore); - if (x < 0) { + const TAtomic x = AtomicDecrement(Semaphore); + if (x < 0) { TThreadCtx& threadCtx = Threads[workerId]; ThreadQueue.Push(workerId + 1, revolvingCounter); hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; - if (threadCtx.Pad.Park()) - return 0; + if (threadCtx.Pad.Park()) + return 0; hpstart = GetCycleCountFast(); parked += hpstart - hpnow; - } - - while (!RelaxedLoad(&StopFlag)) { + } + + while (!RelaxedLoad(&StopFlag)) { if (const ui32 activation = Activations.Pop(++revolvingCounter)) { hpnow = GetCycleCountFast(); elapsed += hpnow - hpstart; @@ -55,18 +55,18 @@ namespace NActors { if (parked > 0) { wctx.AddParkedCycles(parked); } - return activation; + return activation; } - SpinLockPause(); - } - - return 0; - } - + SpinLockPause(); + } + + return 0; + } + void TIOExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - + } + void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { Y_UNUSED(workerId); @@ -86,53 +86,53 @@ namespace NActors { ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); } - void TIOExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) { - Activations.Push(activation, revolvingWriteCounter); - const TAtomic x = AtomicIncrement(Semaphore); - if (x <= 0) { - for (;; ++revolvingWriteCounter) { - if (const ui32 x = ThreadQueue.Pop(revolvingWriteCounter)) { - const ui32 threadIdx = x - 1; - Threads[threadIdx].Pad.Unpark(); - return; - } - SpinLockPause(); - } - } - } - + void TIOExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) { + Activations.Push(activation, revolvingWriteCounter); + const TAtomic x = AtomicIncrement(Semaphore); + if (x <= 0) { + for (;; ++revolvingWriteCounter) { + if (const ui32 x = ThreadQueue.Pop(revolvingWriteCounter)) { + const ui32 threadIdx = x - 1; + Threads[threadIdx].Pad.Unpark(); + return; + } + SpinLockPause(); + } + } + } + void TIOExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - TAffinityGuard affinityGuard(Affinity()); - - ActorSystem = actorSystem; - + TAffinityGuard affinityGuard(Affinity()); + + ActorSystem = actorSystem; + ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); - - for (ui32 i = 0; i != PoolThreads; ++i) { + + for (ui32 i = 0; i != PoolThreads; ++i) { Threads[i].Thread.Reset(new TExecutorThread(i, 0, actorSystem, this, MailboxTable.Get(), PoolName)); - } - - *scheduleReaders = &ScheduleQueue->Reader; - *scheduleSz = 1; - } - - void TIOExecutorPool::Start() { - TAffinityGuard affinityGuard(Affinity()); - - for (ui32 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Start(); - } - - void TIOExecutorPool::PrepareStop() { - AtomicStore(&StopFlag, true); - for (ui32 i = 0; i != PoolThreads; ++i) - Threads[i].Pad.Interrupt(); - } - - void TIOExecutorPool::Shutdown() { - for (ui32 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Join(); - } + } + + *scheduleReaders = &ScheduleQueue->Reader; + *scheduleSz = 1; + } + + void TIOExecutorPool::Start() { + TAffinityGuard affinityGuard(Affinity()); + + for (ui32 i = 0; i != PoolThreads; ++i) + Threads[i].Thread->Start(); + } + + void TIOExecutorPool::PrepareStop() { + AtomicStore(&StopFlag, true); + for (ui32 i = 0; i != PoolThreads; ++i) + Threads[i].Pad.Interrupt(); + } + + void TIOExecutorPool::Shutdown() { + for (ui32 i = 0; i != PoolThreads; ++i) + Threads[i].Thread->Join(); + } void TIOExecutorPool::GetCurrentStats(TExecutorPoolStats& /*poolStats*/, TVector<TExecutorThreadStats>& statsCopy) const { statsCopy.resize(PoolThreads + 1); @@ -148,4 +148,4 @@ namespace NActors { TString TIOExecutorPool::GetName() const { return PoolName; } -} +} diff --git a/library/cpp/actors/core/executor_pool_io.h b/library/cpp/actors/core/executor_pool_io.h index e576d642a1..3917a1b9ad 100644 --- a/library/cpp/actors/core/executor_pool_io.h +++ b/library/cpp/actors/core/executor_pool_io.h @@ -1,49 +1,49 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_thread.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" +#pragma once + +#include "actorsystem.h" +#include "executor_thread.h" +#include "scheduler_queue.h" +#include "executor_pool_base.h" #include <library/cpp/actors/util/ticket_lock.h> #include <library/cpp/actors/util/unordered_cache.h> #include <library/cpp/actors/util/threadparkpad.h> -#include <util/system/condvar.h> - -namespace NActors { - class TIOExecutorPool: public TExecutorPoolBase { - struct TThreadCtx { - TAutoPtr<TExecutorThread> Thread; - TThreadParkPad Pad; - }; - - TArrayHolder<TThreadCtx> Threads; +#include <util/system/condvar.h> + +namespace NActors { + class TIOExecutorPool: public TExecutorPoolBase { + struct TThreadCtx { + TAutoPtr<TExecutorThread> Thread; + TThreadParkPad Pad; + }; + + TArrayHolder<TThreadCtx> Threads; TUnorderedCache<ui32, 512, 4> ThreadQueue; - + THolder<NSchedulerQueue::TQueueType> ScheduleQueue; - TTicketLock ScheduleLock; + TTicketLock ScheduleLock; + + const TString PoolName; - const TString PoolName; - - public: + public: TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName = "", TAffinity* affinity = nullptr, ui32 maxActivityType = 1); explicit TIOExecutorPool(const TIOExecutorPoolConfig& cfg); - ~TIOExecutorPool(); + ~TIOExecutorPool(); ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override; - + void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - + void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; + void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; + void Start() override; + void PrepareStop() override; + void Shutdown() override; void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; TString GetName() const override; - }; -} + }; +} diff --git a/library/cpp/actors/core/executor_pool_united.cpp b/library/cpp/actors/core/executor_pool_united.cpp index dac6245635..99c9ca32f7 100644 --- a/library/cpp/actors/core/executor_pool_united.cpp +++ b/library/cpp/actors/core/executor_pool_united.cpp @@ -4,32 +4,32 @@ #include "cpu_state.h" #include "executor_thread.h" #include "probes.h" -#include "mailbox.h" +#include "mailbox.h" #include "scheduler_queue.h" #include <library/cpp/actors/util/affinity.h> #include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/util/futex.h> #include <library/cpp/actors/util/intrinsics.h> #include <library/cpp/actors/util/timerfd.h> - + #include <util/system/datetime.h> #include <util/system/hp_timer.h> #include <algorithm> -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - +namespace NActors { + LWTRACE_USING(ACTORLIB_PROVIDER); + struct TUnitedWorkers::TWorker: public TNonCopyable { TAutoPtr<TExecutorThread> Thread; volatile TThreadId ThreadId = UnknownThreadId; NSchedulerQueue::TQueueType SchedulerQueue; }; - + struct TUnitedWorkers::TPool: public TNonCopyable { TAtomic Waiters = 0; // Number of idle cpus, waiting for activations in this pool char Padding[64 - sizeof(TAtomic)]; - + TUnorderedCache<ui32, 512, 4> Activations; // MPMC-queue for mailbox activations TAtomic Active = 0; // Number of mailboxes ready for execution or currently executing TAtomic Tokens = 0; // Pending tokens (token is required for worker to start execution, guarantees concurrency limit and activation availability) @@ -93,7 +93,7 @@ namespace NActors { bool TryAcquireToken() { return TryAcquireTokenImpl<false>(&Tokens); } - + // Try acquire pending token. Must be done before execution bool TryAcquireTokenRelaxed() { return TryAcquireTokenImpl<true>(&Tokens); @@ -106,10 +106,10 @@ namespace NActors { return; } SpinLockPause(); - } + } activation = 0; // should stop } - + // End currently active execution and start new one if token is available. // Reuses token if it's not destroyed. // Returned `true` means successful switch, `activation` is filled. @@ -124,7 +124,7 @@ namespace NActors { } return false; // no more tokens available } - + // Stop active execution. Returns released token (unless it is destroyed) bool StopExecution() { TAtomicBase active = AtomicDecrement(Active); @@ -534,13 +534,13 @@ namespace NActors { case Standby: if (!idleTimer) { idleTimer = IdleQueue.Enqueue(); - } + } SetPriority(0, IdlePriority); idleTimer->Wait(); - break; + break; case Stopped: return false; default: Y_FAIL(); - } + } } else { // lease has expired and hard preemption occured, so we are executing in a slow-worker wctx.IncrementPreemptedEvents(); switch (SlowWorkerAction(wctx.PoolId)) { @@ -551,11 +551,11 @@ namespace NActors { wctx.Lease = wctx.Lease.NeverExpire(); wctx.PoolId = MaxPools; idleTimer = nullptr; - break; + break; case Stopped: return false; default: Y_FAIL(); - } - } + } + } } } @@ -576,7 +576,7 @@ namespace NActors { if (AtomicCas(&SlowPoolsMask, slow | WaitPoolsFlag, slow)) { // try set wait flag return RunSlowPool; // wait flag has been successfully set } - } + } } else { // we are about to execute fast pool, token required if (slow & WaitPoolsFlag) { // reset wait flag if required if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag @@ -649,12 +649,12 @@ namespace NActors { // Lease has been changed just now, no way we need preemption right now, so no retry needed return Standby; } - } else { + } else { // Lease has not expired yet (maybe never expiring lease) return Standby; - } + } } - + EWorkerAction SlowWorkerAction(TPoolId pool) { if (Y_UNLIKELY(United->IsStopped())) { return Stopped; @@ -681,7 +681,7 @@ namespace NActors { } } } - + void SetPoolIsSlowFlag(TPoolId pool) { while (true) { TPoolsMask slow = AtomicLoad(&SlowPoolsMask); @@ -693,9 +693,9 @@ namespace NActors { Y_FAIL("two slow-workers executing the same pool on the same core"); return; // pool is already slow } - } - } - + } + } + bool TryBeginHardPreemption(TLease lease) { return AtomicCas(&CurrentLease, HardPreemptionLease, lease); } @@ -723,7 +723,7 @@ namespace NActors { TPoolsMask slow = AtomicLoad(&SlowPoolsMask); if ((slow & WaitPoolsFlag) == 0) { return; // woken by WakeFast action - } + } ui64 ts = GetCycleCountFast(); if (deadlineTs <= ts) { if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag @@ -742,13 +742,13 @@ namespace NActors { } } } - + void WakeFastWorker() { #ifdef _linux_ SysFutex(FastWorkerFutex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); #endif } - + #ifdef _linux_ ui32* FastWorkerFutex() { // Actually we wait on one highest bit, but futex value size is 4 bytes on all platforms @@ -1023,12 +1023,12 @@ namespace NActors { } else { return false; } - } - + } + bool BlockedWait(TPoolId& result, ui64 timeoutNs) { return State.Block(timeoutNs, result); } - + void SwitchPool(TPoolId pool) { return State.SwitchPool(pool); } @@ -1051,9 +1051,9 @@ namespace NActors { case TCpuState::Stopped: return CpuStopped; } - } + } }; - + TUnitedWorkers::TUnitedWorkers( const TUnitedWorkersConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, @@ -1071,14 +1071,14 @@ namespace NActors { } } Pools.Reset(new TPool[PoolCount]); - + // Find max cpu id and initialize cpus CpuCount = 0; for (const TCpuAllocation& cpuAlloc : allocation.Items) { CpuCount = Max<size_t>(CpuCount, cpuAlloc.CpuId + 1); } Cpus.Reset(new TCpu[CpuCount]); - + // Setup allocated cpus // NOTE: leave gaps for not allocated cpus (default-initialized) WorkerCount = 0; @@ -1143,18 +1143,18 @@ namespace NActors { } } } - } - + } + TUnitedWorkers::~TUnitedWorkers() { } - + void TUnitedWorkers::Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders) { // Setup allocated cpus // NOTE: leave gaps for not allocated cpus (default-initialized) TWorkerId workers = 0; for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { TCpu& cpu = Cpus[cpuId]; - + // Setup cpu-local workers if (cpu.LocalManager) { for (size_t i = 0; i < cpu.LocalManager->WorkerCount(); i++) { @@ -1175,9 +1175,9 @@ namespace NActors { scheduleReaders.push_back(&Workers[workerId].SchedulerQueue.Reader); } } - } - } - + } + } + void TUnitedWorkers::Start() { for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { Workers[workerId].Thread->Start(); @@ -1207,31 +1207,31 @@ namespace NActors { } void TUnitedWorkers::PrepareStop() { - AtomicStore(&StopFlag, true); + AtomicStore(&StopFlag, true); for (TPoolId pool = 0; pool < PoolCount; pool++) { Pools[pool].Stop(); } for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { Cpus[cpuId].Stop(); } - } - + } + void TUnitedWorkers::Shutdown() { for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { Workers[workerId].Thread->Join(); } - } - + } + inline void TUnitedWorkers::PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter) { if (Pools[pool].PushActivation(activation, revolvingCounter)) { // token generated TryWake(pool); } } - + inline bool TUnitedWorkers::TryAcquireToken(TPoolId pool) { return Pools[pool].TryAcquireToken(); - } - + } + inline void TUnitedWorkers::TryWake(TPoolId pool) { // Avoid using multiple atomic seq_cst loads in cycle, use barrier once AtomicBarrier(); @@ -1310,7 +1310,7 @@ namespace NActors { while (true) { if (cpu.StartSpinning(this, assignedPool, result)) { break; // token already acquired (or stop) - } + } result = WaitSequence(cpu, wctx, timeTracker); if (Y_UNLIKELY(result == CpuStopped) || TryAcquireToken(result)) { break; // token acquired (or stop) @@ -1319,7 +1319,7 @@ namespace NActors { wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed()); return result; - } + } TPoolId TUnitedWorkers::WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker) { TPoolId result; @@ -1425,4 +1425,4 @@ namespace NActors { statsCopy[0].Aggregate(Stats); United->GetCurrentStats(PoolId, statsCopy); } -} +} diff --git a/library/cpp/actors/core/executor_pool_united.h b/library/cpp/actors/core/executor_pool_united.h index a090ba2466..3afd9efa2b 100644 --- a/library/cpp/actors/core/executor_pool_united.h +++ b/library/cpp/actors/core/executor_pool_united.h @@ -1,9 +1,9 @@ -#pragma once - -#include "actorsystem.h" +#pragma once + +#include "actorsystem.h" #include "balancer.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" +#include "scheduler_queue.h" +#include "executor_pool_base.h" #include <library/cpp/actors/util/unordered_cache.h> @@ -13,28 +13,28 @@ #include <util/generic/noncopyable.h> -namespace NActors { +namespace NActors { class TMailboxTable; - + class TUnitedWorkers: public TNonCopyable { struct TWorker; struct TPool; struct TCpu; - + size_t WorkerCount; TArrayHolder<TWorker> Workers; // indexed by WorkerId size_t PoolCount; TArrayHolder<TPool> Pools; // indexed by PoolId, so may include not used (not united) pools size_t CpuCount; TArrayHolder<TCpu> Cpus; // indexed by CpuId, so may include not allocated CPUs - + IBalancer* Balancer; // external pool cpu balancer TUnitedWorkersConfig Config; TCpuAllocationConfig Allocation; volatile bool StopFlag = false; - + public: TUnitedWorkers( const TUnitedWorkersConfig& config, @@ -46,18 +46,18 @@ namespace NActors { void Start(); void PrepareStop(); void Shutdown(); - + bool IsStopped() const { return RelaxedLoad(&StopFlag); } - + TWorkerId GetWorkerCount() const { return WorkerCount; } - + // Returns thread id of a worker TThreadId GetWorkerThreadId(TWorkerId workerId) const; - + // Returns per worker schedule writers NSchedulerQueue::TWriter* GetScheduleWriter(TWorkerId workerId) const; @@ -69,20 +69,20 @@ namespace NActors { // Try acquire pending token. Must be done before execution bool TryAcquireToken(TPoolId pool); - + // Try to wake idle cpu waiting for tokens on specified pool void TryWake(TPoolId pool); // Get activation from pool; requires pool's token void BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); - + // Stop currently active execution and start new one if token is available // NOTE: Reuses token if it's not destroyed bool NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); // Stop active execution void StopExecution(TPoolId pool); - + // Runs balancer to assign pools to cpus void Balance(); @@ -113,10 +113,10 @@ namespace NActors { TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united); void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; - + void Start() override; + void PrepareStop() override; + void Shutdown() override; + TAffinity* Affinity() const override; ui32 GetThreads() const override; ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; @@ -128,8 +128,8 @@ namespace NActors { void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - TString GetName() const override { - return PoolName; - } - }; -} + TString GetName() const override { + return PoolName; + } + }; +} diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp index 446b651efd..2af7b0debb 100644 --- a/library/cpp/actors/core/executor_thread.cpp +++ b/library/cpp/actors/core/executor_thread.cpp @@ -1,9 +1,9 @@ -#include "executor_thread.h" -#include "actorsystem.h" +#include "executor_thread.h" +#include "actorsystem.h" #include "callstack.h" -#include "mailbox.h" -#include "event.h" -#include "events.h" +#include "mailbox.h" +#include "event.h" +#include "events.h" #include <library/cpp/actors/prof/tag.h> #include <library/cpp/actors/util/affinity.h> @@ -13,7 +13,7 @@ #ifdef BALLOC #include <library/cpp/balloc/optional/operators.h> #endif - + #ifdef _linux_ #include <sys/syscall.h> #include <unistd.h> @@ -24,10 +24,10 @@ LWTRACE_USING(ACTORLIB_PROVIDER) -namespace NActors { - constexpr TDuration TExecutorThread::DEFAULT_TIME_PER_MAILBOX; - - TExecutorThread::TExecutorThread( +namespace NActors { + constexpr TDuration TExecutorThread::DEFAULT_TIME_PER_MAILBOX; + + TExecutorThread::TExecutorThread( TWorkerId workerId, TWorkerId cpuId, TActorSystem* actorSystem, @@ -37,9 +37,9 @@ namespace NActors { TDuration timePerMailbox, ui32 eventsPerMailbox) : ActorSystem(actorSystem) - , ExecutorPool(executorPool) + , ExecutorPool(executorPool) , Ctx(workerId, cpuId, actorSystem ? actorSystem->GetMaxActivityType() : 1) - , ThreadName(threadName) + , ThreadName(threadName) { Ctx.Switch( ExecutorPool, @@ -49,24 +49,24 @@ namespace NActors { ui64(-1), // infinite soft deadline &Ctx.WorkerStats); } - + TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId, const TActorId& parentId) { - if (poolId == Max<ui32>()) + if (poolId == Max<ui32>()) return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); - else - return ActorSystem->Register(actor, mailboxType, poolId, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); - } - + else + return ActorSystem->Register(actor, mailboxType, poolId, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient); + } + TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { return Ctx.Executor->Register(actor, mailbox, hint, parentId ? parentId : CurrentRecipient); - } - - void TExecutorThread::UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId) { - IActor* actor = mailbox->DetachActor(localActorId); + } + + void TExecutorThread::UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId) { + IActor* actor = mailbox->DetachActor(localActorId); Ctx.DecrementActorsAliveByActivity(actor->GetActivityType()); DyingActors.push_back(THolder(actor)); - } - + } + void TExecutorThread::DropUnregistered() { DyingActors.clear(); // here is actual destruction of actors } @@ -74,8 +74,8 @@ namespace NActors { void TExecutorThread::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { ++CurrentActorScheduledEventsCounter; Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); - } - + } + void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { ++CurrentActorScheduledEventsCounter; Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); @@ -86,89 +86,89 @@ namespace NActors { Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId); } - template <class T> - inline TString SafeTypeName(T* t) { - if (t == nullptr) { - return "nullptr"; - } - try { + template <class T> + inline TString SafeTypeName(T* t) { + if (t == nullptr) { + return "nullptr"; + } + try { return TypeName(*t); - } catch (...) { - return "unknown-type"; - } + } catch (...) { + return "unknown-type"; + } } - + inline TString ActorTypeName(const IActor* actor, ui32 activityType) { return actor ? SafeTypeName(actor) : ("activityType_" + ToString(activityType) + " (destroyed)"); } inline void LwTraceSlowDelivery(IEventHandle* ev, const IActor* actor, ui32 poolId, const TActorId& currentRecipient, - double delivMs, double sinceActivationMs, ui32 eventsExecutedBefore) { - const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr; - LWPROBE(EventSlowDelivery, - poolId, - delivMs, - sinceActivationMs, - eventsExecutedBefore, - baseEv ? SafeTypeName(baseEv) : (ev ? ToString(ev->Type) : TString("nullptr")), - currentRecipient.ToString(), - SafeTypeName(actor)); + double delivMs, double sinceActivationMs, ui32 eventsExecutedBefore) { + const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr; + LWPROBE(EventSlowDelivery, + poolId, + delivMs, + sinceActivationMs, + eventsExecutedBefore, + baseEv ? SafeTypeName(baseEv) : (ev ? ToString(ev->Type) : TString("nullptr")), + currentRecipient.ToString(), + SafeTypeName(actor)); } - inline void LwTraceSlowEvent(IEventHandle* ev, ui32 evTypeForTracing, const IActor* actor, ui32 poolId, ui32 activityType, + inline void LwTraceSlowEvent(IEventHandle* ev, ui32 evTypeForTracing, const IActor* actor, ui32 poolId, ui32 activityType, const TActorId& currentRecipient, double eventMs) { - // Event could have been destroyed by actor->Receive(); - const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr; - LWPROBE(SlowEvent, - poolId, - eventMs, - baseEv ? SafeTypeName(baseEv) : ToString(evTypeForTracing), - currentRecipient.ToString(), + // Event could have been destroyed by actor->Receive(); + const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr; + LWPROBE(SlowEvent, + poolId, + eventMs, + baseEv ? SafeTypeName(baseEv) : ToString(evTypeForTracing), + currentRecipient.ToString(), ActorTypeName(actor, activityType)); - } + } - template <typename TMailbox> - void TExecutorThread::Execute(TMailbox* mailbox, ui32 hint) { - Y_VERIFY_DEBUG(DyingActors.empty()); - - bool reclaimAsFree = false; + template <typename TMailbox> + void TExecutorThread::Execute(TMailbox* mailbox, ui32 hint) { + Y_VERIFY_DEBUG(DyingActors.empty()); + bool reclaimAsFree = false; + NHPTimer::STime hpstart = GetCycleCountFast(); - NHPTimer::STime hpprev = hpstart; - + NHPTimer::STime hpprev = hpstart; + IActor* actor = nullptr; ui32 prevActivityType = std::numeric_limits<ui32>::max(); TActorId recipient; for (ui32 executed = 0; executed < Ctx.EventsPerMailbox; ++executed) { - TAutoPtr<IEventHandle> ev(mailbox->Pop()); - if (!!ev) { - NHPTimer::STime hpnow; + TAutoPtr<IEventHandle> ev(mailbox->Pop()); + if (!!ev) { + NHPTimer::STime hpnow; recipient = ev->GetRecipientRewrite(); if (actor = mailbox->FindActor(recipient.LocalId())) { TActorContext ctx(*mailbox, *this, hpprev, recipient); - TlsActivationContext = &ctx; - + TlsActivationContext = &ctx; + #ifdef USE_ACTOR_CALLSTACK - TCallstack::GetTlsCallstack() = ev->Callstack; - TCallstack::GetTlsCallstack().SetLinesToSkip(); + TCallstack::GetTlsCallstack() = ev->Callstack; + TCallstack::GetTlsCallstack().SetLinesToSkip(); #endif - CurrentRecipient = recipient; + CurrentRecipient = recipient; CurrentActorScheduledEventsCounter = 0; - - if (executed == 0) { + + if (executed == 0) { double usec = Ctx.AddActivationStats(AtomicLoad(&mailbox->ScheduleMoment), hpprev); if (usec > 500) { GLOBAL_LWPROBE(ACTORLIB_PROVIDER, SlowActivation, Ctx.PoolId, usec / 1000.0); - } + } } - + i64 usecDeliv = Ctx.AddEventDeliveryStats(ev->SendTime, hpprev); - if (usecDeliv > 5000) { - double sinceActivationMs = NHPTimer::GetSeconds(hpprev - hpstart) * 1000.0; + if (usecDeliv > 5000) { + double sinceActivationMs = NHPTimer::GetSeconds(hpprev - hpstart) * 1000.0; LwTraceSlowDelivery(ev.Get(), actor, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(hpprev - ev->SendTime) * 1000.0, sinceActivationMs, executed); - } + } - ui32 evTypeForTracing = ev->Type; + ui32 evTypeForTracing = ev->Type; ui32 activityType = actor->GetActivityType(); if (activityType != prevActivityType) { @@ -178,39 +178,39 @@ namespace NActors { actor->Receive(ev, ctx); - size_t dyingActorsCnt = DyingActors.size(); + size_t dyingActorsCnt = DyingActors.size(); Ctx.UpdateActorsStats(dyingActorsCnt); - if (dyingActorsCnt) { + if (dyingActorsCnt) { DropUnregistered(); - actor = nullptr; - } + actor = nullptr; + } - if (mailbox->IsEmpty()) // was not-free and become free, we must reclaim mailbox - reclaimAsFree = true; + if (mailbox->IsEmpty()) // was not-free and become free, we must reclaim mailbox + reclaimAsFree = true; hpnow = GetCycleCountFast(); NHPTimer::STime elapsed = Ctx.AddEventProcessingStats(hpprev, hpnow, activityType, CurrentActorScheduledEventsCounter); if (elapsed > 1000000) { LwTraceSlowEvent(ev.Get(), evTypeForTracing, actor, Ctx.PoolId, activityType, CurrentRecipient, NHPTimer::GetSeconds(elapsed) * 1000.0); } - - // The actor might have been destroyed - if (actor) - actor->AddElapsedTicks(elapsed); + + // The actor might have been destroyed + if (actor) + actor->AddElapsedTicks(elapsed); CurrentRecipient = TActorId(); } else { - TAutoPtr<IEventHandle> nonDelivered = ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown); - if (nonDelivered.Get()) { - ActorSystem->Send(nonDelivered); - } else { + TAutoPtr<IEventHandle> nonDelivered = ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown); + if (nonDelivered.Get()) { + ActorSystem->Send(nonDelivered); + } else { Ctx.IncrementNonDeliveredEvents(); - } + } hpnow = GetCycleCountFast(); } - - hpprev = hpnow; - + + hpprev = hpnow; + // Soft preemption in united pool if (Ctx.SoftDeadlineTs < (ui64)hpnow) { AtomicStore(&mailbox->ScheduleMoment, hpnow); @@ -227,7 +227,7 @@ namespace NActors { break; } - // time limit inside one mailbox passed, let others do some work + // time limit inside one mailbox passed, let others do some work if (hpnow - hpstart > (i64)Ctx.TimePerMailboxTs) { AtomicStore(&mailbox->ScheduleMoment, hpnow); Ctx.IncrementMailboxPushedOutByTime(); @@ -240,7 +240,7 @@ namespace NActors { Ctx.WorkerId, recipient.ToString(), SafeTypeName(actor)); - break; + break; } if (executed + 1 == Ctx.EventsPerMailbox) { @@ -257,8 +257,8 @@ namespace NActors { SafeTypeName(actor)); break; } - } else { - if (executed == 0) + } else { + if (executed == 0) Ctx.IncrementEmptyMailboxActivation(); LWTRACK(MailboxEmpty, Ctx.Orbit, @@ -269,15 +269,15 @@ namespace NActors { Ctx.WorkerId, recipient.ToString(), SafeTypeName(actor)); - break; // empty queue, leave - } + break; // empty queue, leave + } } - + NProfiling::TMemoryTagScope::Reset(0); - TlsActivationContext = nullptr; + TlsActivationContext = nullptr; UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter); - } - + } + TThreadId TExecutorThread::GetThreadId() const { #ifdef _linux_ while (AtomicLoad(&ThreadId) == UnknownThreadId) { @@ -287,7 +287,7 @@ namespace NActors { return ThreadId; } - void* TExecutorThread::ThreadProc() { + void* TExecutorThread::ThreadProc() { #ifdef _linux_ pid_t tid = syscall(SYS_gettid); AtomicSet(ThreadId, (ui64)tid); @@ -297,267 +297,267 @@ namespace NActors { ThreadDisableBalloc(); #endif - if (ThreadName) { + if (ThreadName) { ::SetCurrentThreadName(ThreadName); - } - - ExecutorPool->SetRealTimeMode(); - TAffinityGuard affinity(ExecutorPool->Affinity()); + } + + ExecutorPool->SetRealTimeMode(); + TAffinityGuard affinity(ExecutorPool->Affinity()); NHPTimer::STime hpnow = GetCycleCountFast(); - NHPTimer::STime hpprev = hpnow; - ui64 execCount = 0; - ui64 readyActivationCount = 0; - i64 execCycles = 0; - i64 nonExecCycles = 0; + NHPTimer::STime hpprev = hpnow; + ui64 execCount = 0; + ui64 readyActivationCount = 0; + i64 execCycles = 0; + i64 nonExecCycles = 0; - for (;;) { + for (;;) { if (ui32 activation = ExecutorPool->GetReadyActivation(Ctx, ++RevolvingReadCounter)) { LWTRACK(ActivationBegin, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId, NHPTimer::GetSeconds(Ctx.Lease.GetPreciseExpireTs()) * 1e3); - readyActivationCount++; + readyActivationCount++; if (TMailboxHeader* header = Ctx.MailboxTable->Get(activation)) { - if (header->LockForExecution()) { + if (header->LockForExecution()) { hpnow = GetCycleCountFast(); - nonExecCycles += hpnow - hpprev; - hpprev = hpnow; - switch (header->Type) { - case TMailboxType::Simple: - Execute(static_cast<TMailboxTable::TSimpleMailbox*>(header), activation); - break; - case TMailboxType::Revolving: - Execute(static_cast<TMailboxTable::TRevolvingMailbox*>(header), activation); - break; - case TMailboxType::HTSwap: - Execute(static_cast<TMailboxTable::THTSwapMailbox*>(header), activation); - break; - case TMailboxType::ReadAsFilled: - Execute(static_cast<TMailboxTable::TReadAsFilledMailbox*>(header), activation); - break; - case TMailboxType::TinyReadAsFilled: - Execute(static_cast<TMailboxTable::TTinyReadAsFilledMailbox*>(header), activation); - break; - } + nonExecCycles += hpnow - hpprev; + hpprev = hpnow; + switch (header->Type) { + case TMailboxType::Simple: + Execute(static_cast<TMailboxTable::TSimpleMailbox*>(header), activation); + break; + case TMailboxType::Revolving: + Execute(static_cast<TMailboxTable::TRevolvingMailbox*>(header), activation); + break; + case TMailboxType::HTSwap: + Execute(static_cast<TMailboxTable::THTSwapMailbox*>(header), activation); + break; + case TMailboxType::ReadAsFilled: + Execute(static_cast<TMailboxTable::TReadAsFilledMailbox*>(header), activation); + break; + case TMailboxType::TinyReadAsFilled: + Execute(static_cast<TMailboxTable::TTinyReadAsFilledMailbox*>(header), activation); + break; + } hpnow = GetCycleCountFast(); - execCycles += hpnow - hpprev; - hpprev = hpnow; - execCount++; - if (execCycles + nonExecCycles > 39000000) { // every 15 ms at 2.6GHz, so 1000 items is 15 sec (solomon interval) + execCycles += hpnow - hpprev; + hpprev = hpnow; + execCount++; + if (execCycles + nonExecCycles > 39000000) { // every 15 ms at 2.6GHz, so 1000 items is 15 sec (solomon interval) LWPROBE(ExecutorThreadStats, ExecutorPool->PoolId, ExecutorPool->GetName(), Ctx.WorkerId, - execCount, readyActivationCount, - NHPTimer::GetSeconds(execCycles) * 1000.0, NHPTimer::GetSeconds(nonExecCycles) * 1000.0); - execCount = 0; - readyActivationCount = 0; - execCycles = 0; - nonExecCycles = 0; + execCount, readyActivationCount, + NHPTimer::GetSeconds(execCycles) * 1000.0, NHPTimer::GetSeconds(nonExecCycles) * 1000.0); + execCount = 0; + readyActivationCount = 0; + execCycles = 0; + nonExecCycles = 0; Ctx.UpdateThreadTime(); - } - } - } + } + } + } LWTRACK(ActivationEnd, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId); Ctx.Orbit.Reset(); } else { // no activation means PrepareStop was called so thread must terminate - break; + break; } - } - return nullptr; - } - - // there must be barrier and check-read with following cas - // or just cas w/o read. - // or queue unlocks must be performed with exchange and not generic write - // TODO: check performance of those options under contention - - // placed here in hope for better compiler optimization - - bool TMailboxHeader::MarkForSchedule() { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Inactive)) - return true; - break; - case TExecutionState::Scheduled: - return false; - case TExecutionState::Leaving: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::LeavingMarked, TExecutionState::Leaving)) - return true; - break; - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - return false; - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - return false; - case TExecutionState::FreeLeaving: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeLeavingMarked, TExecutionState::FreeLeaving)) - return true; - break; - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_FAIL(); - } - } - } - - bool TMailboxHeader::LockForExecution() { - AtomicBarrier(); // strictly speaking here should be AtomicBarrier, but as we got mailboxes from queue - this barrier is already set implicitly and could be removed - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - return false; - case TExecutionState::Scheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Scheduled)) - return true; - break; - case TExecutionState::Leaving: - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - return false; - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::FreeScheduled)) - return true; - break; - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_FAIL(); - } - } - } - - bool TMailboxHeader::LockFromFree() { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - case TExecutionState::Leaving: - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - Y_FAIL(); - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::FreeScheduled)) - return true; - break; - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_FAIL(); - } - } - } - - void TMailboxHeader::UnlockFromExecution1() { - const ui32 state = AtomicLoad(&ExecutionState); - if (state == TExecutionState::Executing) - AtomicStore(&ExecutionState, (ui32)TExecutionState::Leaving); - else if (state == TExecutionState::FreeExecuting) - AtomicStore(&ExecutionState, (ui32)TExecutionState::FreeLeaving); - else + } + return nullptr; + } + + // there must be barrier and check-read with following cas + // or just cas w/o read. + // or queue unlocks must be performed with exchange and not generic write + // TODO: check performance of those options under contention + + // placed here in hope for better compiler optimization + + bool TMailboxHeader::MarkForSchedule() { + AtomicBarrier(); + for (;;) { + const ui32 state = AtomicLoad(&ExecutionState); + switch (state) { + case TExecutionState::Inactive: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Inactive)) + return true; + break; + case TExecutionState::Scheduled: + return false; + case TExecutionState::Leaving: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::LeavingMarked, TExecutionState::Leaving)) + return true; + break; + case TExecutionState::Executing: + case TExecutionState::LeavingMarked: + return false; + case TExecutionState::Free: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Free)) + return true; + break; + case TExecutionState::FreeScheduled: + return false; + case TExecutionState::FreeLeaving: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeLeavingMarked, TExecutionState::FreeLeaving)) + return true; + break; + case TExecutionState::FreeExecuting: + case TExecutionState::FreeLeavingMarked: + return false; + default: + Y_FAIL(); + } + } + } + + bool TMailboxHeader::LockForExecution() { + AtomicBarrier(); // strictly speaking here should be AtomicBarrier, but as we got mailboxes from queue - this barrier is already set implicitly and could be removed + for (;;) { + const ui32 state = AtomicLoad(&ExecutionState); + switch (state) { + case TExecutionState::Inactive: + return false; + case TExecutionState::Scheduled: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Scheduled)) + return true; + break; + case TExecutionState::Leaving: + case TExecutionState::Executing: + case TExecutionState::LeavingMarked: + return false; + case TExecutionState::Free: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::Free)) + return true; + break; + case TExecutionState::FreeScheduled: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::FreeScheduled)) + return true; + break; + case TExecutionState::FreeLeaving: + case TExecutionState::FreeExecuting: + case TExecutionState::FreeLeavingMarked: + return false; + default: + Y_FAIL(); + } + } + } + + bool TMailboxHeader::LockFromFree() { + AtomicBarrier(); + for (;;) { + const ui32 state = AtomicLoad(&ExecutionState); + switch (state) { + case TExecutionState::Inactive: + case TExecutionState::Scheduled: + case TExecutionState::Leaving: + case TExecutionState::Executing: + case TExecutionState::LeavingMarked: + Y_FAIL(); + case TExecutionState::Free: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Free)) + return true; + break; + case TExecutionState::FreeScheduled: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::FreeScheduled)) + return true; + break; + case TExecutionState::FreeLeaving: + case TExecutionState::FreeExecuting: + case TExecutionState::FreeLeavingMarked: + return false; + default: + Y_FAIL(); + } + } + } + + void TMailboxHeader::UnlockFromExecution1() { + const ui32 state = AtomicLoad(&ExecutionState); + if (state == TExecutionState::Executing) + AtomicStore(&ExecutionState, (ui32)TExecutionState::Leaving); + else if (state == TExecutionState::FreeExecuting) + AtomicStore(&ExecutionState, (ui32)TExecutionState::FreeLeaving); + else Y_FAIL(); - AtomicBarrier(); - } - - bool TMailboxHeader::UnlockFromExecution2(bool wouldReschedule) { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - Y_FAIL(); - case TExecutionState::Leaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Inactive, TExecutionState::Leaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Leaving)) - return true; - } - break; - case TExecutionState::Executing: - Y_FAIL(); - case TExecutionState::LeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::LeavingMarked)) - return true; - break; - case TExecutionState::Free: - case TExecutionState::FreeScheduled: - Y_FAIL(); - case TExecutionState::FreeLeaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::FreeLeaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeaving)) - return true; - } - break; - case TExecutionState::FreeExecuting: - Y_FAIL(); - case TExecutionState::FreeLeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeavingMarked)) - return true; - break; - default: - Y_FAIL(); - } - } - } - - bool TMailboxHeader::UnlockAsFree(bool wouldReschedule) { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - Y_FAIL(); - case TExecutionState::Leaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::Leaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Leaving)) - return true; - } - break; - case TExecutionState::Executing: - Y_FAIL(); - case TExecutionState::LeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::LeavingMarked)) - return true; - break; - case TExecutionState::Free: - case TExecutionState::FreeScheduled: - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - Y_FAIL(); - default: - Y_FAIL(); - } - } - } -} + AtomicBarrier(); + } + + bool TMailboxHeader::UnlockFromExecution2(bool wouldReschedule) { + AtomicBarrier(); + for (;;) { + const ui32 state = AtomicLoad(&ExecutionState); + switch (state) { + case TExecutionState::Inactive: + case TExecutionState::Scheduled: + Y_FAIL(); + case TExecutionState::Leaving: + if (!wouldReschedule) { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Inactive, TExecutionState::Leaving)) + return false; + } else { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Leaving)) + return true; + } + break; + case TExecutionState::Executing: + Y_FAIL(); + case TExecutionState::LeavingMarked: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::LeavingMarked)) + return true; + break; + case TExecutionState::Free: + case TExecutionState::FreeScheduled: + Y_FAIL(); + case TExecutionState::FreeLeaving: + if (!wouldReschedule) { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::FreeLeaving)) + return false; + } else { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeaving)) + return true; + } + break; + case TExecutionState::FreeExecuting: + Y_FAIL(); + case TExecutionState::FreeLeavingMarked: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeavingMarked)) + return true; + break; + default: + Y_FAIL(); + } + } + } + + bool TMailboxHeader::UnlockAsFree(bool wouldReschedule) { + AtomicBarrier(); + for (;;) { + const ui32 state = AtomicLoad(&ExecutionState); + switch (state) { + case TExecutionState::Inactive: + case TExecutionState::Scheduled: + Y_FAIL(); + case TExecutionState::Leaving: + if (!wouldReschedule) { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::Leaving)) + return false; + } else { + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Leaving)) + return true; + } + break; + case TExecutionState::Executing: + Y_FAIL(); + case TExecutionState::LeavingMarked: + if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::LeavingMarked)) + return true; + break; + case TExecutionState::Free: + case TExecutionState::FreeScheduled: + case TExecutionState::FreeLeaving: + case TExecutionState::FreeExecuting: + case TExecutionState::FreeLeavingMarked: + Y_FAIL(); + default: + Y_FAIL(); + } + } + } +} diff --git a/library/cpp/actors/core/executor_thread.h b/library/cpp/actors/core/executor_thread.h index 9d3c573f0d..7cea13f6d7 100644 --- a/library/cpp/actors/core/executor_thread.h +++ b/library/cpp/actors/core/executor_thread.h @@ -1,34 +1,34 @@ -#pragma once - -#include "defs.h" -#include "event.h" -#include "actor.h" -#include "actorsystem.h" +#pragma once + +#include "defs.h" +#include "event.h" +#include "actor.h" +#include "actorsystem.h" #include "callstack.h" #include "probes.h" #include "worker_context.h" - + #include <library/cpp/actors/util/datetime.h> -#include <util/system/thread.h> - -namespace NActors { +#include <util/system/thread.h> + +namespace NActors { class TExecutorThread: public ISimpleThread { - public: - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = - TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - + public: + static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = + TDuration::MilliSeconds(10); + static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; + TExecutorThread(TWorkerId workerId, TWorkerId cpuId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX); - + TActorSystem* actorSystem, + IExecutorPool* executorPool, + TMailboxTable* mailboxTable, + const TString& threadName, + TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, + ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX); + TExecutorThread(TWorkerId workerId, TActorSystem* actorSystem, IExecutorPool* executorPool, @@ -42,7 +42,7 @@ namespace NActors { TActorId RegisterActor(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>(), const TActorId& parentId = TActorId()); TActorId RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId = TActorId()); - void UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId); + void UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId); void DropUnregistered(); const std::vector<THolder<IActor>>& GetUnregistered() const { return DyingActors; } @@ -57,28 +57,28 @@ namespace NActors { #endif Ctx.IncrementSentEvents(); return ActorSystem->Send(ev); - } + } void GetCurrentStats(TExecutorThreadStats& statsCopy) const { Ctx.GetCurrentStats(statsCopy); - } + } TThreadId GetThreadId() const; // blocks, must be called after Start() TWorkerId GetWorkerId() const { return Ctx.WorkerId; } - private: - void* ThreadProc(); - - template <typename TMailbox> - void Execute(TMailbox* mailbox, ui32 hint); - - public: - TActorSystem* const ActorSystem; - - private: + private: + void* ThreadProc(); + + template <typename TMailbox> + void Execute(TMailbox* mailbox, ui32 hint); + + public: + TActorSystem* const ActorSystem; + + private: // Pool-specific - IExecutorPool* const ExecutorPool; - + IExecutorPool* const ExecutorPool; + // Event-specific (currently executing) TVector<THolder<IActor>> DyingActors; TActorId CurrentRecipient; @@ -88,25 +88,25 @@ namespace NActors { TWorkerContext Ctx; ui64 RevolvingReadCounter = 0; ui64 RevolvingWriteCounter = 0; - const TString ThreadName; + const TString ThreadName; volatile TThreadId ThreadId = UnknownThreadId; - }; - - template <typename TMailbox> + }; + + template <typename TMailbox> void UnlockFromExecution(TMailbox* mailbox, IExecutorPool* executorPool, bool asFree, ui32 hint, TWorkerId workerId, ui64& revolvingWriteCounter) { - mailbox->UnlockFromExecution1(); - const bool needReschedule1 = (nullptr != mailbox->Head()); - if (!asFree) { - if (mailbox->UnlockFromExecution2(needReschedule1)) { + mailbox->UnlockFromExecution1(); + const bool needReschedule1 = (nullptr != mailbox->Head()); + if (!asFree) { + if (mailbox->UnlockFromExecution2(needReschedule1)) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); - } - } else { - if (mailbox->UnlockAsFree(needReschedule1)) { + executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); + } + } else { + if (mailbox->UnlockAsFree(needReschedule1)) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); - } + executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); + } executorPool->ReclaimMailbox(TMailbox::MailboxType, hint, workerId, ++revolvingWriteCounter); - } + } } } diff --git a/library/cpp/actors/core/hfunc.h b/library/cpp/actors/core/hfunc.h index 26f3c65013..6922c2aadf 100644 --- a/library/cpp/actors/core/hfunc.h +++ b/library/cpp/actors/core/hfunc.h @@ -1,45 +1,45 @@ -#pragma once - -#include "actor.h" -#include "executor_thread.h" - +#pragma once + +#include "actor.h" +#include "executor_thread.h" + #include <util/system/defaults.h> -#define HFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x, ctx); \ - break; \ - } - -#define hFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x); \ - break; \ - } - -#define HFuncTraced(TEvType, HandleFunc) \ - case TEvType::EventType: { \ +#define HFunc(TEvType, HandleFunc) \ + case TEvType::EventType: { \ + typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ + HandleFunc(*x, ctx); \ + break; \ + } + +#define hFunc(TEvType, HandleFunc) \ + case TEvType::EventType: { \ + typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ + HandleFunc(*x); \ + break; \ + } + +#define HFuncTraced(TEvType, HandleFunc) \ + case TEvType::EventType: { \ TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \ - TEvType::TPtr* x = reinterpret_cast<TEvType::TPtr*>(&ev); \ - HandleFunc(*x, ctx); \ - break; \ + TEvType::TPtr* x = reinterpret_cast<TEvType::TPtr*>(&ev); \ + HandleFunc(*x, ctx); \ + break; \ } -#define hFuncTraced(TEvType, HandleFunc) \ - case TEvType::EventType: { \ +#define hFuncTraced(TEvType, HandleFunc) \ + case TEvType::EventType: { \ TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x); \ - break; \ - } - -#define HTemplFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x, ctx); \ - break; \ + typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ + HandleFunc(*x); \ + break; \ + } + +#define HTemplFunc(TEvType, HandleFunc) \ + case TEvType::EventType: { \ + typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ + HandleFunc(*x, ctx); \ + break; \ } #define hTemplFunc(TEvType, HandleFunc) \ @@ -59,26 +59,26 @@ HandleFunc(); \ break; -#define CFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(ctx); \ - break; - +#define CFunc(TEventType, HandleFunc) \ + case TEventType: \ + HandleFunc(ctx); \ + break; + #define cFunc(TEventType, HandleFunc) \ case TEventType: \ HandleFunc(); \ - break; - -#define FFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(ev, ctx); \ - break; - + break; + +#define FFunc(TEventType, HandleFunc) \ + case TEventType: \ + HandleFunc(ev, ctx); \ + break; + #define fFunc(TEventType, HandleFunc) \ case TEventType: \ HandleFunc(ev); \ break; -#define IgnoreFunc(TEvType) \ - case TEvType::EventType: \ - break; +#define IgnoreFunc(TEvType) \ + case TEvType::EventType: \ + break; diff --git a/library/cpp/actors/core/interconnect.h b/library/cpp/actors/core/interconnect.h index 679a4b8cc6..93b78c9d27 100644 --- a/library/cpp/actors/core/interconnect.h +++ b/library/cpp/actors/core/interconnect.h @@ -1,14 +1,14 @@ -#pragma once +#pragma once #include "events.h" #include "event_local.h" #include <library/cpp/actors/protos/interconnect.pb.h> #include <util/string/cast.h> #include <util/string/builder.h> - -namespace NActors { + +namespace NActors { class TNodeLocation { - public: + public: struct TKeys { enum E : int { DataCenter = 10, @@ -113,21 +113,21 @@ namespace NActors { friend bool operator <=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) <= 0; } friend bool operator > (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) > 0; } friend bool operator >=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) >= 0; } - }; + }; - struct TEvInterconnect { - enum EEv { - EvForward = EventSpaceBegin(TEvents::ES_INTERCONNECT), - EvResolveNode, // resolve info about node (internal) + struct TEvInterconnect { + enum EEv { + EvForward = EventSpaceBegin(TEvents::ES_INTERCONNECT), + EvResolveNode, // resolve info about node (internal) EvNodeAddress, // node info (internal) - EvConnectNode, // request proxy to establish connection (like: we would send something there soon) - EvAcceptIncoming, - EvNodeConnected, // node connected notify - EvNodeDisconnected, // node disconnected notify - EvRegisterNode, - EvRegisterNodeResult, - EvListNodes, - EvNodesInfo, + EvConnectNode, // request proxy to establish connection (like: we would send something there soon) + EvAcceptIncoming, + EvNodeConnected, // node connected notify + EvNodeDisconnected, // node disconnected notify + EvRegisterNode, + EvRegisterNodeResult, + EvListNodes, + EvNodesInfo, EvDisconnect, EvGetNode, EvNodeInfo, @@ -135,48 +135,48 @@ namespace NActors { EvCloseInputSession, EvPoisonSession, EvTerminate, - EvEnd - }; - - enum ESubscribes { - SubConnected, - SubDisconnected, - }; - - static_assert(EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT), "expect EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT)"); - - struct TEvResolveNode; + EvEnd + }; + + enum ESubscribes { + SubConnected, + SubDisconnected, + }; + + static_assert(EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT), "expect EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT)"); + + struct TEvResolveNode; struct TEvNodeAddress; - - struct TEvConnectNode: public TEventBase<TEvConnectNode, EvConnectNode> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectNode, "TEvInterconnect::TEvConnectNode") - }; - - struct TEvAcceptIncoming; - - struct TEvNodeConnected: public TEventLocal<TEvNodeConnected, EvNodeConnected> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeConnected, "TEvInterconnect::TEvNodeConnected") - TEvNodeConnected(ui32 node) noexcept - : NodeId(node) - { - } - const ui32 NodeId; - }; - - struct TEvNodeDisconnected: public TEventLocal<TEvNodeDisconnected, EvNodeDisconnected> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeDisconnected, "TEvInterconnect::TEvNodeDisconnected") - TEvNodeDisconnected(ui32 node) noexcept - : NodeId(node) - { - } - const ui32 NodeId; - }; - - struct TEvRegisterNode; - struct TEvRegisterNodeResult; - - struct TEvListNodes: public TEventLocal<TEvListNodes, EvListNodes> { - }; + + struct TEvConnectNode: public TEventBase<TEvConnectNode, EvConnectNode> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectNode, "TEvInterconnect::TEvConnectNode") + }; + + struct TEvAcceptIncoming; + + struct TEvNodeConnected: public TEventLocal<TEvNodeConnected, EvNodeConnected> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeConnected, "TEvInterconnect::TEvNodeConnected") + TEvNodeConnected(ui32 node) noexcept + : NodeId(node) + { + } + const ui32 NodeId; + }; + + struct TEvNodeDisconnected: public TEventLocal<TEvNodeDisconnected, EvNodeDisconnected> { + DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeDisconnected, "TEvInterconnect::TEvNodeDisconnected") + TEvNodeDisconnected(ui32 node) noexcept + : NodeId(node) + { + } + const ui32 NodeId; + }; + + struct TEvRegisterNode; + struct TEvRegisterNodeResult; + + struct TEvListNodes: public TEventLocal<TEvListNodes, EvListNodes> { + }; struct TNodeInfo { ui32 NodeId; @@ -211,13 +211,13 @@ namespace NActors { struct TEvNodesInfo: public TEventLocal<TEvNodesInfo, EvNodesInfo> { TVector<TNodeInfo> Nodes; - - const TNodeInfo* GetNodeInfo(ui32 nodeId) const { - for (const auto& x : Nodes) { - if (x.NodeId == nodeId) - return &x; - } - return nullptr; + + const TNodeInfo* GetNodeInfo(ui32 nodeId) const { + for (const auto& x : Nodes) { + if (x.NodeId == nodeId) + return &x; + } + return nullptr; } }; @@ -252,4 +252,4 @@ namespace NActors { struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> {}; }; -} +} diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp index 5f63b5af58..1d41c649f7 100644 --- a/library/cpp/actors/core/log.cpp +++ b/library/cpp/actors/core/log.cpp @@ -209,7 +209,7 @@ namespace NActors { TLoggerActor::~TLoggerActor() { } - void TLoggerActor::Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...) { + void TLoggerActor::Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...) { Metrics->IncDirectMsgs(); if (Settings && Settings->Satisfies(priority, component, 0ull)) { va_list params; @@ -235,7 +235,7 @@ namespace NActors { } } - void TLoggerActor::HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx) { + void TLoggerActor::HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx) { Y_UNUSED(ev); LogIgnoredCount(ctx.Now()); IgnoredCount = 0; @@ -254,12 +254,12 @@ namespace NActors { switch (prio) { case ::NActors::NLog::EPrio::Alert: Metrics->IncAlertMsgs(); - break; + break; case ::NActors::NLog::EPrio::Emerg: Metrics->IncEmergMsgs(); - break; - default: - break; + break; + default: + break; } } @@ -273,7 +273,7 @@ namespace NActors { AtomicSet(IsOverflow, 0); // Check if some records have to be dropped - if ((PassedCount > 10 && delayMillisec > (i64)Settings->TimeThresholdMs) || IgnoredCount > 0) { + if ((PassedCount > 10 && delayMillisec > (i64)Settings->TimeThresholdMs) || IgnoredCount > 0) { Metrics->IncIgnoredMsgs(); if (IgnoredCount == 0) { ctx.Send(ctx.SelfID, new TLogIgnored()); @@ -302,7 +302,7 @@ namespace NActors { Schedule(WakeupInterval, new TEvents::TEvWakeup); } - void TLoggerActor::HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const NActors::TActorContext& ctx) { + void TLoggerActor::HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const NActors::TActorContext& ctx) { Metrics->IncLevelRequests(); TString explanation; int code = Settings->SetLevel(ev->Get()->Priority, ev->Get()->Component, explanation); @@ -312,24 +312,24 @@ namespace NActors { void TLoggerActor::RenderComponentPriorities(IOutputStream& str) { using namespace NLog; HTML(str) { - H4() { - str << "Priority Settings for the Components"; - } + H4() { + str << "Priority Settings for the Components"; + } TABLE_SORTABLE_CLASS("table") { TABLEHEAD() { TABLER() { - TABLEH() { - str << "Component"; - } - TABLEH() { - str << "Level"; - } - TABLEH() { - str << "Sampling Level"; - } - TABLEH() { - str << "Sampling Rate"; - } + TABLEH() { + str << "Component"; + } + TABLEH() { + str << "Level"; + } + TABLEH() { + str << "Sampling Level"; + } + TABLEH() { + str << "Sampling Rate"; + } } } TABLEBODY() { @@ -340,18 +340,18 @@ namespace NActors { NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(i); TABLER() { - TABLED() { - str << "<a href='logger?c=" << i << "'>" << name << "</a>"; - } - TABLED() { + TABLED() { + str << "<a href='logger?c=" << i << "'>" << name << "</a>"; + } + TABLED() { str << PriorityToString(EPrio(componentSettings.Raw.X.Level)); - } - TABLED() { + } + TABLED() { str << PriorityToString(EPrio(componentSettings.Raw.X.SamplingLevel)); - } - TABLED() { - str << componentSettings.Raw.X.SamplingRate; - } + } + TABLED() { + str << componentSettings.Raw.X.SamplingRate; + } } } } @@ -366,7 +366,7 @@ namespace NActors { * 3. Number of messages per components, per priority * 4. Log level changes (last N changes) */ - void TLoggerActor::HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { + void TLoggerActor::HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { const auto& params = ev->Get()->Request.GetParams(); NLog::EComponent component = NLog::InvalidComponent; NLog::EPriority priority = NLog::PRI_DEBUG; @@ -415,9 +415,9 @@ namespace NActors { HTML(str) { DIV_CLASS("row") { DIV_CLASS("col-md-12") { - H4() { - str << "Current log settings for " << Settings->ComponentName(component) << Endl; - } + H4() { + str << "Current log settings for " << Settings->ComponentName(component) << Endl; + } UL() { LI() { str << "Priority: " @@ -437,9 +437,9 @@ namespace NActors { DIV_CLASS("row") { DIV_CLASS("col-md-12") { - H4() { - str << "Change priority" << Endl; - } + H4() { + str << "Change priority" << Endl; + } UL() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { LI() { @@ -448,9 +448,9 @@ namespace NActors { } } } - H4() { - str << "Change sampling priority" << Endl; - } + H4() { + str << "Change sampling priority" << Endl; + } UL() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { LI() { @@ -459,17 +459,17 @@ namespace NActors { } } } - H4() { - str << "Change sampling rate" << Endl; - } + H4() { + str << "Change sampling rate" << Endl; + } str << "<form method=\"GET\">" << Endl; str << "Rate: <input type=\"number\" name=\"sr\" value=\"" << samplingRate << "\"/>" << Endl; str << "<input type=\"hidden\" name=\"c\" value=\"" << component << "\">" << Endl; str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl; str << "</form>" << Endl; - H4() { - str << "<a href='logger'>Cancel</a>" << Endl; - } + H4() { + str << "<a href='logger'>Cancel</a>" << Endl; + } } } } @@ -492,76 +492,76 @@ namespace NActors { HTML(str) { if (!explanation.empty()) { DIV_CLASS("row") { - DIV_CLASS("col-md-12 alert alert-info") { - str << explanation; - } + DIV_CLASS("col-md-12 alert alert-info") { + str << explanation; + } } } DIV_CLASS("row") { DIV_CLASS("col-md-6") { - RenderComponentPriorities(str); - } - DIV_CLASS("col-md-6") { - H4() { - str << "Change priority for all components"; - } + RenderComponentPriorities(str); + } + DIV_CLASS("col-md-6") { + H4() { + str << "Change priority for all components"; + } TABLE_CLASS("table table-condensed") { TABLEHEAD() { TABLER() { - TABLEH() { - str << "Priority"; - } + TABLEH() { + str << "Priority"; + } } } TABLEBODY() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { TABLER() { - TABLED() { - str << "<a href = 'logger?c=-1&p=" << p << "'>" + TABLED() { + str << "<a href = 'logger?c=-1&p=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; } } } } } - H4() { - str << "Change sampling priority for all components"; - } + H4() { + str << "Change sampling priority for all components"; + } TABLE_CLASS("table table-condensed") { TABLEHEAD() { TABLER() { - TABLEH() { - str << "Priority"; - } + TABLEH() { + str << "Priority"; + } } } TABLEBODY() { for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { TABLER() { - TABLED() { - str << "<a href = 'logger?c=-1&sp=" << p << "'>" + TABLED() { + str << "<a href = 'logger?c=-1&sp=" << p << "'>" << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; } } } } } - H4() { - str << "Change sampling rate for all components"; - } + H4() { + str << "Change sampling rate for all components"; + } str << "<form method=\"GET\">" << Endl; str << "Rate: <input type=\"number\" name=\"sr\" value=\"0\"/>" << Endl; str << "<input type=\"hidden\" name=\"c\" value=\"-1\">" << Endl; str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl; str << "</form>" << Endl; - H4() { - str << "Drop log entries in case of overflow: " - << (Settings->AllowDrop ? "Enabled" : "Disabled"); - } + H4() { + str << "Drop log entries in case of overflow: " + << (Settings->AllowDrop ? "Enabled" : "Disabled"); + } str << "<form method=\"GET\">" << Endl; - str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl; - str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl; + str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl; + str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl; str << "</form>" << Endl; } } @@ -605,34 +605,34 @@ namespace NActors { TLogRecord(logPrio, logRecord.data(), logRecord.size())); } break; - case NActors::NLog::TSettings::JSON_FORMAT: { - NJsonWriter::TBuf json; - json.BeginObject() - .WriteKey("@timestamp") + case NActors::NLog::TSettings::JSON_FORMAT: { + NJsonWriter::TBuf json; + json.BeginObject() + .WriteKey("@timestamp") .WriteString(Settings->UseLocalTimestamps ? FormatLocalTimestamp(time, buf) : time.ToString().data()) - .WriteKey("microseconds") - .WriteULongLong(time.MicroSeconds()) - .WriteKey("host") - .WriteString(Settings->ShortHostName) - .WriteKey("cluster") - .WriteString(Settings->ClusterName) - .WriteKey("priority") - .WriteString(PriorityToString(priority)) - .WriteKey("npriority") - .WriteInt((int)priority) - .WriteKey("component") - .WriteString(Settings->ComponentName(component)) - .WriteKey("tag") - .WriteString("KIKIMR") - .WriteKey("revision") - .WriteInt(GetProgramSvnRevision()) - .WriteKey("message") - .WriteString(formatted) - .EndObject(); + .WriteKey("microseconds") + .WriteULongLong(time.MicroSeconds()) + .WriteKey("host") + .WriteString(Settings->ShortHostName) + .WriteKey("cluster") + .WriteString(Settings->ClusterName) + .WriteKey("priority") + .WriteString(PriorityToString(priority)) + .WriteKey("npriority") + .WriteInt((int)priority) + .WriteKey("component") + .WriteString(Settings->ComponentName(component)) + .WriteKey("tag") + .WriteString("KIKIMR") + .WriteKey("revision") + .WriteInt(GetProgramSvnRevision()) + .WriteKey("message") + .WriteString(formatted) + .EndObject(); auto logRecord = json.Str(); LogBackend->WriteData( TLogRecord(logPrio, logRecord.data(), logRecord.size())); - } break; + } break; } return true; @@ -657,7 +657,7 @@ namespace NActors { return buf; } - TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, + TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, bool logPError, bool logCons) { int flags = 0; if (logPError) @@ -668,20 +668,20 @@ namespace NActors { return new TSysLogBackend(ident.data(), TSysLogBackend::TSYSLOG_LOCAL1, flags); } - class TStderrBackend: public TLogBackend { + class TStderrBackend: public TLogBackend { public: - TStderrBackend() { - } + TStderrBackend() { + } void WriteData(const TLogRecord& rec) override { -#ifdef _MSC_VER - if (IsDebuggerPresent()) { +#ifdef _MSC_VER + if (IsDebuggerPresent()) { TString x; - x.reserve(rec.Len + 2); - x.append(rec.Data, rec.Len); - x.append('\n'); - OutputDebugString(x.c_str()); - } -#endif + x.reserve(rec.Len + 2); + x.append(rec.Data, rec.Len); + x.append('\n'); + OutputDebugString(x.c_str()); + } +#endif bool isOk = false; do { try { diff --git a/library/cpp/actors/core/log.h b/library/cpp/actors/core/log.h index c11a7cf3c1..3f08af1fc8 100644 --- a/library/cpp/actors/core/log.h +++ b/library/cpp/actors/core/log.h @@ -1,6 +1,6 @@ #pragma once - -#include "defs.h" + +#include "defs.h" #include "log_iface.h" #include "log_settings.h" @@ -41,12 +41,12 @@ ::NActors::MemLogAdapter( \ actorCtxOrSystem, priority, component, __VA_ARGS__); \ } \ - } while (0) /**/ + } while (0) /**/ -#define LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, stream) \ +#define LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, stream) \ LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, "%s", [&]() { \ - TStringBuilder logStringBuilder; \ - logStringBuilder << stream; \ + TStringBuilder logStringBuilder; \ + logStringBuilder << stream; \ return static_cast<TString>(logStringBuilder); \ }().data()) @@ -54,64 +54,64 @@ #define LOG_LOG_S(actorCtxOrSystem, priority, component, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, stream) // use these macros for logging via actor system or actor context -#define LOG_EMERG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, __VA_ARGS__) -#define LOG_ALERT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, __VA_ARGS__) -#define LOG_CRIT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, __VA_ARGS__) -#define LOG_ERROR(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, __VA_ARGS__) -#define LOG_WARN(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, __VA_ARGS__) -#define LOG_NOTICE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, __VA_ARGS__) -#define LOG_INFO(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, __VA_ARGS__) -#define LOG_DEBUG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, __VA_ARGS__) -#define LOG_TRACE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, __VA_ARGS__) - -#define LOG_EMERG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, stream) -#define LOG_ALERT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, stream) -#define LOG_CRIT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, stream) -#define LOG_ERROR_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, stream) -#define LOG_WARN_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, stream) +#define LOG_EMERG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, __VA_ARGS__) +#define LOG_ALERT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, __VA_ARGS__) +#define LOG_CRIT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, __VA_ARGS__) +#define LOG_ERROR(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, __VA_ARGS__) +#define LOG_WARN(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, __VA_ARGS__) +#define LOG_NOTICE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, __VA_ARGS__) +#define LOG_INFO(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, __VA_ARGS__) +#define LOG_DEBUG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, __VA_ARGS__) +#define LOG_TRACE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, __VA_ARGS__) + +#define LOG_EMERG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, stream) +#define LOG_ALERT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, stream) +#define LOG_CRIT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, stream) +#define LOG_ERROR_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, stream) +#define LOG_WARN_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, stream) #define LOG_NOTICE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, stream) -#define LOG_INFO_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, stream) -#define LOG_DEBUG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, stream) -#define LOG_TRACE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, stream) - -#define LOG_EMERG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, __VA_ARGS__) -#define LOG_ALERT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, __VA_ARGS__) -#define LOG_CRIT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, __VA_ARGS__) -#define LOG_ERROR_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, __VA_ARGS__) -#define LOG_WARN_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, __VA_ARGS__) -#define LOG_NOTICE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, __VA_ARGS__) -#define LOG_INFO_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, __VA_ARGS__) -#define LOG_DEBUG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, __VA_ARGS__) -#define LOG_TRACE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, __VA_ARGS__) - -#define LOG_EMERG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, stream) -#define LOG_ALERT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, stream) -#define LOG_CRIT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, stream) -#define LOG_ERROR_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, stream) -#define LOG_WARN_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, stream) +#define LOG_INFO_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, stream) +#define LOG_DEBUG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, stream) +#define LOG_TRACE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, stream) + +#define LOG_EMERG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, __VA_ARGS__) +#define LOG_ALERT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, __VA_ARGS__) +#define LOG_CRIT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, __VA_ARGS__) +#define LOG_ERROR_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, __VA_ARGS__) +#define LOG_WARN_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, __VA_ARGS__) +#define LOG_NOTICE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, __VA_ARGS__) +#define LOG_INFO_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, __VA_ARGS__) +#define LOG_DEBUG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, __VA_ARGS__) +#define LOG_TRACE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, __VA_ARGS__) + +#define LOG_EMERG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, stream) +#define LOG_ALERT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, stream) +#define LOG_CRIT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, stream) +#define LOG_ERROR_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, stream) +#define LOG_WARN_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, stream) #define LOG_NOTICE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, stream) -#define LOG_INFO_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, stream) -#define LOG_DEBUG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, stream) -#define LOG_TRACE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, stream) +#define LOG_INFO_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, stream) +#define LOG_DEBUG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, stream) +#define LOG_TRACE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, stream) // Log Throttling #define LOG_LOG_THROTTLE(throttler, actorCtxOrSystem, priority, component, ...) \ - do { \ - if ((throttler).Kick()) { \ - LOG_LOG(actorCtxOrSystem, priority, component, __VA_ARGS__); \ - } \ - } while (0) /**/ - -#define TRACE_EVENT(component) \ - const auto& currentTracer = component; \ - if (ev->HasEvent()) { \ - LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s: %s", \ - __FUNCTION__, ev->Type, ev->Sender.ToString().data(), SelfId().ToString().data(), ev->GetBase()->ToString().substr(0, 1000).data()); \ - } else { \ - LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s", \ + do { \ + if ((throttler).Kick()) { \ + LOG_LOG(actorCtxOrSystem, priority, component, __VA_ARGS__); \ + } \ + } while (0) /**/ + +#define TRACE_EVENT(component) \ + const auto& currentTracer = component; \ + if (ev->HasEvent()) { \ + LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s: %s", \ + __FUNCTION__, ev->Type, ev->Sender.ToString().data(), SelfId().ToString().data(), ev->GetBase()->ToString().substr(0, 1000).data()); \ + } else { \ + LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s", \ __FUNCTION__, ev->Type, ev->Sender.ToString().data(), ev->Recipient.ToString().data()); \ } -#define TRACE_EVENT_TYPE(eventType) LOG_TRACE(*TlsActivationContext, currentTracer, "%s, processing event %s", __FUNCTION__, eventType) +#define TRACE_EVENT_TYPE(eventType) LOG_TRACE(*TlsActivationContext, currentTracer, "%s, processing event %s", __FUNCTION__, eventType) class TLog; class TLogBackend; @@ -147,7 +147,7 @@ namespace NActors { class TLogComponentLevelResponse: public TEventLocal<TLogComponentLevelResponse, int(NLog::EEv::LevelResp)> { public: - TLogComponentLevelResponse(int code, const TString& explanation) + TLogComponentLevelResponse(int code, const TString& explanation) : Code(code) , Explanation(explanation) { @@ -157,7 +157,7 @@ namespace NActors { return Code; } - const TString& GetExplanation() const { + const TString& GetExplanation() const { return Explanation; } @@ -190,7 +190,7 @@ namespace NActors { virtual void GetOutputHtml(IOutputStream&) = 0; }; - class TLoggerActor: public TActor<TLoggerActor> { + class TLoggerActor: public TActor<TLoggerActor> { public: static constexpr IActor::EActivityType ActorActivityType() { return IActor::LOG_ACTOR; @@ -210,7 +210,7 @@ namespace NActors { std::shared_ptr<NMonitoring::TMetricRegistry> metrics); ~TLoggerActor(); - void StateFunc(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) { + void StateFunc(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) { switch (ev->GetTypeRewrite()) { HFunc(TLogIgnored, HandleIgnoredEvent); HFunc(NLog::TEvLog, HandleLogEvent); @@ -230,7 +230,7 @@ namespace NActors { } // Directly call logger instead of sending a message - void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...); + void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...); static void Throttle(const NLog::TSettings& settings); @@ -244,12 +244,12 @@ namespace NActors { std::unique_ptr<ILoggerMetrics> Metrics; void BecomeDefunct(); - void HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx); + void HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx); void HandleIgnoredEventDrop(); void HandleLogEvent(NLog::TEvLog::TPtr& ev, const TActorContext& ctx); void HandleLogEventDrop(const NLog::TEvLog::TPtr& ev); - void HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const TActorContext& ctx); - void HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx); + void HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const TActorContext& ctx); + void HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx); void HandleWakeup(); [[nodiscard]] bool OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, const TString& formatted) noexcept; void RenderComponentPriorities(IOutputStream& str); @@ -270,8 +270,8 @@ namespace NActors { public: TTrivialLogThrottler(TDuration period) : Period(period) - { - } + { + } // return value: // true -- write to log @@ -294,16 +294,16 @@ namespace NActors { //////////////////////////////////////////////////////////////////////////////// // SYSLOG BACKEND //////////////////////////////////////////////////////////////////////////////// - TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, + TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, bool logPError, bool logCons); TAutoPtr<TLogBackend> CreateStderrBackend(); TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName); TAutoPtr<TLogBackend> CreateNullBackend(); TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends); - ///////////////////////////////////////////////////////////////////// - // Logging adaptors for memory log and logging into filesystem - ///////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + // Logging adaptors for memory log and logging into filesystem + ///////////////////////////////////////////////////////////////////// namespace NDetail { inline void Y_PRINTF_FORMAT(2, 3) PrintfV(TString& dst, const char* format, ...) { @@ -319,18 +319,18 @@ namespace NActors { } // namespace NDetail template <typename TCtx> - inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str) - { - const NLog::TSettings *mSettings = ctx.LoggerSettings(); + inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str) + { + const NLog::TSettings *mSettings = ctx.LoggerSettings(); TLoggerActor::Throttle(*mSettings); ctx.Send(new IEventHandle(mSettings->LoggerActorId, TActorId(), new NLog::TEvLog(mPriority, mComponent, std::move(str)))); } template <typename TCtx, typename... TArgs> inline void MemLogAdapter( - TCtx& actorCtxOrSystem, - NLog::EPriority mPriority, - NLog::EComponent mComponent, + TCtx& actorCtxOrSystem, + NLog::EPriority mPriority, + NLog::EComponent mComponent, const char* format, TArgs&&... params) { TString Formatted; @@ -346,11 +346,11 @@ namespace NActors { } template <typename TCtx> - Y_WRAPPER inline void MemLogAdapter( - TCtx& actorCtxOrSystem, - NLog::EPriority mPriority, - NLog::EComponent mComponent, - const TString& str) { + Y_WRAPPER inline void MemLogAdapter( + TCtx& actorCtxOrSystem, + NLog::EPriority mPriority, + NLog::EComponent mComponent, + const TString& str) { MemLogWrite(str.data(), str.size(), true); DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, TString(str)); diff --git a/library/cpp/actors/core/log_settings.cpp b/library/cpp/actors/core/log_settings.cpp index f52f2fc5d2..b51519c82a 100644 --- a/library/cpp/actors/core/log_settings.cpp +++ b/library/cpp/actors/core/log_settings.cpp @@ -5,7 +5,7 @@ namespace NActors { namespace NLog { TSettings::TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EComponent minVal, EComponent maxVal, EComponentToStringFunc func, + EComponent minVal, EComponent maxVal, EComponentToStringFunc func, EPriority defPriority, EPriority defSamplingPriority, ui32 defSamplingRate, ui64 timeThresholdMs) : LoggerActorId(loggerActorId) @@ -88,8 +88,8 @@ namespace NActors { } int TSettings::SetLevelImpl( - const TString& name, bool isSampling, - EPriority priority, EComponent component, TString& explanation) { + const TString& name, bool isSampling, + EPriority priority, EComponent component, TString& explanation) { TString titleName(name); titleName.to_title(); @@ -143,17 +143,17 @@ namespace NActors { } } - int TSettings::SetLevel(EPriority priority, EComponent component, TString& explanation) { + int TSettings::SetLevel(EPriority priority, EComponent component, TString& explanation) { return SetLevelImpl("priority", false, - priority, component, explanation); + priority, component, explanation); } - int TSettings::SetSamplingLevel(EPriority priority, EComponent component, TString& explanation) { + int TSettings::SetSamplingLevel(EPriority priority, EComponent component, TString& explanation) { return SetLevelImpl("sampling priority", true, - priority, component, explanation); + priority, component, explanation); } - int TSettings::SetSamplingRate(ui32 sampling, EComponent component, TString& explanation) { + int TSettings::SetSamplingRate(ui32 sampling, EComponent component, TString& explanation) { if (component == InvalidComponent) { for (int i = 0; i < Mask + 1; i++) { TComponentSettings settings = AtomicGet(ComponentInfo[i]); @@ -174,8 +174,8 @@ namespace NActors { AtomicSet(ComponentInfo[component], settings.Raw.Data); TStringStream str; str << "Sampling rate for the component " << ComponentNames[component] - << " has been changed from " << oldSampling - << " to " << sampling; + << " has been changed from " << oldSampling + << " to " << sampling; explanation = str.Str(); } return 0; @@ -192,9 +192,9 @@ namespace NActors { bool TSettings::IsValidPriority(EPriority priority) { return priority == PRI_EMERG || priority == PRI_ALERT || - priority == PRI_CRIT || priority == PRI_ERROR || - priority == PRI_WARN || priority == PRI_NOTICE || - priority == PRI_INFO || priority == PRI_DEBUG || priority == PRI_TRACE; + priority == PRI_CRIT || priority == PRI_ERROR || + priority == PRI_WARN || priority == PRI_NOTICE || + priority == PRI_INFO || priority == PRI_DEBUG || priority == PRI_TRACE; } bool TSettings::IsValidComponent(EComponent component) { diff --git a/library/cpp/actors/core/log_settings.h b/library/cpp/actors/core/log_settings.h index 7fe4504edd..3bb332319c 100644 --- a/library/cpp/actors/core/log_settings.h +++ b/library/cpp/actors/core/log_settings.h @@ -11,25 +11,25 @@ namespace NActors { inline const char* PriorityToString(EPrio priority) { switch (priority) { case EPrio::Emerg: - return "EMERG"; + return "EMERG"; case EPrio::Alert: - return "ALERT"; + return "ALERT"; case EPrio::Crit: - return "CRIT"; + return "CRIT"; case EPrio::Error: - return "ERROR"; + return "ERROR"; case EPrio::Warn: - return "WARN"; + return "WARN"; case EPrio::Notice: - return "NOTICE"; + return "NOTICE"; case EPrio::Info: - return "INFO"; + return "INFO"; case EPrio::Debug: - return "DEBUG"; + return "DEBUG"; case EPrio::Trace: - return "TRACE"; - default: - return "UNKNOWN"; + return "TRACE"; + default: + return "UNKNOWN"; } } @@ -67,7 +67,7 @@ namespace NActors { } }; - struct TSettings: public TThrRefBase { + struct TSettings: public TThrRefBase { public: TActorId LoggerActorId; EComponent LoggerComponent; @@ -99,7 +99,7 @@ namespace NActors { // automatically generates YOURTYPE_MIN, YOURTYPE_MAX and // YOURTYPE_Name for you. TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EComponent minVal, EComponent maxVal, EComponentToStringFunc func, + EComponent minVal, EComponent maxVal, EComponentToStringFunc func, EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG, ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000); @@ -149,14 +149,14 @@ namespace NActors { return TComponentSettings(AtomicGet(ComponentInfo[component & Mask])); } - const char* ComponentName(EComponent component) const { + const char* ComponentName(EComponent component) const { Y_VERIFY_DEBUG((component & Mask) == component); return ComponentNames[component & Mask].data(); } - int SetLevel(EPriority priority, EComponent component, TString& explanation); - int SetSamplingLevel(EPriority priority, EComponent component, TString& explanation); - int SetSamplingRate(ui32 sampling, EComponent component, TString& explanation); + int SetLevel(EPriority priority, EComponent component, TString& explanation); + int SetSamplingLevel(EPriority priority, EComponent component, TString& explanation); + int SetSamplingRate(ui32 sampling, EComponent component, TString& explanation); EComponent FindComponent(const TStringBuf& componentName) const; static int PowerOf2Mask(int val); static bool IsValidPriority(EPriority priority); @@ -168,7 +168,7 @@ namespace NActors { private: int SetLevelImpl( const TString& name, bool isSampling, - EPriority priority, EComponent component, TString& explanation); + EPriority priority, EComponent component, TString& explanation); }; } diff --git a/library/cpp/actors/core/mailbox.cpp b/library/cpp/actors/core/mailbox.cpp index d84b4f9e46..cf1fca5630 100644 --- a/library/cpp/actors/core/mailbox.cpp +++ b/library/cpp/actors/core/mailbox.cpp @@ -1,381 +1,381 @@ -#include "mailbox.h" -#include "actorsystem.h" - +#include "mailbox.h" +#include "actorsystem.h" + #include <library/cpp/actors/util/datetime.h> #include <util/system/sanitizers.h> -namespace NActors { - TMailboxTable::TMailboxTable() - : LastAllocatedLine(0) - , AllocatedMailboxCount(0) - , CachedSimpleMailboxes(0) - , CachedRevolvingMailboxes(0) - , CachedHTSwapMailboxes(0) - , CachedReadAsFilledMailboxes(0) - , CachedTinyReadAsFilledMailboxes(0) - { - memset((void*)Lines, 0, sizeof(Lines)); - } - - bool IsGoodForCleanup(const TMailboxHeader* header) { - switch (AtomicLoad(&header->ExecutionState)) { - case TMailboxHeader::TExecutionState::Inactive: - case TMailboxHeader::TExecutionState::Scheduled: - return true; - case TMailboxHeader::TExecutionState::Leaving: - case TMailboxHeader::TExecutionState::Executing: - case TMailboxHeader::TExecutionState::LeavingMarked: - return false; - case TMailboxHeader::TExecutionState::Free: - case TMailboxHeader::TExecutionState::FreeScheduled: - return true; - case TMailboxHeader::TExecutionState::FreeLeaving: - case TMailboxHeader::TExecutionState::FreeExecuting: - case TMailboxHeader::TExecutionState::FreeLeavingMarked: - return false; - default: - Y_FAIL(); - } - } - - template <typename TMailbox> - void DestructMailboxLine(ui8* begin, ui8* end) { - const ui32 sx = TMailbox::AlignedSize(); - for (ui8* x = begin; x + sx <= end; x += sx) { - TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); - Y_VERIFY(IsGoodForCleanup(mailbox)); - mailbox->ExecutionState = Max<ui32>(); - mailbox->~TMailbox(); - } - } - - template <typename TMailbox> - bool CleanupMailboxLine(ui8* begin, ui8* end) { - const ui32 sx = TMailbox::AlignedSize(); - bool done = true; - for (ui8* x = begin; x + sx <= end; x += sx) { - TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); - Y_VERIFY(IsGoodForCleanup(mailbox)); - done &= mailbox->CleanupActors() && mailbox->CleanupEvents(); - } - return done; - } - - TMailboxTable::~TMailboxTable() { - // on cleanup we must traverse everything and free stuff - for (ui32 i = 0; i < LastAllocatedLine; ++i) { - if (TMailboxLineHeader* lineHeader = Lines[i]) { - switch (lineHeader->MailboxType) { - case TMailboxType::Simple: - DestructMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::Revolving: - DestructMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::HTSwap: - DestructMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::ReadAsFilled: - DestructMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::TinyReadAsFilled: - DestructMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - default: - Y_FAIL(); - } - - lineHeader->~TMailboxLineHeader(); - free(lineHeader); - Lines[i] = nullptr; - } - } - - while (MailboxCacheSimple.Pop(0)) - ; - while (MailboxCacheRevolving.Pop(0)) - ; - while (MailboxCacheHTSwap.Pop(0)) - ; - while (MailboxCacheReadAsFilled.Pop(0)) - ; - while (MailboxCacheTinyReadAsFilled.Pop(0)) - ; - } - - bool TMailboxTable::Cleanup() { - bool done = true; - for (ui32 i = 0; i < LastAllocatedLine; ++i) { - if (TMailboxLineHeader* lineHeader = Lines[i]) { - switch (lineHeader->MailboxType) { - case TMailboxType::Simple: - done &= CleanupMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::Revolving: - done &= CleanupMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::HTSwap: - done &= CleanupMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::ReadAsFilled: - done &= CleanupMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::TinyReadAsFilled: - done &= CleanupMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - default: - Y_FAIL(); - } - } - } - return done; - } - - TMailboxHeader* TMailboxTable::Get(ui32 hint) { - // get line - const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; - const ui32 lineHint = hint & LineHintMask; - - Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64)); - if (lineHint == 0) - return nullptr; - - if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { - switch (x->MailboxType) { - case TMailboxType::Simple: - return TSimpleMailbox::Get(lineHint, x); - case TMailboxType::Revolving: - return TRevolvingMailbox::Get(lineHint, x); - case TMailboxType::HTSwap: - return THTSwapMailbox::Get(lineHint, x); - case TMailboxType::ReadAsFilled: - return TReadAsFilledMailbox::Get(lineHint, x); - case TMailboxType::TinyReadAsFilled: - return TTinyReadAsFilledMailbox::Get(lineHint, x); - default: - Y_VERIFY_DEBUG(false); - break; - } - } - - return nullptr; - } - - bool TMailboxTable::SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) { +namespace NActors { + TMailboxTable::TMailboxTable() + : LastAllocatedLine(0) + , AllocatedMailboxCount(0) + , CachedSimpleMailboxes(0) + , CachedRevolvingMailboxes(0) + , CachedHTSwapMailboxes(0) + , CachedReadAsFilledMailboxes(0) + , CachedTinyReadAsFilledMailboxes(0) + { + memset((void*)Lines, 0, sizeof(Lines)); + } + + bool IsGoodForCleanup(const TMailboxHeader* header) { + switch (AtomicLoad(&header->ExecutionState)) { + case TMailboxHeader::TExecutionState::Inactive: + case TMailboxHeader::TExecutionState::Scheduled: + return true; + case TMailboxHeader::TExecutionState::Leaving: + case TMailboxHeader::TExecutionState::Executing: + case TMailboxHeader::TExecutionState::LeavingMarked: + return false; + case TMailboxHeader::TExecutionState::Free: + case TMailboxHeader::TExecutionState::FreeScheduled: + return true; + case TMailboxHeader::TExecutionState::FreeLeaving: + case TMailboxHeader::TExecutionState::FreeExecuting: + case TMailboxHeader::TExecutionState::FreeLeavingMarked: + return false; + default: + Y_FAIL(); + } + } + + template <typename TMailbox> + void DestructMailboxLine(ui8* begin, ui8* end) { + const ui32 sx = TMailbox::AlignedSize(); + for (ui8* x = begin; x + sx <= end; x += sx) { + TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); + Y_VERIFY(IsGoodForCleanup(mailbox)); + mailbox->ExecutionState = Max<ui32>(); + mailbox->~TMailbox(); + } + } + + template <typename TMailbox> + bool CleanupMailboxLine(ui8* begin, ui8* end) { + const ui32 sx = TMailbox::AlignedSize(); + bool done = true; + for (ui8* x = begin; x + sx <= end; x += sx) { + TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); + Y_VERIFY(IsGoodForCleanup(mailbox)); + done &= mailbox->CleanupActors() && mailbox->CleanupEvents(); + } + return done; + } + + TMailboxTable::~TMailboxTable() { + // on cleanup we must traverse everything and free stuff + for (ui32 i = 0; i < LastAllocatedLine; ++i) { + if (TMailboxLineHeader* lineHeader = Lines[i]) { + switch (lineHeader->MailboxType) { + case TMailboxType::Simple: + DestructMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::Revolving: + DestructMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::HTSwap: + DestructMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::ReadAsFilled: + DestructMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::TinyReadAsFilled: + DestructMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + default: + Y_FAIL(); + } + + lineHeader->~TMailboxLineHeader(); + free(lineHeader); + Lines[i] = nullptr; + } + } + + while (MailboxCacheSimple.Pop(0)) + ; + while (MailboxCacheRevolving.Pop(0)) + ; + while (MailboxCacheHTSwap.Pop(0)) + ; + while (MailboxCacheReadAsFilled.Pop(0)) + ; + while (MailboxCacheTinyReadAsFilled.Pop(0)) + ; + } + + bool TMailboxTable::Cleanup() { + bool done = true; + for (ui32 i = 0; i < LastAllocatedLine; ++i) { + if (TMailboxLineHeader* lineHeader = Lines[i]) { + switch (lineHeader->MailboxType) { + case TMailboxType::Simple: + done &= CleanupMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::Revolving: + done &= CleanupMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::HTSwap: + done &= CleanupMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::ReadAsFilled: + done &= CleanupMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + case TMailboxType::TinyReadAsFilled: + done &= CleanupMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); + break; + default: + Y_FAIL(); + } + } + } + return done; + } + + TMailboxHeader* TMailboxTable::Get(ui32 hint) { + // get line + const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; + const ui32 lineHint = hint & LineHintMask; + + Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64)); + if (lineHint == 0) + return nullptr; + + if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { + switch (x->MailboxType) { + case TMailboxType::Simple: + return TSimpleMailbox::Get(lineHint, x); + case TMailboxType::Revolving: + return TRevolvingMailbox::Get(lineHint, x); + case TMailboxType::HTSwap: + return THTSwapMailbox::Get(lineHint, x); + case TMailboxType::ReadAsFilled: + return TReadAsFilledMailbox::Get(lineHint, x); + case TMailboxType::TinyReadAsFilled: + return TTinyReadAsFilledMailbox::Get(lineHint, x); + default: + Y_VERIFY_DEBUG(false); + break; + } + } + + return nullptr; + } + + bool TMailboxTable::SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) { const TActorId& recipient = ev->GetRecipientRewrite(); - const ui32 hint = recipient.Hint(); - - // copy-paste from Get to avoid duplicated type-switches - const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; - const ui32 lineHint = hint & LineHintMask; - - Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64)); - if (lineHint == 0) - return false; - - if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { - switch (x->MailboxType) { - case TMailboxType::Simple: { - TSimpleMailbox* const mailbox = TSimpleMailbox::Get(lineHint, x); + const ui32 hint = recipient.Hint(); + + // copy-paste from Get to avoid duplicated type-switches + const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; + const ui32 lineHint = hint & LineHintMask; + + Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64)); + if (lineHint == 0) + return false; + + if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { + switch (x->MailboxType) { + case TMailboxType::Simple: { + TSimpleMailbox* const mailbox = TSimpleMailbox::Get(lineHint, x); #if (!defined(_tsan_enabled_)) - Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); + Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); #endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { + mailbox->Queue.Push(ev.Release()); + if (mailbox->MarkForSchedule()) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivation(hint); - } - } - return true; - case TMailboxType::Revolving: { - // The actorid could be stale and coming from a different machine. If local process has restarted than - // the stale actorid coming from a remote machine might be referencing an actor with simple mailbox - // which is smaller than revolving mailbox. In this cases 'lineHint' index might be greater than actual - // array size. Normally its ok to store stale event to other actor's valid mailbox beacuse Receive will - // compare receiver actor id and discard stale event. But in this case we should discard the event right away - // instead of trying to enque it to a mailbox at invalid address. - // NOTE: lineHint is 1-based - static_assert(TSimpleMailbox::AlignedSize() <= TRevolvingMailbox::AlignedSize(), - "We expect that one line can store more simple mailboxes than revolving mailboxes"); - if (lineHint > TRevolvingMailbox::MaxMailboxesInLine()) - return false; - - TRevolvingMailbox* const mailbox = TRevolvingMailbox::Get(lineHint, x); + executorPool->ScheduleActivation(hint); + } + } + return true; + case TMailboxType::Revolving: { + // The actorid could be stale and coming from a different machine. If local process has restarted than + // the stale actorid coming from a remote machine might be referencing an actor with simple mailbox + // which is smaller than revolving mailbox. In this cases 'lineHint' index might be greater than actual + // array size. Normally its ok to store stale event to other actor's valid mailbox beacuse Receive will + // compare receiver actor id and discard stale event. But in this case we should discard the event right away + // instead of trying to enque it to a mailbox at invalid address. + // NOTE: lineHint is 1-based + static_assert(TSimpleMailbox::AlignedSize() <= TRevolvingMailbox::AlignedSize(), + "We expect that one line can store more simple mailboxes than revolving mailboxes"); + if (lineHint > TRevolvingMailbox::MaxMailboxesInLine()) + return false; + + TRevolvingMailbox* const mailbox = TRevolvingMailbox::Get(lineHint, x); #if (!defined(_tsan_enabled_)) - Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); + Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); #endif - mailbox->QueueWriter.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { + mailbox->QueueWriter.Push(ev.Release()); + if (mailbox->MarkForSchedule()) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivation(hint); - } - } - return true; - case TMailboxType::HTSwap: { - THTSwapMailbox* const mailbox = THTSwapMailbox::Get(lineHint, x); + executorPool->ScheduleActivation(hint); + } + } + return true; + case TMailboxType::HTSwap: { + THTSwapMailbox* const mailbox = THTSwapMailbox::Get(lineHint, x); #if (!defined(_tsan_enabled_)) - Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); + Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); #endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { + mailbox->Queue.Push(ev.Release()); + if (mailbox->MarkForSchedule()) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivation(hint); - } + executorPool->ScheduleActivation(hint); + } } - return true; - case TMailboxType::ReadAsFilled: { - if (lineHint > TReadAsFilledMailbox::MaxMailboxesInLine()) - return false; + return true; + case TMailboxType::ReadAsFilled: { + if (lineHint > TReadAsFilledMailbox::MaxMailboxesInLine()) + return false; - TReadAsFilledMailbox* const mailbox = TReadAsFilledMailbox::Get(lineHint, x); + TReadAsFilledMailbox* const mailbox = TReadAsFilledMailbox::Get(lineHint, x); #if (!defined(_tsan_enabled_)) - Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); + Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); #endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { + mailbox->Queue.Push(ev.Release()); + if (mailbox->MarkForSchedule()) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivation(hint); - } + executorPool->ScheduleActivation(hint); + } } - return true; - case TMailboxType::TinyReadAsFilled: { - if (lineHint > TTinyReadAsFilledMailbox::MaxMailboxesInLine()) - return false; + return true; + case TMailboxType::TinyReadAsFilled: { + if (lineHint > TTinyReadAsFilledMailbox::MaxMailboxesInLine()) + return false; - TTinyReadAsFilledMailbox* const mailbox = TTinyReadAsFilledMailbox::Get(lineHint, x); + TTinyReadAsFilledMailbox* const mailbox = TTinyReadAsFilledMailbox::Get(lineHint, x); #if (!defined(_tsan_enabled_)) - Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); + Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType); #endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { + mailbox->Queue.Push(ev.Release()); + if (mailbox->MarkForSchedule()) { RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivation(hint); - } + executorPool->ScheduleActivation(hint); + } } - return true; - default: - Y_FAIL("unknown mailbox type"); + return true; + default: + Y_FAIL("unknown mailbox type"); } - } - - return false; - } - - ui32 TMailboxTable::AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { - ui32 x = TryAllocateMailbox(type, revolvingCounter); - if (x == 0) - x = AllocateNewLine(type); - return x; - } - - ui32 TMailboxTable::TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { - switch (type) { - case TMailboxType::Simple: - do { - if (ui32 ret = MailboxCacheSimple.Pop(revolvingCounter)) { - AtomicDecrement(CachedSimpleMailboxes); - return ret; - } - } while (AtomicGet(CachedSimpleMailboxes) > (MailboxCacheSimple.Concurrency * 512)); - return 0; - case TMailboxType::Revolving: - do { - if (ui32 ret = MailboxCacheRevolving.Pop(revolvingCounter)) { - AtomicDecrement(CachedRevolvingMailboxes); - return ret; - } - } while (AtomicGet(CachedRevolvingMailboxes) > (MailboxCacheRevolving.Concurrency * 512)); - return 0; - case TMailboxType::HTSwap: - do { - if (ui32 ret = MailboxCacheHTSwap.Pop(revolvingCounter)) { - AtomicDecrement(CachedHTSwapMailboxes); - return ret; - } - } while (AtomicGet(CachedHTSwapMailboxes) > (MailboxCacheHTSwap.Concurrency * 512)); - return 0; - case TMailboxType::ReadAsFilled: - do { - if (ui32 ret = MailboxCacheReadAsFilled.Pop(revolvingCounter)) { - AtomicDecrement(CachedReadAsFilledMailboxes); - return ret; - } - } while (AtomicGet(CachedReadAsFilledMailboxes) > (MailboxCacheReadAsFilled.Concurrency * 512)); - return 0; - case TMailboxType::TinyReadAsFilled: - do { - if (ui32 ret = MailboxCacheTinyReadAsFilled.Pop(revolvingCounter)) { - AtomicDecrement(CachedTinyReadAsFilledMailboxes); - return ret; - } - } while (AtomicGet(CachedTinyReadAsFilledMailboxes) > (MailboxCacheTinyReadAsFilled.Concurrency * 512)); - return 0; - default: - Y_FAIL("Unknown mailbox type"); - } - } - - void TMailboxTable::ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter) { - if (hint != 0) { - switch (type) { - case TMailboxType::Simple: - MailboxCacheSimple.Push(hint, revolvingCounter); - AtomicIncrement(CachedSimpleMailboxes); - break; - case TMailboxType::Revolving: - MailboxCacheRevolving.Push(hint, revolvingCounter); - AtomicIncrement(CachedRevolvingMailboxes); - break; - case TMailboxType::HTSwap: - MailboxCacheHTSwap.Push(hint, revolvingCounter); - AtomicIncrement(CachedHTSwapMailboxes); - break; - case TMailboxType::ReadAsFilled: - MailboxCacheReadAsFilled.Push(hint, revolvingCounter); - AtomicIncrement(CachedReadAsFilledMailboxes); - break; - case TMailboxType::TinyReadAsFilled: - MailboxCacheTinyReadAsFilled.Push(hint, revolvingCounter); - AtomicIncrement(CachedTinyReadAsFilledMailboxes); - break; - default: - Y_FAIL(); - } - } - } - - TMailboxHeader::TMailboxHeader(TMailboxType::EType type) - : ExecutionState(TExecutionState::Free) + } + + return false; + } + + ui32 TMailboxTable::AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { + ui32 x = TryAllocateMailbox(type, revolvingCounter); + if (x == 0) + x = AllocateNewLine(type); + return x; + } + + ui32 TMailboxTable::TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { + switch (type) { + case TMailboxType::Simple: + do { + if (ui32 ret = MailboxCacheSimple.Pop(revolvingCounter)) { + AtomicDecrement(CachedSimpleMailboxes); + return ret; + } + } while (AtomicGet(CachedSimpleMailboxes) > (MailboxCacheSimple.Concurrency * 512)); + return 0; + case TMailboxType::Revolving: + do { + if (ui32 ret = MailboxCacheRevolving.Pop(revolvingCounter)) { + AtomicDecrement(CachedRevolvingMailboxes); + return ret; + } + } while (AtomicGet(CachedRevolvingMailboxes) > (MailboxCacheRevolving.Concurrency * 512)); + return 0; + case TMailboxType::HTSwap: + do { + if (ui32 ret = MailboxCacheHTSwap.Pop(revolvingCounter)) { + AtomicDecrement(CachedHTSwapMailboxes); + return ret; + } + } while (AtomicGet(CachedHTSwapMailboxes) > (MailboxCacheHTSwap.Concurrency * 512)); + return 0; + case TMailboxType::ReadAsFilled: + do { + if (ui32 ret = MailboxCacheReadAsFilled.Pop(revolvingCounter)) { + AtomicDecrement(CachedReadAsFilledMailboxes); + return ret; + } + } while (AtomicGet(CachedReadAsFilledMailboxes) > (MailboxCacheReadAsFilled.Concurrency * 512)); + return 0; + case TMailboxType::TinyReadAsFilled: + do { + if (ui32 ret = MailboxCacheTinyReadAsFilled.Pop(revolvingCounter)) { + AtomicDecrement(CachedTinyReadAsFilledMailboxes); + return ret; + } + } while (AtomicGet(CachedTinyReadAsFilledMailboxes) > (MailboxCacheTinyReadAsFilled.Concurrency * 512)); + return 0; + default: + Y_FAIL("Unknown mailbox type"); + } + } + + void TMailboxTable::ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter) { + if (hint != 0) { + switch (type) { + case TMailboxType::Simple: + MailboxCacheSimple.Push(hint, revolvingCounter); + AtomicIncrement(CachedSimpleMailboxes); + break; + case TMailboxType::Revolving: + MailboxCacheRevolving.Push(hint, revolvingCounter); + AtomicIncrement(CachedRevolvingMailboxes); + break; + case TMailboxType::HTSwap: + MailboxCacheHTSwap.Push(hint, revolvingCounter); + AtomicIncrement(CachedHTSwapMailboxes); + break; + case TMailboxType::ReadAsFilled: + MailboxCacheReadAsFilled.Push(hint, revolvingCounter); + AtomicIncrement(CachedReadAsFilledMailboxes); + break; + case TMailboxType::TinyReadAsFilled: + MailboxCacheTinyReadAsFilled.Push(hint, revolvingCounter); + AtomicIncrement(CachedTinyReadAsFilledMailboxes); + break; + default: + Y_FAIL(); + } + } + } + + TMailboxHeader::TMailboxHeader(TMailboxType::EType type) + : ExecutionState(TExecutionState::Free) , Reserved(0) - , Type(type) - , ActorPack(TMailboxActorPack::Simple) - , Knobs(0) - { + , Type(type) + , ActorPack(TMailboxActorPack::Simple) + , Knobs(0) + { ActorsInfo.Simple.ActorId = 0; ActorsInfo.Simple.Actor = nullptr; - } - - TMailboxHeader::~TMailboxHeader() { - CleanupActors(); - } - - bool TMailboxHeader::CleanupActors() { - bool done = true; - switch (ActorPack) { + } + + TMailboxHeader::~TMailboxHeader() { + CleanupActors(); + } + + bool TMailboxHeader::CleanupActors() { + bool done = true; + switch (ActorPack) { case TMailboxActorPack::Simple: { if (ActorsInfo.Simple.ActorId != 0) { delete ActorsInfo.Simple.Actor; - done = false; - } - break; + done = false; + } + break; } - case TMailboxActorPack::Map: { + case TMailboxActorPack::Map: { for (auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) { delete actor; } delete ActorsInfo.Map.ActorsMap; - done = false; + done = false; break; } case TMailboxActorPack::Array: { @@ -386,166 +386,166 @@ namespace NActors { done = false; break; } - } - ActorPack = TMailboxActorPack::Simple; + } + ActorPack = TMailboxActorPack::Simple; ActorsInfo.Simple.ActorId = 0; ActorsInfo.Simple.Actor = nullptr; - return done; - } - - std::pair<ui32, ui32> TMailboxHeader::CountMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - switch (Type) { - case TMailboxType::Simple: - return static_cast<TMailboxTable::TSimpleMailbox*>(this)->CountSimpleMailboxEvents(localActorId, maxTraverse); - case TMailboxType::Revolving: - return static_cast<TMailboxTable::TRevolvingMailbox*>(this)->CountRevolvingMailboxEvents(localActorId, maxTraverse); - default: - return {0, 0}; - } - } - - TMailboxTable::TSimpleMailbox::TSimpleMailbox() - : TMailboxHeader(TMailboxType::Simple) - , ScheduleMoment(0) - { - } - - TMailboxTable::TSimpleMailbox::~TSimpleMailbox() { - CleanupEvents(); - } - - bool TMailboxTable::TSimpleMailbox::CleanupEvents() { - const bool done = (Queue.Head() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - - std::pair<ui32, ui32> TMailboxTable::TSimpleMailbox::CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - ui32 local = 0; - ui32 total = 0; - - auto it = Queue.ReadIterator(); - while (IEventHandle* x = it.Next()) { - ++total; - if (x->GetRecipientRewrite().LocalId() == localActorId) - ++local; - if (total >= maxTraverse) - break; - } - - return std::make_pair(local, total); - } - - TMailboxTable::TRevolvingMailbox::TRevolvingMailbox() - : TMailboxHeader(TMailboxType::Revolving) - , QueueWriter(QueueReader) - , Reserved1(0) - , Reserved2(0) - , ScheduleMoment(0) - { - } - - TMailboxTable::TRevolvingMailbox::~TRevolvingMailbox() { - CleanupEvents(); - } - - bool TMailboxTable::TRevolvingMailbox::CleanupEvents() { - const bool done = (QueueReader.Head() == nullptr); - while (IEventHandle* ev = QueueReader.Pop()) - delete ev; - return done; - } - - std::pair<ui32, ui32> TMailboxTable::TRevolvingMailbox::CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - ui32 local = 0; - ui32 total = 0; - - auto it = QueueReader.Iterator(); - - while (IEventHandle* x = it.Next()) { - ++total; - if (x->GetRecipientRewrite().LocalId() == localActorId) - ++local; - if (total >= maxTraverse) - break; - } - - return std::make_pair(local, total); - } - - template <typename T> - static ui32 InitNewLine(ui8* x, ui8* end) { - const ui32 sx = T::AlignedSize(); - - for (ui32 index = 1; x + sx <= end; x += sx, ++index) - ::new (x) T(); - - return sx; - } - - ui32 TMailboxTable::AllocateNewLine(TMailboxType::EType type) { - ui8* ptr = (ui8*)malloc(LineSize); - ui8* end = ptr + LineSize; - - const ui32 lineIndex = (ui32)AtomicIncrement(LastAllocatedLine) - 1; - const ui32 lineIndexMask = (lineIndex << LineIndexShift) & LineIndexMask; - - // first 64 bytes is TMailboxLineHeader - TMailboxLineHeader* header = ::new (ptr) TMailboxLineHeader(type, lineIndex); - - ui8* x = ptr + 64; - ui32 sx = 0; - TMailboxCache* cache = nullptr; - TAtomic* counter = nullptr; - - switch (type) { - case TMailboxType::Simple: - sx = InitNewLine<TSimpleMailbox>(x, end); - cache = &MailboxCacheSimple; - counter = &CachedSimpleMailboxes; - break; - case TMailboxType::Revolving: - sx = InitNewLine<TRevolvingMailbox>(x, end); - cache = &MailboxCacheRevolving; - counter = &CachedRevolvingMailboxes; - break; - case TMailboxType::HTSwap: - sx = InitNewLine<THTSwapMailbox>(x, end); - cache = &MailboxCacheHTSwap; - counter = &CachedHTSwapMailboxes; - break; - case TMailboxType::ReadAsFilled: - sx = InitNewLine<TReadAsFilledMailbox>(x, end); - cache = &MailboxCacheReadAsFilled; - counter = &CachedReadAsFilledMailboxes; - break; - case TMailboxType::TinyReadAsFilled: - sx = InitNewLine<TTinyReadAsFilledMailbox>(x, end); - cache = &MailboxCacheTinyReadAsFilled; - counter = &CachedTinyReadAsFilledMailboxes; - break; - default: - Y_FAIL(); - } - + return done; + } + + std::pair<ui32, ui32> TMailboxHeader::CountMailboxEvents(ui64 localActorId, ui32 maxTraverse) { + switch (Type) { + case TMailboxType::Simple: + return static_cast<TMailboxTable::TSimpleMailbox*>(this)->CountSimpleMailboxEvents(localActorId, maxTraverse); + case TMailboxType::Revolving: + return static_cast<TMailboxTable::TRevolvingMailbox*>(this)->CountRevolvingMailboxEvents(localActorId, maxTraverse); + default: + return {0, 0}; + } + } + + TMailboxTable::TSimpleMailbox::TSimpleMailbox() + : TMailboxHeader(TMailboxType::Simple) + , ScheduleMoment(0) + { + } + + TMailboxTable::TSimpleMailbox::~TSimpleMailbox() { + CleanupEvents(); + } + + bool TMailboxTable::TSimpleMailbox::CleanupEvents() { + const bool done = (Queue.Head() == nullptr); + while (IEventHandle* ev = Queue.Pop()) + delete ev; + return done; + } + + std::pair<ui32, ui32> TMailboxTable::TSimpleMailbox::CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse) { + ui32 local = 0; + ui32 total = 0; + + auto it = Queue.ReadIterator(); + while (IEventHandle* x = it.Next()) { + ++total; + if (x->GetRecipientRewrite().LocalId() == localActorId) + ++local; + if (total >= maxTraverse) + break; + } + + return std::make_pair(local, total); + } + + TMailboxTable::TRevolvingMailbox::TRevolvingMailbox() + : TMailboxHeader(TMailboxType::Revolving) + , QueueWriter(QueueReader) + , Reserved1(0) + , Reserved2(0) + , ScheduleMoment(0) + { + } + + TMailboxTable::TRevolvingMailbox::~TRevolvingMailbox() { + CleanupEvents(); + } + + bool TMailboxTable::TRevolvingMailbox::CleanupEvents() { + const bool done = (QueueReader.Head() == nullptr); + while (IEventHandle* ev = QueueReader.Pop()) + delete ev; + return done; + } + + std::pair<ui32, ui32> TMailboxTable::TRevolvingMailbox::CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse) { + ui32 local = 0; + ui32 total = 0; + + auto it = QueueReader.Iterator(); + + while (IEventHandle* x = it.Next()) { + ++total; + if (x->GetRecipientRewrite().LocalId() == localActorId) + ++local; + if (total >= maxTraverse) + break; + } + + return std::make_pair(local, total); + } + + template <typename T> + static ui32 InitNewLine(ui8* x, ui8* end) { + const ui32 sx = T::AlignedSize(); + + for (ui32 index = 1; x + sx <= end; x += sx, ++index) + ::new (x) T(); + + return sx; + } + + ui32 TMailboxTable::AllocateNewLine(TMailboxType::EType type) { + ui8* ptr = (ui8*)malloc(LineSize); + ui8* end = ptr + LineSize; + + const ui32 lineIndex = (ui32)AtomicIncrement(LastAllocatedLine) - 1; + const ui32 lineIndexMask = (lineIndex << LineIndexShift) & LineIndexMask; + + // first 64 bytes is TMailboxLineHeader + TMailboxLineHeader* header = ::new (ptr) TMailboxLineHeader(type, lineIndex); + + ui8* x = ptr + 64; + ui32 sx = 0; + TMailboxCache* cache = nullptr; + TAtomic* counter = nullptr; + + switch (type) { + case TMailboxType::Simple: + sx = InitNewLine<TSimpleMailbox>(x, end); + cache = &MailboxCacheSimple; + counter = &CachedSimpleMailboxes; + break; + case TMailboxType::Revolving: + sx = InitNewLine<TRevolvingMailbox>(x, end); + cache = &MailboxCacheRevolving; + counter = &CachedRevolvingMailboxes; + break; + case TMailboxType::HTSwap: + sx = InitNewLine<THTSwapMailbox>(x, end); + cache = &MailboxCacheHTSwap; + counter = &CachedHTSwapMailboxes; + break; + case TMailboxType::ReadAsFilled: + sx = InitNewLine<TReadAsFilledMailbox>(x, end); + cache = &MailboxCacheReadAsFilled; + counter = &CachedReadAsFilledMailboxes; + break; + case TMailboxType::TinyReadAsFilled: + sx = InitNewLine<TTinyReadAsFilledMailbox>(x, end); + cache = &MailboxCacheTinyReadAsFilled; + counter = &CachedTinyReadAsFilledMailboxes; + break; + default: + Y_FAIL(); + } + AtomicStore(Lines + lineIndex, header); - - ui32 ret = lineIndexMask | 1; - - ui32 index = 2; - for (ui32 endIndex = LineSize / sx; index != endIndex;) { - const ui32 bufSize = 8; - ui32 buf[bufSize]; - ui32 bufIndex; - for (bufIndex = 0; index != endIndex && bufIndex != bufSize; ++bufIndex, ++index) - buf[bufIndex] = lineIndexMask | index; - cache->PushBulk(buf, bufIndex, index); - AtomicAdd(*counter, bufIndex); - } - - AtomicAdd(AllocatedMailboxCount, index - 1); - - return ret; - } -} + + ui32 ret = lineIndexMask | 1; + + ui32 index = 2; + for (ui32 endIndex = LineSize / sx; index != endIndex;) { + const ui32 bufSize = 8; + ui32 buf[bufSize]; + ui32 bufIndex; + for (bufIndex = 0; index != endIndex && bufIndex != bufSize; ++bufIndex, ++index) + buf[bufIndex] = lineIndexMask | index; + cache->PushBulk(buf, bufIndex, index); + AtomicAdd(*counter, bufIndex); + } + + AtomicAdd(AllocatedMailboxCount, index - 1); + + return ret; + } +} diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h index 0bd9c4d314..3a9f070bc4 100644 --- a/library/cpp/actors/core/mailbox.h +++ b/library/cpp/actors/core/mailbox.h @@ -1,64 +1,64 @@ -#pragma once - -#include "defs.h" -#include "event.h" -#include "actor.h" -#include "mailbox_queue_simple.h" -#include "mailbox_queue_revolving.h" +#pragma once + +#include "defs.h" +#include "event.h" +#include "actor.h" +#include "mailbox_queue_simple.h" +#include "mailbox_queue_revolving.h" #include <library/cpp/actors/util/unordered_cache.h> #include <library/cpp/threading/queue/mpsc_htswap.h> #include <library/cpp/threading/queue/mpsc_read_as_filled.h> #include <util/generic/hash.h> -#include <util/system/hp_timer.h> +#include <util/system/hp_timer.h> #include <util/generic/ptr.h> -// TODO: clean all broken arcadia atomic stuff and replace with intrinsics - -namespace NActors { - class IActor; - class IExecutorPool; - +// TODO: clean all broken arcadia atomic stuff and replace with intrinsics + +namespace NActors { + class IActor; + class IExecutorPool; + const ui64 ARRAY_CAPACITY = 8; - // structure of hint: - // 1 bit: is service or direct hint - // 2 bits: pool index - // 17 bits: line - // 12 bits: index of mailbox inside of line - - struct TMailboxHeader { - struct TMailboxActorPack { - enum EType { - Simple = 0, + // structure of hint: + // 1 bit: is service or direct hint + // 2 bits: pool index + // 17 bits: line + // 12 bits: index of mailbox inside of line + + struct TMailboxHeader { + struct TMailboxActorPack { + enum EType { + Simple = 0, Array = 1, Map = 2 - }; - }; - + }; + }; + using TActorMap = THashMap<ui64, IActor*>; - - struct TExecutionState { - enum EState { - // normal states - Inactive = 0, - Scheduled = 1, - Leaving = 2, - Executing = 3, - LeavingMarked = 4, - // states for free mailboxes (they can still be scheduled so we need duplicates) - Free = 5, - FreeScheduled = 6, - FreeLeaving = 7, - FreeExecuting = 8, - FreeLeavingMarked = 9, - }; - }; - - volatile ui32 ExecutionState; + + struct TExecutionState { + enum EState { + // normal states + Inactive = 0, + Scheduled = 1, + Leaving = 2, + Executing = 3, + LeavingMarked = 4, + // states for free mailboxes (they can still be scheduled so we need duplicates) + Free = 5, + FreeScheduled = 6, + FreeLeaving = 7, + FreeExecuting = 8, + FreeLeavingMarked = 9, + }; + }; + + volatile ui32 ExecutionState; ui32 Reserved : 4; // never changes, always zero - ui32 Type : 4; // never changes - ui32 ActorPack : 2; - ui32 Knobs : 22; - + ui32 Type : 4; // never changes + ui32 ActorPack : 2; + ui32 Knobs : 22; + struct TActorPair { IActor *Actor; ui64 ActorId; @@ -79,26 +79,26 @@ namespace NActors { } Map; } ActorsInfo; - TMailboxHeader(TMailboxType::EType type); - ~TMailboxHeader(); - - bool CleanupActors(); - - // this interface is used exclusively by executor thread, so implementation is there - - bool MarkForSchedule(); // we put something in queue, check should we schedule? - - bool LockForExecution(); // we got activation, try to lock mailbox - bool LockFromFree(); // try to claim mailbox from recycled (could fail if other thread process garbage) - - void UnlockFromExecution1(); // prepare for releasing lock - bool UnlockFromExecution2(bool wouldReschedule); // proceed with releasing lock - bool UnlockAsFree(bool wouldReschedule); // preceed with releasing lock, but mark as free one - + TMailboxHeader(TMailboxType::EType type); + ~TMailboxHeader(); + + bool CleanupActors(); + + // this interface is used exclusively by executor thread, so implementation is there + + bool MarkForSchedule(); // we put something in queue, check should we schedule? + + bool LockForExecution(); // we got activation, try to lock mailbox + bool LockFromFree(); // try to claim mailbox from recycled (could fail if other thread process garbage) + + void UnlockFromExecution1(); // prepare for releasing lock + bool UnlockFromExecution2(bool wouldReschedule); // proceed with releasing lock + bool UnlockAsFree(bool wouldReschedule); // preceed with releasing lock, but mark as free one + bool IsEmpty() const noexcept { return (ActorPack == TMailboxActorPack::Simple && ActorsInfo.Simple.ActorId == 0); - } - + } + template<typename T> void ForEach(T&& callback) noexcept { switch (ActorPack) { @@ -124,16 +124,16 @@ namespace NActors { } IActor* FindActor(ui64 localActorId) noexcept { - switch (ActorPack) { + switch (ActorPack) { case TMailboxActorPack::Simple: { if (ActorsInfo.Simple.ActorId == localActorId) return ActorsInfo.Simple.Actor; - break; + break; } - case TMailboxActorPack::Map: { + case TMailboxActorPack::Map: { TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId); if (it != ActorsInfo.Map.ActorsMap->end()) - return it->second; + return it->second; break; } case TMailboxActorPack::Array: { @@ -144,20 +144,20 @@ namespace NActors { } break; } - default: - Y_FAIL(); - } - return nullptr; - } - + default: + Y_FAIL(); + } + return nullptr; + } + void AttachActor(ui64 localActorId, IActor* actor) noexcept { - switch (ActorPack) { + switch (ActorPack) { case TMailboxActorPack::Simple: { if (ActorsInfo.Simple.ActorId == 0) { ActorsInfo.Simple.ActorId = localActorId; ActorsInfo.Simple.Actor = actor; - return; - } else { + return; + } else { auto ar = new TActorArray; ar->Actors[0] = ActorsInfo.Simple; ar->Actors[1] = TActorPair{actor, localActorId}; @@ -184,35 +184,35 @@ namespace NActors { ActorsInfo.Map.ActorsMap = mp; } else { ActorsInfo.Array.ActorsArray->Actors[ActorsInfo.Array.ActorsCount++] = TActorPair{actor, localActorId}; - } - break; + } + break; } - default: - Y_FAIL(); - } - } - + default: + Y_FAIL(); + } + } + IActor* DetachActor(ui64 localActorId) noexcept { - Y_VERIFY_DEBUG(FindActor(localActorId) != nullptr); - - IActor* actorToDestruct = nullptr; - - switch (ActorPack) { + Y_VERIFY_DEBUG(FindActor(localActorId) != nullptr); + + IActor* actorToDestruct = nullptr; + + switch (ActorPack) { case TMailboxActorPack::Simple: { Y_VERIFY(ActorsInfo.Simple.ActorId == localActorId); actorToDestruct = ActorsInfo.Simple.Actor; - + ActorsInfo.Simple.ActorId = 0; ActorsInfo.Simple.Actor = nullptr; - break; + break; } - case TMailboxActorPack::Map: { + case TMailboxActorPack::Map: { TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId); Y_VERIFY(it != ActorsInfo.Map.ActorsMap->end()); - - actorToDestruct = it->second; + + actorToDestruct = it->second; ActorsInfo.Map.ActorsMap->erase(it); - + if (ActorsInfo.Map.ActorsMap->size() == ARRAY_CAPACITY) { auto ar = new TActorArray; ui64 i = 0; @@ -242,312 +242,312 @@ namespace NActors { if (ActorsInfo.Array.ActorsCount == 1) { const TActorPair Actor = ActorsInfo.Array.ActorsArray->Actors[0]; delete ActorsInfo.Array.ActorsArray; - ActorPack = TMailboxActorPack::Simple; + ActorPack = TMailboxActorPack::Simple; ActorsInfo.Simple = Actor; - } + } break; } - } - - return actorToDestruct; - } - - std::pair<ui32, ui32> CountMailboxEvents(ui64 localActorId, ui32 maxTraverse); - }; - - class TMailboxTable : TNonCopyable { - private: - struct TMailboxLineHeader { - const TMailboxType::EType MailboxType; - const ui32 Index; - // some more stuff in first cache line, then goes mailboxes - ui8 Padding[52]; - - TMailboxLineHeader(TMailboxType::EType type, ui32 index) - : MailboxType(type) - , Index(index) - { - } - }; - static_assert(sizeof(TMailboxLineHeader) <= 64, "expect sizeof(TMailboxLineHeader) <= 64"); - - constexpr static ui64 MaxLines = 131000; // somewhat less then 2^17. - constexpr static ui64 LineSize = 262144; // 64 * 2^12. - - TAtomic LastAllocatedLine; - TAtomic AllocatedMailboxCount; - + } + + return actorToDestruct; + } + + std::pair<ui32, ui32> CountMailboxEvents(ui64 localActorId, ui32 maxTraverse); + }; + + class TMailboxTable : TNonCopyable { + private: + struct TMailboxLineHeader { + const TMailboxType::EType MailboxType; + const ui32 Index; + // some more stuff in first cache line, then goes mailboxes + ui8 Padding[52]; + + TMailboxLineHeader(TMailboxType::EType type, ui32 index) + : MailboxType(type) + , Index(index) + { + } + }; + static_assert(sizeof(TMailboxLineHeader) <= 64, "expect sizeof(TMailboxLineHeader) <= 64"); + + constexpr static ui64 MaxLines = 131000; // somewhat less then 2^17. + constexpr static ui64 LineSize = 262144; // 64 * 2^12. + + TAtomic LastAllocatedLine; + TAtomic AllocatedMailboxCount; + typedef TUnorderedCache<ui32, 512, 4> TMailboxCache; - TMailboxCache MailboxCacheSimple; - TAtomic CachedSimpleMailboxes; - TMailboxCache MailboxCacheRevolving; - TAtomic CachedRevolvingMailboxes; - TMailboxCache MailboxCacheHTSwap; - TAtomic CachedHTSwapMailboxes; - TMailboxCache MailboxCacheReadAsFilled; - TAtomic CachedReadAsFilledMailboxes; - TMailboxCache MailboxCacheTinyReadAsFilled; - TAtomic CachedTinyReadAsFilledMailboxes; - - // and here goes large chunk of lines - // presented as array of static size to avoid sync on access - TMailboxLineHeader* volatile Lines[MaxLines]; - - ui32 AllocateNewLine(TMailboxType::EType type); - ui32 TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); - - public: - TMailboxTable(); - ~TMailboxTable(); - - bool Cleanup(); // returns true if nothing found to destruct (so nothing new is possible to be created) - - static const ui32 LineIndexShift = 12; - static const ui32 LineIndexMask = 0x1FFFFu << LineIndexShift; - static const ui32 LineHintMask = 0xFFFu; + TMailboxCache MailboxCacheSimple; + TAtomic CachedSimpleMailboxes; + TMailboxCache MailboxCacheRevolving; + TAtomic CachedRevolvingMailboxes; + TMailboxCache MailboxCacheHTSwap; + TAtomic CachedHTSwapMailboxes; + TMailboxCache MailboxCacheReadAsFilled; + TAtomic CachedReadAsFilledMailboxes; + TMailboxCache MailboxCacheTinyReadAsFilled; + TAtomic CachedTinyReadAsFilledMailboxes; + + // and here goes large chunk of lines + // presented as array of static size to avoid sync on access + TMailboxLineHeader* volatile Lines[MaxLines]; + + ui32 AllocateNewLine(TMailboxType::EType type); + ui32 TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); + + public: + TMailboxTable(); + ~TMailboxTable(); + + bool Cleanup(); // returns true if nothing found to destruct (so nothing new is possible to be created) + + static const ui32 LineIndexShift = 12; + static const ui32 LineIndexMask = 0x1FFFFu << LineIndexShift; + static const ui32 LineHintMask = 0xFFFu; static const ui32 PoolIndexShift = TActorId::PoolIndexShift; static const ui32 PoolIndexMask = TActorId::PoolIndexMask; - - static ui32 LineIndex(ui32 hint) { - return ((hint & LineIndexMask) >> LineIndexShift); - } - static ui32 PoolIndex(ui32 hint) { + + static ui32 LineIndex(ui32 hint) { + return ((hint & LineIndexMask) >> LineIndexShift); + } + static ui32 PoolIndex(ui32 hint) { return TActorId::PoolIndex(hint); - } - - TMailboxHeader* Get(ui32 hint); - ui32 AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); - void ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter); - ui64 GetAllocatedMailboxCount() const { - return RelaxedLoad(&AllocatedMailboxCount); - } - - bool SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - - struct TSimpleMailbox: public TMailboxHeader { - // 4 bytes - state - // 4 bytes - knobs - // 8 bytes - actorid - // 8 bytes - actor* - TSimpleMailboxQueue<IEventHandle*, 64> Queue; // 24 + 8 bytes (body, lock) - NHPTimer::STime ScheduleMoment; - - TSimpleMailbox(); - ~TSimpleMailbox(); - - IEventHandle* Pop() { - return Queue.Pop(); - } - IEventHandle* Head() { - return Queue.Head(); - } - - static TSimpleMailbox* Get(ui32 hint, void* line) { - return (TSimpleMailbox*)((ui8*)line + hint * 64); // - } - static const TMailboxType::EType MailboxType = TMailboxType::Simple; - constexpr static ui32 AlignedSize() { - return ((sizeof(TSimpleMailbox) + 63) / 64) * 64; - } - - std::pair<ui32, ui32> CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse); - bool CleanupEvents(); - }; - - static_assert(sizeof(TSimpleMailbox) == 64, "expect sizeof(TSimpleMailbox) == 64"); - - struct TRevolvingMailbox: public TMailboxHeader { - // 4 bytes - state - // 4 bytes - knobs - // 8 bytes - actorid - // 8 bytes - actor* - TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TReader QueueReader; // 8 * 3 + 4 * 3 + (padding): 40 bytes - // here goes next cache-line, so less writers<-> reader interference - TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TWriter QueueWriter; // 8 * 3 + 4 * 3 + 8 : 48 bytes - ui32 Reserved1; - ui32 Reserved2; - NHPTimer::STime ScheduleMoment; - - TRevolvingMailbox(); - ~TRevolvingMailbox(); - - IEventHandle* Pop() { - return QueueReader.Pop(); - } - IEventHandle* Head() { - return QueueReader.Head(); - } - - static TRevolvingMailbox* Get(ui32 hint, void* line) { - return (TRevolvingMailbox*)((ui8*)line + 64 + (hint - 1) * 128); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - static const TMailboxType::EType MailboxType = TMailboxType::Revolving; - constexpr static ui32 AlignedSize() { - return ((sizeof(TRevolvingMailbox) + 63) / 64) * 64; - } - - std::pair<ui32, ui32> CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse); - bool CleanupEvents(); - }; - - static_assert(sizeof(TRevolvingMailbox) == 128, "expect sizeof(TRevolvingMailbox) == 128"); - - struct THTSwapMailbox: public TMailboxHeader { + } + + TMailboxHeader* Get(ui32 hint); + ui32 AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); + void ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter); + ui64 GetAllocatedMailboxCount() const { + return RelaxedLoad(&AllocatedMailboxCount); + } + + bool SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); + + struct TSimpleMailbox: public TMailboxHeader { + // 4 bytes - state + // 4 bytes - knobs + // 8 bytes - actorid + // 8 bytes - actor* + TSimpleMailboxQueue<IEventHandle*, 64> Queue; // 24 + 8 bytes (body, lock) + NHPTimer::STime ScheduleMoment; + + TSimpleMailbox(); + ~TSimpleMailbox(); + + IEventHandle* Pop() { + return Queue.Pop(); + } + IEventHandle* Head() { + return Queue.Head(); + } + + static TSimpleMailbox* Get(ui32 hint, void* line) { + return (TSimpleMailbox*)((ui8*)line + hint * 64); // + } + static const TMailboxType::EType MailboxType = TMailboxType::Simple; + constexpr static ui32 AlignedSize() { + return ((sizeof(TSimpleMailbox) + 63) / 64) * 64; + } + + std::pair<ui32, ui32> CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse); + bool CleanupEvents(); + }; + + static_assert(sizeof(TSimpleMailbox) == 64, "expect sizeof(TSimpleMailbox) == 64"); + + struct TRevolvingMailbox: public TMailboxHeader { + // 4 bytes - state + // 4 bytes - knobs + // 8 bytes - actorid + // 8 bytes - actor* + TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TReader QueueReader; // 8 * 3 + 4 * 3 + (padding): 40 bytes + // here goes next cache-line, so less writers<-> reader interference + TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TWriter QueueWriter; // 8 * 3 + 4 * 3 + 8 : 48 bytes + ui32 Reserved1; + ui32 Reserved2; + NHPTimer::STime ScheduleMoment; + + TRevolvingMailbox(); + ~TRevolvingMailbox(); + + IEventHandle* Pop() { + return QueueReader.Pop(); + } + IEventHandle* Head() { + return QueueReader.Head(); + } + + static TRevolvingMailbox* Get(ui32 hint, void* line) { + return (TRevolvingMailbox*)((ui8*)line + 64 + (hint - 1) * 128); + } + + constexpr static ui64 MaxMailboxesInLine() { + return (LineSize - 64) / AlignedSize(); + } + static const TMailboxType::EType MailboxType = TMailboxType::Revolving; + constexpr static ui32 AlignedSize() { + return ((sizeof(TRevolvingMailbox) + 63) / 64) * 64; + } + + std::pair<ui32, ui32> CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse); + bool CleanupEvents(); + }; + + static_assert(sizeof(TRevolvingMailbox) == 128, "expect sizeof(TRevolvingMailbox) == 128"); + + struct THTSwapMailbox: public TMailboxHeader { using TQueueType = NThreading::THTSwapQueue<IEventHandle*>; TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[16]; + NHPTimer::STime ScheduleMoment; + char Padding_[16]; - THTSwapMailbox() - : TMailboxHeader(TMailboxType::HTSwap) - , ScheduleMoment(0) - { - } + THTSwapMailbox() + : TMailboxHeader(TMailboxType::HTSwap) + , ScheduleMoment(0) + { + } - ~THTSwapMailbox() { - CleanupEvents(); - } + ~THTSwapMailbox() { + CleanupEvents(); + } - IEventHandle* Pop() { - return Queue.Pop(); - } + IEventHandle* Pop() { + return Queue.Pop(); + } - IEventHandle* Head() { - return Queue.Peek(); - } + IEventHandle* Head() { + return Queue.Peek(); + } - static THTSwapMailbox* Get(ui32 hint, void* line) { - return (THTSwapMailbox*)((ui8*)line + 64 + (hint - 1) * 64); - } + static THTSwapMailbox* Get(ui32 hint, void* line) { + return (THTSwapMailbox*)((ui8*)line + 64 + (hint - 1) * 64); + } - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } + constexpr static ui64 MaxMailboxesInLine() { + return (LineSize - 64) / AlignedSize(); + } - static const TMailboxType::EType MailboxType = TMailboxType::HTSwap; + static const TMailboxType::EType MailboxType = TMailboxType::HTSwap; - constexpr static ui32 AlignedSize() { - return ((sizeof(THTSwapMailbox) + 63) / 64) * 64; - } + constexpr static ui32 AlignedSize() { + return ((sizeof(THTSwapMailbox) + 63) / 64) * 64; + } - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; + bool CleanupEvents() { + const bool done = (Queue.Peek() == nullptr); + while (IEventHandle* ev = Queue.Pop()) + delete ev; + return done; + } + }; - static_assert(sizeof(THTSwapMailbox) == 64, - "expect sizeof(THTSwapMailbox) == 64"); + static_assert(sizeof(THTSwapMailbox) == 64, + "expect sizeof(THTSwapMailbox) == 64"); - struct TReadAsFilledMailbox: public TMailboxHeader { + struct TReadAsFilledMailbox: public TMailboxHeader { using TQueueType = NThreading::TReadAsFilledQueue<IEventHandle>; TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[8]; - - TReadAsFilledMailbox() - : TMailboxHeader(TMailboxType::ReadAsFilled) - , ScheduleMoment(0) - { - } - - ~TReadAsFilledMailbox() { - CleanupEvents(); - } - - IEventHandle* Pop() { - return Queue.Pop(); - } - - IEventHandle* Head() { - return Queue.Peek(); - } - - static TReadAsFilledMailbox* Get(ui32 hint, void* line) { - return (TReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - - static const TMailboxType::EType MailboxType = - TMailboxType::ReadAsFilled; - - constexpr static ui32 AlignedSize() { - return ((sizeof(TReadAsFilledMailbox) + 63) / 64) * 64; - } - - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; - - static_assert(sizeof(TReadAsFilledMailbox) == 192, - "expect sizeof(TReadAsFilledMailbox) == 192"); - - struct TTinyReadAsFilledMailbox: public TMailboxHeader { + NHPTimer::STime ScheduleMoment; + char Padding_[8]; + + TReadAsFilledMailbox() + : TMailboxHeader(TMailboxType::ReadAsFilled) + , ScheduleMoment(0) + { + } + + ~TReadAsFilledMailbox() { + CleanupEvents(); + } + + IEventHandle* Pop() { + return Queue.Pop(); + } + + IEventHandle* Head() { + return Queue.Peek(); + } + + static TReadAsFilledMailbox* Get(ui32 hint, void* line) { + return (TReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192); + } + + constexpr static ui64 MaxMailboxesInLine() { + return (LineSize - 64) / AlignedSize(); + } + + static const TMailboxType::EType MailboxType = + TMailboxType::ReadAsFilled; + + constexpr static ui32 AlignedSize() { + return ((sizeof(TReadAsFilledMailbox) + 63) / 64) * 64; + } + + bool CleanupEvents() { + const bool done = (Queue.Peek() == nullptr); + while (IEventHandle* ev = Queue.Pop()) + delete ev; + return done; + } + }; + + static_assert(sizeof(TReadAsFilledMailbox) == 192, + "expect sizeof(TReadAsFilledMailbox) == 192"); + + struct TTinyReadAsFilledMailbox: public TMailboxHeader { using TQueueType = NThreading::TReadAsFilledQueue< - IEventHandle, - NThreading::TRaFQueueBunchSize<4>>; + IEventHandle, + NThreading::TRaFQueueBunchSize<4>>; TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[8]; - - TTinyReadAsFilledMailbox() - : TMailboxHeader(TMailboxType::TinyReadAsFilled) - , ScheduleMoment(0) - { - } - - ~TTinyReadAsFilledMailbox() { - CleanupEvents(); - } - - IEventHandle* Pop() { - return Queue.Pop(); - } - - IEventHandle* Head() { - return Queue.Peek(); - } - - static TTinyReadAsFilledMailbox* Get(ui32 hint, void* line) { - return (TTinyReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - - static const TMailboxType::EType MailboxType = - TMailboxType::TinyReadAsFilled; - - constexpr static ui32 AlignedSize() { - return ((sizeof(TTinyReadAsFilledMailbox) + 63) / 64) * 64; - } - - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; - - static_assert(sizeof(TTinyReadAsFilledMailbox) == 192, - "expect sizeof(TTinyReadAsFilledMailbox) == 192"); + NHPTimer::STime ScheduleMoment; + char Padding_[8]; + + TTinyReadAsFilledMailbox() + : TMailboxHeader(TMailboxType::TinyReadAsFilled) + , ScheduleMoment(0) + { + } + + ~TTinyReadAsFilledMailbox() { + CleanupEvents(); + } + + IEventHandle* Pop() { + return Queue.Pop(); + } + + IEventHandle* Head() { + return Queue.Peek(); + } + + static TTinyReadAsFilledMailbox* Get(ui32 hint, void* line) { + return (TTinyReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192); + } + + constexpr static ui64 MaxMailboxesInLine() { + return (LineSize - 64) / AlignedSize(); + } + + static const TMailboxType::EType MailboxType = + TMailboxType::TinyReadAsFilled; + + constexpr static ui32 AlignedSize() { + return ((sizeof(TTinyReadAsFilledMailbox) + 63) / 64) * 64; + } + + bool CleanupEvents() { + const bool done = (Queue.Peek() == nullptr); + while (IEventHandle* ev = Queue.Pop()) + delete ev; + return done; + } + }; + + static_assert(sizeof(TTinyReadAsFilledMailbox) == 192, + "expect sizeof(TTinyReadAsFilledMailbox) == 192"); }; -} +} diff --git a/library/cpp/actors/core/mailbox_queue_revolving.h b/library/cpp/actors/core/mailbox_queue_revolving.h index b0e78a18db..49eed7ad7c 100644 --- a/library/cpp/actors/core/mailbox_queue_revolving.h +++ b/library/cpp/actors/core/mailbox_queue_revolving.h @@ -1,214 +1,214 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include <library/cpp/actors/util/queue_chunk.h> - -namespace NActors { - // add some concurrency to basic queue to avoid hangs under contention (we pay with memory, so use only when really expect contention) - // ordering: every completed push guarantied to seen before any not-yet-initiated push. parallel pushes could reorder (and that is natural for concurrent queues). - // try to place reader/writer on different cache-lines to avoid congestion b/w reader and writers. - // if strict ordering does not matter - look at TManyOneQueue. - - template <typename T, ui32 TWriteConcurrency = 3, ui32 TSize = 128> - class TRevolvingMailboxQueue { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); - - struct TValTagPair { - volatile T Value; - volatile ui64 Tag; - }; - - typedef TQueueChunk<TValTagPair, TSize> TChunk; - - static_assert(sizeof(TAtomic) == sizeof(TChunk*), "expect sizeof(TAtomic) == sizeof(TChunk*)"); - static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); - - public: - class TWriter; - - class TReader { - TChunk* ReadFrom[TWriteConcurrency]; - ui32 ReadPosition[TWriteConcurrency]; - - friend class TRevolvingMailboxQueue<T, TWriteConcurrency, TSize>::TWriter; // for access to ReadFrom in constructor - - bool ChunkHead(ui32 idx, ui64* tag, T* value) { - TChunk* head = ReadFrom[idx]; - const ui32 pos = ReadPosition[idx]; - if (pos != TChunk::EntriesCount) { - if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { - const ui64 xtag = head->Entries[pos].Tag; - if (xtag < *tag) { - *value = xval; - *tag = xtag; - return true; - } - } - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom[idx] = next; - delete head; - ReadPosition[idx] = 0; - return ChunkHead(idx, tag, value); - } - - return false; - } - - T Head(bool pop) { - ui64 tag = Max<ui64>(); + +namespace NActors { + // add some concurrency to basic queue to avoid hangs under contention (we pay with memory, so use only when really expect contention) + // ordering: every completed push guarantied to seen before any not-yet-initiated push. parallel pushes could reorder (and that is natural for concurrent queues). + // try to place reader/writer on different cache-lines to avoid congestion b/w reader and writers. + // if strict ordering does not matter - look at TManyOneQueue. + + template <typename T, ui32 TWriteConcurrency = 3, ui32 TSize = 128> + class TRevolvingMailboxQueue { + static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); + + struct TValTagPair { + volatile T Value; + volatile ui64 Tag; + }; + + typedef TQueueChunk<TValTagPair, TSize> TChunk; + + static_assert(sizeof(TAtomic) == sizeof(TChunk*), "expect sizeof(TAtomic) == sizeof(TChunk*)"); + static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); + + public: + class TWriter; + + class TReader { + TChunk* ReadFrom[TWriteConcurrency]; + ui32 ReadPosition[TWriteConcurrency]; + + friend class TRevolvingMailboxQueue<T, TWriteConcurrency, TSize>::TWriter; // for access to ReadFrom in constructor + + bool ChunkHead(ui32 idx, ui64* tag, T* value) { + TChunk* head = ReadFrom[idx]; + const ui32 pos = ReadPosition[idx]; + if (pos != TChunk::EntriesCount) { + if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { + const ui64 xtag = head->Entries[pos].Tag; + if (xtag < *tag) { + *value = xval; + *tag = xtag; + return true; + } + } + } else if (TChunk* next = AtomicLoad(&head->Next)) { + ReadFrom[idx] = next; + delete head; + ReadPosition[idx] = 0; + return ChunkHead(idx, tag, value); + } + + return false; + } + + T Head(bool pop) { + ui64 tag = Max<ui64>(); T ret = T{}; - ui32 idx = 0; - - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - - // w/o second pass we could reorder updates with 'already scanned' range - if (ret) { - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - } - - if (pop && ret) - ++ReadPosition[idx]; - - return ret; - } - - public: - TReader() { - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - ReadFrom[i] = new TChunk(); - ReadPosition[i] = 0; - } - } - - ~TReader() { - Y_VERIFY_DEBUG(Head() == 0); - for (ui32 i = 0; i < TWriteConcurrency; ++i) - delete ReadFrom[i]; - } - - T Pop() { - return Head(true); - } - - T Head() { - return Head(false); - } - - class TReadIterator { - TChunk* ReadFrom[TWriteConcurrency]; - ui32 ReadPosition[TWriteConcurrency]; - - bool ChunkHead(ui32 idx, ui64* tag, T* value) { - TChunk* head = ReadFrom[idx]; - const ui32 pos = ReadPosition[idx]; - if (pos != TChunk::EntriesCount) { - if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { - const ui64 xtag = head->Entries[pos].Tag; - if (xtag < *tag) { - *value = xval; - *tag = xtag; - return true; - } - } - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom[idx] = next; - ReadPosition[idx] = 0; - return ChunkHead(idx, tag, value); - } - - return false; - } - - public: - TReadIterator(TChunk* const* readFrom, const ui32* readPosition) { - memcpy(ReadFrom, readFrom, TWriteConcurrency * sizeof(TChunk*)); - memcpy(ReadPosition, readPosition, TWriteConcurrency * sizeof(ui32)); - } - - T Next() { - ui64 tag = Max<ui64>(); - T ret = T{}; - ui32 idx = 0; - - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - - // w/o second pass we could reorder updates with 'already scanned' range - if (ret) { - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - } - - if (ret) - ++ReadPosition[idx]; - - return ret; - } - }; - - TReadIterator Iterator() const { - return TReadIterator(ReadFrom, ReadPosition); - } - }; - - class TWriter { - TChunk* volatile WriteTo[TWriteConcurrency]; - volatile ui64 Tag; - ui32 WritePosition[TWriteConcurrency]; - - public: - TWriter(const TReader& reader) - : Tag(0) - { - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - WriteTo[i] = reader.ReadFrom[i]; - WritePosition[i] = 0; - } - } - - bool TryPush(T x) { - Y_VERIFY(x != 0); - - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - if (RelaxedLoad(&WriteTo[i]) != nullptr) { - if (TChunk* writeTo = AtomicSwap(&WriteTo[i], nullptr)) { - const ui64 nextTag = AtomicIncrement(Tag); - Y_VERIFY_DEBUG(nextTag < Max<ui64>()); - const ui32 writePosition = WritePosition[i]; - if (writePosition != TChunk::EntriesCount) { - writeTo->Entries[writePosition].Tag = nextTag; - AtomicStore(&writeTo->Entries[writePosition].Value, x); - ++WritePosition[i]; - } else { - TChunk* next = new TChunk(); - next->Entries[0].Tag = nextTag; - next->Entries[0].Value = x; - AtomicStore(&writeTo->Next, next); - writeTo = next; - WritePosition[i] = 1; - } - AtomicStore(WriteTo + i, writeTo); - return true; - } - } - } - return false; - } - - ui32 Push(T x) { - ui32 spins = 0; - while (!TryPush(x)) { - ++spins; - SpinLockPause(); - } - return spins; - } - }; - }; -} + ui32 idx = 0; + + for (ui32 i = 0; i < TWriteConcurrency; ++i) + if (ChunkHead(i, &tag, &ret)) + idx = i; + + // w/o second pass we could reorder updates with 'already scanned' range + if (ret) { + for (ui32 i = 0; i < TWriteConcurrency; ++i) + if (ChunkHead(i, &tag, &ret)) + idx = i; + } + + if (pop && ret) + ++ReadPosition[idx]; + + return ret; + } + + public: + TReader() { + for (ui32 i = 0; i != TWriteConcurrency; ++i) { + ReadFrom[i] = new TChunk(); + ReadPosition[i] = 0; + } + } + + ~TReader() { + Y_VERIFY_DEBUG(Head() == 0); + for (ui32 i = 0; i < TWriteConcurrency; ++i) + delete ReadFrom[i]; + } + + T Pop() { + return Head(true); + } + + T Head() { + return Head(false); + } + + class TReadIterator { + TChunk* ReadFrom[TWriteConcurrency]; + ui32 ReadPosition[TWriteConcurrency]; + + bool ChunkHead(ui32 idx, ui64* tag, T* value) { + TChunk* head = ReadFrom[idx]; + const ui32 pos = ReadPosition[idx]; + if (pos != TChunk::EntriesCount) { + if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { + const ui64 xtag = head->Entries[pos].Tag; + if (xtag < *tag) { + *value = xval; + *tag = xtag; + return true; + } + } + } else if (TChunk* next = AtomicLoad(&head->Next)) { + ReadFrom[idx] = next; + ReadPosition[idx] = 0; + return ChunkHead(idx, tag, value); + } + + return false; + } + + public: + TReadIterator(TChunk* const* readFrom, const ui32* readPosition) { + memcpy(ReadFrom, readFrom, TWriteConcurrency * sizeof(TChunk*)); + memcpy(ReadPosition, readPosition, TWriteConcurrency * sizeof(ui32)); + } + + T Next() { + ui64 tag = Max<ui64>(); + T ret = T{}; + ui32 idx = 0; + + for (ui32 i = 0; i < TWriteConcurrency; ++i) + if (ChunkHead(i, &tag, &ret)) + idx = i; + + // w/o second pass we could reorder updates with 'already scanned' range + if (ret) { + for (ui32 i = 0; i < TWriteConcurrency; ++i) + if (ChunkHead(i, &tag, &ret)) + idx = i; + } + + if (ret) + ++ReadPosition[idx]; + + return ret; + } + }; + + TReadIterator Iterator() const { + return TReadIterator(ReadFrom, ReadPosition); + } + }; + + class TWriter { + TChunk* volatile WriteTo[TWriteConcurrency]; + volatile ui64 Tag; + ui32 WritePosition[TWriteConcurrency]; + + public: + TWriter(const TReader& reader) + : Tag(0) + { + for (ui32 i = 0; i != TWriteConcurrency; ++i) { + WriteTo[i] = reader.ReadFrom[i]; + WritePosition[i] = 0; + } + } + + bool TryPush(T x) { + Y_VERIFY(x != 0); + + for (ui32 i = 0; i != TWriteConcurrency; ++i) { + if (RelaxedLoad(&WriteTo[i]) != nullptr) { + if (TChunk* writeTo = AtomicSwap(&WriteTo[i], nullptr)) { + const ui64 nextTag = AtomicIncrement(Tag); + Y_VERIFY_DEBUG(nextTag < Max<ui64>()); + const ui32 writePosition = WritePosition[i]; + if (writePosition != TChunk::EntriesCount) { + writeTo->Entries[writePosition].Tag = nextTag; + AtomicStore(&writeTo->Entries[writePosition].Value, x); + ++WritePosition[i]; + } else { + TChunk* next = new TChunk(); + next->Entries[0].Tag = nextTag; + next->Entries[0].Value = x; + AtomicStore(&writeTo->Next, next); + writeTo = next; + WritePosition[i] = 1; + } + AtomicStore(WriteTo + i, writeTo); + return true; + } + } + } + return false; + } + + ui32 Push(T x) { + ui32 spins = 0; + while (!TryPush(x)) { + ++spins; + SpinLockPause(); + } + return spins; + } + }; + }; +} diff --git a/library/cpp/actors/core/mailbox_queue_simple.h b/library/cpp/actors/core/mailbox_queue_simple.h index 2e44c21adb..e600854f55 100644 --- a/library/cpp/actors/core/mailbox_queue_simple.h +++ b/library/cpp/actors/core/mailbox_queue_simple.h @@ -1,34 +1,34 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include <library/cpp/actors/util/ticket_lock.h> #include <library/cpp/actors/util/queue_oneone_inplace.h> - -namespace NActors { - // dead-simple one-one queue, based on serializability guaranties of x64 and ticket lock to ensure writer unicity. - template <typename T, ui32 TSize> - class TSimpleMailboxQueue { - TOneOneQueueInplace<T, TSize> Queue; - TTicketLock Lock; - - public: + +namespace NActors { + // dead-simple one-one queue, based on serializability guaranties of x64 and ticket lock to ensure writer unicity. + template <typename T, ui32 TSize> + class TSimpleMailboxQueue { + TOneOneQueueInplace<T, TSize> Queue; + TTicketLock Lock; + + public: ui32 Push(T x) noexcept { - const ui32 spins = Lock.Acquire(); - Queue.Push(x); - Lock.Release(); - return spins; - } - - T Head() { - return Queue.Head(); - } - - T Pop() { - return Queue.Pop(); - } - - typename TOneOneQueueInplace<T, TSize>::TReadIterator ReadIterator() { - return Queue.Iterator(); - } - }; -} + const ui32 spins = Lock.Acquire(); + Queue.Push(x); + Lock.Release(); + return spins; + } + + T Head() { + return Queue.Head(); + } + + T Pop() { + return Queue.Pop(); + } + + typename TOneOneQueueInplace<T, TSize>::TReadIterator ReadIterator() { + return Queue.Iterator(); + } + }; +} diff --git a/library/cpp/actors/core/mon.h b/library/cpp/actors/core/mon.h index c450f2338e..93dfbe28b1 100644 --- a/library/cpp/actors/core/mon.h +++ b/library/cpp/actors/core/mon.h @@ -20,7 +20,7 @@ namespace NActors { static_assert(End < EventSpaceEnd(NActors::TEvents::ES_MON), "expect End < EventSpaceEnd(NActors::TEvents::ES_MON)"); // request info from an actor in HTML format - struct TEvHttpInfo: public NActors::TEventLocal<TEvHttpInfo, HttpInfo> { + struct TEvHttpInfo: public NActors::TEventLocal<TEvHttpInfo, HttpInfo> { TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, int subReqId = 0) : Request(request) , SubRequestId(subReqId) @@ -41,7 +41,7 @@ namespace NActors { }; // base class for HTTP info response - struct IEvHttpInfoRes: public NActors::TEventLocal<IEvHttpInfoRes, HttpInfoRes> { + struct IEvHttpInfoRes: public NActors::TEventLocal<IEvHttpInfoRes, HttpInfoRes> { enum EContentType { Html, Custom, @@ -58,8 +58,8 @@ namespace NActors { }; // Ready to output HTML in TString - struct TEvHttpInfoRes: public IEvHttpInfoRes { - TEvHttpInfoRes(const TString& answer, int subReqId = 0, EContentType contentType = Html) + struct TEvHttpInfoRes: public IEvHttpInfoRes { + TEvHttpInfoRes(const TString& answer, int subReqId = 0, EContentType contentType = Html) : Answer(answer) , SubRequestId(subReqId) , ContentType(contentType) @@ -79,14 +79,14 @@ namespace NActors { const EContentType ContentType; }; - struct TEvRemoteHttpInfo: public NActors::TEventBase<TEvRemoteHttpInfo, RemoteHttpInfo> { - TEvRemoteHttpInfo() { - } + struct TEvRemoteHttpInfo: public NActors::TEventBase<TEvRemoteHttpInfo, RemoteHttpInfo> { + TEvRemoteHttpInfo() { + } TEvRemoteHttpInfo(const TString& query) : Query(query) - { - } + { + } TEvRemoteHttpInfo(const TString& query, HTTP_METHOD method) : Query(query) @@ -133,14 +133,14 @@ namespace NActors { } }; - struct TEvRemoteHttpInfoRes: public NActors::TEventBase<TEvRemoteHttpInfoRes, RemoteHttpInfoRes> { - TEvRemoteHttpInfoRes() { - } + struct TEvRemoteHttpInfoRes: public NActors::TEventBase<TEvRemoteHttpInfoRes, RemoteHttpInfoRes> { + TEvRemoteHttpInfoRes() { + } TEvRemoteHttpInfoRes(const TString& html) : Html(html) - { - } + { + } TString Html; @@ -165,14 +165,14 @@ namespace NActors { } }; - struct TEvRemoteJsonInfoRes: public NActors::TEventBase<TEvRemoteJsonInfoRes, RemoteJsonInfoRes> { - TEvRemoteJsonInfoRes() { - } + struct TEvRemoteJsonInfoRes: public NActors::TEventBase<TEvRemoteJsonInfoRes, RemoteJsonInfoRes> { + TEvRemoteJsonInfoRes() { + } TEvRemoteJsonInfoRes(const TString& json) : Json(json) - { - } + { + } TString Json; @@ -197,14 +197,14 @@ namespace NActors { } }; - struct TEvRemoteBinaryInfoRes: public NActors::TEventBase<TEvRemoteBinaryInfoRes, RemoteBinaryInfoRes> { - TEvRemoteBinaryInfoRes() { - } + struct TEvRemoteBinaryInfoRes: public NActors::TEventBase<TEvRemoteBinaryInfoRes, RemoteBinaryInfoRes> { + TEvRemoteBinaryInfoRes() { + } TEvRemoteBinaryInfoRes(const TString& blob) : Blob(blob) - { - } + { + } TString Blob; diff --git a/library/cpp/actors/core/mon_stats.h b/library/cpp/actors/core/mon_stats.h index d55552af0c..0f691d5125 100644 --- a/library/cpp/actors/core/mon_stats.h +++ b/library/cpp/actors/core/mon_stats.h @@ -7,33 +7,33 @@ namespace NActors { struct TLogHistogram : public NMonitoring::IHistogramSnapshot { - TLogHistogram() { + TLogHistogram() { memset(Buckets, 0, sizeof(Buckets)); - } + } - inline void Add(ui64 val, ui64 inc = 1) { - size_t ind = 0; + inline void Add(ui64 val, ui64 inc = 1) { + size_t ind = 0; #if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7 - asm volatile("" :: - : "memory"); + asm volatile("" :: + : "memory"); #endif if (val > 1) { ind = GetValueBitCount(val - 1); - } + } #if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7 - asm volatile("" :: - : "memory"); + asm volatile("" :: + : "memory"); #endif - RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); - RelaxedStore(&Buckets[ind], RelaxedLoad(&Buckets[ind]) + inc); - } - - void Aggregate(const TLogHistogram& other) { - const ui64 inc = RelaxedLoad(&other.TotalSamples); - RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); - for (size_t i = 0; i < Y_ARRAY_SIZE(Buckets); ++i) { - Buckets[i] += RelaxedLoad(&other.Buckets[i]); - } + RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); + RelaxedStore(&Buckets[ind], RelaxedLoad(&Buckets[ind]) + inc); + } + + void Aggregate(const TLogHistogram& other) { + const ui64 inc = RelaxedLoad(&other.TotalSamples); + RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); + for (size_t i = 0; i < Y_ARRAY_SIZE(Buckets); ++i) { + Buckets[i] += RelaxedLoad(&other.Buckets[i]); + } } // IHistogramSnapshot @@ -55,14 +55,14 @@ namespace NActors { } ui64 TotalSamples = 0; - ui64 Buckets[65]; - }; - - struct TExecutorPoolStats { - ui64 MaxUtilizationTime = 0; - }; - - struct TExecutorThreadStats { + ui64 Buckets[65]; + }; + + struct TExecutorPoolStats { + ui64 MaxUtilizationTime = 0; + }; + + struct TExecutorThreadStats { ui64 SentEvents = 0; ui64 ReceivedEvents = 0; ui64 PreemptedEvents = 0; // Number of events experienced hard preemption @@ -72,10 +72,10 @@ namespace NActors { NHPTimer::STime ElapsedTicks = 0; NHPTimer::STime ParkedTicks = 0; NHPTimer::STime BlockedTicks = 0; - TLogHistogram ActivationTimeHistogram; - TLogHistogram EventDeliveryTimeHistogram; - TLogHistogram EventProcessingCountHistogram; - TLogHistogram EventProcessingTimeHistogram; + TLogHistogram ActivationTimeHistogram; + TLogHistogram EventDeliveryTimeHistogram; + TLogHistogram EventProcessingCountHistogram; + TLogHistogram EventProcessingTimeHistogram; TVector<NHPTimer::STime> ElapsedTicksByActivity; TVector<ui64> ReceivedEventsByActivity; TVector<i64> ActorsAliveByActivity; // the sum should be positive, but per-thread might be negative @@ -87,61 +87,61 @@ namespace NActors { ui64 MailboxPushedOutByTime = 0; ui64 MailboxPushedOutByEventCount = 0; - TExecutorThreadStats(size_t activityVecSize = 1) // must be not empty as 0 used as default + TExecutorThreadStats(size_t activityVecSize = 1) // must be not empty as 0 used as default : ElapsedTicksByActivity(activityVecSize) , ReceivedEventsByActivity(activityVecSize) , ActorsAliveByActivity(activityVecSize) , ScheduledEventsByActivity(activityVecSize) {} - - template <typename T> + + template <typename T> static void AggregateOne(TVector<T>& self, const TVector<T>& other) { - const size_t selfSize = self.size(); - const size_t otherSize = other.size(); - if (selfSize < otherSize) - self.resize(otherSize); - for (size_t at = 0; at < otherSize; ++at) - self[at] += RelaxedLoad(&other[at]); - } - - void Aggregate(const TExecutorThreadStats& other) { - SentEvents += RelaxedLoad(&other.SentEvents); - ReceivedEvents += RelaxedLoad(&other.ReceivedEvents); + const size_t selfSize = self.size(); + const size_t otherSize = other.size(); + if (selfSize < otherSize) + self.resize(otherSize); + for (size_t at = 0; at < otherSize; ++at) + self[at] += RelaxedLoad(&other[at]); + } + + void Aggregate(const TExecutorThreadStats& other) { + SentEvents += RelaxedLoad(&other.SentEvents); + ReceivedEvents += RelaxedLoad(&other.ReceivedEvents); PreemptedEvents += RelaxedLoad(&other.PreemptedEvents); - NonDeliveredEvents += RelaxedLoad(&other.NonDeliveredEvents); - EmptyMailboxActivation += RelaxedLoad(&other.EmptyMailboxActivation); + NonDeliveredEvents += RelaxedLoad(&other.NonDeliveredEvents); + EmptyMailboxActivation += RelaxedLoad(&other.EmptyMailboxActivation); CpuNs += RelaxedLoad(&other.CpuNs); - ElapsedTicks += RelaxedLoad(&other.ElapsedTicks); - ParkedTicks += RelaxedLoad(&other.ParkedTicks); + ElapsedTicks += RelaxedLoad(&other.ElapsedTicks); + ParkedTicks += RelaxedLoad(&other.ParkedTicks); BlockedTicks += RelaxedLoad(&other.BlockedTicks); MailboxPushedOutBySoftPreemption += RelaxedLoad(&other.MailboxPushedOutBySoftPreemption); MailboxPushedOutByTime += RelaxedLoad(&other.MailboxPushedOutByTime); MailboxPushedOutByEventCount += RelaxedLoad(&other.MailboxPushedOutByEventCount); - ActivationTimeHistogram.Aggregate(other.ActivationTimeHistogram); - EventDeliveryTimeHistogram.Aggregate(other.EventDeliveryTimeHistogram); - EventProcessingCountHistogram.Aggregate(other.EventProcessingCountHistogram); - EventProcessingTimeHistogram.Aggregate(other.EventProcessingTimeHistogram); - - AggregateOne(ElapsedTicksByActivity, other.ElapsedTicksByActivity); - AggregateOne(ReceivedEventsByActivity, other.ReceivedEventsByActivity); - AggregateOne(ActorsAliveByActivity, other.ActorsAliveByActivity); + ActivationTimeHistogram.Aggregate(other.ActivationTimeHistogram); + EventDeliveryTimeHistogram.Aggregate(other.EventDeliveryTimeHistogram); + EventProcessingCountHistogram.Aggregate(other.EventProcessingCountHistogram); + EventProcessingTimeHistogram.Aggregate(other.EventProcessingTimeHistogram); + + AggregateOne(ElapsedTicksByActivity, other.ElapsedTicksByActivity); + AggregateOne(ReceivedEventsByActivity, other.ReceivedEventsByActivity); + AggregateOne(ActorsAliveByActivity, other.ActorsAliveByActivity); AggregateOne(ScheduledEventsByActivity, other.ScheduledEventsByActivity); - - RelaxedStore( - &PoolActorRegistrations, - std::max(RelaxedLoad(&PoolActorRegistrations), RelaxedLoad(&other.PoolActorRegistrations))); - RelaxedStore( - &PoolDestroyedActors, - std::max(RelaxedLoad(&PoolDestroyedActors), RelaxedLoad(&other.PoolDestroyedActors))); - RelaxedStore( - &PoolAllocatedMailboxes, - std::max(RelaxedLoad(&PoolAllocatedMailboxes), RelaxedLoad(&other.PoolAllocatedMailboxes))); - } - - size_t MaxActivityType() const { - return ActorsAliveByActivity.size(); - } - }; + + RelaxedStore( + &PoolActorRegistrations, + std::max(RelaxedLoad(&PoolActorRegistrations), RelaxedLoad(&other.PoolActorRegistrations))); + RelaxedStore( + &PoolDestroyedActors, + std::max(RelaxedLoad(&PoolDestroyedActors), RelaxedLoad(&other.PoolDestroyedActors))); + RelaxedStore( + &PoolAllocatedMailboxes, + std::max(RelaxedLoad(&PoolAllocatedMailboxes), RelaxedLoad(&other.PoolAllocatedMailboxes))); + } + + size_t MaxActivityType() const { + return ActorsAliveByActivity.size(); + } + }; } diff --git a/library/cpp/actors/core/probes.h b/library/cpp/actors/core/probes.h index 4912d6dd26..44abe77d5d 100644 --- a/library/cpp/actors/core/probes.h +++ b/library/cpp/actors/core/probes.h @@ -7,22 +7,22 @@ #define LWTYPE_ACTORID ui64, ui64, ui32, ui32 #define LWNAME_ACTORID(n) n "Raw1", n "Raw2", n "NodeId", n "PoolId" -#define ACTORLIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(SlowEvent, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double, TString, TString, TString), \ - NAMES("poolId", "eventMs", "eventType", "actorId", "actorType")) \ - PROBE(EventSlowDelivery, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double, double, ui64, TString, TString, TString), \ - NAMES("poolId", "deliveryMs", "sinceActivationMs", "eventProcessedBefore", "eventType", "actorId", "actorType")) \ - PROBE(SlowActivation, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "activationMs")) \ - PROBE(SlowRegisterNew, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "registerNewMs")) \ - PROBE(SlowRegisterAdd, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "registerAddMs")) \ +#define ACTORLIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(SlowEvent, GROUPS("ActorLibSlow"), \ + TYPES(ui32, double, TString, TString, TString), \ + NAMES("poolId", "eventMs", "eventType", "actorId", "actorType")) \ + PROBE(EventSlowDelivery, GROUPS("ActorLibSlow"), \ + TYPES(ui32, double, double, ui64, TString, TString, TString), \ + NAMES("poolId", "deliveryMs", "sinceActivationMs", "eventProcessedBefore", "eventType", "actorId", "actorType")) \ + PROBE(SlowActivation, GROUPS("ActorLibSlow"), \ + TYPES(ui32, double), \ + NAMES("poolId", "activationMs")) \ + PROBE(SlowRegisterNew, GROUPS("ActorLibSlow"), \ + TYPES(ui32, double), \ + NAMES("poolId", "registerNewMs")) \ + PROBE(SlowRegisterAdd, GROUPS("ActorLibSlow"), \ + TYPES(ui32, double), \ + NAMES("poolId", "registerAddMs")) \ PROBE(MailboxPushedOutBySoftPreemption, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ @@ -41,32 +41,32 @@ PROBE(ActivationEnd, GROUPS(), \ TYPES(ui32, ui32, ui32), \ NAMES("cpu", "poolId", "workerId")) \ - PROBE(ExecutorThreadStats, GROUPS("ActorLibStats"), \ + PROBE(ExecutorThreadStats, GROUPS("ActorLibStats"), \ TYPES(ui32, TString, ui64, ui64, ui64, double, double), \ NAMES("poolId", "pool", "workerId", "execCount", "readyActivationCount", "execMs", "nonExecMs")) \ - PROBE(SlowICReadLoopAdjustSize, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadLoopAdjustSizeMs")) \ - PROBE(SlowICReadFromSocket, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadFromSocketMs")) \ - PROBE(SlowICReadLoopSend, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadLoopSendMs")) \ - PROBE(SlowICAllocPacketBuffer, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icAllocPacketBufferMs")) \ - PROBE(SlowICFillSendingBuffer, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icFillSendingBufferMs")) \ - PROBE(SlowICPushSentPackets, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icPushSentPacketsMs")) \ - PROBE(SlowICPushSendQueue, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icPushSendQueueMs")) \ + PROBE(SlowICReadLoopAdjustSize, GROUPS("ActorLibSlowIC"), \ + TYPES(double), \ + NAMES("icReadLoopAdjustSizeMs")) \ + PROBE(SlowICReadFromSocket, GROUPS("ActorLibSlowIC"), \ + TYPES(double), \ + NAMES("icReadFromSocketMs")) \ + PROBE(SlowICReadLoopSend, GROUPS("ActorLibSlowIC"), \ + TYPES(double), \ + NAMES("icReadLoopSendMs")) \ + PROBE(SlowICAllocPacketBuffer, GROUPS("ActorLibSlowIC"), \ + TYPES(ui32, double), \ + NAMES("peerId", "icAllocPacketBufferMs")) \ + PROBE(SlowICFillSendingBuffer, GROUPS("ActorLibSlowIC"), \ + TYPES(ui32, double), \ + NAMES("peerId", "icFillSendingBufferMs")) \ + PROBE(SlowICPushSentPackets, GROUPS("ActorLibSlowIC"), \ + TYPES(ui32, double), \ + NAMES("peerId", "icPushSentPacketsMs")) \ + PROBE(SlowICPushSendQueue, GROUPS("ActorLibSlowIC"), \ + TYPES(ui32, double), \ + NAMES("peerId", "icPushSendQueueMs")) \ PROBE(SlowICWriteData, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ + TYPES(ui32, double), \ NAMES("peerId", "icWriteDataMs")) \ PROBE(SlowICDropConfirmed, GROUPS("ActorLibSlowIC"), \ TYPES(ui32, double), \ diff --git a/library/cpp/actors/core/process_stats.cpp b/library/cpp/actors/core/process_stats.cpp index 0e1dbd0031..3c5fd82afd 100644 --- a/library/cpp/actors/core/process_stats.cpp +++ b/library/cpp/actors/core/process_stats.cpp @@ -13,84 +13,84 @@ #include <util/string/split.h> #ifndef _win_ -#include <sys/user.h> -#include <sys/sysctl.h> +#include <sys/user.h> +#include <sys/sysctl.h> #endif namespace NActors { #ifdef _linux_ - namespace { - template <typename TVal> - static bool ExtractVal(const TString& str, const TString& name, TVal& res) { - if (!str.StartsWith(name)) - return false; + namespace { + template <typename TVal> + static bool ExtractVal(const TString& str, const TString& name, TVal& res) { + if (!str.StartsWith(name)) + return false; size_t pos = name.size(); while (pos < str.size() && (str[pos] == ' ' || str[pos] == '\t')) { - pos++; - } + pos++; + } res = atol(str.data() + pos); - return true; - } + return true; + } - float TicksPerMillisec() { + float TicksPerMillisec() { #ifdef _SC_CLK_TCK - return sysconf(_SC_CLK_TCK) / 1000.0; + return sysconf(_SC_CLK_TCK) / 1000.0; #else - return 1.f; + return 1.f; #endif } - } + } - bool TProcStat::Fill(pid_t pid) { - try { + bool TProcStat::Fill(pid_t pid) { + try { TString strPid(ToString(pid)); TFileInput proc("/proc/" + strPid + "/status"); - TString str; - while (proc.ReadLine(str)) { - if (ExtractVal(str, "VmRSS:", Rss)) - continue; - if (ExtractVal(str, "voluntary_ctxt_switches:", VolCtxSwtch)) - continue; - if (ExtractVal(str, "nonvoluntary_ctxt_switches:", NonvolCtxSwtch)) - continue; - } - // Convert from kB to bytes - Rss *= 1024; - - float tickPerMillisec = TicksPerMillisec(); + TString str; + while (proc.ReadLine(str)) { + if (ExtractVal(str, "VmRSS:", Rss)) + continue; + if (ExtractVal(str, "voluntary_ctxt_switches:", VolCtxSwtch)) + continue; + if (ExtractVal(str, "nonvoluntary_ctxt_switches:", NonvolCtxSwtch)) + continue; + } + // Convert from kB to bytes + Rss *= 1024; + + float tickPerMillisec = TicksPerMillisec(); TFileInput procStat("/proc/" + strPid + "/stat"); - procStat.ReadLine(str); - if (!str.empty()) { + procStat.ReadLine(str); + if (!str.empty()) { sscanf(str.data(), - "%d %*s %c %d %d %d %d %d %u %lu %lu " - "%lu %lu %lu %lu %ld %ld %ld %ld %ld " - "%ld %llu %lu %ld %lu", - &Pid, &State, &Ppid, &Pgrp, &Session, &TtyNr, &TPgid, &Flags, &MinFlt, &CMinFlt, - &MajFlt, &CMajFlt, &Utime, &Stime, &CUtime, &CStime, &Priority, &Nice, &NumThreads, - &ItRealValue, &StartTime, &Vsize, &RssPages, &RssLim); - Utime /= tickPerMillisec; - Stime /= tickPerMillisec; - CUtime /= tickPerMillisec; - CStime /= tickPerMillisec; + "%d %*s %c %d %d %d %d %d %u %lu %lu " + "%lu %lu %lu %lu %ld %ld %ld %ld %ld " + "%ld %llu %lu %ld %lu", + &Pid, &State, &Ppid, &Pgrp, &Session, &TtyNr, &TPgid, &Flags, &MinFlt, &CMinFlt, + &MajFlt, &CMajFlt, &Utime, &Stime, &CUtime, &CStime, &Priority, &Nice, &NumThreads, + &ItRealValue, &StartTime, &Vsize, &RssPages, &RssLim); + Utime /= tickPerMillisec; + Stime /= tickPerMillisec; + CUtime /= tickPerMillisec; + CStime /= tickPerMillisec; SystemUptime = ::Uptime(); Uptime = SystemUptime - TDuration::MilliSeconds(StartTime / TicksPerMillisec()); } - + TFileInput statm("/proc/" + strPid + "/statm"); - statm.ReadLine(str); + statm.ReadLine(str); TVector<TString> fields; StringSplitter(str).Split(' ').SkipEmpty().Collect(&fields); - if (fields.size() >= 7) { - ui64 resident = FromString<ui64>(fields[1]); - ui64 shared = FromString<ui64>(fields[2]); - if (PageSize == 0) { - PageSize = ObtainPageSize(); - } - FileRss = shared * PageSize; - AnonRss = (resident - shared) * PageSize; - } + if (fields.size() >= 7) { + ui64 resident = FromString<ui64>(fields[1]); + ui64 shared = FromString<ui64>(fields[2]); + if (PageSize == 0) { + PageSize = ObtainPageSize(); + } + FileRss = shared * PageSize; + AnonRss = (resident - shared) * PageSize; + } TFileInput cgroup("/proc/" + strPid + "/cgroup"); TString line; @@ -112,70 +112,70 @@ namespace NActors { } } - } catch (...) { - return false; + } catch (...) { + return false; } - return true; + return true; } - long TProcStat::ObtainPageSize() { - long sz = sysconf(_SC_PAGESIZE); - return sz; - } + long TProcStat::ObtainPageSize() { + long sz = sysconf(_SC_PAGESIZE); + return sz; + } #else - bool TProcStat::Fill(pid_t pid) { - Y_UNUSED(pid); - return false; - } + bool TProcStat::Fill(pid_t pid) { + Y_UNUSED(pid); + return false; + } - long TProcStat::ObtainPageSize() { - return 0; - } + long TProcStat::ObtainPageSize() { + return 0; + } #endif namespace { - // Periodically collects process stats and exposes them as mon counters + // Periodically collects process stats and exposes them as mon counters template <typename TDerived> class TProcStatCollectingActor: public TActorBootstrapped<TProcStatCollectingActor<TDerived>> { - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::ACTORLIB_STATS; - } + public: + static constexpr IActor::EActivityType ActorActivityType() { + return IActor::ACTORLIB_STATS; + } TProcStatCollectingActor(TDuration interval) : Interval(interval) - { - } + { + } - void Bootstrap(const TActorContext& ctx) { + void Bootstrap(const TActorContext& ctx) { ctx.Schedule(Interval, new TEvents::TEvWakeup()); Self()->Become(&TDerived::StateWork); - } + } - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - CFunc(TEvents::TSystem::Wakeup, Wakeup); - } - } + STFUNC(StateWork) { + switch (ev->GetTypeRewrite()) { + CFunc(TEvents::TSystem::Wakeup, Wakeup); + } + } - private: - void Wakeup(const TActorContext& ctx) { + private: + void Wakeup(const TActorContext& ctx) { Self()->UpdateCounters(ProcStat); ctx.Schedule(Interval, new TEvents::TEvWakeup()); } TDerived* Self() { - ProcStat.Fill(getpid()); + ProcStat.Fill(getpid()); return static_cast<TDerived*>(this); - } + } private: const TDuration Interval; TProcStat ProcStat; - }; + }; // Periodically collects process stats and exposes them as mon counters class TDynamicCounterCollector: public TProcStatCollectingActor<TDynamicCounterCollector> { diff --git a/library/cpp/actors/core/scheduler_basic.cpp b/library/cpp/actors/core/scheduler_basic.cpp index fba200e16b..abba1f818f 100644 --- a/library/cpp/actors/core/scheduler_basic.cpp +++ b/library/cpp/actors/core/scheduler_basic.cpp @@ -1,6 +1,6 @@ -#include "scheduler_basic.h" -#include "scheduler_queue.h" - +#include "scheduler_basic.h" +#include "scheduler_queue.h" + #include <library/cpp/actors/util/datetime.h> #include <library/cpp/actors/util/thread.h> @@ -8,7 +8,7 @@ #include <library/cpp/balloc/optional/operators.h> #endif -namespace NActors { +namespace NActors { struct TBasicSchedulerThread::TMonCounters { NMonitoring::TDynamicCounters::TCounterPtr TimeDelayMs; @@ -32,144 +32,144 @@ namespace NActors { { } }; - TBasicSchedulerThread::TBasicSchedulerThread(const TSchedulerConfig& config) - : Config(config) + TBasicSchedulerThread::TBasicSchedulerThread(const TSchedulerConfig& config) + : Config(config) , MonCounters(Config.MonCounters ? new TMonCounters(Config.MonCounters) : nullptr) - , ActorSystem(nullptr) - , CurrentTimestamp(nullptr) + , ActorSystem(nullptr) + , CurrentTimestamp(nullptr) , CurrentMonotonic(nullptr) - , TotalReaders(0) - , StopFlag(false) - , ScheduleMap(3600) - { + , TotalReaders(0) + , StopFlag(false) + , ScheduleMap(3600) + { Y_VERIFY(!Config.UseSchedulerActor, "Cannot create scheduler thread because Config.UseSchedulerActor# true"); - } - - TBasicSchedulerThread::~TBasicSchedulerThread() { - Y_VERIFY(!MainCycle); - } - - void TBasicSchedulerThread::CycleFunc() { + } + + TBasicSchedulerThread::~TBasicSchedulerThread() { + Y_VERIFY(!MainCycle); + } + + void TBasicSchedulerThread::CycleFunc() { #ifdef BALLOC ThreadDisableBalloc(); #endif ::SetCurrentThreadName("Scheduler"); - + ui64 currentMonotonic = RelaxedLoad(CurrentMonotonic); ui64 throttledMonotonic = currentMonotonic; ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold); - TAutoPtr<TMomentMap> activeSec; - + TAutoPtr<TMomentMap> activeSec; + NHPTimer::STime hpprev = GetCycleCountFast(); ui64 nextTimestamp = TInstant::Now().MicroSeconds(); ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - while (!AtomicLoad(&StopFlag)) { - { + 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; } - bool somethingDone = false; - - // first step - send everything triggered on schedule + bool somethingDone = false; + + // first step - send everything triggered on schedule ui64 eventsSent = 0; ui64 eventsDropped = 0; - for (;;) { - while (!!activeSec && !activeSec->empty()) { - TMomentMap::iterator it = activeSec->begin(); + for (;;) { + while (!!activeSec && !activeSec->empty()) { + TMomentMap::iterator it = activeSec->begin(); if (it->first <= throttledMonotonic) { if (NSchedulerQueue::TQueueType* q = it->second.Get()) { - while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) { - somethingDone = true; - Y_VERIFY_DEBUG(x->InstantMicroseconds <= activeTick); - IEventHandle* ev = x->Ev; - ISchedulerCookie* cookie = x->Cookie; - // TODO: lazy send with backoff queue to not hang over contended mailboxes - if (cookie) { + while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) { + somethingDone = true; + Y_VERIFY_DEBUG(x->InstantMicroseconds <= activeTick); + IEventHandle* ev = x->Ev; + ISchedulerCookie* cookie = x->Cookie; + // TODO: lazy send with backoff queue to not hang over contended mailboxes + if (cookie) { if (cookie->Detach()) { - ActorSystem->Send(ev); + ActorSystem->Send(ev); ++eventsSent; } else { - delete ev; + delete ev; ++eventsDropped; } - } else { - ActorSystem->Send(ev); + } else { + ActorSystem->Send(ev); ++eventsSent; - } - } - } - activeSec->erase(it); - } else - break; - } - + } + } + } + activeSec->erase(it); + } else + break; + } + if (activeTick <= throttledMonotonic) { - Y_VERIFY_DEBUG(!activeSec || activeSec->empty()); - activeSec.Destroy(); - activeTick += IntrasecondThreshold; - TScheduleMap::iterator it = ScheduleMap.find(activeTick); - if (it != ScheduleMap.end()) { - activeSec = it->second; - ScheduleMap.erase(it); - } - continue; - } - - // ok, if we are here - then nothing is ready, so send step complete - break; - } - - // second step - collect everything from queues - + Y_VERIFY_DEBUG(!activeSec || activeSec->empty()); + activeSec.Destroy(); + activeTick += IntrasecondThreshold; + TScheduleMap::iterator it = ScheduleMap.find(activeTick); + if (it != ScheduleMap.end()) { + activeSec = it->second; + ScheduleMap.erase(it); + } + continue; + } + + // ok, if we are here - then nothing is ready, so send step complete + break; + } + + // second step - collect everything from queues + ui64 eventsAdded = 0; - for (ui32 i = 0; i != TotalReaders; ++i) { - while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) { - somethingDone = true; - const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Config.ResolutionMicroseconds); - IEventHandle* const ev = x->Ev; - ISchedulerCookie* const cookie = x->Cookie; - - // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save - - if (instant <= activeTick) { - if (!activeSec) - activeSec.Reset(new TMomentMap()); + for (ui32 i = 0; i != TotalReaders; ++i) { + while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) { + somethingDone = true; + const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Config.ResolutionMicroseconds); + IEventHandle* const ev = x->Ev; + ISchedulerCookie* const cookie = x->Cookie; + + // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save + + if (instant <= activeTick) { + if (!activeSec) + activeSec.Reset(new TMomentMap()); TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*activeSec)[instant]; - if (!queue) + if (!queue) queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } else { - const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold); - TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond]; - if (!msec) - msec.Reset(new TMomentMap()); + queue->Writer.Push(instant, ev, cookie); + } else { + const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold); + TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond]; + if (!msec) + msec.Reset(new TMomentMap()); TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*msec)[instant]; - if (!queue) + if (!queue) queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } + queue->Writer.Push(instant, ev, cookie); + } ++eventsAdded; - } - } - + } + } + NHPTimer::STime hpnow = GetCycleCountFast(); if (MonCounters) { @@ -185,46 +185,46 @@ namespace NActors { nextTimestamp = TInstant::Now().MicroSeconds(); nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - // ok complete, if nothing left - sleep - if (!somethingDone) { + // 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 - continue; - + continue; + const ui64 delta = nextInstant - nextMonotonic; - if (delta < Config.SpinThreshold) // not so much time left, just spin - continue; - + if (delta < Config.SpinThreshold) // not so much time left, just spin + continue; + if (MonCounters) { ++*MonCounters->Sleeps; } - NanoSleep(delta * 1000); // ok, looks like we should sleep a bit. + NanoSleep(delta * 1000); // ok, looks like we should sleep a bit. // Don't count sleep in elapsed microseconds hpprev = GetCycleCountFast(); nextTimestamp = TInstant::Now().MicroSeconds(); nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - } - } - // ok, die! - } - + } + } + // ok, die! + } + void TBasicSchedulerThread::Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) { - ActorSystem = actorSystem; - CurrentTimestamp = currentTimestamp; + ActorSystem = actorSystem; + CurrentTimestamp = currentTimestamp; CurrentMonotonic = currentMonotonic; *CurrentTimestamp = TInstant::Now().MicroSeconds(); *CurrentMonotonic = GetMonotonicMicroSeconds(); - } - + } + void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) { - Y_VERIFY(scheduleReadersCount > 0); - TotalReaders = scheduleReadersCount; - Readers.Reset(new NSchedulerQueue::TReader*[scheduleReadersCount]); - Copy(readers, readers + scheduleReadersCount, Readers.Get()); - } - + Y_VERIFY(scheduleReadersCount > 0); + TotalReaders = scheduleReadersCount; + Readers.Reset(new NSchedulerQueue::TReader*[scheduleReadersCount]); + 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 @@ -235,18 +235,18 @@ namespace NActors { AtomicStore(CurrentMonotonic, Max(RelaxedLoad(CurrentMonotonic), GetMonotonicMicroSeconds())); } - void TBasicSchedulerThread::Start() { - MainCycle.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TBasicSchedulerThread::CycleFunc, this))); - } - - void TBasicSchedulerThread::PrepareStop() { - AtomicStore(&StopFlag, true); - } - - void TBasicSchedulerThread::Stop() { - MainCycle->Get(); - MainCycle.Destroy(); - } + void TBasicSchedulerThread::Start() { + MainCycle.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TBasicSchedulerThread::CycleFunc, this))); + } + + void TBasicSchedulerThread::PrepareStop() { + AtomicStore(&StopFlag, true); + } + + void TBasicSchedulerThread::Stop() { + MainCycle->Get(); + MainCycle.Destroy(); + } } @@ -269,6 +269,6 @@ namespace NActors { ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& config) { return new TBasicSchedulerThread(config); } -} +} #endif // __linux__ diff --git a/library/cpp/actors/core/scheduler_basic.h b/library/cpp/actors/core/scheduler_basic.h index 2ccde39235..f66e784696 100644 --- a/library/cpp/actors/core/scheduler_basic.h +++ b/library/cpp/actors/core/scheduler_basic.h @@ -1,54 +1,54 @@ -#pragma once - -#include "actorsystem.h" +#pragma once + +#include "actorsystem.h" #include "monotonic.h" -#include "scheduler_queue.h" +#include "scheduler_queue.h" #include <library/cpp/actors/util/queue_chunk.h> #include <library/cpp/threading/future/legacy_future.h> -#include <util/generic/hash.h> -#include <util/generic/map.h> - -namespace NActors { - - class TBasicSchedulerThread: public ISchedulerThread { - // TODO: replace with NUMA-local threads and per-thread schedules - const TSchedulerConfig Config; - +#include <util/generic/hash.h> +#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; - TActorSystem* ActorSystem; - volatile ui64* CurrentTimestamp; + TActorSystem* ActorSystem; + volatile ui64* CurrentTimestamp; volatile ui64* CurrentMonotonic; - - ui32 TotalReaders; - TArrayHolder<NSchedulerQueue::TReader*> Readers; - - volatile bool StopFlag; - + + ui32 TotalReaders; + TArrayHolder<NSchedulerQueue::TReader*> Readers; + + volatile bool StopFlag; + typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues typedef THashMap<ui64, TAutoPtr<TMomentMap>> TScheduleMap; // over-second schedule - - TScheduleMap ScheduleMap; - - THolder<NThreading::TLegacyFuture<void, false>> MainCycle; - - static const ui64 IntrasecondThreshold = 1048576; // ~second - - void CycleFunc(); - - public: - TBasicSchedulerThread(const TSchedulerConfig& config = TSchedulerConfig()); - ~TBasicSchedulerThread(); - + + TScheduleMap ScheduleMap; + + THolder<NThreading::TLegacyFuture<void, false>> MainCycle; + + static const ui64 IntrasecondThreshold = 1048576; // ~second + + void CycleFunc(); + + public: + TBasicSchedulerThread(const TSchedulerConfig& config = TSchedulerConfig()); + ~TBasicSchedulerThread(); + void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override; void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override; - + void PrepareStart() override; void Start() override; void PrepareStop() override; void Stop() override; - }; + }; class TMockSchedulerThread: public ISchedulerThread { public: @@ -78,4 +78,4 @@ namespace NActors { ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& cfg); -} +} diff --git a/library/cpp/actors/core/scheduler_cookie.cpp b/library/cpp/actors/core/scheduler_cookie.cpp index 0fa6f543a7..99717f56e4 100644 --- a/library/cpp/actors/core/scheduler_cookie.cpp +++ b/library/cpp/actors/core/scheduler_cookie.cpp @@ -1,84 +1,84 @@ -#include "scheduler_cookie.h" - -namespace NActors { - class TSchedulerCookie2Way: public ISchedulerCookie { - TAtomic Value; - - public: - TSchedulerCookie2Way() - : Value(2) - { - } - +#include "scheduler_cookie.h" + +namespace NActors { + class TSchedulerCookie2Way: public ISchedulerCookie { + TAtomic Value; + + public: + TSchedulerCookie2Way() + : Value(2) + { + } + bool IsArmed() noexcept override { return (AtomicGet(Value) == 2); - } - + } + bool Detach() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 1) - return true; - - if (x == 0) { - delete this; - return false; - } - - Y_FAIL(); - } - + const ui64 x = AtomicDecrement(Value); + if (x == 1) + return true; + + if (x == 0) { + delete this; + return false; + } + + Y_FAIL(); + } + bool DetachEvent() noexcept override { - Y_FAIL(); - } - }; - - ISchedulerCookie* ISchedulerCookie::Make2Way() { - return new TSchedulerCookie2Way(); - } - - class TSchedulerCookie3Way: public ISchedulerCookie { - TAtomic Value; - - public: - TSchedulerCookie3Way() - : Value(3) - { - } - + Y_FAIL(); + } + }; + + ISchedulerCookie* ISchedulerCookie::Make2Way() { + return new TSchedulerCookie2Way(); + } + + class TSchedulerCookie3Way: public ISchedulerCookie { + TAtomic Value; + + public: + TSchedulerCookie3Way() + : Value(3) + { + } + bool IsArmed() noexcept override { return (AtomicGet(Value) == 3); - } - + } + bool Detach() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 2) - return true; - if (x == 1) - return false; - if (x == 0) { - delete this; - return false; - } - - Y_FAIL(); - } - + const ui64 x = AtomicDecrement(Value); + if (x == 2) + return true; + if (x == 1) + return false; + if (x == 0) { + delete this; + return false; + } + + Y_FAIL(); + } + bool DetachEvent() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 2) - return false; - if (x == 1) - return true; - if (x == 0) { - delete this; - return false; - } - - Y_FAIL(); - } - }; - - ISchedulerCookie* ISchedulerCookie::Make3Way() { - return new TSchedulerCookie3Way(); - } -} + const ui64 x = AtomicDecrement(Value); + if (x == 2) + return false; + if (x == 1) + return true; + if (x == 0) { + delete this; + return false; + } + + Y_FAIL(); + } + }; + + ISchedulerCookie* ISchedulerCookie::Make3Way() { + return new TSchedulerCookie3Way(); + } +} diff --git a/library/cpp/actors/core/scheduler_cookie.h b/library/cpp/actors/core/scheduler_cookie.h index 2c20ca67f3..638c1ab5fe 100644 --- a/library/cpp/actors/core/scheduler_cookie.h +++ b/library/cpp/actors/core/scheduler_cookie.h @@ -1,78 +1,78 @@ -#pragma once - -#include "defs.h" -#include <util/generic/noncopyable.h> - -namespace NActors { - class ISchedulerCookie : TNonCopyable { - protected: - virtual ~ISchedulerCookie() { - } - - public: +#pragma once + +#include "defs.h" +#include <util/generic/noncopyable.h> + +namespace NActors { + class ISchedulerCookie : TNonCopyable { + protected: + virtual ~ISchedulerCookie() { + } + + public: virtual bool Detach() noexcept = 0; virtual bool DetachEvent() noexcept = 0; virtual bool IsArmed() noexcept = 0; - - static ISchedulerCookie* Make2Way(); - static ISchedulerCookie* Make3Way(); - }; - + + static ISchedulerCookie* Make2Way(); + static ISchedulerCookie* Make3Way(); + }; + class TSchedulerCookieHolder : TNonCopyable { - ISchedulerCookie* Cookie; - - public: - TSchedulerCookieHolder() + ISchedulerCookie* Cookie; + + public: + TSchedulerCookieHolder() : Cookie(nullptr) - { - } - - TSchedulerCookieHolder(ISchedulerCookie* x) - : Cookie(x) - { - } - - ~TSchedulerCookieHolder() { - Detach(); - } - + { + } + + TSchedulerCookieHolder(ISchedulerCookie* x) + : Cookie(x) + { + } + + ~TSchedulerCookieHolder() { + Detach(); + } + bool operator==(const TSchedulerCookieHolder& x) const noexcept { - return (Cookie == x.Cookie); - } - + return (Cookie == x.Cookie); + } + ISchedulerCookie* Get() const { - return Cookie; - } - + return Cookie; + } + ISchedulerCookie* Release() { ISchedulerCookie* result = Cookie; Cookie = nullptr; return result; } - void Reset(ISchedulerCookie* cookie) { - Detach(); - Cookie = cookie; - } - + void Reset(ISchedulerCookie* cookie) { + Detach(); + Cookie = cookie; + } + bool Detach() noexcept { - if (Cookie) { - const bool res = Cookie->Detach(); + if (Cookie) { + const bool res = Cookie->Detach(); Cookie = nullptr; - return res; - } else { - return false; - } - } - + return res; + } else { + return false; + } + } + bool DetachEvent() noexcept { - if (Cookie) { - const bool res = Cookie->DetachEvent(); + if (Cookie) { + const bool res = Cookie->DetachEvent(); Cookie = nullptr; - return res; - } else { - return false; - } - } - }; -} + return res; + } else { + return false; + } + } + }; +} diff --git a/library/cpp/actors/core/scheduler_queue.h b/library/cpp/actors/core/scheduler_queue.h index 3b8fac28f0..4d353096d2 100644 --- a/library/cpp/actors/core/scheduler_queue.h +++ b/library/cpp/actors/core/scheduler_queue.h @@ -1,120 +1,120 @@ -#pragma once - +#pragma once + #include <library/cpp/actors/util/queue_chunk.h> - -namespace NActors { - class IEventHandle; - class ISchedulerCookie; - - namespace NSchedulerQueue { - struct TEntry { - ui64 InstantMicroseconds; - IEventHandle* Ev; - ISchedulerCookie* Cookie; - }; - + +namespace NActors { + class IEventHandle; + class ISchedulerCookie; + + namespace NSchedulerQueue { + struct TEntry { + ui64 InstantMicroseconds; + IEventHandle* Ev; + ISchedulerCookie* Cookie; + }; + struct TChunk : TQueueChunkDerived<TEntry, 512, TChunk> {}; - - class TReader; - class TWriter; - class TWriterWithPadding; - - class TReader : ::TNonCopyable { - TChunk* ReadFrom; - ui32 ReadPosition; - - friend class TWriter; - - public: - TReader() - : ReadFrom(new TChunk()) - , ReadPosition(0) - { - } - - ~TReader() { - while (TEntry* x = Pop()) { - if (x->Cookie) - x->Cookie->Detach(); - delete x->Ev; - } - delete ReadFrom; - } - - TEntry* Pop() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - if (AtomicLoad(&head->Entries[ReadPosition].InstantMicroseconds) != 0) - return const_cast<TEntry*>(&head->Entries[ReadPosition++]); - else - return nullptr; - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - delete head; - ReadPosition = 0; - return Pop(); - } - - return nullptr; - } - }; - - class TWriter : ::TNonCopyable { - TChunk* WriteTo; - ui32 WritePosition; - - public: - TWriter() - : WriteTo(nullptr) - , WritePosition(0) - { - } - - void Init(const TReader& reader) { - WriteTo = reader.ReadFrom; - WritePosition = 0; - } - - void Push(ui64 instantMicrosends, IEventHandle* ev, ISchedulerCookie* cookie) { + + class TReader; + class TWriter; + class TWriterWithPadding; + + class TReader : ::TNonCopyable { + TChunk* ReadFrom; + ui32 ReadPosition; + + friend class TWriter; + + public: + TReader() + : ReadFrom(new TChunk()) + , ReadPosition(0) + { + } + + ~TReader() { + while (TEntry* x = Pop()) { + if (x->Cookie) + x->Cookie->Detach(); + delete x->Ev; + } + delete ReadFrom; + } + + TEntry* Pop() { + TChunk* head = ReadFrom; + if (ReadPosition != TChunk::EntriesCount) { + if (AtomicLoad(&head->Entries[ReadPosition].InstantMicroseconds) != 0) + return const_cast<TEntry*>(&head->Entries[ReadPosition++]); + else + return nullptr; + } else if (TChunk* next = AtomicLoad(&head->Next)) { + ReadFrom = next; + delete head; + ReadPosition = 0; + return Pop(); + } + + return nullptr; + } + }; + + class TWriter : ::TNonCopyable { + TChunk* WriteTo; + ui32 WritePosition; + + public: + TWriter() + : WriteTo(nullptr) + , WritePosition(0) + { + } + + void Init(const TReader& reader) { + WriteTo = reader.ReadFrom; + WritePosition = 0; + } + + void Push(ui64 instantMicrosends, IEventHandle* ev, ISchedulerCookie* cookie) { 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; - entry.Ev = ev; - AtomicStore(&entry.InstantMicroseconds, instantMicrosends); - ++WritePosition; - } else { - TChunk* next = new TChunk(); - volatile TEntry& entry = next->Entries[0]; - entry.Cookie = cookie; - entry.Ev = ev; - entry.InstantMicroseconds = instantMicrosends; - AtomicStore(&WriteTo->Next, next); - WriteTo = next; - WritePosition = 1; - } - } - }; - - class TWriterWithPadding: public TWriter { - private: - ui8 CacheLinePadding[64 - sizeof(TWriter)]; - - void UnusedCacheLinePadding() { - Y_UNUSED(CacheLinePadding); - } - }; - + if (WritePosition != TChunk::EntriesCount) { + volatile TEntry& entry = WriteTo->Entries[WritePosition]; + entry.Cookie = cookie; + entry.Ev = ev; + AtomicStore(&entry.InstantMicroseconds, instantMicrosends); + ++WritePosition; + } else { + TChunk* next = new TChunk(); + volatile TEntry& entry = next->Entries[0]; + entry.Cookie = cookie; + entry.Ev = ev; + entry.InstantMicroseconds = instantMicrosends; + AtomicStore(&WriteTo->Next, next); + WriteTo = next; + WritePosition = 1; + } + } + }; + + class TWriterWithPadding: public TWriter { + private: + ui8 CacheLinePadding[64 - sizeof(TWriter)]; + + void UnusedCacheLinePadding() { + Y_UNUSED(CacheLinePadding); + } + }; + struct TQueueType { - TReader Reader; - TWriter Writer; - + TReader Reader; + TWriter Writer; + TQueueType() { - Writer.Init(Reader); - } - }; - } -} + Writer.Init(Reader); + } + }; + } +} diff --git a/library/cpp/actors/core/servicemap.h b/library/cpp/actors/core/servicemap.h index d72e50cae5..ac879b53ad 100644 --- a/library/cpp/actors/core/servicemap.h +++ b/library/cpp/actors/core/servicemap.h @@ -1,168 +1,168 @@ -#pragma once - -#include "defs.h" - -namespace NActors { - // wait-free one writer multi reader hash-tree for service mapping purposes - // on fast updates on same key - could lead to false-negatives, we don't care as such cases are broken from service-map app logic - - template <typename TKey, typename TValue, typename THash, ui64 BaseSize = 256 * 1024, ui64 ExtCount = 4, ui64 ExtBranching = 4> - class TServiceMap : TNonCopyable { - struct TEntry : TNonCopyable { - ui32 CounterIn; - ui32 CounterOut; - TKey Key; - TValue Value; - - TEntry() - : CounterIn(0) - , CounterOut(0) - , Key() - , Value() - { - } - }; - - struct TBranch : TNonCopyable { - TEntry Entries[ExtCount]; - TBranch* Branches[ExtBranching]; - - TBranch() { - Fill(Branches, Branches + ExtBranching, (TBranch*)nullptr); - } - }; - - ui32 Counter; - TBranch* Line[BaseSize]; - - bool ScanBranch(TBranch* branch, const TKey& key, ui64 hash, TValue& ret) { - for (ui32 i = 0; i != ExtCount; ++i) { - const TEntry& entry = branch->Entries[i]; - const ui32 counterIn = AtomicLoad(&entry.CounterIn); - if (counterIn != 0 && entry.Key == key) { - ret = entry.Value; - const ui32 counterOut = AtomicLoad(&entry.CounterOut); - if (counterOut == counterIn) - return true; - } - } - - const ui64 hash0 = hash % ExtBranching; - if (TBranch* next = AtomicLoad(branch->Branches + hash0)) - return ScanBranch(next, key, hash / ExtBranching, ret); - - return false; - } - - void ScanZeroOld(TBranch* branch, const TKey& key, ui64 hash, TEntry** zeroEntry, TEntry*& oldEntry) { - for (ui32 i = 0; i != ExtCount; ++i) { - TEntry& entry = branch->Entries[i]; - if (entry.CounterIn == 0) { - if (zeroEntry && !*zeroEntry) { - *zeroEntry = &entry; - if (oldEntry != nullptr) - return; - } - } else { - if (entry.Key == key) { - oldEntry = &entry; - if (!zeroEntry || *zeroEntry) - return; - } - } - } - - const ui64 hash0 = hash % ExtBranching; - if (TBranch* next = branch->Branches[hash0]) { - ScanZeroOld(next, key, hash / ExtBranching, zeroEntry, oldEntry); - } else { // found tail, if zeroEntry requested, but not yet found - insert one - if (zeroEntry && !*zeroEntry) { - TBranch* next = new TBranch(); - *zeroEntry = next->Entries; - AtomicStore(branch->Branches + hash0, next); - } - } - } - - public: - TServiceMap() - : Counter(0) - { - Fill(Line, Line + BaseSize, (TBranch*)nullptr); - } - - ~TServiceMap() { - for (ui64 i = 0; i < BaseSize; ++i) { - delete Line[i]; - } - } - - TValue Find(const TKey& key) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - if (TBranch* branch = AtomicLoad(Line + hash0)) { - TValue ret; - if (ScanBranch(branch, key, hash / BaseSize, ret)) - return ret; - } - - return TValue(); - } - - // returns true on update, false on insert - TValue Update(const TKey& key, const TValue& value) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - TEntry* zeroEntry = nullptr; - TEntry* oldEntry = nullptr; - - if (TBranch* branch = Line[hash0]) { - ScanZeroOld(branch, key, hash / BaseSize, &zeroEntry, oldEntry); - } else { - TBranch* next = new TBranch(); - zeroEntry = next->Entries; - AtomicStore(Line + hash0, next); - } - - // now we got both entries, first - push new one - const ui32 counter = AtomicUi32Increment(&Counter); - AtomicStore(&zeroEntry->CounterOut, counter); - zeroEntry->Key = key; - zeroEntry->Value = value; - AtomicStore(&zeroEntry->CounterIn, counter); - - if (oldEntry != nullptr) { - const TValue ret = oldEntry->Value; - AtomicStore<ui32>(&oldEntry->CounterOut, 0); - AtomicStore<ui32>(&oldEntry->CounterIn, 0); - return ret; - } else { - return TValue(); - } - } - - bool Erase(const TKey& key) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - TEntry* oldEntry = 0; - - if (TBranch* branch = Line[hash0]) { - ScanZeroOld(branch, key, hash / BaseSize, 0, oldEntry); - } - - if (oldEntry != 0) { - AtomicStore<ui32>(&oldEntry->CounterOut, 0); - AtomicStore<ui32>(&oldEntry->CounterIn, 0); - return true; - } else { - return false; - } - } - }; -} +#pragma once + +#include "defs.h" + +namespace NActors { + // wait-free one writer multi reader hash-tree for service mapping purposes + // on fast updates on same key - could lead to false-negatives, we don't care as such cases are broken from service-map app logic + + template <typename TKey, typename TValue, typename THash, ui64 BaseSize = 256 * 1024, ui64 ExtCount = 4, ui64 ExtBranching = 4> + class TServiceMap : TNonCopyable { + struct TEntry : TNonCopyable { + ui32 CounterIn; + ui32 CounterOut; + TKey Key; + TValue Value; + + TEntry() + : CounterIn(0) + , CounterOut(0) + , Key() + , Value() + { + } + }; + + struct TBranch : TNonCopyable { + TEntry Entries[ExtCount]; + TBranch* Branches[ExtBranching]; + + TBranch() { + Fill(Branches, Branches + ExtBranching, (TBranch*)nullptr); + } + }; + + ui32 Counter; + TBranch* Line[BaseSize]; + + bool ScanBranch(TBranch* branch, const TKey& key, ui64 hash, TValue& ret) { + for (ui32 i = 0; i != ExtCount; ++i) { + const TEntry& entry = branch->Entries[i]; + const ui32 counterIn = AtomicLoad(&entry.CounterIn); + if (counterIn != 0 && entry.Key == key) { + ret = entry.Value; + const ui32 counterOut = AtomicLoad(&entry.CounterOut); + if (counterOut == counterIn) + return true; + } + } + + const ui64 hash0 = hash % ExtBranching; + if (TBranch* next = AtomicLoad(branch->Branches + hash0)) + return ScanBranch(next, key, hash / ExtBranching, ret); + + return false; + } + + void ScanZeroOld(TBranch* branch, const TKey& key, ui64 hash, TEntry** zeroEntry, TEntry*& oldEntry) { + for (ui32 i = 0; i != ExtCount; ++i) { + TEntry& entry = branch->Entries[i]; + if (entry.CounterIn == 0) { + if (zeroEntry && !*zeroEntry) { + *zeroEntry = &entry; + if (oldEntry != nullptr) + return; + } + } else { + if (entry.Key == key) { + oldEntry = &entry; + if (!zeroEntry || *zeroEntry) + return; + } + } + } + + const ui64 hash0 = hash % ExtBranching; + if (TBranch* next = branch->Branches[hash0]) { + ScanZeroOld(next, key, hash / ExtBranching, zeroEntry, oldEntry); + } else { // found tail, if zeroEntry requested, but not yet found - insert one + if (zeroEntry && !*zeroEntry) { + TBranch* next = new TBranch(); + *zeroEntry = next->Entries; + AtomicStore(branch->Branches + hash0, next); + } + } + } + + public: + TServiceMap() + : Counter(0) + { + Fill(Line, Line + BaseSize, (TBranch*)nullptr); + } + + ~TServiceMap() { + for (ui64 i = 0; i < BaseSize; ++i) { + delete Line[i]; + } + } + + TValue Find(const TKey& key) { + THash hashOp; + const ui64 hash = hashOp(key); + const ui64 hash0 = hash % BaseSize; + + if (TBranch* branch = AtomicLoad(Line + hash0)) { + TValue ret; + if (ScanBranch(branch, key, hash / BaseSize, ret)) + return ret; + } + + return TValue(); + } + + // returns true on update, false on insert + TValue Update(const TKey& key, const TValue& value) { + THash hashOp; + const ui64 hash = hashOp(key); + const ui64 hash0 = hash % BaseSize; + + TEntry* zeroEntry = nullptr; + TEntry* oldEntry = nullptr; + + if (TBranch* branch = Line[hash0]) { + ScanZeroOld(branch, key, hash / BaseSize, &zeroEntry, oldEntry); + } else { + TBranch* next = new TBranch(); + zeroEntry = next->Entries; + AtomicStore(Line + hash0, next); + } + + // now we got both entries, first - push new one + const ui32 counter = AtomicUi32Increment(&Counter); + AtomicStore(&zeroEntry->CounterOut, counter); + zeroEntry->Key = key; + zeroEntry->Value = value; + AtomicStore(&zeroEntry->CounterIn, counter); + + if (oldEntry != nullptr) { + const TValue ret = oldEntry->Value; + AtomicStore<ui32>(&oldEntry->CounterOut, 0); + AtomicStore<ui32>(&oldEntry->CounterIn, 0); + return ret; + } else { + return TValue(); + } + } + + bool Erase(const TKey& key) { + THash hashOp; + const ui64 hash = hashOp(key); + const ui64 hash0 = hash % BaseSize; + + TEntry* oldEntry = 0; + + if (TBranch* branch = Line[hash0]) { + ScanZeroOld(branch, key, hash / BaseSize, 0, oldEntry); + } + + if (oldEntry != 0) { + AtomicStore<ui32>(&oldEntry->CounterOut, 0); + AtomicStore<ui32>(&oldEntry->CounterIn, 0); + return true; + } else { + return false; + } + } + }; +} diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make index 880a9d00db..fef4811b53 100644 --- a/library/cpp/actors/core/ya.make +++ b/library/cpp/actors/core/ya.make @@ -1,10 +1,10 @@ -LIBRARY() - +LIBRARY() + OWNER( ddoarn g:kikimr ) - + NO_WSHADOW() IF (PROFILE_MEMORY_ALLOCATIONS) @@ -18,16 +18,16 @@ IF (ALLOCATOR == "B" OR ALLOCATOR == "BS" OR ALLOCATOR == "C") ) ENDIF() -SRCS( - actor_bootstrapped.h +SRCS( + actor_bootstrapped.h actor_coroutine.cpp actor_coroutine.h actor.cpp actor.h actorid.cpp - actorid.h + actorid.h actorsystem.cpp - actorsystem.h + actorsystem.h ask.cpp ask.h balancer.h @@ -40,29 +40,29 @@ SRCS( cpu_manager.cpp cpu_manager.h cpu_state.h - defs.h + defs.h event.cpp - event.h + event.h event_load.h event_local.h event_pb.cpp - event_pb.h - events.h - events_undelivered.cpp + event_pb.h + events.h + events_undelivered.cpp executelater.h - executor_pool_base.cpp - executor_pool_base.h - executor_pool_basic.cpp - executor_pool_basic.h - executor_pool_io.cpp - executor_pool_io.h + executor_pool_base.cpp + executor_pool_base.h + executor_pool_basic.cpp + executor_pool_basic.h + executor_pool_io.cpp + executor_pool_io.h executor_pool_united.cpp executor_pool_united.h - executor_thread.cpp - executor_thread.h - hfunc.h + executor_thread.cpp + executor_thread.h + hfunc.h interconnect.cpp - interconnect.h + interconnect.h invoke.h io_dispatcher.cpp io_dispatcher.h @@ -72,9 +72,9 @@ SRCS( log_settings.cpp log_settings.h mailbox.cpp - mailbox.h - mailbox_queue_revolving.h - mailbox_queue_simple.h + mailbox.h + mailbox_queue_revolving.h + mailbox_queue_simple.h memory_track.cpp memory_track.h memory_tracker.cpp @@ -91,18 +91,18 @@ SRCS( process_stats.h scheduler_actor.cpp scheduler_actor.h - scheduler_basic.cpp - scheduler_basic.h - scheduler_cookie.cpp - scheduler_cookie.h - scheduler_queue.h - servicemap.h -) - + scheduler_basic.cpp + scheduler_basic.h + scheduler_cookie.cpp + scheduler_cookie.h + scheduler_queue.h + servicemap.h +) + GENERATE_ENUM_SERIALIZATION(defs.h) GENERATE_ENUM_SERIALIZATION(actor.h) -PEERDIR( +PEERDIR( library/cpp/actors/memory_log library/cpp/actors/prof library/cpp/actors/protos @@ -114,9 +114,9 @@ PEERDIR( library/cpp/monlib/dynamic_counters library/cpp/svnversion library/cpp/threading/future -) - -END() +) + +END() RECURSE_FOR_TESTS( ut diff --git a/library/cpp/actors/dnscachelib/dnscache.cpp b/library/cpp/actors/dnscachelib/dnscache.cpp index 649339ddb2..4114b8023e 100644 --- a/library/cpp/actors/dnscachelib/dnscache.cpp +++ b/library/cpp/actors/dnscachelib/dnscache.cpp @@ -12,7 +12,7 @@ LWTRACE_USING(DNSCACHELIB_PROVIDER); static_assert(sizeof(ares_channel) == sizeof(void*), "expect sizeof(ares_channel) == sizeof(void *)"); -TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg, ui32 timeout) +TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg, ui32 timeout) : EntryLifetime(lifetime) , NegativeLifetime(neg) , Timeout(TDuration::MicroSeconds(timeout)) @@ -24,12 +24,12 @@ TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg , PtrCacheMisses(0) { #ifdef _win_ - if (ares_library_init(ARES_LIB_INIT_WIN32) != ARES_SUCCESS) { - LWPROBE(AresInitFailed); - ythrow yexception() << "ares_init() failed"; - } + if (ares_library_init(ARES_LIB_INIT_WIN32) != ARES_SUCCESS) { + LWPROBE(AresInitFailed); + ythrow yexception() << "ares_init() failed"; + } #endif - + ares_channel chan; if (ares_init(&chan) != ARES_SUCCESS) { @@ -46,9 +46,9 @@ TDnsCache::~TDnsCache(void) { ares_cancel(chan); ares_destroy(chan); LWPROBE(Destroyed); - + #ifdef _win_ - ares_library_cleanup(); + ares_library_cleanup(); #endif } diff --git a/library/cpp/actors/dnscachelib/dnscache.h b/library/cpp/actors/dnscachelib/dnscache.h index 3313a251a1..2c7686cec5 100644 --- a/library/cpp/actors/dnscachelib/dnscache.h +++ b/library/cpp/actors/dnscachelib/dnscache.h @@ -15,17 +15,17 @@ * 3) most of the time IP addresses do not change * 4) it's OK to return old IP address when DNS server not responding in time */ - + class TDnsCache { public: - TDnsCache(bool allowIpv4 = true, bool allowIpv6 = true, time_t entry_lifetime = 1800, time_t neg_lifetime = 1, ui32 request_timeout = 500000); + TDnsCache(bool allowIpv4 = true, bool allowIpv6 = true, time_t entry_lifetime = 1800, time_t neg_lifetime = 1, ui32 request_timeout = 500000); ~TDnsCache(); TString GetHostByAddr(const NAddr::IRemoteAddr&); // ip in network byte order TIpHost Get(const TString& host); - + /* use with AF_INET, AF_INET6 or AF_UNSPEC */ NAddr::IRemoteAddrPtr GetAddr(const TString& host, int family, @@ -113,8 +113,8 @@ private: const time_t EntryLifetime; const time_t NegativeLifetime; const TDuration Timeout; - const bool AllowIpV4; - const bool AllowIpV6; + const bool AllowIpV4; + const bool AllowIpV6; TMutex CacheMtx; THostCache HostCache; diff --git a/library/cpp/actors/helpers/flow_controlled_queue.cpp b/library/cpp/actors/helpers/flow_controlled_queue.cpp index d75cc54023..81d26c3e55 100644 --- a/library/cpp/actors/helpers/flow_controlled_queue.cpp +++ b/library/cpp/actors/helpers/flow_controlled_queue.cpp @@ -1,215 +1,215 @@ -#include "flow_controlled_queue.h" - +#include "flow_controlled_queue.h" + #include <library/cpp/actors/core/interconnect.h> #include <library/cpp/actors/core/hfunc.h> #include <library/cpp/actors/util/datetime.h> - -#include <util/generic/deque.h> -#include <util/datetime/cputimer.h> -#include <util/generic/algorithm.h> - -namespace NActors { - -class TFlowControlledRequestQueue; - -class TFlowControlledRequestActor : public IActor { - TFlowControlledRequestQueue * const QueueActor; - - void HandleReply(TAutoPtr<IEventHandle> &ev); - void HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev); -public: + +#include <util/generic/deque.h> +#include <util/datetime/cputimer.h> +#include <util/generic/algorithm.h> + +namespace NActors { + +class TFlowControlledRequestQueue; + +class TFlowControlledRequestActor : public IActor { + TFlowControlledRequestQueue * const QueueActor; + + void HandleReply(TAutoPtr<IEventHandle> &ev); + void HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev); +public: const TActorId Source; - const ui64 Cookie; - const ui32 Flags; - const ui64 StartCounter; - + const ui64 Cookie; + const ui32 Flags; + const ui64 StartCounter; + TFlowControlledRequestActor(ui32 activity, TFlowControlledRequestQueue *queue, TActorId source, ui64 cookie, ui32 flags) - : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestActor::StateWait), activity) - , QueueActor(queue) - , Source(source) - , Cookie(cookie) - , Flags(flags) + : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestActor::StateWait), activity) + , QueueActor(queue) + , Source(source) + , Cookie(cookie) + , Flags(flags) , StartCounter(GetCycleCountFast()) - {} - - STATEFN(StateWait) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvents::TEvUndelivered, HandleUndelivered); - default: - HandleReply(ev); - } - } - - TDuration AccumulatedLatency() const { + {} + + STATEFN(StateWait) { + switch (ev->GetTypeRewrite()) { + hFunc(TEvents::TEvUndelivered, HandleUndelivered); + default: + HandleReply(ev); + } + } + + TDuration AccumulatedLatency() const { const ui64 cc = GetCycleCountFast() - StartCounter; - return CyclesToDuration(cc); - } - - using IActor::PassAway; -}; - -class TFlowControlledRequestQueue : public IActor { + return CyclesToDuration(cc); + } + + using IActor::PassAway; +}; + +class TFlowControlledRequestQueue : public IActor { const TActorId Target; - const TFlowControlledQueueConfig Config; - - TDeque<THolder<IEventHandle>> UnhandledRequests; - TDeque<TFlowControlledRequestActor *> RegisteredRequests; - - bool Subscribed = false; - - TDuration MinimalSeenLatency; - - bool CanRegister() { - const ui64 inFly = RegisteredRequests.size(); - if (inFly <= Config.MinAllowedInFly) // <= for handling minAllowed == 0 - return true; - - if (inFly >= Config.MaxAllowedInFly) - return false; - - if (Config.TargetDynamicRate) { - if (const ui64 dynMax = MinimalSeenLatency.MicroSeconds() * Config.TargetDynamicRate / 1000000) { - if (inFly >= dynMax) - return false; - } - } - - const TDuration currentLatency = RegisteredRequests.front()->AccumulatedLatency(); - if (currentLatency <= Config.MinTrackedLatency) - return true; - - if (currentLatency <= MinimalSeenLatency * Config.LatencyFactor) - return true; - - return false; - } - - void HandleForwardedEvent(TAutoPtr<IEventHandle> &ev) { - if (CanRegister()) { - RegisterReqActor(ev); - } else { - UnhandledRequests.emplace_back(ev.Release()); - } - } - - void RegisterReqActor(THolder<IEventHandle> ev) { - TFlowControlledRequestActor *reqActor = new TFlowControlledRequestActor(ActivityType, this, ev->Sender, ev->Cookie, ev->Flags); + const TFlowControlledQueueConfig Config; + + TDeque<THolder<IEventHandle>> UnhandledRequests; + TDeque<TFlowControlledRequestActor *> RegisteredRequests; + + bool Subscribed = false; + + TDuration MinimalSeenLatency; + + bool CanRegister() { + const ui64 inFly = RegisteredRequests.size(); + if (inFly <= Config.MinAllowedInFly) // <= for handling minAllowed == 0 + return true; + + if (inFly >= Config.MaxAllowedInFly) + return false; + + if (Config.TargetDynamicRate) { + if (const ui64 dynMax = MinimalSeenLatency.MicroSeconds() * Config.TargetDynamicRate / 1000000) { + if (inFly >= dynMax) + return false; + } + } + + const TDuration currentLatency = RegisteredRequests.front()->AccumulatedLatency(); + if (currentLatency <= Config.MinTrackedLatency) + return true; + + if (currentLatency <= MinimalSeenLatency * Config.LatencyFactor) + return true; + + return false; + } + + void HandleForwardedEvent(TAutoPtr<IEventHandle> &ev) { + if (CanRegister()) { + RegisterReqActor(ev); + } else { + UnhandledRequests.emplace_back(ev.Release()); + } + } + + void RegisterReqActor(THolder<IEventHandle> ev) { + TFlowControlledRequestActor *reqActor = new TFlowControlledRequestActor(ActivityType, this, ev->Sender, ev->Cookie, ev->Flags); const TActorId reqActorId = RegisterWithSameMailbox(reqActor); - RegisteredRequests.emplace_back(reqActor); - - if (!Subscribed && (Target.NodeId() != SelfId().NodeId())) { - Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvSubscribe(), IEventHandle::FlagTrackDelivery); - Subscribed = true; - } - - TActivationContext::Send(new IEventHandle(Target, reqActorId, ev->ReleaseBase().Release(), IEventHandle::FlagTrackDelivery, ev->Cookie)); - } - - void PumpQueue() { - while (RegisteredRequests && RegisteredRequests.front() == nullptr) - RegisteredRequests.pop_front(); - - while (UnhandledRequests && CanRegister()) { - RegisterReqActor(std::move(UnhandledRequests.front())); - UnhandledRequests.pop_front(); - } - } - - void HandleDisconnected() { - Subscribed = false; - - const ui32 nodeid = Target.NodeId(); - for (TFlowControlledRequestActor *reqActor : RegisteredRequests) { - if (reqActor) { - if (reqActor->Flags & IEventHandle::FlagSubscribeOnSession) { - TActivationContext::Send( + RegisteredRequests.emplace_back(reqActor); + + if (!Subscribed && (Target.NodeId() != SelfId().NodeId())) { + Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvSubscribe(), IEventHandle::FlagTrackDelivery); + Subscribed = true; + } + + TActivationContext::Send(new IEventHandle(Target, reqActorId, ev->ReleaseBase().Release(), IEventHandle::FlagTrackDelivery, ev->Cookie)); + } + + void PumpQueue() { + while (RegisteredRequests && RegisteredRequests.front() == nullptr) + RegisteredRequests.pop_front(); + + while (UnhandledRequests && CanRegister()) { + RegisterReqActor(std::move(UnhandledRequests.front())); + UnhandledRequests.pop_front(); + } + } + + void HandleDisconnected() { + Subscribed = false; + + const ui32 nodeid = Target.NodeId(); + for (TFlowControlledRequestActor *reqActor : RegisteredRequests) { + if (reqActor) { + if (reqActor->Flags & IEventHandle::FlagSubscribeOnSession) { + TActivationContext::Send( new IEventHandle(reqActor->Source, TActorId(), new TEvInterconnect::TEvNodeDisconnected(nodeid), 0, reqActor->Cookie) - ); - } - reqActor->PassAway(); - } - } - - RegisteredRequests.clear(); - - for (auto &ev : UnhandledRequests) { - const auto reason = TEvents::TEvUndelivered::Disconnected; - if (ev->Flags & IEventHandle::FlagTrackDelivery) { - TActivationContext::Send( - new IEventHandle(ev->Sender, ev->Recipient, new TEvents::TEvUndelivered(ev->GetTypeRewrite(), reason), 0, ev->Cookie) - ); - } - } - - UnhandledRequests.clear(); - } - - void HandlePoison() { - HandleDisconnected(); - - if (SelfId().NodeId() != Target.NodeId()) - Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvUnsubscribe()); - - PassAway(); - } -public: + ); + } + reqActor->PassAway(); + } + } + + RegisteredRequests.clear(); + + for (auto &ev : UnhandledRequests) { + const auto reason = TEvents::TEvUndelivered::Disconnected; + if (ev->Flags & IEventHandle::FlagTrackDelivery) { + TActivationContext::Send( + new IEventHandle(ev->Sender, ev->Recipient, new TEvents::TEvUndelivered(ev->GetTypeRewrite(), reason), 0, ev->Cookie) + ); + } + } + + UnhandledRequests.clear(); + } + + void HandlePoison() { + HandleDisconnected(); + + if (SelfId().NodeId() != Target.NodeId()) + Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvUnsubscribe()); + + PassAway(); + } +public: TFlowControlledRequestQueue(TActorId target, ui32 activity, const TFlowControlledQueueConfig &config) - : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestQueue::StateWork), activity) - , Target(target) - , Config(config) - , MinimalSeenLatency(TDuration::Seconds(1)) - {} - - STATEFN(StateWork) { - switch (ev->GetTypeRewrite()) { - cFunc(TEvInterconnect::TEvNodeDisconnected::EventType, HandleDisconnected); - IgnoreFunc(TEvInterconnect::TEvNodeConnected); - cFunc(TEvents::TEvUndelivered::EventType, HandleDisconnected); - cFunc(TEvents::TEvPoison::EventType, HandlePoison); - default: - HandleForwardedEvent(ev); - } - } - - void HandleRequestReply(TAutoPtr<IEventHandle> &ev, TFlowControlledRequestActor *reqActor) { - auto it = Find(RegisteredRequests, reqActor); - if (it == RegisteredRequests.end()) - return; - - TActivationContext::Send(ev->Forward(reqActor->Source)); - const TDuration reqLatency = reqActor->AccumulatedLatency(); - if (reqLatency < MinimalSeenLatency) - MinimalSeenLatency = reqLatency; - - *it = nullptr; - PumpQueue(); - } - - void HandleRequestUndelivered(TEvents::TEvUndelivered::TPtr &ev, TFlowControlledRequestActor *reqActor) { - auto it = Find(RegisteredRequests, reqActor); - if (it == RegisteredRequests.end()) - return; - - TActivationContext::Send(ev->Forward(reqActor->Source)); - - *it = nullptr; - PumpQueue(); - } -}; - -void TFlowControlledRequestActor::HandleReply(TAutoPtr<IEventHandle> &ev) { - QueueActor->HandleRequestReply(ev, this); - PassAway(); -} - -void TFlowControlledRequestActor::HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev) { - QueueActor->HandleRequestUndelivered(ev, this); - PassAway(); -} - - + : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestQueue::StateWork), activity) + , Target(target) + , Config(config) + , MinimalSeenLatency(TDuration::Seconds(1)) + {} + + STATEFN(StateWork) { + switch (ev->GetTypeRewrite()) { + cFunc(TEvInterconnect::TEvNodeDisconnected::EventType, HandleDisconnected); + IgnoreFunc(TEvInterconnect::TEvNodeConnected); + cFunc(TEvents::TEvUndelivered::EventType, HandleDisconnected); + cFunc(TEvents::TEvPoison::EventType, HandlePoison); + default: + HandleForwardedEvent(ev); + } + } + + void HandleRequestReply(TAutoPtr<IEventHandle> &ev, TFlowControlledRequestActor *reqActor) { + auto it = Find(RegisteredRequests, reqActor); + if (it == RegisteredRequests.end()) + return; + + TActivationContext::Send(ev->Forward(reqActor->Source)); + const TDuration reqLatency = reqActor->AccumulatedLatency(); + if (reqLatency < MinimalSeenLatency) + MinimalSeenLatency = reqLatency; + + *it = nullptr; + PumpQueue(); + } + + void HandleRequestUndelivered(TEvents::TEvUndelivered::TPtr &ev, TFlowControlledRequestActor *reqActor) { + auto it = Find(RegisteredRequests, reqActor); + if (it == RegisteredRequests.end()) + return; + + TActivationContext::Send(ev->Forward(reqActor->Source)); + + *it = nullptr; + PumpQueue(); + } +}; + +void TFlowControlledRequestActor::HandleReply(TAutoPtr<IEventHandle> &ev) { + QueueActor->HandleRequestReply(ev, this); + PassAway(); +} + +void TFlowControlledRequestActor::HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev) { + QueueActor->HandleRequestUndelivered(ev, this); + PassAway(); +} + + IActor* CreateFlowControlledRequestQueue(TActorId targetId, ui32 activity, const TFlowControlledQueueConfig &config) { - return new TFlowControlledRequestQueue(targetId, activity, config); -} - -} + return new TFlowControlledRequestQueue(targetId, activity, config); +} + +} diff --git a/library/cpp/actors/helpers/flow_controlled_queue.h b/library/cpp/actors/helpers/flow_controlled_queue.h index d250405304..0699b35ca6 100644 --- a/library/cpp/actors/helpers/flow_controlled_queue.h +++ b/library/cpp/actors/helpers/flow_controlled_queue.h @@ -1,18 +1,18 @@ -#pragma once - +#pragma once + #include <library/cpp/actors/core/actor.h> - -namespace NActors { - - struct TFlowControlledQueueConfig { - ui32 MinAllowedInFly = 20; - ui32 MaxAllowedInFly = 100; - ui32 TargetDynamicRate = 0; - - TDuration MinTrackedLatency = TDuration::MilliSeconds(20); - ui32 LatencyFactor = 4; - }; - + +namespace NActors { + + struct TFlowControlledQueueConfig { + ui32 MinAllowedInFly = 20; + ui32 MaxAllowedInFly = 100; + ui32 TargetDynamicRate = 0; + + TDuration MinTrackedLatency = TDuration::MilliSeconds(20); + ui32 LatencyFactor = 4; + }; + IActor* CreateFlowControlledRequestQueue(TActorId targetId, ui32 activity = IActor::ACTORLIB_COMMON, const TFlowControlledQueueConfig &config = TFlowControlledQueueConfig()); - -} + +} diff --git a/library/cpp/actors/helpers/mon_histogram_helper.h b/library/cpp/actors/helpers/mon_histogram_helper.h index a9a57e3823..35d030b822 100644 --- a/library/cpp/actors/helpers/mon_histogram_helper.h +++ b/library/cpp/actors/helpers/mon_histogram_helper.h @@ -1,10 +1,10 @@ -#pragma once - +#pragma once + #include <library/cpp/monlib/dynamic_counters/counters.h> #include <util/string/cast.h> -namespace NActors { +namespace NActors { namespace NMon { class THistogramCounterHelper { public: @@ -13,7 +13,7 @@ namespace NActors { , BucketCount(0) { } - + THistogramCounterHelper(const THistogramCounterHelper&) = default; void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit, @@ -21,7 +21,7 @@ namespace NActors { { Y_ASSERT(FirstBucketVal == 0); Y_ASSERT(BucketCount == 0); - + FirstBucketVal = firstBucket; BucketCount = bucketCnt; BucketsHolder.reserve(BucketCount); @@ -33,7 +33,7 @@ namespace NActors { Buckets.push_back(BucketsHolder.back().Get()); } } - + void Add(ui64 val) { Y_ASSERT(FirstBucketVal != 0); Y_ASSERT(BucketCount != 0); @@ -47,7 +47,7 @@ namespace NActors { } Buckets[ind]->Inc(); } - + ui64 GetBucketCount() const { return BucketCount; } @@ -73,8 +73,8 @@ namespace NActors { // Last slot is up to +INF return "INF"; } - } - + } + private: ui64 FirstBucketVal; ui64 BucketCount; @@ -82,5 +82,5 @@ namespace NActors { TVector<NMonitoring::TDeprecatedCounter*> Buckets; }; - } + } } diff --git a/library/cpp/actors/helpers/ya.make b/library/cpp/actors/helpers/ya.make index d8771179de..b6cce2cc23 100644 --- a/library/cpp/actors/helpers/ya.make +++ b/library/cpp/actors/helpers/ya.make @@ -1,23 +1,23 @@ -LIBRARY() - +LIBRARY() + OWNER(g:kikimr) - -SRCS( + +SRCS( activeactors.cpp activeactors.h - flow_controlled_queue.cpp - flow_controlled_queue.h + flow_controlled_queue.cpp + flow_controlled_queue.h future_callback.h mon_histogram_helper.h selfping_actor.cpp -) - -PEERDIR( +) + +PEERDIR( library/cpp/actors/core library/cpp/monlib/dynamic_counters -) - -END() +) + +END() RECURSE_FOR_TESTS( ut diff --git a/library/cpp/actors/interconnect/interconnect_mon.cpp b/library/cpp/actors/interconnect/interconnect_mon.cpp index cf924ccbf9..75104af8de 100644 --- a/library/cpp/actors/interconnect/interconnect_mon.cpp +++ b/library/cpp/actors/interconnect/interconnect_mon.cpp @@ -20,10 +20,10 @@ namespace NInterconnect { ui32 PendingReplies = 0; public: - static constexpr IActor::EActorActivity ActorActivityType() { - return INTERCONNECT_MONACTOR; - } - + static constexpr IActor::EActorActivity ActorActivityType() { + return INTERCONNECT_MONACTOR; + } + TQueryProcessor(const TActorId& sender, bool json) : Sender(sender) , Json(json) @@ -186,10 +186,10 @@ namespace NInterconnect { TIntrusivePtr<TInterconnectProxyCommon> Common; public: - static constexpr IActor::EActorActivity ActorActivityType() { - return INTERCONNECT_MONACTOR; - } - + static constexpr IActor::EActorActivity ActorActivityType() { + return INTERCONNECT_MONACTOR; + } + TInterconnectMonActor(TIntrusivePtr<TInterconnectProxyCommon> common) : TActor(&TThis::StateFunc) , Common(std::move(common)) diff --git a/library/cpp/actors/interconnect/slowpoke_actor.h b/library/cpp/actors/interconnect/slowpoke_actor.h index 4b02e5da48..00eb020b07 100644 --- a/library/cpp/actors/interconnect/slowpoke_actor.h +++ b/library/cpp/actors/interconnect/slowpoke_actor.h @@ -12,10 +12,10 @@ namespace NActors { const TDuration RescheduleMax; public: - static constexpr NKikimrServices::TActivity::EType ActorActivityType() { - return NKikimrServices::TActivity::INTERCONNECT_COMMON; - } - + static constexpr NKikimrServices::TActivity::EType ActorActivityType() { + return NKikimrServices::TActivity::INTERCONNECT_COMMON; + } + TSlowpokeActor(TDuration duration, TDuration sleepMin, TDuration sleepMax, TDuration rescheduleMin, TDuration rescheduleMax) : Duration(duration) , SleepMin(sleepMin) diff --git a/library/cpp/actors/memory_log/memlog.cpp b/library/cpp/actors/memory_log/memlog.cpp index 8e6b46727d..9cd7dee0fe 100644 --- a/library/cpp/actors/memory_log/memlog.cpp +++ b/library/cpp/actors/memory_log/memlog.cpp @@ -15,11 +15,11 @@ static int (*FastGetCpu)(unsigned* cpu, unsigned* node, void* unused); #endif #if defined(_unix_) -#include <sched.h> +#include <sched.h> #elif defined(_win_) -#include <WinBase.h> +#include <WinBase.h> #else -#error NO IMPLEMENTATION FOR THE PLATFORM +#error NO IMPLEMENTATION FOR THE PLATFORM #endif const char TMemoryLog::DEFAULT_LAST_MARK[16] = { @@ -62,34 +62,34 @@ const char TMemoryLog::CLEAR_MARK[16] = { unsigned TMemoryLog::GetSelfCpu() noexcept { #if defined(_unix_) -#if HAVE_VDSO_GETCPU +#if HAVE_VDSO_GETCPU unsigned cpu; if (Y_LIKELY(FastGetCpu != nullptr)) { auto result = FastGetCpu(&cpu, nullptr, nullptr); Y_VERIFY(result == 0); - return cpu; + return cpu; } else { return 0; } -#elif defined(_x86_64_) || defined(_i386_) +#elif defined(_x86_64_) || defined(_i386_) -#define CPUID(func, eax, ebx, ecx, edx) \ - __asm__ __volatile__( \ - "cpuid" \ - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) \ - : "a"(func)); +#define CPUID(func, eax, ebx, ecx, edx) \ + __asm__ __volatile__( \ + "cpuid" \ + : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) \ + : "a"(func)); int a = 0, b = 0, c = 0, d = 0; CPUID(0x1, a, b, c, d); int acpiID = (b >> 24); return acpiID; -#elif defined(__CNUC__) +#elif defined(__CNUC__) return sched_getcpu(); -#else +#else return 0; -#endif +#endif #elif defined(_win_) return GetCurrentProcessorNumber(); @@ -99,16 +99,16 @@ unsigned TMemoryLog::GetSelfCpu() noexcept { } TMemoryLog* TMemoryLog::MemLogBuffer = nullptr; -Y_POD_THREAD(TThread::TId) -TMemoryLog::LogThreadId; +Y_POD_THREAD(TThread::TId) +TMemoryLog::LogThreadId; char* TMemoryLog::LastMarkIsHere = nullptr; std::atomic<bool> TMemoryLog::PrintLastMark(true); TMemoryLog::TMemoryLog(size_t totalSize, size_t grainSize) - : GrainSize(grainSize) - , FreeGrains(DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE * 2) - , Buf(totalSize) + : GrainSize(grainSize) + , FreeGrains(DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE * 2) + , Buf(totalSize) { Y_VERIFY(DEFAULT_TOTAL_SIZE % DEFAULT_GRAIN_SIZE == 0); NumberOfGrains = DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE; @@ -266,7 +266,7 @@ bool MemLogWrite(const char* begin, size_t msgSize, bool addLF) noexcept { // alignment required by NoCacheMemcpy // check for format for snprintf constexpr size_t prologSize = 48; - alignas(TMemoryLog::MemcpyAlignment) char prolog[prologSize + 1]; + alignas(TMemoryLog::MemcpyAlignment) char prolog[prologSize + 1]; Y_VERIFY(AlignDown(&prolog, TMemoryLog::MemcpyAlignment) == &prolog); int snprintfResult = snprintf(prolog, prologSize + 1, @@ -291,7 +291,7 @@ bool MemLogWrite(const char* begin, size_t msgSize, bool addLF) noexcept { // warning: copy prolog first to avoid corruption of the message // by prolog tail NoCacheMemcpy(buffer, prolog, prologSize); - if (AlignDown(begin + prologSize, TMemoryLog::MemcpyAlignment) == begin + prologSize) { + if (AlignDown(begin + prologSize, TMemoryLog::MemcpyAlignment) == begin + prologSize) { NoCacheMemcpy(buffer + prologSize, begin, msgSize); } else { NoWCacheMemcpy(buffer + prologSize, begin, msgSize); @@ -335,14 +335,14 @@ bool MemLogVPrintF(const char* format, va_list params) noexcept { auto threadId = TMemoryLog::GetTheadId(); // alignment required by NoCacheMemcpy - alignas(TMemoryLog::MemcpyAlignment) char buf[TMemoryLog::MAX_MESSAGE_SIZE]; + alignas(TMemoryLog::MemcpyAlignment) char buf[TMemoryLog::MAX_MESSAGE_SIZE]; Y_VERIFY(AlignDown(&buf, TMemoryLog::MemcpyAlignment) == &buf); int prologSize = snprintf(buf, - TMemoryLog::MAX_MESSAGE_SIZE - 2, - "TS %020" PRIu64 " TI %020" PRIu64 " ", + TMemoryLog::MAX_MESSAGE_SIZE - 2, + "TS %020" PRIu64 " TI %020" PRIu64 " ", GetCycleCountFast(), - threadId); + threadId); if (Y_UNLIKELY(prologSize < 0)) { return false; diff --git a/library/cpp/actors/memory_log/memlog.h b/library/cpp/actors/memory_log/memlog.h index 2aa27272a6..ffeb1c308d 100644 --- a/library/cpp/actors/memory_log/memlog.h +++ b/library/cpp/actors/memory_log/memlog.h @@ -18,14 +18,14 @@ #endif #ifndef NO_SANITIZE_THREAD -#define NO_SANITIZE_THREAD -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#undef NO_SANITIZE_THREAD -#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) -#endif -#endif +#define NO_SANITIZE_THREAD +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#undef NO_SANITIZE_THREAD +#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) #endif +#endif +#endif class TMemoryLog { public: @@ -60,8 +60,8 @@ public: } inline static void CreateMemoryLogBuffer( - size_t totalSize = DEFAULT_TOTAL_SIZE, - size_t grainSize = DEFAULT_GRAIN_SIZE) + size_t totalSize = DEFAULT_TOTAL_SIZE, + size_t grainSize = DEFAULT_GRAIN_SIZE) Y_COLD { if (AtomicGet(MemLogBuffer) != nullptr) { return; @@ -193,11 +193,11 @@ bool MemLogWriteStruct(const TObj* obj) noexcept { return MemLogWrite(begin, begin + sizeof(TObj)); } -Y_PRINTF_FORMAT(1, 0) +Y_PRINTF_FORMAT(1, 0) bool MemLogVPrintF(const char* format, va_list params) noexcept; -Y_PRINTF_FORMAT(1, 2) -Y_WRAPPER +Y_PRINTF_FORMAT(1, 2) +Y_WRAPPER inline bool MemLogPrintF(const char* format, ...) noexcept { va_list params; va_start(params, format); diff --git a/library/cpp/actors/memory_log/mmap.cpp b/library/cpp/actors/memory_log/mmap.cpp index 201998d343..67dfd9a16f 100644 --- a/library/cpp/actors/memory_log/mmap.cpp +++ b/library/cpp/actors/memory_log/mmap.cpp @@ -1,11 +1,11 @@ #include "memlog.h" -#if defined(_unix_) -#include <sys/mman.h> -#elif defined(_win_) -#include <util/system/winint.h> +#if defined(_unix_) +#include <sys/mman.h> +#elif defined(_win_) +#include <util/system/winint.h> #else -#error NO IMPLEMENTATION FOR THE PLATFORM +#error NO IMPLEMENTATION FOR THE PLATFORM #endif void TMemoryLog::TMMapArea::MMap(size_t amount) { @@ -44,7 +44,7 @@ void TMemoryLog::TMMapArea::MUnmap() { return; } -#if defined(_unix_) +#if defined(_unix_) int result = ::munmap(BufPtr, Size); Y_VERIFY(result == 0); diff --git a/library/cpp/actors/prof/tag.cpp b/library/cpp/actors/prof/tag.cpp index 9ccf03e1a9..f97191f94c 100644 --- a/library/cpp/actors/prof/tag.cpp +++ b/library/cpp/actors/prof/tag.cpp @@ -18,8 +18,8 @@ namespace NProfiling { class TStringAtoms { private: - TMutex Mutex; - atomizer<ci_hash, ci_equal_to> Tags; + TMutex Mutex; + atomizer<ci_hash, ci_equal_to> Tags; public: static TStringAtoms& Instance() { @@ -58,17 +58,17 @@ namespace NProfiling { return Tags.size(); } } - }; + }; - ui32 MakeTag(const char* s) { + ui32 MakeTag(const char* s) { return TStringAtoms::Instance().MakeTag(s); - } + } ui32 MakeTags(const TVector<const char*>& ss) { return TStringAtoms::Instance().MakeTags(ss); - } + } - const char* GetTag(ui32 tag) { + const char* GetTag(ui32 tag) { return TStringAtoms::Instance().GetTag(tag); } diff --git a/library/cpp/actors/prof/tag.h b/library/cpp/actors/prof/tag.h index 357e264a22..7b743ca183 100644 --- a/library/cpp/actors/prof/tag.h +++ b/library/cpp/actors/prof/tag.h @@ -9,65 +9,65 @@ */ namespace NProfiling { - ui32 MakeTag(const char* s); + ui32 MakeTag(const char* s); - // Make only unique tags. Y_VERIFY inside. + // Make only unique tags. Y_VERIFY inside. ui32 MakeTags(const TVector<const char*>& ss); - const char* GetTag(ui32 tag); + const char* GetTag(ui32 tag); size_t GetTagsCount(); using TSetThreadAllocTag = ui32(ui32 tag); extern TSetThreadAllocTag* SetThreadAllocTag; - class TMemoryTagScope { - public: + class TMemoryTagScope { + public: explicit TMemoryTagScope(ui32 tag) : RestoreTag(SetThreadAllocTag(tag)) - { - } + { + } explicit TMemoryTagScope(const char* tagName) { - ui32 newTag = MakeTag(tagName); + ui32 newTag = MakeTag(tagName); RestoreTag = SetThreadAllocTag(newTag); - } + } - TMemoryTagScope(TMemoryTagScope&& move) - : RestoreTag(move.RestoreTag) + TMemoryTagScope(TMemoryTagScope&& move) + : RestoreTag(move.RestoreTag) , Released(move.Released) - { + { move.Released = true; - } + } - TMemoryTagScope& operator=(TMemoryTagScope&& move) { - RestoreTag = move.RestoreTag; + TMemoryTagScope& operator=(TMemoryTagScope&& move) { + RestoreTag = move.RestoreTag; Released = move.Released; move.Released = true; - return *this; - } + return *this; + } static void Reset(ui32 tag) { SetThreadAllocTag(tag); } - void Release() { + void Release() { if (!Released) { SetThreadAllocTag(RestoreTag); Released = true; - } - } + } + } ~TMemoryTagScope() { if (!Released) { SetThreadAllocTag(RestoreTag); } - } - - protected: - TMemoryTagScope(const TMemoryTagScope&) = delete; - void operator=(const TMemoryTagScope&) = delete; - + } + + protected: + TMemoryTagScope(const TMemoryTagScope&) = delete; + void operator=(const TMemoryTagScope&) = delete; + ui32 RestoreTag = 0; bool Released = false; - }; + }; } diff --git a/library/cpp/actors/prof/ut/tag_ut.cpp b/library/cpp/actors/prof/ut/tag_ut.cpp index accf3921ab..f40dcc423c 100644 --- a/library/cpp/actors/prof/ut/tag_ut.cpp +++ b/library/cpp/actors/prof/ut/tag_ut.cpp @@ -15,7 +15,7 @@ private: UNIT_TEST(Test_MakeVector); UNIT_TEST_SUITE_END(); - + public: void Test_MakeTag(); void Test_Make2Tags(); @@ -58,7 +58,7 @@ void TAtomTagsTest::Test_MakeVector() { "vector tag 0", "vector tag 1", "vector tag 3", - "vector tag 4"}; + "vector tag 4"}; ui32 baseTag = MakeTags(strs); UNIT_ASSERT(baseTag != 0); for (ui32 i = 0; i < strs.size(); ++i) { diff --git a/library/cpp/actors/protos/services_common.proto b/library/cpp/actors/protos/services_common.proto index afa0ec0073..f3e8f3794f 100644 --- a/library/cpp/actors/protos/services_common.proto +++ b/library/cpp/actors/protos/services_common.proto @@ -13,7 +13,7 @@ enum EServiceCommon { INTERCONNECT_STATUS = 5; INTERCONNECT_NETWORK = 6; INTERCONNECT_SESSION = 7; - HTTP = 8; + HTTP = 8; // This value is reserved boundary. Is must not be aliased with any values // TODO: use reseved values upon protobuf update diff --git a/library/cpp/actors/protos/ya.make b/library/cpp/actors/protos/ya.make index 3a1488d78e..dafcf64f09 100644 --- a/library/cpp/actors/protos/ya.make +++ b/library/cpp/actors/protos/ya.make @@ -1,14 +1,14 @@ -PROTO_LIBRARY() - +PROTO_LIBRARY() + OWNER(g:kikimr) - -SRCS( - actors.proto + +SRCS( + actors.proto interconnect.proto services_common.proto unittests.proto -) - +) + EXCLUDE_TAGS(GO_PROTO) -END() +END() diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp index 6fa25b9965..5f5fdb1536 100644 --- a/library/cpp/actors/testlib/test_runtime.cpp +++ b/library/cpp/actors/testlib/test_runtime.cpp @@ -65,11 +65,11 @@ namespace NActors { if (Poller) Poller->Stop(); - if (MailboxTable) { - for (ui32 round = 0; !MailboxTable->Cleanup(); ++round) - Y_VERIFY(round < 10, "cyclic event/actor spawn while trying to shutdown actorsystem stub"); - } - + if (MailboxTable) { + for (ui32 round = 0; !MailboxTable->Cleanup(); ++round) + Y_VERIFY(round < 10, "cyclic event/actor spawn while trying to shutdown actorsystem stub"); + } + if (ActorSystem) ActorSystem->Stop(); @@ -427,10 +427,10 @@ namespace NActors { void Shutdown() override { } - bool Cleanup() override { - return true; - } - + bool Cleanup() override { + return true; + } + // generic TAffinity* Affinity() const override { Y_FAIL(); @@ -1574,7 +1574,7 @@ namespace NActors { node->ActorToActorId[recipientActor] = ev->GetRecipientRewrite(); TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), actorId); TActivationContext *prevTlsActivationContext = TlsActivationContext; - TlsActivationContext = &ctx; + TlsActivationContext = &ctx; CurrentRecipient = actorId; { TInverseGuard<TMutex> inverseGuard(Mutex); diff --git a/library/cpp/actors/util/affinity.cpp b/library/cpp/actors/util/affinity.cpp index cc1b6e70ec..aab8219d6f 100644 --- a/library/cpp/actors/util/affinity.cpp +++ b/library/cpp/actors/util/affinity.cpp @@ -1,41 +1,41 @@ -#include "affinity.h" - -#ifdef _linux_ -#include <sched.h> -#endif - -class TAffinity::TImpl { -#ifdef _linux_ - cpu_set_t Mask; -#endif -public: - TImpl() { -#ifdef _linux_ - int ar = sched_getaffinity(0, sizeof(cpu_set_t), &Mask); +#include "affinity.h" + +#ifdef _linux_ +#include <sched.h> +#endif + +class TAffinity::TImpl { +#ifdef _linux_ + cpu_set_t Mask; +#endif +public: + TImpl() { +#ifdef _linux_ + int ar = sched_getaffinity(0, sizeof(cpu_set_t), &Mask); Y_VERIFY_DEBUG(ar == 0); -#endif - } - +#endif + } + explicit TImpl(const ui8* cpus, ui32 size) { -#ifdef _linux_ - CPU_ZERO(&Mask); +#ifdef _linux_ + CPU_ZERO(&Mask); for (ui32 i = 0; i != size; ++i) { if (cpus[i]) { CPU_SET(i, &Mask); } } -#else +#else Y_UNUSED(cpus); Y_UNUSED(size); -#endif - } - - void Set() const { -#ifdef _linux_ - int ar = sched_setaffinity(0, sizeof(cpu_set_t), &Mask); +#endif + } + + void Set() const { +#ifdef _linux_ + int ar = sched_setaffinity(0, sizeof(cpu_set_t), &Mask); Y_VERIFY_DEBUG(ar == 0); -#endif - } +#endif + } operator TCpuMask() const { TCpuMask result; @@ -48,20 +48,20 @@ public: return result; } -}; - -TAffinity::TAffinity() { -} - -TAffinity::~TAffinity() { -} - -TAffinity::TAffinity(const ui8* x, ui32 sz) { +}; + +TAffinity::TAffinity() { +} + +TAffinity::~TAffinity() { +} + +TAffinity::TAffinity(const ui8* x, ui32 sz) { if (x && sz) { - Impl.Reset(new TImpl(x, sz)); + Impl.Reset(new TImpl(x, sz)); } -} - +} + TAffinity::TAffinity(const TCpuMask& mask) { if (!mask.IsEmpty()) { static_assert(sizeof(ui8) == sizeof(mask.Cpus[0])); @@ -71,19 +71,19 @@ TAffinity::TAffinity(const TCpuMask& mask) { } } -void TAffinity::Current() { - Impl.Reset(new TImpl()); -} - -void TAffinity::Set() const { +void TAffinity::Current() { + Impl.Reset(new TImpl()); +} + +void TAffinity::Set() const { if (!!Impl) { - Impl->Set(); + Impl->Set(); } -} - -bool TAffinity::Empty() const { +} + +bool TAffinity::Empty() const { return !Impl; -} +} TAffinity::operator TCpuMask() const { if (!!Impl) { diff --git a/library/cpp/actors/util/affinity.h b/library/cpp/actors/util/affinity.h index ae106ed180..0a20744240 100644 --- a/library/cpp/actors/util/affinity.h +++ b/library/cpp/actors/util/affinity.h @@ -1,49 +1,49 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include "cpumask.h" - + // Platform-specific class to set or get thread affinity -class TAffinity: public TThrRefBase, TNonCopyable { - class TImpl; - THolder<TImpl> Impl; - -public: - TAffinity(); +class TAffinity: public TThrRefBase, TNonCopyable { + class TImpl; + THolder<TImpl> Impl; + +public: + TAffinity(); TAffinity(const ui8* cpus, ui32 size); explicit TAffinity(const TCpuMask& mask); - ~TAffinity(); - - void Current(); - void Set() const; - bool Empty() const; + ~TAffinity(); + + void Current(); + void Set() const; + bool Empty() const; operator TCpuMask() const; -}; - +}; + // Scoped affinity setter -class TAffinityGuard : TNonCopyable { - bool Stacked; - TAffinity OldAffinity; - -public: - TAffinityGuard(const TAffinity* affinity) { +class TAffinityGuard : TNonCopyable { + bool Stacked; + TAffinity OldAffinity; + +public: + TAffinityGuard(const TAffinity* affinity) { Stacked = false; - if (affinity && !affinity->Empty()) { - OldAffinity.Current(); - affinity->Set(); - Stacked = true; - } - } - - ~TAffinityGuard() { - Release(); - } - - void Release() { - if (Stacked) { - OldAffinity.Set(); - Stacked = false; - } - } -}; + if (affinity && !affinity->Empty()) { + OldAffinity.Current(); + affinity->Set(); + Stacked = true; + } + } + + ~TAffinityGuard() { + Release(); + } + + void Release() { + if (Stacked) { + OldAffinity.Set(); + Stacked = false; + } + } +}; diff --git a/library/cpp/actors/util/defs.h b/library/cpp/actors/util/defs.h index 5c3b57665b..b88ce59ec6 100644 --- a/library/cpp/actors/util/defs.h +++ b/library/cpp/actors/util/defs.h @@ -1,16 +1,16 @@ -#pragma once - -// unique tag to fix pragma once gcc glueing: ./library/actors/util/defs.h - -#include <util/system/defaults.h> -#include <util/generic/bt_exception.h> -#include <util/generic/noncopyable.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/yexception.h> -#include <util/system/atomic.h> -#include <util/system/align.h> -#include <util/generic/vector.h> -#include <util/datetime/base.h> -#include <util/generic/ylimits.h> -#include "intrinsics.h" +#pragma once + +// unique tag to fix pragma once gcc glueing: ./library/actors/util/defs.h + +#include <util/system/defaults.h> +#include <util/generic/bt_exception.h> +#include <util/generic/noncopyable.h> +#include <util/generic/ptr.h> +#include <util/generic/string.h> +#include <util/generic/yexception.h> +#include <util/system/atomic.h> +#include <util/system/align.h> +#include <util/generic/vector.h> +#include <util/datetime/base.h> +#include <util/generic/ylimits.h> +#include "intrinsics.h" diff --git a/library/cpp/actors/util/futex.h b/library/cpp/actors/util/futex.h index c193f8d128..9f8a7b53bc 100644 --- a/library/cpp/actors/util/futex.h +++ b/library/cpp/actors/util/futex.h @@ -1,13 +1,13 @@ -#pragma once - -#ifdef _linux_ - -#include <linux/futex.h> -#include <unistd.h> -#include <sys/syscall.h> - -static long SysFutex(void* addr1, int op, int val1, struct timespec* timeout, void* addr2, int val3) { - return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); -} - -#endif +#pragma once + +#ifdef _linux_ + +#include <linux/futex.h> +#include <unistd.h> +#include <sys/syscall.h> + +static long SysFutex(void* addr1, int op, int val1, struct timespec* timeout, void* addr2, int val3) { + return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); +} + +#endif diff --git a/library/cpp/actors/util/intrinsics.h b/library/cpp/actors/util/intrinsics.h index df07e36896..983bf4788d 100644 --- a/library/cpp/actors/util/intrinsics.h +++ b/library/cpp/actors/util/intrinsics.h @@ -1,97 +1,97 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/system/atomic.h> -#include <util/system/spinlock.h> - +#pragma once + +#include <util/system/defaults.h> +#include <util/system/atomic.h> +#include <util/system/spinlock.h> + #include <library/cpp/sse/sse.h> // The header chooses appropriate SSE support - -static_assert(sizeof(TAtomic) == 8, "expect sizeof(TAtomic) == 8"); - -// we need explicit 32 bit operations to keep cache-line friendly packs -// so have to define some atomics additionaly to arcadia one -#ifdef _win_ -#pragma intrinsic(_InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd) -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#endif - -inline bool AtomicUi32Cas(volatile ui32* a, ui32 exchange, ui32 compare) { -#ifdef _win_ - return _InterlockedCompareExchange((volatile long*)a, exchange, compare) == (long)compare; -#else - ui32 expected = compare; - return __atomic_compare_exchange_n(a, &expected, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Add(volatile ui32* a, ui32 add) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, add) + add; -#else - return __atomic_add_fetch(a, add, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Sub(volatile ui32* a, ui32 sub) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, -(long)sub) - sub; -#else - return __atomic_sub_fetch(a, sub, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Increment(volatile ui32* a) { -#ifdef _win_ - return _InterlockedIncrement((volatile long*)a); -#else - return __atomic_add_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Decrement(volatile ui32* a) { -#ifdef _win_ - return _InterlockedDecrement((volatile long*)a); -#else - return __atomic_sub_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -template <typename T> -inline void AtomicStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELEASE); -#endif -} - -template <typename T> -inline void RelaxedStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELAXED); -#endif -} - -template <typename T> -inline T AtomicLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_ACQUIRE); -#endif -} - -template <typename T> -inline T RelaxedLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_RELAXED); -#endif -} + +static_assert(sizeof(TAtomic) == 8, "expect sizeof(TAtomic) == 8"); + +// we need explicit 32 bit operations to keep cache-line friendly packs +// so have to define some atomics additionaly to arcadia one +#ifdef _win_ +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#endif + +inline bool AtomicUi32Cas(volatile ui32* a, ui32 exchange, ui32 compare) { +#ifdef _win_ + return _InterlockedCompareExchange((volatile long*)a, exchange, compare) == (long)compare; +#else + ui32 expected = compare; + return __atomic_compare_exchange_n(a, &expected, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +#endif +} + +inline ui32 AtomicUi32Add(volatile ui32* a, ui32 add) { +#ifdef _win_ + return _InterlockedExchangeAdd((volatile long*)a, add) + add; +#else + return __atomic_add_fetch(a, add, __ATOMIC_SEQ_CST); +#endif +} + +inline ui32 AtomicUi32Sub(volatile ui32* a, ui32 sub) { +#ifdef _win_ + return _InterlockedExchangeAdd((volatile long*)a, -(long)sub) - sub; +#else + return __atomic_sub_fetch(a, sub, __ATOMIC_SEQ_CST); +#endif +} + +inline ui32 AtomicUi32Increment(volatile ui32* a) { +#ifdef _win_ + return _InterlockedIncrement((volatile long*)a); +#else + return __atomic_add_fetch(a, 1, __ATOMIC_SEQ_CST); +#endif +} + +inline ui32 AtomicUi32Decrement(volatile ui32* a) { +#ifdef _win_ + return _InterlockedDecrement((volatile long*)a); +#else + return __atomic_sub_fetch(a, 1, __ATOMIC_SEQ_CST); +#endif +} + +template <typename T> +inline void AtomicStore(volatile T* a, T x) { + static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); +#ifdef _win_ + *a = x; +#else + __atomic_store_n(a, x, __ATOMIC_RELEASE); +#endif +} + +template <typename T> +inline void RelaxedStore(volatile T* a, T x) { + static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); +#ifdef _win_ + *a = x; +#else + __atomic_store_n(a, x, __ATOMIC_RELAXED); +#endif +} + +template <typename T> +inline T AtomicLoad(volatile T* a) { +#ifdef _win_ + return *a; +#else + return __atomic_load_n(a, __ATOMIC_ACQUIRE); +#endif +} + +template <typename T> +inline T RelaxedLoad(volatile T* a) { +#ifdef _win_ + return *a; +#else + return __atomic_load_n(a, __ATOMIC_RELAXED); +#endif +} diff --git a/library/cpp/actors/util/named_tuple.h b/library/cpp/actors/util/named_tuple.h index 67f185bba8..5a8999c4ce 100644 --- a/library/cpp/actors/util/named_tuple.h +++ b/library/cpp/actors/util/named_tuple.h @@ -2,29 +2,29 @@ #include "defs.h" -template <typename TDerived> +template <typename TDerived> struct TNamedTupleBase { - friend bool operator==(const TDerived& x, const TDerived& y) { + friend bool operator==(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() == y.ConvertToTuple(); } - friend bool operator!=(const TDerived& x, const TDerived& y) { + friend bool operator!=(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() != y.ConvertToTuple(); } - friend bool operator<(const TDerived& x, const TDerived& y) { + friend bool operator<(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() < y.ConvertToTuple(); } - friend bool operator<=(const TDerived& x, const TDerived& y) { + friend bool operator<=(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() <= y.ConvertToTuple(); } - friend bool operator>(const TDerived& x, const TDerived& y) { + friend bool operator>(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() > y.ConvertToTuple(); } - friend bool operator>=(const TDerived& x, const TDerived& y) { + friend bool operator>=(const TDerived& x, const TDerived& y) { return x.ConvertToTuple() >= y.ConvertToTuple(); } }; diff --git a/library/cpp/actors/util/queue_chunk.h b/library/cpp/actors/util/queue_chunk.h index 8a4e02d8cb..96657ee890 100644 --- a/library/cpp/actors/util/queue_chunk.h +++ b/library/cpp/actors/util/queue_chunk.h @@ -1,29 +1,29 @@ -#pragma once - -#include "defs.h" - -template <typename T, ui32 TSize, typename TDerived> -struct TQueueChunkDerived { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunkDerived*)) / sizeof(T); +#pragma once + +#include "defs.h" + +template <typename T, ui32 TSize, typename TDerived> +struct TQueueChunkDerived { + static const ui32 EntriesCount = (TSize - sizeof(TQueueChunkDerived*)) / sizeof(T); static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TDerived* volatile Next; - - TQueueChunkDerived() { - memset(this, 0, sizeof(TQueueChunkDerived)); - } -}; - -template <typename T, ui32 TSize> -struct TQueueChunk { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunk*)) / sizeof(T); + + volatile T Entries[EntriesCount]; + TDerived* volatile Next; + + TQueueChunkDerived() { + memset(this, 0, sizeof(TQueueChunkDerived)); + } +}; + +template <typename T, ui32 TSize> +struct TQueueChunk { + static const ui32 EntriesCount = (TSize - sizeof(TQueueChunk*)) / sizeof(T); static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TQueueChunk* volatile Next; - - TQueueChunk() { - memset(this, 0, sizeof(TQueueChunk)); - } -}; + + volatile T Entries[EntriesCount]; + TQueueChunk* volatile Next; + + TQueueChunk() { + memset(this, 0, sizeof(TQueueChunk)); + } +}; diff --git a/library/cpp/actors/util/queue_oneone_inplace.h b/library/cpp/actors/util/queue_oneone_inplace.h index d7ec8bb21c..48507a5235 100644 --- a/library/cpp/actors/util/queue_oneone_inplace.h +++ b/library/cpp/actors/util/queue_oneone_inplace.h @@ -1,118 +1,118 @@ -#pragma once - -#include "defs.h" -#include "queue_chunk.h" - -template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>> -class TOneOneQueueInplace : TNonCopyable { +#pragma once + +#include "defs.h" +#include "queue_chunk.h" + +template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>> +class TOneOneQueueInplace : TNonCopyable { static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::valuer"); - - TChunk* ReadFrom; - ui32 ReadPosition; - ui32 WritePosition; - TChunk* WriteTo; - - friend class TReadIterator; - -public: - class TReadIterator { - TChunk* ReadFrom; - ui32 ReadPosition; - - public: - TReadIterator(TChunk* readFrom, ui32 readPosition) - : ReadFrom(readFrom) - , ReadPosition(readPosition) - { - } - - inline T Next() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition++]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - ReadPosition = 0; - return Next(); - } + + TChunk* ReadFrom; + ui32 ReadPosition; + ui32 WritePosition; + TChunk* WriteTo; + + friend class TReadIterator; + +public: + class TReadIterator { + TChunk* ReadFrom; + ui32 ReadPosition; + + public: + TReadIterator(TChunk* readFrom, ui32 readPosition) + : ReadFrom(readFrom) + , ReadPosition(readPosition) + { + } + + inline T Next() { + TChunk* head = ReadFrom; + if (ReadPosition != TChunk::EntriesCount) { + return AtomicLoad(&head->Entries[ReadPosition++]); + } else if (TChunk* next = AtomicLoad(&head->Next)) { + ReadFrom = next; + ReadPosition = 0; + return Next(); + } return T{}; - } - }; - - TOneOneQueueInplace() - : ReadFrom(new TChunk()) - , ReadPosition(0) - , WritePosition(0) - , WriteTo(ReadFrom) - { - } - - ~TOneOneQueueInplace() { + } + }; + + TOneOneQueueInplace() + : ReadFrom(new TChunk()) + , ReadPosition(0) + , WritePosition(0) + , WriteTo(ReadFrom) + { + } + + ~TOneOneQueueInplace() { Y_VERIFY_DEBUG(Head() == 0); - delete ReadFrom; - } - - struct TPtrCleanDestructor { + delete ReadFrom; + } + + struct TPtrCleanDestructor { static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { - while (T head = x->Pop()) - delete head; - delete x; - } - }; - - struct TCleanDestructor { + while (T head = x->Pop()) + delete head; + delete x; + } + }; + + struct TCleanDestructor { static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { while (x->Pop() != nullptr) - continue; - delete x; - } - }; - - struct TPtrCleanInplaceMallocDestructor { - template <typename TPtrVal> + continue; + delete x; + } + }; + + struct TPtrCleanInplaceMallocDestructor { + template <typename TPtrVal> static inline void Destroy(TOneOneQueueInplace<TPtrVal*, TSize>* x) noexcept { - while (TPtrVal* head = x->Pop()) { - head->~TPtrVal(); - free(head); - } - delete x; - } - }; - + while (TPtrVal* head = x->Pop()) { + head->~TPtrVal(); + free(head); + } + delete x; + } + }; + void Push(T x) noexcept { - if (WritePosition != TChunk::EntriesCount) { - AtomicStore(&WriteTo->Entries[WritePosition], x); - ++WritePosition; - } else { - TChunk* next = new TChunk(); - next->Entries[0] = x; - AtomicStore(&WriteTo->Next, next); - WriteTo = next; - WritePosition = 1; - } - } - - T Head() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - delete head; - ReadPosition = 0; - return Head(); - } + if (WritePosition != TChunk::EntriesCount) { + AtomicStore(&WriteTo->Entries[WritePosition], x); + ++WritePosition; + } else { + TChunk* next = new TChunk(); + next->Entries[0] = x; + AtomicStore(&WriteTo->Next, next); + WriteTo = next; + WritePosition = 1; + } + } + + T Head() { + TChunk* head = ReadFrom; + if (ReadPosition != TChunk::EntriesCount) { + return AtomicLoad(&head->Entries[ReadPosition]); + } else if (TChunk* next = AtomicLoad(&head->Next)) { + ReadFrom = next; + delete head; + ReadPosition = 0; + return Head(); + } return T{}; - } - - T Pop() { - T ret = Head(); - if (ret) - ++ReadPosition; - return ret; - } - - TReadIterator Iterator() { - return TReadIterator(ReadFrom, ReadPosition); - } -}; + } + + T Pop() { + T ret = Head(); + if (ret) + ++ReadPosition; + return ret; + } + + TReadIterator Iterator() { + return TReadIterator(ReadFrom, ReadPosition); + } +}; diff --git a/library/cpp/actors/util/should_continue.cpp b/library/cpp/actors/util/should_continue.cpp index 258e6a0aff..38bb6a28b3 100644 --- a/library/cpp/actors/util/should_continue.cpp +++ b/library/cpp/actors/util/should_continue.cpp @@ -1,23 +1,23 @@ -#include "should_continue.h" - -void TProgramShouldContinue::ShouldRestart() { - AtomicSet(State, Restart); -} - -void TProgramShouldContinue::ShouldStop(int returnCode) { - AtomicSet(ReturnCode, returnCode); - AtomicSet(State, Stop); -} - -TProgramShouldContinue::EState TProgramShouldContinue::PollState() { - return static_cast<EState>(AtomicGet(State)); -} - -int TProgramShouldContinue::GetReturnCode() { - return static_cast<int>(AtomicGet(ReturnCode)); -} - -void TProgramShouldContinue::Reset() { - AtomicSet(ReturnCode, 0); - AtomicSet(State, Continue); -} +#include "should_continue.h" + +void TProgramShouldContinue::ShouldRestart() { + AtomicSet(State, Restart); +} + +void TProgramShouldContinue::ShouldStop(int returnCode) { + AtomicSet(ReturnCode, returnCode); + AtomicSet(State, Stop); +} + +TProgramShouldContinue::EState TProgramShouldContinue::PollState() { + return static_cast<EState>(AtomicGet(State)); +} + +int TProgramShouldContinue::GetReturnCode() { + return static_cast<int>(AtomicGet(ReturnCode)); +} + +void TProgramShouldContinue::Reset() { + AtomicSet(ReturnCode, 0); + AtomicSet(State, Continue); +} diff --git a/library/cpp/actors/util/should_continue.h b/library/cpp/actors/util/should_continue.h index 76acc40dc4..8fc7f9dab0 100644 --- a/library/cpp/actors/util/should_continue.h +++ b/library/cpp/actors/util/should_continue.h @@ -1,22 +1,22 @@ -#pragma once -#include "defs.h" - -class TProgramShouldContinue { -public: - enum EState { - Continue, - Stop, - Restart, - }; - - void ShouldRestart(); - void ShouldStop(int returnCode = 0); - - EState PollState(); - int GetReturnCode(); - - void Reset(); -private: - TAtomic ReturnCode = 0; - TAtomic State = Continue; -}; +#pragma once +#include "defs.h" + +class TProgramShouldContinue { +public: + enum EState { + Continue, + Stop, + Restart, + }; + + void ShouldRestart(); + void ShouldStop(int returnCode = 0); + + EState PollState(); + int GetReturnCode(); + + void Reset(); +private: + TAtomic ReturnCode = 0; + TAtomic State = Continue; +}; diff --git a/library/cpp/actors/util/thread.h b/library/cpp/actors/util/thread.h index d742c8c585..0afbe10921 100644 --- a/library/cpp/actors/util/thread.h +++ b/library/cpp/actors/util/thread.h @@ -8,7 +8,7 @@ #include <time.h> inline void SetCurrentThreadName(const TString& name, - const ui32 maxCharsFromProcessName = 8) { + const ui32 maxCharsFromProcessName = 8) { #if defined(_linux_) // linux limits threadname by 15 + \0 diff --git a/library/cpp/actors/util/threadparkpad.cpp b/library/cpp/actors/util/threadparkpad.cpp index 74069ff15b..88813e270c 100644 --- a/library/cpp/actors/util/threadparkpad.cpp +++ b/library/cpp/actors/util/threadparkpad.cpp @@ -1,15 +1,15 @@ -#include "threadparkpad.h" -#include <util/system/winint.h> - -#ifdef _linux_ - -#include "futex.h" - -namespace NActors { +#include "threadparkpad.h" +#include <util/system/winint.h> + +#ifdef _linux_ + +#include "futex.h" + +namespace NActors { class TThreadParkPad::TImpl { volatile bool Interrupted; int Futex; - + public: TImpl() : Interrupted(false) @@ -18,39 +18,39 @@ namespace NActors { } ~TImpl() { } - + bool Park() noexcept { __atomic_fetch_sub(&Futex, 1, __ATOMIC_SEQ_CST); while (__atomic_load_n(&Futex, __ATOMIC_ACQUIRE) == -1) SysFutex(&Futex, FUTEX_WAIT_PRIVATE, -1, nullptr, nullptr, 0); return IsInterrupted(); } - + void Unpark() noexcept { const int old = __atomic_fetch_add(&Futex, 1, __ATOMIC_SEQ_CST); if (old == -1) SysFutex(&Futex, FUTEX_WAKE_PRIVATE, -1, nullptr, nullptr, 0); } - + void Interrupt() noexcept { __atomic_store_n(&Interrupted, true, __ATOMIC_SEQ_CST); Unpark(); } - + bool IsInterrupted() const noexcept { return __atomic_load_n(&Interrupted, __ATOMIC_ACQUIRE); } }; - -#elif defined _win32_ + +#elif defined _win32_ #include <util/generic/bt_exception.h> -#include <util/generic/yexception.h> - -namespace NActors { +#include <util/generic/yexception.h> + +namespace NActors { class TThreadParkPad::TImpl { TAtomic Interrupted; HANDLE EvHandle; - + public: TImpl() : Interrupted(false) @@ -63,35 +63,35 @@ namespace NActors { if (EvHandle) ::CloseHandle(EvHandle); } - + bool Park() noexcept { ::WaitForSingleObject(EvHandle, INFINITE); return AtomicGet(Interrupted); } - + void Unpark() noexcept { ::SetEvent(EvHandle); } - + void Interrupt() noexcept { AtomicSet(Interrupted, true); Unpark(); } - + bool IsInterrupted() const noexcept { return AtomicGet(Interrupted); } }; - -#else - -#include <util/system/event.h> - -namespace NActors { + +#else + +#include <util/system/event.h> + +namespace NActors { class TThreadParkPad::TImpl { TAtomic Interrupted; TSystemEvent Ev; - + public: TImpl() : Interrupted(false) @@ -100,7 +100,7 @@ namespace NActors { } ~TImpl() { } - + bool Park() noexcept { Ev.Wait(); return AtomicGet(Interrupted); @@ -123,26 +123,26 @@ namespace NActors { TThreadParkPad::TThreadParkPad() : Impl(new TThreadParkPad::TImpl()) - { - } + { + } TThreadParkPad::~TThreadParkPad() { - } - + } + bool TThreadParkPad::Park() noexcept { return Impl->Park(); - } - + } + void TThreadParkPad::Unpark() noexcept { Impl->Unpark(); - } - + } + void TThreadParkPad::Interrupt() noexcept { Impl->Interrupt(); - } - + } + bool TThreadParkPad::Interrupted() const noexcept { return Impl->IsInterrupted(); - } - -} + } + +} diff --git a/library/cpp/actors/util/threadparkpad.h b/library/cpp/actors/util/threadparkpad.h index 5b574ccf34..30f9cffdb9 100644 --- a/library/cpp/actors/util/threadparkpad.h +++ b/library/cpp/actors/util/threadparkpad.h @@ -1,21 +1,21 @@ -#pragma once - -#include <util/generic/ptr.h> - -namespace NActors { - class TThreadParkPad { - private: - class TImpl; - THolder<TImpl> Impl; - - public: - TThreadParkPad(); +#pragma once + +#include <util/generic/ptr.h> + +namespace NActors { + class TThreadParkPad { + private: + class TImpl; + THolder<TImpl> Impl; + + public: + TThreadParkPad(); ~TThreadParkPad(); - + bool Park() noexcept; void Unpark() noexcept; void Interrupt() noexcept; bool Interrupted() const noexcept; - }; - -} + }; + +} diff --git a/library/cpp/actors/util/ticket_lock.h b/library/cpp/actors/util/ticket_lock.h index 3b1fa80393..334922a088 100644 --- a/library/cpp/actors/util/ticket_lock.h +++ b/library/cpp/actors/util/ticket_lock.h @@ -1,48 +1,48 @@ -#pragma once - -#include "intrinsics.h" -#include <util/system/guard.h> -#include <util/system/yassert.h> - -class TTicketLock : TNonCopyable { - ui32 TicketIn; - ui32 TicketOut; - -public: - TTicketLock() - : TicketIn(0) - , TicketOut(0) - { - } - +#pragma once + +#include "intrinsics.h" +#include <util/system/guard.h> +#include <util/system/yassert.h> + +class TTicketLock : TNonCopyable { + ui32 TicketIn; + ui32 TicketOut; + +public: + TTicketLock() + : TicketIn(0) + , TicketOut(0) + { + } + void Release() noexcept { - AtomicUi32Increment(&TicketOut); - } - + AtomicUi32Increment(&TicketOut); + } + ui32 Acquire() noexcept { - ui32 revolves = 0; - const ui32 ticket = AtomicUi32Increment(&TicketIn) - 1; - while (ticket != AtomicLoad(&TicketOut)) { + ui32 revolves = 0; + const ui32 ticket = AtomicUi32Increment(&TicketIn) - 1; + while (ticket != AtomicLoad(&TicketOut)) { Y_VERIFY_DEBUG(ticket >= AtomicLoad(&TicketOut)); - SpinLockPause(); - ++revolves; - } - return revolves; - } - + SpinLockPause(); + ++revolves; + } + return revolves; + } + bool TryAcquire() noexcept { - const ui32 x = AtomicLoad(&TicketOut); - if (x == AtomicLoad(&TicketIn) && AtomicUi32Cas(&TicketIn, x + 1, x)) - return true; - else - return false; - } - + const ui32 x = AtomicLoad(&TicketOut); + if (x == AtomicLoad(&TicketIn) && AtomicUi32Cas(&TicketIn, x + 1, x)) + return true; + else + return false; + } + bool IsLocked() noexcept { - const ui32 ticketIn = AtomicLoad(&TicketIn); - const ui32 ticketOut = AtomicLoad(&TicketOut); - return (ticketIn != ticketOut); - } - - typedef ::TGuard<TTicketLock> TGuard; -}; + const ui32 ticketIn = AtomicLoad(&TicketIn); + const ui32 ticketOut = AtomicLoad(&TicketOut); + return (ticketIn != ticketOut); + } + + typedef ::TGuard<TTicketLock> TGuard; +}; diff --git a/library/cpp/actors/util/unordered_cache.h b/library/cpp/actors/util/unordered_cache.h index 76f036c0cf..57b9c6663d 100644 --- a/library/cpp/actors/util/unordered_cache.h +++ b/library/cpp/actors/util/unordered_cache.h @@ -1,22 +1,22 @@ -#pragma once - -#include "defs.h" +#pragma once + +#include "defs.h" #include "queue_chunk.h" - + template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>> -class TUnorderedCache : TNonCopyable { +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: + +public: static constexpr ui32 Concurrency = ConcurrencyFactor * 4; - -private: + +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; @@ -31,7 +31,7 @@ private: TWriteSlot WriteSlots[Concurrency]; static_assert(sizeof(TChunk*) == sizeof(TAtomic), "expect sizeof(TChunk*) == sizeof(TAtomic)"); - + private: struct TLockedWriter { TWriteSlot* Slot; @@ -82,53 +82,53 @@ private: private: TLockedWriter LockWriter(ui64 writerRotation) { ui32 cycle = 0; - for (;;) { + for (;;) { 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; } } - } - + } + void WriteOne(TLockedWriter& lock, T x) { Y_VERIFY_DEBUG(x != 0); - + const ui32 pos = AtomicLoad(&lock.Slot->WritePosition); - if (pos != TChunk::EntriesCount) { + if (pos != TChunk::EntriesCount) { AtomicStore(&lock.Slot->WritePosition, pos + 1); AtomicStore(&lock.WriteTo->Entries[pos], x); - } else { + } else { TChunk* next = new TChunk(); - AtomicStore(&next->Entries[0], x); + AtomicStore(&next->Entries[0], x); AtomicStore(&lock.Slot->WritePosition, 1u); AtomicStore(&lock.WriteTo->Next, next); lock.WriteTo = next; - } - } - -public: + } + } + +public: 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; - } - } - + } + } + ~TUnorderedCache() { Y_VERIFY(!Pop(0)); - + for (ui64 i = 0; i < Concurrency; ++i) { if (ReadSlots[i].ReadFrom) { delete ReadSlots[i].ReadFrom; @@ -139,63 +139,63 @@ public: } T Pop(ui64 readerRotation) noexcept { - ui64 readerIndex = readerRotation; - const ui64 endIndex = readerIndex + Concurrency; - for (; readerIndex != endIndex; ++readerIndex) { + 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); - if (pos != TChunk::EntriesCount) { - if (T ret = AtomicLoad(&readFrom->Entries[pos])) { + 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 - } else { + } else { AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk - } - } else if (TChunk* next = AtomicLoad(&readFrom->Next)) { - if (T ret = AtomicLoad(&next->Entries[0])) { + } + } 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 - delete readFrom; - return ret; - } else { + delete readFrom; + return ret; + } else { AtomicStore(&slot->ReadPosition, 0u); AtomicStore(&slot->ReadFrom, next); // release lock with new chunk - delete readFrom; - } - } else { + delete readFrom; + } + } else { // nothing in old chunk and no next chunk, just release lock with old chunk AtomicStore(&slot->ReadFrom, readFrom); - } - } - } - } - - return 0; // got nothing after full cycle, return - } - - void Push(T x, ui64 writerRotation) { + } + } + } + } + + return 0; // got nothing after full cycle, return + } + + void Push(T x, ui64 writerRotation) { TLockedWriter lock = LockWriter(writerRotation); WriteOne(lock, x); - } - - void PushBulk(T* x, ui32 xcount, ui64 writerRotation) { + } + + void PushBulk(T* x, ui32 xcount, ui64 writerRotation) { for (;;) { // Fill no more then one queue chunk per round - const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount); - + const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount); + { TLockedWriter lock = LockWriter(writerRotation++); for (T* end = x + xround; x != end; ++x) WriteOne(lock, *x); } - - if (xcount <= TChunk::EntriesCount) - break; - - xcount -= TChunk::EntriesCount; - } - } -}; + + if (xcount <= TChunk::EntriesCount) + break; + + xcount -= TChunk::EntriesCount; + } + } +}; diff --git a/library/cpp/actors/util/ya.make b/library/cpp/actors/util/ya.make index 37488c3962..a8bc36c769 100644 --- a/library/cpp/actors/util/ya.make +++ b/library/cpp/actors/util/ya.make @@ -1,37 +1,37 @@ -LIBRARY() - +LIBRARY() + OWNER( ddoarn g:kikimr ) - -SRCS( - affinity.cpp - affinity.h + +SRCS( + affinity.cpp + affinity.h cpumask.h datetime.h - defs.h + defs.h funnel_queue.h - futex.h - intrinsics.h + futex.h + intrinsics.h local_process_key.h - named_tuple.h - queue_chunk.h - queue_oneone_inplace.h + named_tuple.h + queue_chunk.h + queue_oneone_inplace.h recentwnd.h rope.h - should_continue.cpp - should_continue.h - thread.h - threadparkpad.cpp - threadparkpad.h - ticket_lock.h + should_continue.cpp + should_continue.h + thread.h + threadparkpad.cpp + threadparkpad.h + ticket_lock.h timerfd.h - unordered_cache.h -) - -PEERDIR( - util -) - -END() + unordered_cache.h +) + +PEERDIR( + util +) + +END() diff --git a/library/cpp/actors/wilson/wilson_event.h b/library/cpp/actors/wilson/wilson_event.h index 7d89c33b51..0bf0953096 100644 --- a/library/cpp/actors/wilson/wilson_event.h +++ b/library/cpp/actors/wilson/wilson_event.h @@ -10,46 +10,46 @@ namespace NWilson { #if !defined(_win_) // works only for those compilers, who trait C++ as ISO IEC 14882, not their own standard -#define __UNROLL_PARAMS_8(N, F, X, ...) \ - F(X, N - 8) \ - __UNROLL_PARAMS_7(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_7(N, F, X, ...) \ - F(X, N - 7) \ - __UNROLL_PARAMS_6(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_6(N, F, X, ...) \ - F(X, N - 6) \ - __UNROLL_PARAMS_5(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_5(N, F, X, ...) \ - F(X, N - 5) \ - __UNROLL_PARAMS_4(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_4(N, F, X, ...) \ - F(X, N - 4) \ - __UNROLL_PARAMS_3(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_3(N, F, X, ...) \ - F(X, N - 3) \ - __UNROLL_PARAMS_2(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_2(N, F, X, ...) \ - F(X, N - 2) \ - __UNROLL_PARAMS_1(N, F, ##__VA_ARGS__) -#define __UNROLL_PARAMS_1(N, F, X) F(X, N - 1) +#define __UNROLL_PARAMS_8(N, F, X, ...) \ + F(X, N - 8) \ + __UNROLL_PARAMS_7(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_7(N, F, X, ...) \ + F(X, N - 7) \ + __UNROLL_PARAMS_6(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_6(N, F, X, ...) \ + F(X, N - 6) \ + __UNROLL_PARAMS_5(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_5(N, F, X, ...) \ + F(X, N - 5) \ + __UNROLL_PARAMS_4(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_4(N, F, X, ...) \ + F(X, N - 4) \ + __UNROLL_PARAMS_3(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_3(N, F, X, ...) \ + F(X, N - 3) \ + __UNROLL_PARAMS_2(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_2(N, F, X, ...) \ + F(X, N - 2) \ + __UNROLL_PARAMS_1(N, F, ##__VA_ARGS__) +#define __UNROLL_PARAMS_1(N, F, X) F(X, N - 1) #define __UNROLL_PARAMS_0(N, F) #define __EX(...) __VA_ARGS__ #define __NUM_PARAMS(...) __NUM_PARAMS_SELECT_N(__VA_ARGS__, __NUM_PARAMS_SEQ) #define __NUM_PARAMS_SELECT_N(...) __EX(__NUM_PARAMS_SELECT(__VA_ARGS__)) #define __NUM_PARAMS_SELECT(X, _1, _2, _3, _4, _5, _6, _7, _8, N, ...) N #define __NUM_PARAMS_SEQ 8, 7, 6, 5, 4, 3, 2, 1, 0, ERROR -#define __CAT(X, Y) X##Y +#define __CAT(X, Y) X##Y #define __UNROLL_PARAMS_N(N, F, ...) __EX(__CAT(__UNROLL_PARAMS_, N)(N, F, ##__VA_ARGS__)) #define __UNROLL_PARAMS(F, ...) __UNROLL_PARAMS_N(__NUM_PARAMS(X, ##__VA_ARGS__), F, ##__VA_ARGS__) #define __EX2(F, X, INDEX) __INVOKE(F, __EX X, INDEX) #define __INVOKE(F, ...) F(__VA_ARGS__) #define __DECLARE_PARAM(X, INDEX) __EX2(__DECLARE_PARAM_X, X, INDEX) -#define __DECLARE_PARAM_X(TYPE, NAME, INDEX) \ - static const struct T##NAME##Param \ - : ::NWilson::TParamBinder<INDEX, TYPE> { \ - T##NAME##Param() { \ - } \ +#define __DECLARE_PARAM_X(TYPE, NAME, INDEX) \ + static const struct T##NAME##Param \ + : ::NWilson::TParamBinder<INDEX, TYPE> { \ + T##NAME##Param() { \ + } \ using ::NWilson::TParamBinder<INDEX, TYPE>::operator=; \ } NAME; @@ -59,70 +59,70 @@ namespace NWilson { #define __OUTPUT_PARAM(X, INDEX) __EX2(__OUTPUT_PARAM_X, X, INDEX) #define __OUTPUT_PARAM_X(TYPE, NAME, INDEX) str << (INDEX ? ", " : "") << #NAME << "# " << std::get<INDEX>(ParamPack); -#define __FILL_PARAM(P, INDEX) \ - do { \ - const auto& boundParam = (NParams::P); \ - boundParam.Apply(event.ParamPack); \ - } while (false); - -#define DECLARE_WILSON_EVENT(EVENT_NAME, ...) \ - namespace N##EVENT_NAME##Params { \ - __UNROLL_PARAMS(__DECLARE_PARAM, ##__VA_ARGS__) \ - \ - using TParamPack = std::tuple< \ - __UNROLL_PARAMS(__TUPLE_PARAM, ##__VA_ARGS__) char>; \ - } \ - struct T##EVENT_NAME { \ - using TParamPack = N##EVENT_NAME##Params::TParamPack; \ - TParamPack ParamPack; \ - \ +#define __FILL_PARAM(P, INDEX) \ + do { \ + const auto& boundParam = (NParams::P); \ + boundParam.Apply(event.ParamPack); \ + } while (false); + +#define DECLARE_WILSON_EVENT(EVENT_NAME, ...) \ + namespace N##EVENT_NAME##Params { \ + __UNROLL_PARAMS(__DECLARE_PARAM, ##__VA_ARGS__) \ + \ + using TParamPack = std::tuple< \ + __UNROLL_PARAMS(__TUPLE_PARAM, ##__VA_ARGS__) char>; \ + } \ + struct T##EVENT_NAME { \ + using TParamPack = N##EVENT_NAME##Params::TParamPack; \ + TParamPack ParamPack; \ + \ void Output(IOutputStream& str) { \ - str << #EVENT_NAME << "{"; \ - __UNROLL_PARAMS(__OUTPUT_PARAM, ##__VA_ARGS__) \ - str << "}"; \ - } \ + str << #EVENT_NAME << "{"; \ + __UNROLL_PARAMS(__OUTPUT_PARAM, ##__VA_ARGS__) \ + str << "}"; \ + } \ }; - template <size_t INDEX, typename T> + template <size_t INDEX, typename T> class TBoundParam { mutable T Value; public: TBoundParam(T&& value) : Value(std::move(value)) - { - } + { + } - template <typename TParamPack> + template <typename TParamPack> void Apply(TParamPack& pack) const { std::get<INDEX>(pack) = std::move(Value); } }; - template <size_t INDEX, typename T> + template <size_t INDEX, typename T> struct TParamBinder { - template <typename TValue> + template <typename TValue> TBoundParam<INDEX, T> operator=(const TValue& value) const { return TBoundParam<INDEX, T>(TValue(value)); } - template <typename TValue> + template <typename TValue> TBoundParam<INDEX, T> operator=(TValue&& value) const { return TBoundParam<INDEX, T>(std::move(value)); } }; // generate wilson event having parent TRACE_ID and span TRACE_ID to become parent of logged event -#define WILSON_TRACE(CTX, TRACE_ID, EVENT_NAME, ...) \ +#define WILSON_TRACE(CTX, TRACE_ID, EVENT_NAME, ...) \ if (::NWilson::TraceEnabled(CTX)) { \ - ::NWilson::TTraceId* __traceId = (TRACE_ID); \ - if (__traceId && *__traceId) { \ - TInstant now = Now(); \ - T##EVENT_NAME event; \ - namespace NParams = N##EVENT_NAME##Params; \ - __UNROLL_PARAMS(__FILL_PARAM, ##__VA_ARGS__) \ + ::NWilson::TTraceId* __traceId = (TRACE_ID); \ + if (__traceId && *__traceId) { \ + TInstant now = Now(); \ + T##EVENT_NAME event; \ + namespace NParams = N##EVENT_NAME##Params; \ + __UNROLL_PARAMS(__FILL_PARAM, ##__VA_ARGS__) \ ::NWilson::TraceEvent((CTX), __traceId, event, now); \ - } \ + } \ } inline ui32 GetNodeId(const NActors::TActorSystem& actorSystem) { @@ -140,8 +140,8 @@ namespace NWilson { return loggerSettings && loggerSettings->Satisfies(NActors::NLog::PRI_DEBUG, WilsonComponentId); } - template <typename TActorSystem, typename TEvent> - void TraceEvent(const TActorSystem& actorSystem, TTraceId* traceId, TEvent&& event, TInstant timestamp) { + template <typename TActorSystem, typename TEvent> + void TraceEvent(const TActorSystem& actorSystem, TTraceId* traceId, TEvent&& event, TInstant timestamp) { // ensure that we are not using obsolete TraceId traceId->CheckConsistency(); @@ -153,7 +153,7 @@ namespace NWilson { const ui64 timestampValue = timestamp.GetValue(); const size_t base64size = Base64EncodeBufSize(sizeof(timestampValue)); char base64[base64size]; - char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(×tampValue), sizeof(timestampValue)); + char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(×tampValue), sizeof(timestampValue)); // cut trailing padding character to save some space Y_VERIFY(end > base64 && end[-1] == '='); diff --git a/library/cpp/actors/wilson/wilson_trace.h b/library/cpp/actors/wilson/wilson_trace.h index 3d1ca50562..3f5bbbafa3 100644 --- a/library/cpp/actors/wilson/wilson_trace.h +++ b/library/cpp/actors/wilson/wilson_trace.h @@ -16,8 +16,8 @@ namespace NWilson { TTraceId(ui64 traceId, ui64 spanId) : TraceId(traceId) , SpanId(spanId) - { - } + { + } static ui64 GenerateTraceId() { ui64 traceId = 0; @@ -38,8 +38,8 @@ namespace NWilson { TTraceId() : TraceId(0) , SpanId(0) - { - } + { + } explicit TTraceId(ui64 traceId) : TraceId(traceId) @@ -48,10 +48,10 @@ namespace NWilson { } TTraceId(const TSerializedTraceId& in) - : TraceId(reinterpret_cast<const ui64*>(in)[0]) - , SpanId(reinterpret_cast<const ui64*>(in)[1]) - { - } + : TraceId(reinterpret_cast<const ui64*>(in)[0]) + , SpanId(reinterpret_cast<const ui64*>(in)[1]) + { + } // allow move semantic TTraceId(TTraceId&& other) @@ -62,7 +62,7 @@ namespace NWilson { other.SpanId = 1; // explicitly mark invalid } - TTraceId& operator=(TTraceId&& other) { + TTraceId& operator=(TTraceId&& other) { TraceId = other.TraceId; SpanId = other.SpanId; other.TraceId = 0; @@ -72,7 +72,7 @@ namespace NWilson { // do not allow implicit copy of trace id TTraceId(const TTraceId& other) = delete; - TTraceId& operator=(const TTraceId& other) = delete; + TTraceId& operator=(const TTraceId& other) = delete; static TTraceId NewTraceId() { return TTraceId(GenerateTraceId(), 0); @@ -117,7 +117,7 @@ namespace NWilson { const size_t base64size = Base64EncodeBufSize(sizeof(x)); char base64[base64size]; - char* end = Base64Encode(base64, buffer, sizeof(x)); + char* end = Base64Encode(base64, buffer, sizeof(x)); s << TStringBuf(base64, end); } @@ -125,7 +125,7 @@ namespace NWilson { void OutputSpanId(IOutputStream& s) const { const size_t base64size = Base64EncodeBufSize(sizeof(SpanId)); char base64[base64size]; - char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(&SpanId), sizeof(SpanId)); + char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(&SpanId), sizeof(SpanId)); // cut trailing padding character Y_VERIFY(end > base64 && end[-1] == '='); @@ -139,7 +139,7 @@ namespace NWilson { Y_VERIFY_DEBUG(*this || !SpanId); } - friend bool operator==(const TTraceId& x, const TTraceId& y) { + friend bool operator==(const TTraceId& x, const TTraceId& y) { return x.TraceId == y.TraceId && x.SpanId == y.SpanId; } @@ -151,8 +151,8 @@ namespace NWilson { return TraceId == other.TraceId; } - void Serialize(TSerializedTraceId* out) { - ui64* p = reinterpret_cast<ui64*>(*out); + void Serialize(TSerializedTraceId* out) { + ui64* p = reinterpret_cast<ui64*>(*out); p[0] = TraceId; p[1] = SpanId; } diff --git a/library/cpp/actors/wilson/ya.make b/library/cpp/actors/wilson/ya.make index e371f5061d..177884ad69 100644 --- a/library/cpp/actors/wilson/ya.make +++ b/library/cpp/actors/wilson/ya.make @@ -1,9 +1,9 @@ LIBRARY() - + PEERDIR( library/cpp/string_utils/base64 ) - + OWNER(alexvru) SRCS( diff --git a/library/cpp/actors/ya.make b/library/cpp/actors/ya.make index 737c7fbc18..95655c27ce 100644 --- a/library/cpp/actors/ya.make +++ b/library/cpp/actors/ya.make @@ -1,16 +1,16 @@ RECURSE_FOR_TESTS(ut) -RECURSE( +RECURSE( log_backend - core + core dnsresolver - examples - memory_log + examples + memory_log helpers - prof - protos - util - wilson + prof + protos + util + wilson testlib http -) +) diff --git a/library/cpp/digest/crc32c/ya.make b/library/cpp/digest/crc32c/ya.make index d6faf16c9c..e324c587e5 100644 --- a/library/cpp/digest/crc32c/ya.make +++ b/library/cpp/digest/crc32c/ya.make @@ -1,5 +1,5 @@ -LIBRARY() - +LIBRARY() + #!!! OWNER( ddoarn @@ -15,8 +15,8 @@ PEERDIR( contrib/libs/crcutil ) -SRCS( +SRCS( crc32c.cpp -) - -END() +) + +END() diff --git a/library/cpp/malloc/ya.make b/library/cpp/malloc/ya.make index 0ec9db71d2..bacc38d54e 100644 --- a/library/cpp/malloc/ya.make +++ b/library/cpp/malloc/ya.make @@ -6,7 +6,7 @@ RECURSE( galloc jemalloc lockless - nalf + nalf sample-client system mimalloc diff --git a/library/cpp/threading/queue/mpsc_read_as_filled.h b/library/cpp/threading/queue/mpsc_read_as_filled.h index be33ba5a58..7670fc4c6f 100644 --- a/library/cpp/threading/queue/mpsc_read_as_filled.h +++ b/library/cpp/threading/queue/mpsc_read_as_filled.h @@ -4,14 +4,14 @@ Completely wait-free queue, multiple producers - one consumer. Strict order. The queue algorithm is using concept of virtual infinite array. - A producer takes a number from a counter and atomically increments the counter. + A producer takes a number from a counter and atomically increments the counter. The number taken is a number of a slot for the producer to put a new message into infinite array. Then producer constructs a virtual infinite array by bidirectional linked list of blocks. Each block contains several slots. - There is a hint pointer which optimistically points to the last block + There is a hint pointer which optimistically points to the last block of the list and never goes backward. Consumer exploits the property of the hint pointer always going forward @@ -25,7 +25,7 @@ Consumer can't stop the progress for producers. Consumer can skip not-yet-filled slots and read them later. Thus no producer can stop the progress for consumer. - The algorithm is virtually strictly ordered because it skips slots only + The algorithm is virtually strictly ordered because it skips slots only if it is really does not matter in which order the slots were produced and consumed. @@ -35,7 +35,7 @@ WARNING: though the algorithm itself is completely wait-free but producers and consumer could be blocked by memory allocator - WARNING: copy constructors of the queue are not thread-safe + WARNING: copy constructors of the queue are not thread-safe */ #include <util/generic/deque.h> |