From f96d61dd4dbf6e198ee83290fa950fcfda1d2481 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 2 Nov 2021 01:06:43 +0300 Subject: [PATCH 1/7] Use InvokeAfter for ToggleDialogIsBlocked queries. --- td/telegram/MessagesManager.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 59055a4ec..59ecf4fb5 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -1740,26 +1740,25 @@ class ToggleDialogUnreadMarkQuery final : public Td::ResultHandler { } }; -class ToggleDialogIsBlockedQuery final : public Td::ResultHandler { +class ToggleDialogIsBlockedActor final : public NetActorOnce { Promise promise_; DialogId dialog_id_; bool is_blocked_; public: - explicit ToggleDialogIsBlockedQuery(Promise &&promise) : promise_(std::move(promise)) { + explicit ToggleDialogIsBlockedActor(Promise &&promise) : promise_(std::move(promise)) { } - void send(DialogId dialog_id, bool is_blocked) { + void send(DialogId dialog_id, bool is_blocked, uint64 sequence_dispatcher_id) { dialog_id_ = dialog_id; is_blocked_ = is_blocked; auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Know); CHECK(input_peer != nullptr && input_peer->get_id() != telegram_api::inputPeerEmpty::ID); - if (is_blocked) { - send_query(G()->net_query_creator().create(telegram_api::contacts_block(std::move(input_peer)))); - } else { - send_query(G()->net_query_creator().create(telegram_api::contacts_unblock(std::move(input_peer)))); - } + auto query = is_blocked ? G()->net_query_creator().create(telegram_api::contacts_block(std::move(input_peer))) + : G()->net_query_creator().create(telegram_api::contacts_unblock(std::move(input_peer))); + send_closure(td->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback, + std::move(query), actor_shared(this), sequence_dispatcher_id); } void on_result(uint64 id, BufferSlice packet) final { @@ -1777,13 +1776,13 @@ class ToggleDialogIsBlockedQuery final : public Td::ResultHandler { } void on_error(uint64 id, Status status) final { - if (!td->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleDialogIsBlockedQuery")) { - LOG(ERROR) << "Receive error for ToggleDialogIsBlockedQuery: " << status; + if (!td->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleDialogIsBlockedActor")) { + LOG(ERROR) << "Receive error for ToggleDialogIsBlockedActor: " << status; } if (!G()->close_flag()) { td->messages_manager_->on_update_dialog_is_blocked(dialog_id_, !is_blocked_); - td->messages_manager_->get_dialog_info_full(dialog_id_, Auto(), "ToggleDialogIsBlockedQuery"); - td->messages_manager_->reget_dialog_action_bar(dialog_id_, "ToggleDialogIsBlockedQuery"); + td->messages_manager_->get_dialog_info_full(dialog_id_, Auto(), "ToggleDialogIsBlockedActor"); + td->messages_manager_->reget_dialog_action_bar(dialog_id_, "ToggleDialogIsBlockedActor"); } promise_.set_error(std::move(status)); } @@ -19188,8 +19187,9 @@ void MessagesManager::toggle_dialog_is_blocked_on_server(DialogId dialog_id, boo log_event_id = save_toggle_dialog_is_blocked_on_server_log_event(dialog_id, is_blocked); } - td_->create_handler(get_erase_log_event_promise(log_event_id)) - ->send(dialog_id, is_blocked); + send_closure(td_->create_net_actor(get_erase_log_event_promise(log_event_id)), + &ToggleDialogIsBlockedActor::send, dialog_id, is_blocked, + get_sequence_dispatcher_id(dialog_id, MessageContentType::Text)); } Status MessagesManager::toggle_dialog_silent_send_message(DialogId dialog_id, bool silent_send_message) { From f964067da655a3092b0ae1db86792835c202424f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 00:57:20 +0300 Subject: [PATCH 2/7] Store name of lite actors. --- tdactor/td/actor/impl/ActorInfo.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tdactor/td/actor/impl/ActorInfo.h b/tdactor/td/actor/impl/ActorInfo.h index 226490af9..c20bbeb2e 100644 --- a/tdactor/td/actor/impl/ActorInfo.h +++ b/tdactor/td/actor/impl/ActorInfo.h @@ -41,10 +41,10 @@ inline void ActorInfo::init(int32 sched_id, Slice name, ObjectPool::O if (!is_lite) { context_ = Scheduler::context()->this_ptr_.lock(); VLOG(actor) << "Set context " << context_.get() << " for " << name; -#ifdef TD_DEBUG - name_ = name.str(); -#endif } +#ifdef TD_DEBUG + name_.assign(name.data(), name.size()); +#endif actor_->init(std::move(this_ptr)); deleter_ = deleter; From ffa48e523a0f5e9730d11df70638e895728a01cf Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 14:18:16 +0300 Subject: [PATCH 3/7] Add Actor life cycle benchmark. --- benchmark/bench_actor.cpp | 55 +++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/benchmark/bench_actor.cpp b/benchmark/bench_actor.cpp index 63cc1fca3..bfcaa65a7 100644 --- a/benchmark/bench_actor.cpp +++ b/benchmark/bench_actor.cpp @@ -18,6 +18,51 @@ #pragma comment(linker, "/STACK:16777216") #endif +class CreateActorBench final : public td::Benchmark { + private: + td::ConcurrentScheduler scheduler_; + + struct TestActor final : public td::Actor { + static td::int32 actor_count_; + + void start_up() final { + actor_count_++; + stop(); + } + + void tear_down() final { + if (--actor_count_ == 0) { + td::Scheduler::instance()->finish(); + } + } + }; + + void start_up() final { + scheduler_.init(0); + scheduler_.start(); + } + + void tear_down() final { + scheduler_.finish(); + } + + public: + td::string get_description() const final { + return "CreateActor"; + } + + void run(int n) final { + for (int i = 0; i < n; i++) { + scheduler_.create_actor_unsafe(0, "TestActor").release(); + } + while (scheduler_.run_main(10)) { + // empty + } + } +}; + +td::int32 CreateActorBench::TestActor::actor_count_; + template class RingBench final : public td::Benchmark { public: @@ -26,11 +71,11 @@ class RingBench final : public td::Benchmark { private: int actor_n_ = -1; int thread_n_ = -1; - std::vector> actor_array_; + td::vector> actor_array_; td::ConcurrentScheduler *scheduler_ = nullptr; public: - std::string get_description() const final { + td::string get_description() const final { static const char *types[] = {"later", "immediate", "raw", "tail", "lambda"}; static_assert(0 <= type && type < 5, ""); return PSTRING() << "Ring (send_" << types[type] << ") (threads_n = " << thread_n_ << ")"; @@ -89,7 +134,7 @@ class RingBench final : public td::Benchmark { scheduler_ = new td::ConcurrentScheduler(); scheduler_->init(thread_n_); - actor_array_ = std::vector>(actor_n_); + actor_array_ = td::vector>(actor_n_); for (int i = 0; i < actor_n_; i++) { actor_array_[i] = scheduler_->create_actor_unsafe(thread_n_ ? i % thread_n_ : 0, "PassActor").release(); @@ -118,7 +163,7 @@ class RingBench final : public td::Benchmark { template class QueryBench final : public td::Benchmark { public: - std::string get_description() const final { + td::string get_description() const final { static const char *types[] = {"callback", "immediate future", "delayed future", "dummy", "lambda", "lambda_future"}; static_assert(0 <= type && type < 6, ""); return PSTRING() << "QueryBench: " << types[type]; @@ -269,7 +314,7 @@ class QueryBench final : public td::Benchmark { int main() { td::init_openssl_threads(); - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG)); + bench(CreateActorBench()); bench(RingBench<4>(504, 0)); bench(RingBench<3>(504, 0)); bench(RingBench<0>(504, 0)); From 6a5b0506e51fdbdb91d70d2c579da37058fda930 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 15:10:43 +0300 Subject: [PATCH 4/7] Split Actor.is_lite to need_context and need_start_up. --- benchmark/bench_actor.cpp | 41 +++++++++++++++----------- tdactor/td/actor/PromiseFuture.h | 3 +- tdactor/td/actor/impl/Actor-decl.h | 3 +- tdactor/td/actor/impl/ActorInfo-decl.h | 8 +++-- tdactor/td/actor/impl/ActorInfo.h | 20 +++++++++---- tdactor/td/actor/impl/Scheduler.cpp | 10 +++---- tdactor/td/actor/impl/Scheduler.h | 4 +-- 7 files changed, 55 insertions(+), 34 deletions(-) diff --git a/benchmark/bench_actor.cpp b/benchmark/bench_actor.cpp index bfcaa65a7..338442c62 100644 --- a/benchmark/bench_actor.cpp +++ b/benchmark/bench_actor.cpp @@ -18,25 +18,34 @@ #pragma comment(linker, "/STACK:16777216") #endif +struct TestActor final : public td::Actor { + static td::int32 actor_count_; + + void start_up() final { + actor_count_++; + stop(); + } + + void tear_down() final { + if (--actor_count_ == 0) { + td::Scheduler::instance()->finish(); + } + } +}; + +td::int32 TestActor::actor_count_; + +template <> +class td::ActorTraits { + public: + static constexpr bool need_context = false; + static constexpr bool need_start_up = true; +}; + class CreateActorBench final : public td::Benchmark { private: td::ConcurrentScheduler scheduler_; - struct TestActor final : public td::Actor { - static td::int32 actor_count_; - - void start_up() final { - actor_count_++; - stop(); - } - - void tear_down() final { - if (--actor_count_ == 0) { - td::Scheduler::instance()->finish(); - } - } - }; - void start_up() final { scheduler_.init(0); scheduler_.start(); @@ -61,8 +70,6 @@ class CreateActorBench final : public td::Benchmark { } }; -td::int32 CreateActorBench::TestActor::actor_count_; - template class RingBench final : public td::Benchmark { public: diff --git a/tdactor/td/actor/PromiseFuture.h b/tdactor/td/actor/PromiseFuture.h index a4439f2d1..2b47b1d48 100644 --- a/tdactor/td/actor/PromiseFuture.h +++ b/tdactor/td/actor/PromiseFuture.h @@ -469,7 +469,8 @@ class PromiseActor; template class ActorTraits> { public: - static constexpr bool is_lite = true; + static constexpr bool need_context = false; + static constexpr bool need_start_up = false; }; template diff --git a/tdactor/td/actor/impl/Actor-decl.h b/tdactor/td/actor/impl/Actor-decl.h index bd3bb4e96..99eccef42 100644 --- a/tdactor/td/actor/impl/Actor-decl.h +++ b/tdactor/td/actor/impl/Actor-decl.h @@ -115,7 +115,8 @@ class Actor : public ObserverBase { template class ActorTraits { public: - static constexpr bool is_lite = false; + static constexpr bool need_context = true; + static constexpr bool need_start_up = true; }; } // namespace td diff --git a/tdactor/td/actor/impl/ActorInfo-decl.h b/tdactor/td/actor/impl/ActorInfo-decl.h index cb9a8e7bd..1b79a4016 100644 --- a/tdactor/td/actor/impl/ActorInfo-decl.h +++ b/tdactor/td/actor/impl/ActorInfo-decl.h @@ -63,7 +63,7 @@ class ActorInfo final ActorInfo &operator=(const ActorInfo &) = delete; void init(int32 sched_id, Slice name, ObjectPool::OwnerPtr &&this_ptr, Actor *actor_ptr, Deleter deleter, - bool is_lite); + bool need_context, bool need_start_up); void on_actor_moved(Actor *actor_new_ptr); template @@ -105,7 +105,8 @@ class ActorInfo final vector mailbox_; - bool is_lite() const; + bool need_context() const; + bool need_start_up() const; void set_wait_generation(uint32 wait_generation); bool must_wait(uint32 wait_generation) const; @@ -113,7 +114,8 @@ class ActorInfo final private: Deleter deleter_ = Deleter::None; - bool is_lite_ = false; + bool need_context_ = true; + bool need_start_up_ = true; bool is_running_ = false; bool always_wait_for_mailbox_{false}; uint32 wait_generation_{0}; diff --git a/tdactor/td/actor/impl/ActorInfo.h b/tdactor/td/actor/impl/ActorInfo.h index c20bbeb2e..f8e467fdd 100644 --- a/tdactor/td/actor/impl/ActorInfo.h +++ b/tdactor/td/actor/impl/ActorInfo.h @@ -32,13 +32,13 @@ inline StringBuilder &operator<<(StringBuilder &sb, const ActorInfo &info) { } inline void ActorInfo::init(int32 sched_id, Slice name, ObjectPool::OwnerPtr &&this_ptr, Actor *actor_ptr, - Deleter deleter, bool is_lite) { + Deleter deleter, bool need_context, bool need_start_up) { CHECK(!is_running()); CHECK(!is_migrating()); sched_id_.store(sched_id, std::memory_order_relaxed); actor_ = actor_ptr; - if (!is_lite) { + if (need_context) { context_ = Scheduler::context()->this_ptr_.lock(); VLOG(actor) << "Set context " << context_.get() << " for " << name; } @@ -48,22 +48,32 @@ inline void ActorInfo::init(int32 sched_id, Slice name, ObjectPool::O actor_->init(std::move(this_ptr)); deleter_ = deleter; - is_lite_ = is_lite; + need_context_ = need_context; + need_start_up_ = need_start_up; is_running_ = false; wait_generation_ = 0; } -inline bool ActorInfo::is_lite() const { - return is_lite_; + +inline bool ActorInfo::need_context() const { + return need_context_; } + +inline bool ActorInfo::need_start_up() const { + return need_start_up_; +} + inline void ActorInfo::set_wait_generation(uint32 wait_generation) { wait_generation_ = wait_generation; } + inline bool ActorInfo::must_wait(uint32 wait_generation) const { return wait_generation_ == wait_generation || (always_wait_for_mailbox_ && !mailbox_.empty()); } + inline void ActorInfo::always_wait_for_mailbox() { always_wait_for_mailbox_ = true; } + inline void ActorInfo::on_actor_moved(Actor *actor_new_ptr) { actor_ = actor_new_ptr; } diff --git a/tdactor/td/actor/impl/Scheduler.cpp b/tdactor/td/actor/impl/Scheduler.cpp index 45d54c21e..2407b8b14 100644 --- a/tdactor/td/actor/impl/Scheduler.cpp +++ b/tdactor/td/actor/impl/Scheduler.cpp @@ -168,10 +168,10 @@ EventGuard::~EventGuard() { } info->finish_run(); swap_context(info); - CHECK(info->is_lite() || save_context_ == info->get_context()); + CHECK(!info->need_context() || save_context_ == info->get_context()); #ifdef TD_DEBUG - LOG_CHECK(info->is_lite() || save_log_tag2_ == info->get_name().c_str()) - << info->is_lite() << " " << info->empty() << " " << info->is_migrating() << " " << save_log_tag2_ << " " + LOG_CHECK(!info->need_context() || save_log_tag2_ == info->get_name().c_str()) + << info->need_context() << " " << info->empty() << " " << info->is_migrating() << " " << save_log_tag2_ << " " << info->get_name() << " " << scheduler_->close_flag_; #endif if (event_context_.flags & Scheduler::EventContext::Stop) { @@ -186,7 +186,7 @@ EventGuard::~EventGuard() { void EventGuard::swap_context(ActorInfo *info) { std::swap(scheduler_->event_context_ptr_, event_context_ptr_); - if (info->is_lite()) { + if (!info->need_context()) { return; } @@ -353,7 +353,7 @@ void Scheduler::do_stop_actor(ActorInfo *actor_info) { CHECK(!actor_info->is_migrating()); LOG_CHECK(actor_info->migrate_dest() == sched_id_) << actor_info->migrate_dest() << " " << sched_id_; ObjectPool::OwnerPtr owner_ptr; - if (!actor_info->is_lite()) { + if (actor_info->need_start_up()) { EventGuard guard(this, actor_info); do_event(actor_info, Event::stop()); owner_ptr = actor_info->get_actor_unsafe()->clear(); diff --git a/tdactor/td/actor/impl/Scheduler.h b/tdactor/td/actor/impl/Scheduler.h index 60e6d66b9..712b77be0 100644 --- a/tdactor/td/actor/impl/Scheduler.h +++ b/tdactor/td/actor/impl/Scheduler.h @@ -109,7 +109,7 @@ ActorOwn Scheduler::register_actor_impl(Slice name, ActorT *actor_ptr, A auto weak_info = info.get_weak(); auto actor_info = info.get(); actor_info->init(sched_id_, name, std::move(info), static_cast(actor_ptr), deleter, - ActorTraits::is_lite); + ActorTraits::need_context, ActorTraits::need_start_up); ActorId actor_id = weak_info->actor_id(actor_ptr); if (sched_id != sched_id_) { @@ -117,7 +117,7 @@ ActorOwn Scheduler::register_actor_impl(Slice name, ActorT *actor_ptr, A do_migrate_actor(actor_info, sched_id); } else { pending_actors_list_.put(weak_info->get_list_node()); - if (!ActorTraits::is_lite) { + if (ActorTraits::need_start_up) { send(actor_id, Event::start()); } } From 94172ee9ae55fa4e707bd6e295fe7bc96996f866 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 16:46:01 +0300 Subject: [PATCH 5/7] Fix logging on actor creation/destroying. --- tdactor/td/actor/impl/Scheduler.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tdactor/td/actor/impl/Scheduler.h b/tdactor/td/actor/impl/Scheduler.h index 712b77be0..30205a493 100644 --- a/tdactor/td/actor/impl/Scheduler.h +++ b/tdactor/td/actor/impl/Scheduler.h @@ -103,13 +103,12 @@ ActorOwn Scheduler::register_actor_impl(Slice name, ActorT *actor_ptr, A LOG_CHECK(sched_id == sched_id_ || (0 <= sched_id && sched_id < static_cast(outbound_queues_.size()))) << sched_id; auto info = actor_info_pool_->create_empty(); - VLOG(actor) << "Create actor: " << tag("name", name) << tag("ptr", *info) << tag("context", context()) - << tag("this", this) << tag("actor_count", actor_count_); actor_count_++; auto weak_info = info.get_weak(); auto actor_info = info.get(); actor_info->init(sched_id_, name, std::move(info), static_cast(actor_ptr), deleter, ActorTraits::need_context, ActorTraits::need_start_up); + VLOG(actor) << "Create actor " << *actor_info << ": " << tag("actor_count", actor_count_); ActorId actor_id = weak_info->actor_id(actor_ptr); if (sched_id != sched_id_) { @@ -134,8 +133,7 @@ ActorOwn Scheduler::register_existing_actor(unique_ptr actor_ptr } inline void Scheduler::destroy_actor(ActorInfo *actor_info) { - VLOG(actor) << "Destroy actor: " << tag("name", *actor_info) << tag("ptr", actor_info) - << tag("actor_count", actor_count_); + VLOG(actor) << "Destroy actor " << *actor_info << ": " << tag("actor_count", actor_count_); LOG_CHECK(actor_info->migrate_dest() == sched_id_) << actor_info->migrate_dest() << " " << sched_id_; cancel_actor_timeout(actor_info); From 4266841b6428a3e8f05d6993699a1aa78a769470 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 16:53:14 +0300 Subject: [PATCH 6/7] Simplify logging in tdactor. --- tdactor/td/actor/impl/ActorInfo.h | 5 +---- tdactor/td/actor/impl/Scheduler.h | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tdactor/td/actor/impl/ActorInfo.h b/tdactor/td/actor/impl/ActorInfo.h index f8e467fdd..6c0bc0d3c 100644 --- a/tdactor/td/actor/impl/ActorInfo.h +++ b/tdactor/td/actor/impl/ActorInfo.h @@ -11,7 +11,6 @@ #include "td/actor/impl/Scheduler-decl.h" #include "td/utils/common.h" -#include "td/utils/format.h" #include "td/utils/Heap.h" #include "td/utils/List.h" #include "td/utils/logging.h" @@ -79,8 +78,6 @@ inline void ActorInfo::on_actor_moved(Actor *actor_new_ptr) { } inline void ActorInfo::clear() { - // LOG_IF(WARNING, !mailbox_.empty()) << "Destroy actor with non-empty mailbox: " << get_name() - // << format::as_array(mailbox_); CHECK(mailbox_.empty()); CHECK(!actor_); CHECK(!is_running()); @@ -189,7 +186,7 @@ inline CSlice ActorInfo::get_name() const { inline void ActorInfo::start_run() { VLOG(actor) << "Start run actor: " << *this; - LOG_CHECK(!is_running_) << "Recursive call of actor " << tag("name", get_name()); + LOG_CHECK(!is_running_) << "Recursive call of actor " << get_name(); is_running_ = true; } inline void ActorInfo::finish_run() { diff --git a/tdactor/td/actor/impl/Scheduler.h b/tdactor/td/actor/impl/Scheduler.h index 30205a493..715960e7a 100644 --- a/tdactor/td/actor/impl/Scheduler.h +++ b/tdactor/td/actor/impl/Scheduler.h @@ -10,7 +10,6 @@ #include "td/actor/impl/Scheduler-decl.h" #include "td/utils/common.h" -#include "td/utils/format.h" #include "td/utils/Heap.h" #include "td/utils/logging.h" #include "td/utils/MpscPollableQueue.h" @@ -108,7 +107,7 @@ ActorOwn Scheduler::register_actor_impl(Slice name, ActorT *actor_ptr, A auto actor_info = info.get(); actor_info->init(sched_id_, name, std::move(info), static_cast(actor_ptr), deleter, ActorTraits::need_context, ActorTraits::need_start_up); - VLOG(actor) << "Create actor " << *actor_info << ": " << tag("actor_count", actor_count_); + VLOG(actor) << "Create actor " << *actor_info << " (actor_count = " << actor_count_ << ')'; ActorId actor_id = weak_info->actor_id(actor_ptr); if (sched_id != sched_id_) { @@ -133,7 +132,7 @@ ActorOwn Scheduler::register_existing_actor(unique_ptr actor_ptr } inline void Scheduler::destroy_actor(ActorInfo *actor_info) { - VLOG(actor) << "Destroy actor " << *actor_info << ": " << tag("actor_count", actor_count_); + VLOG(actor) << "Destroy actor " << *actor_info << " (actor_count = " << actor_count_ << ')'; LOG_CHECK(actor_info->migrate_dest() == sched_id_) << actor_info->migrate_dest() << " " << sched_id_; cancel_actor_timeout(actor_info); From 0208b7058b1c092dc1b5f9a7509359d36a48ba8c Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 3 Nov 2021 18:05:53 +0300 Subject: [PATCH 7/7] Don't catch ActorContext by MutiPromiseActor and SleepActor. --- tdactor/td/actor/MultiPromise.h | 7 +++++++ tdactor/td/actor/SleepActor.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tdactor/td/actor/MultiPromise.h b/tdactor/td/actor/MultiPromise.h index 630a689ad..017bc5988 100644 --- a/tdactor/td/actor/MultiPromise.h +++ b/tdactor/td/actor/MultiPromise.h @@ -91,6 +91,13 @@ class MultiPromiseActor final } }; +template <> +class ActorTraits { + public: + static constexpr bool need_context = false; + static constexpr bool need_start_up = true; +}; + class MultiPromiseActorSafe final : public MultiPromiseInterface { public: void add_promise(Promise &&promise) final; diff --git a/tdactor/td/actor/SleepActor.h b/tdactor/td/actor/SleepActor.h index 659db5f1a..3e257dd8d 100644 --- a/tdactor/td/actor/SleepActor.h +++ b/tdactor/td/actor/SleepActor.h @@ -31,4 +31,11 @@ class SleepActor final : public Actor { } }; +template <> +class ActorTraits { + public: + static constexpr bool need_context = false; + static constexpr bool need_start_up = true; +}; + } // namespace td