From 606b4276732d2399a1bb056adfad0f19da85c363 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 1 Apr 2019 22:38:17 +0300 Subject: [PATCH] Invalidate cache of getGroupsInCommon when count is changed or in 1 hour. GitOrigin-RevId: e57edb01d3fe3a21e208e8247ca666284a755bcb --- td/generate/scheme/td_api.tl | 2 +- td/telegram/ContactsManager.cpp | 33 +++++++++++++- td/telegram/ContactsManager.h | 3 ++ td/telegram/MessagesManager.cpp | 80 ++++++++++++++++++++++----------- td/telegram/MessagesManager.h | 12 ++++- 5 files changed, 98 insertions(+), 32 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index ea632b58f..2c7cb6635 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2756,7 +2756,7 @@ checkChatUsername chat_id:int53 username:string = CheckChatUsernameResult; getCreatedPublicChats = Chats; -//@description Returns a list of common chats with a given user. Chats are sorted by their type and creation date @user_id User identifier @offset_chat_id Chat identifier starting from which to return chats; use 0 for the first request @limit Maximum number of chats to be returned; up to 100 +//@description Returns a list of common group chats with a given user. Chats are sorted by their type and creation date @user_id User identifier @offset_chat_id Chat identifier starting from which to return chats; use 0 for the first request @limit Maximum number of chats to be returned; up to 100 getGroupsInCommon user_id:int32 offset_chat_id:int53 limit:int32 = Chats; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9a9ea3c5a..eeb068543 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6404,6 +6404,10 @@ void ContactsManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat void ContactsManager::update_user_full(UserFull *user_full, UserId user_id) { CHECK(user_full != nullptr); + if (user_full->is_common_chat_count_changed) { + td_->messages_manager_->drop_common_dialogs_cache(user_id); + user_full->is_common_chat_count_changed = false; + } if (user_full->is_changed) { user_full->is_changed = false; if (user_full->is_inited) { @@ -6487,15 +6491,15 @@ void ContactsManager::on_get_user_full(tl_object_ptr &&u user->is_inited = true; on_update_user_full_is_blocked(user, user_id, (user_full->flags_ & USER_FULL_FLAG_IS_BLOCKED) != 0); + on_update_user_full_common_chat_count(user, user_id, user_full->common_chats_count_); bool can_be_called = user_full->phone_calls_available_ && !user_full->phone_calls_private_; bool has_private_calls = user_full->phone_calls_private_; if (user->can_be_called != can_be_called || user->has_private_calls != has_private_calls || - user->about != user_full->about_ || user->common_chat_count != user_full->common_chats_count_) { + user->about != user_full->about_) { user->can_be_called = can_be_called; user->has_private_calls = has_private_calls; user->about = std::move(user_full->about_); - user->common_chat_count = user_full->common_chats_count_; user->is_changed = true; } @@ -7091,6 +7095,31 @@ void ContactsManager::on_update_user_full_is_blocked(UserFull *user_full, UserId } } +void ContactsManager::on_update_user_common_chat_count(UserId user_id, int32 common_chat_count) { + LOG(INFO) << "Receive " << common_chat_count << " common chat count with " << user_id; + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << user_id; + return; + } + + UserFull *user_full = get_user_full(user_id); + if (user_full == nullptr) { + return; + } + on_update_user_full_common_chat_count(user_full, user_id, common_chat_count); + update_user_full(user_full, user_id); +} + +void ContactsManager::on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, + int32 common_chat_count) { + CHECK(user_full != nullptr); + if (user_full->is_inited && user_full->common_chat_count != common_chat_count) { + user_full->common_chat_count = common_chat_count; + user_full->is_common_chat_count_changed = true; + user_full->is_changed = true; + } +} + void ContactsManager::on_delete_profile_photo(int64 profile_photo_id, Promise promise) { UserId my_id = get_my_id(); diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 2ec9dd9be..1919f90df 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -157,6 +157,7 @@ class ContactsManager : public Actor { void on_update_user_links(UserId user_id, tl_object_ptr &&outbound, tl_object_ptr &&inbound); void on_update_user_blocked(UserId user_id, bool is_blocked); + void on_update_user_common_chat_count(UserId user_id, int32 common_chat_count); void on_delete_profile_photo(int64 profile_photo_id, Promise promise); @@ -547,6 +548,7 @@ class ContactsManager : public Actor { bool can_be_called = false; bool has_private_calls = false; + bool is_common_chat_count_changed = true; bool is_changed = true; double expires_at = 0.0; @@ -873,6 +875,7 @@ class ContactsManager : public Actor { void add_user_photo_id(User *u, UserId user_id, int64 photo_id, const vector &photo_file_ids); void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked); + void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count); bool on_update_user_full_bot_info(UserFull *user_full, UserId user_id, int32 bot_info_version, tl_object_ptr &&bot_info); void invalidate_user_full(UserId user_id); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8b0340cef..c60b73912 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -484,6 +484,7 @@ class SearchPublicDialogsQuery : public Td::ResultHandler { class GetCommonDialogsQuery : public Td::ResultHandler { Promise promise_; UserId user_id_; + int32 offset_chat_id_ = 0; public: explicit GetCommonDialogsQuery(Promise &&promise) : promise_(std::move(promise)) { @@ -491,6 +492,7 @@ class GetCommonDialogsQuery : public Td::ResultHandler { void send(UserId user_id, int32 offset_chat_id, int32 limit) { user_id_ = user_id; + offset_chat_id_ = offset_chat_id; LOG(INFO) << "Get common dialogs with " << user_id << " from " << offset_chat_id << " with limit " << limit; auto input_user = td->contacts_manager_->get_input_user(user_id); @@ -512,13 +514,14 @@ class GetCommonDialogsQuery : public Td::ResultHandler { switch (constructor_id) { case telegram_api::messages_chats::ID: { auto chats = move_tl_object_as(chats_ptr); - td->messages_manager_->on_get_common_dialogs(user_id_, std::move(chats->chats_), + td->messages_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_), narrow_cast(chats->chats_.size())); break; } case telegram_api::messages_chatsSlice::ID: { auto chats = move_tl_object_as(chats_ptr); - td->messages_manager_->on_get_common_dialogs(user_id_, std::move(chats->chats_), chats->count_); + td->messages_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_), + chats->count_); break; } default: @@ -11681,6 +11684,13 @@ vector MessagesManager::search_dialogs_on_server(const string &query, return vector(); } +void MessagesManager::drop_common_dialogs_cache(UserId user_id) { + auto it = found_common_dialogs_.find(user_id); + if (it != found_common_dialogs_.end()) { + it->second.is_outdated = true; + } +} + vector MessagesManager::get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force, Promise &&promise) { if (!td_->contacts_manager_->have_input_user(user_id)) { @@ -11723,42 +11733,58 @@ vector MessagesManager::get_common_dialogs(UserId user_id, DialogId of } auto it = found_common_dialogs_.find(user_id); - if (it != found_common_dialogs_.end() && !it->second.empty()) { - vector &common_dialog_ids = it->second; - auto offset_it = common_dialog_ids.begin(); - if (offset_dialog_id != DialogId()) { - offset_it = std::find(common_dialog_ids.begin(), common_dialog_ids.end(), offset_dialog_id); - if (offset_it == common_dialog_ids.end()) { - promise.set_error(Status::Error(6, "Wrong offset_chat_id")); - return vector(); + if (it != found_common_dialogs_.end() && !it->second.dialog_ids.empty()) { + vector &common_dialog_ids = it->second.dialog_ids; + bool use_cache = (!it->second.is_outdated && it->second.received_date >= Time::now() - 3600) || force || + offset_chat_id != 0 || common_dialog_ids.size() >= static_cast(MAX_GET_DIALOGS); + // use cache if it's up to date, or we required to use it or we can't update it + if (use_cache) { + auto offset_it = common_dialog_ids.begin(); + if (offset_dialog_id != DialogId()) { + offset_it = std::find(common_dialog_ids.begin(), common_dialog_ids.end(), offset_dialog_id); + if (offset_it == common_dialog_ids.end()) { + promise.set_error(Status::Error(6, "Wrong offset_chat_id")); + return vector(); + } + ++offset_it; } - ++offset_it; - } - vector result; - while (result.size() < static_cast(limit)) { - if (offset_it == common_dialog_ids.end()) { - break; + vector result; + while (result.size() < static_cast(limit)) { + if (offset_it == common_dialog_ids.end()) { + break; + } + auto dialog_id = *offset_it++; + if (dialog_id == DialogId()) { // end of the list + promise.set_value(Unit()); + return result; + } + result.push_back(dialog_id); } - auto dialog_id = *offset_it++; - if (dialog_id == DialogId()) { // end of the list + if (result.size() == static_cast(limit) || force) { promise.set_value(Unit()); return result; } - result.push_back(dialog_id); - } - if (result.size() == static_cast(limit) || force) { - promise.set_value(Unit()); - return result; } } - td_->create_handler(std::move(promise))->send(user_id, offset_chat_id, limit); + td_->create_handler(std::move(promise))->send(user_id, offset_chat_id, MAX_GET_DIALOGS); return vector(); } -void MessagesManager::on_get_common_dialogs(UserId user_id, vector> &&chats, - int32 total_count) { - auto &result = found_common_dialogs_[user_id]; +void MessagesManager::on_get_common_dialogs(UserId user_id, int32 offset_chat_id, + vector> &&chats, int32 total_count) { + td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count); + + auto &common_dialogs = found_common_dialogs_[user_id]; + if (common_dialogs.is_outdated && offset_chat_id == 0 && common_dialogs.dialog_ids.size() < static_cast(MAX_GET_DIALOGS)) { + // drop outdated cache if possible + common_dialogs = CommonDialogs(); + } + if (common_dialogs.received_date == 0) { + common_dialogs.received_date = Time::now(); + } + common_dialogs.is_outdated = false; + auto &result = common_dialogs.dialog_ids; if (!result.empty() && result.back() == DialogId()) { return; } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 896a2521e..dd6566619 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -266,7 +266,8 @@ class MessagesManager : public Actor { void on_get_dialogs(vector> &&dialogs, int32 total_count, vector> &&messages, Promise &&promise); - void on_get_common_dialogs(UserId user_id, vector> &&chats, int32 total_count); + void on_get_common_dialogs(UserId user_id, int32 offset_chat_id, vector> &&chats, + int32 total_count); bool on_update_message_id(int64 random_id, MessageId new_message_id, const string &source); @@ -465,6 +466,8 @@ class MessagesManager : public Actor { vector search_dialogs_on_server(const string &query, int32 limit, Promise &&promise); + void drop_common_dialogs_cache(UserId user_id); + vector get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force, Promise &&promise); @@ -2239,7 +2242,12 @@ class MessagesManager : public Actor { std::unordered_map> found_public_dialogs_; // TODO time bound cache std::unordered_map> found_on_server_dialogs_; // TODO time bound cache - std::unordered_map, UserIdHash> found_common_dialogs_; // TODO time bound cache + struct CommonDialogs { + vector dialog_ids; + double received_date = 0; + bool is_outdated = false; + }; + std::unordered_map found_common_dialogs_; std::unordered_map get_dialog_message_by_date_results_;