2018-12-31 20:04:05 +01:00
|
|
|
//
|
2024-01-01 01:07:21 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
2022-07-02 22:32:18 +02:00
|
|
|
#include "td/actor/MultiTimeout.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-02-12 21:48:16 +01:00
|
|
|
#include "td/utils/logging.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
|
|
|
bool MultiTimeout::has_timeout(int64 key) const {
|
2022-05-01 22:03:06 +02:00
|
|
|
return items_.count(Item(key)) > 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MultiTimeout::set_timeout_at(int64 key, double timeout) {
|
2019-09-04 18:41:30 +02:00
|
|
|
LOG(DEBUG) << "Set " << get_name() << " for " << key << " in " << timeout - Time::now();
|
2018-12-31 20:04:05 +01:00
|
|
|
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()) {
|
2023-03-08 14:19:02 +01:00
|
|
|
update_timeout("set_timeout");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CHECK(item.second);
|
|
|
|
timeout_queue_.insert(timeout, heap_node);
|
|
|
|
if (heap_node->is_top()) {
|
2023-03-08 14:19:02 +01:00
|
|
|
update_timeout("set_timeout 2");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiTimeout::add_timeout_at(int64 key, double timeout) {
|
2019-09-04 18:41:30 +02:00
|
|
|
LOG(DEBUG) << "Add " << get_name() << " for " << key << " in " << timeout - Time::now();
|
2018-12-31 20:04:05 +01:00
|
|
|
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()) {
|
2023-03-08 14:19:02 +01:00
|
|
|
update_timeout("add_timeout");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-16 23:02:30 +01:00
|
|
|
void MultiTimeout::cancel_timeout(int64 key, const char *source) {
|
2019-09-04 18:41:30 +02:00
|
|
|
LOG(DEBUG) << "Cancel " << get_name() << " for " << key;
|
2018-12-31 20:04:05 +01:00
|
|
|
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) {
|
2023-03-16 23:02:30 +01:00
|
|
|
update_timeout(source);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-08 14:19:02 +01:00
|
|
|
void MultiTimeout::update_timeout(const char *source) {
|
2018-12-31 20:04:05 +01:00
|
|
|
if (items_.empty()) {
|
2019-09-04 18:41:30 +02:00
|
|
|
LOG(DEBUG) << "Cancel timeout of " << get_name();
|
2023-03-08 14:19:02 +01:00
|
|
|
LOG_CHECK(timeout_queue_.empty()) << get_name() << ' ' << source;
|
2023-03-21 10:25:01 +01:00
|
|
|
if (!Actor::has_timeout()) {
|
|
|
|
bool has_pending_timeout = false;
|
|
|
|
for (auto &event : get_info()->mailbox_) {
|
|
|
|
if (event.type == Event::Type::Timeout) {
|
|
|
|
has_pending_timeout = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_CHECK(has_pending_timeout) << get_name() << ' ' << get_info()->mailbox_.size() << ' ' << source;
|
|
|
|
} else {
|
|
|
|
Actor::cancel_timeout();
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2019-09-04 18:41:30 +02:00
|
|
|
LOG(DEBUG) << "Set timeout of " << get_name() << " in " << timeout_queue_.top_key() - Time::now_cached();
|
2018-12-31 20:04:05 +01:00
|
|
|
Actor::set_timeout_at(timeout_queue_.top_key());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-27 02:10:52 +01:00
|
|
|
vector<int64> MultiTimeout::get_expired_keys(double now) {
|
|
|
|
vector<int64> expired_keys;
|
2018-12-31 20:04:05 +01:00
|
|
|
while (!timeout_queue_.empty() && timeout_queue_.top_key() < now) {
|
|
|
|
int64 key = static_cast<Item *>(timeout_queue_.pop())->key;
|
|
|
|
items_.erase(Item(key));
|
2018-11-27 02:10:52 +01:00
|
|
|
expired_keys.push_back(key);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-11-27 02:10:52 +01:00
|
|
|
return expired_keys;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultiTimeout::timeout_expired() {
|
|
|
|
vector<int64> expired_keys = get_expired_keys(Time::now_cached());
|
2018-12-31 20:04:05 +01:00
|
|
|
if (!items_.empty()) {
|
2023-03-08 14:19:02 +01:00
|
|
|
update_timeout("timeout_expired");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-11-27 02:10:52 +01:00
|
|
|
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()) {
|
2023-03-08 14:19:02 +01:00
|
|
|
update_timeout("run_all");
|
2018-11-27 02:10:52 +01:00
|
|
|
}
|
|
|
|
for (auto key : expired_keys) {
|
2018-01-29 12:25:29 +01:00
|
|
|
callback_(data_, key);
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace td
|