From 2c2866b5fc3755e3767d1153ce38e007b7b3f198 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 25 Feb 2019 06:08:18 +0300 Subject: [PATCH] Add simple QueryCombiner. GitOrigin-RevId: b863a06adff6ed010424ca42be338c410a487ccb --- CMakeLists.txt | 2 + td/telegram/ContactsManager.cpp | 100 +++++++------------------------- td/telegram/ContactsManager.h | 13 ++--- td/telegram/QueryCombiner.cpp | 40 +++++++++++++ td/telegram/QueryCombiner.h | 38 ++++++++++++ 5 files changed, 104 insertions(+), 89 deletions(-) create mode 100644 td/telegram/QueryCombiner.cpp create mode 100644 td/telegram/QueryCombiner.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 38bc11ae6..22384df56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,6 +418,7 @@ set(TDLIB_SOURCE td/telegram/PrivacyManager.cpp td/telegram/Photo.cpp td/telegram/PollManager.cpp + td/telegram/QueryCombiner.cpp td/telegram/ReplyMarkup.cpp td/telegram/SecretChatActor.cpp td/telegram/SecretChatDb.cpp @@ -572,6 +573,7 @@ set(TDLIB_SOURCE td/telegram/PollManager.h td/telegram/PrivacyManager.h td/telegram/PtsManager.h + td/telegram/QueryCombiner.h td/telegram/ReplyMarkup.h td/telegram/RequestActor.h td/telegram/SecretChatActor.h diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 16d47fae6..c21734412 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -8378,33 +8378,13 @@ bool ContactsManager::get_user_full(UserId user_id, Promise &&promise) { void ContactsManager::send_get_user_full_query(UserId user_id, tl_object_ptr &&input_user, Promise &&promise) { - auto &promises = get_user_full_queries_[user_id]; - promises.push_back(std::move(promise)); - if (promises.size() != 1) { - // query has already been sent, just wait for the result - return; - } - - auto request_promise = PromiseCreator::lambda([actor_id = actor_id(this), user_id](Result &&result) { - send_closure(actor_id, &ContactsManager::on_get_user_full_result, user_id, std::move(result)); - }); - td_->create_handler(std::move(request_promise))->send(std::move(input_user)); -} - -void ContactsManager::on_get_user_full_result(UserId user_id, Result &&result) { - auto it = get_user_full_queries_.find(user_id); - CHECK(it != get_user_full_queries_.end()); - CHECK(!it->second.empty()); - auto promises = std::move(it->second); - get_user_full_queries_.erase(it); - - for (auto &promise : promises) { - if (result.is_ok()) { - promise.set_value(Unit()); - } else { - promise.set_error(result.error().clone()); - } - } + auto send_query = + PromiseCreator::lambda([td = td_, input_user = std::move(input_user)](Result> &&promise) mutable { + if (promise.is_ok()) { + td->create_handler(promise.move_as_ok())->send(std::move(input_user)); + } + }); + get_user_full_queries_.add_query(user_id.get(), std::move(send_query), std::move(promise)); } std::pair> ContactsManager::get_user_profile_photos(UserId user_id, int32 offset, @@ -8653,33 +8633,13 @@ bool ContactsManager::get_chat_full(ChatId chat_id, Promise &&promise) { } void ContactsManager::send_get_chat_full_query(ChatId chat_id, Promise &&promise) { - auto &promises = get_chat_full_queries_[chat_id]; - promises.push_back(std::move(promise)); - if (promises.size() != 1) { - // query has already been sent, just wait for the result - return; - } - - auto request_promise = PromiseCreator::lambda([actor_id = actor_id(this), chat_id](Result &&result) { - send_closure(actor_id, &ContactsManager::on_get_chat_full_result, chat_id, std::move(result)); - }); - td_->create_handler(std::move(request_promise))->send(chat_id); -} - -void ContactsManager::on_get_chat_full_result(ChatId chat_id, Result &&result) { - auto it = get_chat_full_queries_.find(chat_id); - CHECK(it != get_chat_full_queries_.end()); - CHECK(!it->second.empty()); - auto promises = std::move(it->second); - get_chat_full_queries_.erase(it); - - for (auto &promise : promises) { - if (result.is_ok()) { - promise.set_value(Unit()); - } else { - promise.set_error(result.error().clone()); + auto send_query = PromiseCreator::lambda([td = td_, chat_id](Result> &&promise) mutable { + if (promise.is_ok()) { + td->create_handler(promise.move_as_ok())->send(chat_id); } - } + }); + + get_chat_full_queries_.add_query(chat_id.get(), std::move(send_query), std::move(promise)); } bool ContactsManager::get_chat_is_active(ChatId chat_id) const { @@ -8934,33 +8894,13 @@ bool ContactsManager::get_channel_full(ChannelId channel_id, Promise &&pro void ContactsManager::send_get_channel_full_query(ChannelId channel_id, tl_object_ptr &&input_channel, Promise &&promise) { - auto &promises = get_channel_full_queries_[channel_id]; - promises.push_back(std::move(promise)); - if (promises.size() != 1) { - // query has already been sent, just wait for the result - return; - } - - auto request_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id](Result &&result) { - send_closure(actor_id, &ContactsManager::on_get_channel_full_result, channel_id, std::move(result)); - }); - td_->create_handler(std::move(request_promise))->send(channel_id, std::move(input_channel)); -} - -void ContactsManager::on_get_channel_full_result(ChannelId channel_id, Result &&result) { - auto it = get_channel_full_queries_.find(channel_id); - CHECK(it != get_channel_full_queries_.end()); - CHECK(!it->second.empty()); - auto promises = std::move(it->second); - get_channel_full_queries_.erase(it); - - for (auto &promise : promises) { - if (result.is_ok()) { - promise.set_value(Unit()); - } else { - promise.set_error(result.error().clone()); - } - } + auto send_query = PromiseCreator::lambda( + [td = td_, channel_id, input_channel = std::move(input_channel)](Result> &&promise) mutable { + if (promise.is_ok()) { + td->create_handler(promise.move_as_ok())->send(channel_id, std::move(input_channel)); + } + }); + get_channel_full_queries_.add_query(channel_id.get(), std::move(send_query), std::move(promise)); } bool ContactsManager::have_secret_chat(SecretChatId secret_chat_id) const { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index e1a2873a6..033659a2b 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -19,6 +19,7 @@ #include "td/telegram/files/FileSourceId.h" #include "td/telegram/MessageId.h" #include "td/telegram/Photo.h" +#include "td/telegram/QueryCombiner.h" #include "td/telegram/SecretChatId.h" #include "td/telegram/UserId.h" @@ -943,12 +944,6 @@ class ContactsManager : public Actor { void update_chat_full(ChatFull *chat_full, ChatId chat_id); void update_channel_full(ChannelFull *channel_full, ChannelId channel_id); - void on_get_user_full_result(UserId user_id, Result &&result); - - void on_get_chat_full_result(ChatId chat_id, Result &&result); - - void on_get_channel_full_result(ChannelId channel_id, Result &&result); - bool is_chat_full_outdated(ChatFull *chat_full, Chat *c, ChatId chat_id); int32 get_contacts_hash(); @@ -1095,9 +1090,9 @@ class ContactsManager : public Actor { std::unordered_map>, SecretChatIdHash> load_secret_chat_from_database_queries_; std::unordered_set loaded_from_database_secret_chats_; - std::unordered_map>, UserIdHash> get_user_full_queries_; - std::unordered_map>, ChatIdHash> get_chat_full_queries_; - std::unordered_map>, ChannelIdHash> get_channel_full_queries_; + QueryCombiner get_user_full_queries_{"GetUserFullCombiner"}; + QueryCombiner get_chat_full_queries_{"GetChatFullCombiner"}; + QueryCombiner get_channel_full_queries_{"GetChannelFullCombiner"}; std::unordered_map, DialogIdHash> dialog_administrators_; diff --git a/td/telegram/QueryCombiner.cpp b/td/telegram/QueryCombiner.cpp new file mode 100644 index 000000000..e4cb907be --- /dev/null +++ b/td/telegram/QueryCombiner.cpp @@ -0,0 +1,40 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// 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/telegram/QueryCombiner.h" + +namespace td { + +void QueryCombiner::add_query(int64 query_id, Promise> &&send_query, Promise &&promise) { + auto &query = queries_[query_id]; + query.promises.push_back(std::move(promise)); + if (query.promises.size() != 1) { + // query has already been sent, just wait for the result + return; + } + + send_query.set_value(PromiseCreator::lambda([actor_id = actor_id(this), query_id](Result &&result) { + send_closure(actor_id, &QueryCombiner::on_get_query_result, query_id, std::move(result)); + })); +} + +void QueryCombiner::on_get_query_result(int64 query_id, Result &&result) { + auto it = queries_.find(query_id); + CHECK(it != queries_.end()); + CHECK(!it->second.promises.empty()); + auto promises = std::move(it->second.promises); + queries_.erase(it); + + for (auto &promise : promises) { + if (result.is_ok()) { + promise.set_value(Unit()); + } else { + promise.set_error(result.error().clone()); + } + } +} + +} // namespace td diff --git a/td/telegram/QueryCombiner.h b/td/telegram/QueryCombiner.h new file mode 100644 index 000000000..26aad601d --- /dev/null +++ b/td/telegram/QueryCombiner.h @@ -0,0 +1,38 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// 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) +// +#pragma once + +#include "td/actor/actor.h" +#include "td/actor/PromiseFuture.h" + +#include "td/utils/common.h" + +#include +#include + +namespace td { + +// combines identical queries into one request +class QueryCombiner : public Actor { + public: + explicit QueryCombiner(Slice name) { + register_actor(name, this).release(); + } + + void add_query(int64 query_id, Promise> &&send_query, Promise &&promise); + + private: + struct QueryInfo { + vector> promises; + }; + + std::unordered_map queries_; + + void on_get_query_result(int64 query_id, Result &&result); +}; + +} // namespace td