diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdactor/td/actor/MultiTimeout.cpp')
-rw-r--r-- | protocols/Telegram/tdlib/td/tdactor/td/actor/MultiTimeout.cpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/tdactor/td/actor/MultiTimeout.cpp b/protocols/Telegram/tdlib/td/tdactor/td/actor/MultiTimeout.cpp new file mode 100644 index 0000000000..8c3dcb942f --- /dev/null +++ b/protocols/Telegram/tdlib/td/tdactor/td/actor/MultiTimeout.cpp @@ -0,0 +1,110 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/actor/MultiTimeout.h" + +#include "td/utils/logging.h" + +namespace td { + +bool MultiTimeout::has_timeout(int64 key) const { + return items_.count(Item(key)) > 0; +} + +void MultiTimeout::set_timeout_at(int64 key, double timeout) { + LOG(DEBUG) << "Set " << get_name() << " for " << key << " in " << timeout - Time::now(); + auto item = items_.emplace(key); + auto heap_node = static_cast<HeapNode *>(const_cast<Item *>(&*item.first)); + if (heap_node->in_heap()) { + CHECK(!item.second); + bool need_update_timeout = heap_node->is_top(); + timeout_queue_.fix(timeout, heap_node); + if (need_update_timeout || heap_node->is_top()) { + update_timeout(); + } + } else { + CHECK(item.second); + timeout_queue_.insert(timeout, heap_node); + if (heap_node->is_top()) { + update_timeout(); + } + } +} + +void MultiTimeout::add_timeout_at(int64 key, double timeout) { + LOG(DEBUG) << "Add " << get_name() << " for " << key << " in " << timeout - Time::now(); + auto item = items_.emplace(key); + auto heap_node = static_cast<HeapNode *>(const_cast<Item *>(&*item.first)); + if (heap_node->in_heap()) { + CHECK(!item.second); + } else { + CHECK(item.second); + timeout_queue_.insert(timeout, heap_node); + if (heap_node->is_top()) { + update_timeout(); + } + } +} + +void MultiTimeout::cancel_timeout(int64 key) { + LOG(DEBUG) << "Cancel " << get_name() << " for " << key; + auto item = items_.find(Item(key)); + if (item != items_.end()) { + auto heap_node = static_cast<HeapNode *>(const_cast<Item *>(&*item)); + CHECK(heap_node->in_heap()); + bool need_update_timeout = heap_node->is_top(); + timeout_queue_.erase(heap_node); + items_.erase(item); + + if (need_update_timeout) { + update_timeout(); + } + } +} + +void MultiTimeout::update_timeout() { + if (items_.empty()) { + LOG(DEBUG) << "Cancel timeout of " << get_name(); + CHECK(timeout_queue_.empty()); + CHECK(Actor::has_timeout()); + Actor::cancel_timeout(); + } else { + LOG(DEBUG) << "Set timeout of " << get_name() << " in " << timeout_queue_.top_key() - Time::now_cached(); + Actor::set_timeout_at(timeout_queue_.top_key()); + } +} + +vector<int64> MultiTimeout::get_expired_keys(double now) { + vector<int64> expired_keys; + while (!timeout_queue_.empty() && timeout_queue_.top_key() < now) { + int64 key = static_cast<Item *>(timeout_queue_.pop())->key; + items_.erase(Item(key)); + expired_keys.push_back(key); + } + return expired_keys; +} + +void MultiTimeout::timeout_expired() { + vector<int64> expired_keys = get_expired_keys(Time::now_cached()); + if (!items_.empty()) { + update_timeout(); + } + for (auto key : expired_keys) { + callback_(data_, key); + } +} + +void MultiTimeout::run_all() { + vector<int64> expired_keys = get_expired_keys(Time::now_cached() + 1e10); + if (!expired_keys.empty()) { + update_timeout(); + } + for (auto key : expired_keys) { + callback_(data_, key); + } +} + +} // namespace td |