diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index e4069b663..8a4992f33 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -5137,7 +5137,6 @@ void MessagesManager::Message::parse(ParserT &parser) { if (!message_id.is_valid() && !message_id.is_valid_scheduled()) { return parser.set_error("Invalid message identifier"); } - random_y = get_random_y(message_id); if (has_sender) { parse(sender_user_id, parser); } @@ -5739,7 +5738,12 @@ void MessagesManager::Dialog::parse(ParserT &parser) { parse(last_clear_history_date, parser); parse(order, parser); if (has_last_database_message) { - parse(messages, parser); + unique_ptr last_database_message; + parse(last_database_message, parser); + auto loaded_last_database_message_id = last_database_message->message_id; + if (loaded_last_database_message_id.is_valid()) { + messages.set(loaded_last_database_message_id, std::move(last_database_message)); + } } if (has_first_database_message_id) { parse(first_database_message_id, parser); @@ -8482,7 +8486,7 @@ void MessagesManager::set_dialog_next_available_reactions_generation(Dialog *d, void MessagesManager::hide_dialog_message_reactions(Dialog *d) { CHECK(!td_->auth_manager_->is_bot()); vector message_ids; - find_messages(d->messages.get(), message_ids, + find_messages(d, d->ordered_messages.get(), message_ids, [](const Message *m) { return m->reactions != nullptr && !m->reactions->reactions_.empty(); }); for (auto message_id : message_ids) { Message *m = get_message(d, message_id); @@ -9809,7 +9813,7 @@ void MessagesManager::on_get_messages(vector message_ids; - find_newer_messages(d->messages.get(), max_message_id, message_ids); + find_newer_messages(d->ordered_messages.get(), max_message_id, message_ids); if (message_ids.empty()) { return false; } @@ -9873,7 +9877,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ on_dialog_updated(dialog_id, "set have_full_history"); } - if (from_the_end && d->have_full_history && d->messages == nullptr) { + if (from_the_end && d->have_full_history && d->messages.empty()) { if (!d->last_database_message_id.is_valid()) { set_dialog_is_empty(d, "on_get_history empty"); } else { @@ -10049,7 +10053,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ set_dialog_last_database_message_id(d, message_id, "on_get_history"); } new_first_database_message_id = message_id; - try_restore_dialog_reply_markup(d, *it); + try_restore_dialog_reply_markup(d, get_message(d, message_id)); } --it; } @@ -10075,7 +10079,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ auto message_id = (*it)->message_id; if ((message_id.is_server() || message_id.is_local()) && message_id < new_first_database_message_id) { new_first_database_message_id = message_id; - try_restore_dialog_reply_markup(d, *it); + try_restore_dialog_reply_markup(d, get_message(d, message_id)); } --it; } @@ -11413,7 +11417,7 @@ void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from // TODO get dialog from the server and delete history from last message identifier } - bool allow_error = d->messages == nullptr; + bool allow_error = d->messages.empty(); auto old_order = d->order; delete_all_dialog_messages(d, remove_from_dialog_list, true); @@ -11610,53 +11614,56 @@ void MessagesManager::delete_all_call_messages_on_server(bool revoke, uint64 log get_erase_log_event_promise(log_event_id, std::move(promise))); } -void MessagesManager::find_messages(const Message *m, vector &message_ids, +void MessagesManager::find_messages(const Dialog *d, const OrderedMessage *ordered_message, + vector &message_ids, const std::function &condition) { - if (m == nullptr) { + if (ordered_message == nullptr) { return; } - find_messages(m->left.get(), message_ids, condition); + find_messages(d, ordered_message->left.get(), message_ids, condition); - if (condition(m)) { - message_ids.push_back(m->message_id); + if (condition(get_message(d, ordered_message->message_id))) { + message_ids.push_back(ordered_message->message_id); } - find_messages(m->right.get(), message_ids, condition); + find_messages(d, ordered_message->right.get(), message_ids, condition); } -void MessagesManager::find_old_messages(const Message *m, MessageId max_message_id, vector &message_ids) { - if (m == nullptr) { +void MessagesManager::find_old_messages(const OrderedMessage *ordered_message, MessageId max_message_id, + vector &message_ids) { + if (ordered_message == nullptr) { return; } - find_old_messages(m->left.get(), max_message_id, message_ids); + find_old_messages(ordered_message->left.get(), max_message_id, message_ids); - if (m->message_id <= max_message_id) { - message_ids.push_back(m->message_id); + if (ordered_message->message_id <= max_message_id) { + message_ids.push_back(ordered_message->message_id); - find_old_messages(m->right.get(), max_message_id, message_ids); + find_old_messages(ordered_message->right.get(), max_message_id, message_ids); } } -void MessagesManager::find_newer_messages(const Message *m, MessageId min_message_id, vector &message_ids) { - if (m == nullptr) { +void MessagesManager::find_newer_messages(const OrderedMessage *ordered_message, MessageId min_message_id, + vector &message_ids) { + if (ordered_message == nullptr) { return; } - if (m->message_id > min_message_id) { - find_newer_messages(m->left.get(), min_message_id, message_ids); + if (ordered_message->message_id > min_message_id) { + find_newer_messages(ordered_message->left.get(), min_message_id, message_ids); - message_ids.push_back(m->message_id); + message_ids.push_back(ordered_message->message_id); } - find_newer_messages(m->right.get(), min_message_id, message_ids); + find_newer_messages(ordered_message->right.get(), min_message_id, message_ids); } -void MessagesManager::find_unloadable_messages(const Dialog *d, int32 unload_before_date, const Message *m, - vector &message_ids, +void MessagesManager::find_unloadable_messages(const Dialog *d, int32 unload_before_date, + const OrderedMessage *ordered_message, vector &message_ids, bool &has_left_to_unload_messages) const { - if (m == nullptr) { + if (ordered_message == nullptr) { return; } if (message_ids.size() >= MAX_UNLOADED_MESSAGES) { @@ -11664,11 +11671,14 @@ void MessagesManager::find_unloadable_messages(const Dialog *d, int32 unload_bef return; } - find_unloadable_messages(d, unload_before_date, m->left.get(), message_ids, has_left_to_unload_messages); + find_unloadable_messages(d, unload_before_date, ordered_message->left.get(), message_ids, + has_left_to_unload_messages); + const Message *m = get_message(d, ordered_message->message_id); + CHECK(m != nullptr); if (can_unload_message(d, m)) { if (m->last_access_date <= unload_before_date) { - message_ids.push_back(m->message_id); + message_ids.push_back(ordered_message->message_id); } else { has_left_to_unload_messages = true; } @@ -11679,7 +11689,8 @@ void MessagesManager::find_unloadable_messages(const Dialog *d, int32 unload_bef return; } - find_unloadable_messages(d, unload_before_date, m->right.get(), message_ids, has_left_to_unload_messages); + find_unloadable_messages(d, unload_before_date, ordered_message->right.get(), message_ids, + has_left_to_unload_messages); } void MessagesManager::delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, @@ -11738,9 +11749,10 @@ void MessagesManager::delete_dialog_messages_by_sender(DialogId dialog_id, Dialo } vector message_ids; - find_messages(d->messages.get(), message_ids, [sender_dialog_id, channel_status, is_bot](const Message *m) { - return sender_dialog_id == get_message_sender(m) && can_delete_channel_message(channel_status, m, is_bot); - }); + find_messages( + d, d->ordered_messages.get(), message_ids, [sender_dialog_id, channel_status, is_bot](const Message *m) { + return sender_dialog_id == get_message_sender(m) && can_delete_channel_message(channel_status, m, is_bot); + }); delete_dialog_messages(d, message_ids, false, DELETE_MESSAGE_USER_REQUEST_SOURCE); @@ -11850,7 +11862,7 @@ void MessagesManager::delete_dialog_messages_by_date(DialogId dialog_id, int32 m // TODO delete in database by dates vector message_ids; - find_messages_by_date(d->messages.get(), min_date, max_date, message_ids); + find_messages_by_date(d, d->ordered_messages.get(), min_date, max_date, message_ids); delete_dialog_messages(d, message_ids, false, DELETE_MESSAGE_USER_REQUEST_SOURCE); @@ -11948,7 +11960,7 @@ void MessagesManager::unload_dialog(DialogId dialog_id) { vector to_unload_message_ids; bool has_left_to_unload_messages = false; - find_unloadable_messages(d, G()->unix_time_cached() - get_unload_dialog_delay() + 2, d->messages.get(), + find_unloadable_messages(d, G()->unix_time_cached() - get_unload_dialog_delay() + 2, d->ordered_messages.get(), to_unload_message_ids, has_left_to_unload_messages); vector unloaded_message_ids; @@ -12028,7 +12040,7 @@ void MessagesManager::delete_all_dialog_messages(Dialog *d, bool remove_from_dia } vector deleted_message_ids; - do_delete_all_dialog_messages(d, d->messages, is_permanently_deleted, deleted_message_ids); + do_delete_all_dialog_messages(d, is_permanently_deleted, deleted_message_ids); delete_all_dialog_messages_from_database(d, MessageId::max(), "delete_all_dialog_messages 3"); if (is_permanently_deleted) { for (auto id : deleted_message_ids) { @@ -12148,7 +12160,7 @@ void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, MessageId top } vector message_ids; - find_messages(d->messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; }); + find_messages(d, d->ordered_messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; }); LOG(INFO) << "Found " << message_ids.size() << " messages with unread mentions in memory"; bool is_update_sent = false; @@ -12248,7 +12260,7 @@ void MessagesManager::read_all_dialog_reactions(DialogId dialog_id, MessageId to } vector message_ids; - find_messages(d->messages.get(), message_ids, + find_messages(d, d->ordered_messages.get(), message_ids, [this, dialog_id](const Message *m) { return has_unread_message_reactions(dialog_id, m); }); LOG(INFO) << "Found " << message_ids.size() << " messages with unread reactions in memory"; @@ -12386,6 +12398,7 @@ bool MessagesManager::read_message_content(Dialog *d, Message *m, bool is_local_ } bool MessagesManager::has_incoming_notification(DialogId dialog_id, const Message *m) const { + CHECK(m != nullptr); if (m->is_from_scheduled) { return true; } @@ -12402,7 +12415,8 @@ int32 MessagesManager::calc_new_unread_count_from_last_unread(Dialog *d, Message int32 unread_count = type == MessageType::Server ? d->server_unread_count : d->local_unread_count; while (*it != nullptr && (*it)->message_id > d->last_read_inbox_message_id) { - if (has_incoming_notification(d->dialog_id, *it) && (*it)->message_id.get_type() == type) { + auto message_id = (*it)->message_id; + if (message_id.get_type() == type && has_incoming_notification(d->dialog_id, get_message(d, message_id))) { unread_count--; } --it; @@ -12421,7 +12435,8 @@ int32 MessagesManager::calc_new_unread_count_from_the_end(Dialog *d, MessageId m int32 unread_count = 0; MessagesConstIterator it(d, MessageId::max()); while (*it != nullptr && (*it)->message_id > max_message_id) { - if (has_incoming_notification(d->dialog_id, *it) && (*it)->message_id.get_type() == type) { + auto message_id = (*it)->message_id; + if (message_id.get_type() == type && has_incoming_notification(d->dialog_id, get_message(d, message_id))) { unread_count++; } --it; @@ -13056,7 +13071,7 @@ void MessagesManager::set_dialog_max_unavailable_message_id(DialogId dialog_id, d->max_unavailable_message_id = max_unavailable_message_id; vector message_ids; - find_old_messages(d->messages.get(), max_unavailable_message_id, message_ids); + find_old_messages(d->ordered_messages.get(), max_unavailable_message_id, message_ids); vector deleted_message_ids; bool need_update_dialog_pos = false; @@ -13322,7 +13337,8 @@ void MessagesManager::ttl_read_history_impl(DialogId dialog_id, bool is_outgoing CHECK(d != nullptr); auto now = Time::now(); for (auto it = MessagesIterator(d, from_message_id); *it && (*it)->message_id >= till_message_id; --it) { - auto *m = *it; + auto *m = get_message(d, (*it)->message_id); + CHECK(m != nullptr); if (m->is_outgoing == is_outgoing) { ttl_on_view(d, m, view_date, now); } @@ -14062,7 +14078,7 @@ void MessagesManager::read_secret_chat_outbox_inner(DialogId dialog_id, int32 up CHECK(d != nullptr); auto end = MessagesConstIterator(d, MessageId::max()); - while (*end && ((*end)->date > up_to_date || (*end)->message_id.is_yet_unsent())) { + while (*end && (get_message(d, (*end)->message_id)->date > up_to_date || (*end)->message_id.is_yet_unsent())) { --end; } if (!*end) { @@ -14948,7 +14964,6 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f if (dialog_id.get_type() == DialogType::Channel && !have_input_peer(dialog_id, AccessRights::Read)) { auto p = delete_message(d, message_id, false, &need_update_dialog_pos, "get a message in inaccessible chat"); CHECK(p.get() == m); - // CHECK(d->messages == nullptr); send_update_delete_messages(dialog_id, {p->message_id.get()}, false); // don't need to update dialog pos return FullMessageId(); @@ -15053,7 +15068,7 @@ void MessagesManager::remove_dialog_newer_messages(Dialog *d, MessageId from_mes invalidate_message_indexes(d); vector to_delete_message_ids; - find_newer_messages(d->messages.get(), from_message_id, to_delete_message_ids); + find_newer_messages(d->ordered_messages.get(), from_message_id, to_delete_message_ids); td::remove_if(to_delete_message_ids, [](MessageId message_id) { return message_id.is_yet_unsent(); }); if (!to_delete_message_ids.empty()) { LOG(INFO) << "Delete " << format::as_array(to_delete_message_ids) << " newer than " << from_message_id << " in " @@ -15441,7 +15456,7 @@ void MessagesManager::remove_dialog_mention_notifications(Dialog *d) { vector message_ids; FlatHashSet removed_notification_ids_set; - find_messages(d->messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; }); + find_messages(d, d->ordered_messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; }); VLOG(notifications) << "Found unread mentions in " << message_ids; for (auto &message_id : message_ids) { auto m = get_message(d, message_id); @@ -16226,7 +16241,7 @@ void MessagesManager::fix_dialog_last_notification_id(Dialog *d, bool from_menti << d->dialog_id << " from " << message_id << "/" << group_info.last_notification_id; if (*it != nullptr && ((*it)->message_id == message_id || (*it)->have_next)) { while (*it != nullptr) { - const Message *m = *it; + const Message *m = get_message(d, (*it)->message_id); if (is_from_mention_notification_group(m) == from_mentions && m->notification_id.is_valid() && is_message_notification_active(d, m) && m->message_id != message_id) { bool is_fixed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->notification_id, @@ -16301,14 +16316,15 @@ unique_ptr MessagesManager::do_delete_message(Dialog * } FullMessageId full_message_id(d->dialog_id, message_id); - unique_ptr *v = treap_find_message(&d->messages, message_id); - if (*v == nullptr) { - LOG(INFO) << message_id << " is not found in " << d->dialog_id << " to be deleted from " << source; + const Message *m = get_message(d, message_id); + if (m == nullptr) { if (only_from_memory) { return nullptr; } - if (get_message_force(d, message_id, "do_delete_message") == nullptr) { + LOG(INFO) << message_id << " is not found in " << d->dialog_id << " to be deleted from " << source; + m = get_message_force(d, message_id, "do_delete_message"); + if (m == nullptr) { // currently there may be a race between add_message_to_database and get_message_force, // so delete a message from database just in case delete_message_from_database(d, message_id, nullptr, is_permanently_deleted); @@ -16338,13 +16354,8 @@ unique_ptr MessagesManager::do_delete_message(Dialog * */ return nullptr; } - v = treap_find_message(&d->messages, message_id); - CHECK(*v != nullptr); } - const Message *m = v->get(); - CHECK(m->message_id == message_id); - if (only_from_memory && !can_unload_message(d, m)) { return nullptr; } @@ -16359,8 +16370,7 @@ unique_ptr MessagesManager::do_delete_message(Dialog * bool need_get_history = false; if (!only_from_memory) { - LOG(INFO) << "Deleting " << full_message_id << " with have_previous = " << m->have_previous - << " and have_next = " << m->have_next << " from " << source; + LOG(INFO) << "Deleting " << full_message_id << " from " << source; delete_message_from_database(d, message_id, m, is_permanently_deleted); @@ -16464,7 +16474,7 @@ unique_ptr MessagesManager::do_delete_message(Dialog * if ((*message_it)->have_previous && (only_from_memory || !(*message_it)->have_next)) { auto it = message_it; --it; - Message *prev_m = *it; + OrderedMessage *prev_m = *it; if (prev_m != nullptr) { prev_m->have_next = false; } else { @@ -16475,7 +16485,7 @@ unique_ptr MessagesManager::do_delete_message(Dialog * if ((*message_it)->have_next && (only_from_memory || !(*message_it)->have_previous)) { auto it = message_it; ++it; - Message *next_m = *it; + OrderedMessage *next_m = *it; if (next_m != nullptr) { next_m->have_previous = false; } else { @@ -16483,7 +16493,11 @@ unique_ptr MessagesManager::do_delete_message(Dialog * } } - auto result = treap_delete_message(v); + auto result = std::move(d->messages[message_id]); + CHECK(m == result.get()); + d->messages.erase(message_id); + + treap_delete_message(treap_find_message(&d->ordered_messages, message_id)); d->being_deleted_message_id = MessageId(); @@ -16698,26 +16712,20 @@ unique_ptr MessagesManager::do_delete_scheduled_messag return result; } -void MessagesManager::do_delete_all_dialog_messages(Dialog *d, unique_ptr &message, - bool is_permanently_deleted, vector &deleted_message_ids) { - if (message == nullptr) { - return; - } - const Message *m = message.get(); - MessageId message_id = m->message_id; +void MessagesManager::do_delete_all_dialog_messages(Dialog *d, bool is_permanently_deleted, + vector &deleted_message_ids) { + d->messages.foreach([&](const MessageId &message_id, unique_ptr &message) { + Message *m = message.get(); - LOG(INFO) << "Delete " << message_id; - deleted_message_ids.push_back(message_id.get()); + LOG(INFO) << "Delete " << message_id; + deleted_message_ids.push_back(message_id.get()); - do_delete_all_dialog_messages(d, message->right, is_permanently_deleted, deleted_message_ids); - do_delete_all_dialog_messages(d, message->left, is_permanently_deleted, deleted_message_ids); + delete_active_live_location(d->dialog_id, m); + remove_message_file_sources(d->dialog_id, m); - delete_active_live_location(d->dialog_id, m); - remove_message_file_sources(d->dialog_id, m); - - on_message_deleted(d, message.get(), is_permanently_deleted, "do_delete_all_dialog_messages"); - - message = nullptr; + on_message_deleted(d, m, is_permanently_deleted, "do_delete_all_dialog_messages"); + }); + Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), d->messages, d->ordered_messages); } bool MessagesManager::have_dialog(DialogId dialog_id) const { @@ -17685,7 +17693,7 @@ void MessagesManager::block_message_sender_from_replies(MessageId message_id, bo } vector message_ids; if (need_delete_all_messages && sender_user_id.is_valid()) { - find_messages(d->messages.get(), message_ids, [sender_user_id](const Message *m) { + find_messages(d, d->ordered_messages.get(), message_ids, [sender_user_id](const Message *m) { return !m->is_outgoing && m->forward_info != nullptr && m->forward_info->sender_user_id == sender_user_id; }); CHECK(td::contains(message_ids, message_id)); @@ -20507,14 +20515,14 @@ void MessagesManager::open_dialog(Dialog *d) { d->was_opened = true; auto min_message_id = MessageId(ServerMessageId(1)); - if (d->last_message_id == MessageId() && d->last_read_outbox_message_id < min_message_id && d->messages != nullptr && - d->messages->message_id < min_message_id) { - Message *m = d->messages.get(); - while (m->right != nullptr) { - m = m->right.get(); + if (d->last_message_id == MessageId() && d->last_read_outbox_message_id < min_message_id && + d->ordered_messages != nullptr && d->ordered_messages->message_id < min_message_id) { + OrderedMessage *ordered_message = d->ordered_messages.get(); + while (ordered_message->right != nullptr) { + ordered_message = ordered_message->right.get(); } - if (m->message_id < min_message_id) { - read_history_inbox(dialog_id, m->message_id, -1, "open_dialog"); + if (ordered_message->message_id < min_message_id) { + read_history_inbox(dialog_id, ordered_message->message_id, -1, "open_dialog"); } } @@ -21103,8 +21111,8 @@ tl_object_ptr MessagesManager::get_dialog_history(DialogId dia bool have_a_gap = false; if (*p == nullptr) { // there is no gap if from_message_id is less than first message in the dialog - if (left_tries == 0 && d->messages != nullptr && offset < 0) { - const Message *cur = d->messages.get(); + if (left_tries == 0 && d->ordered_messages != nullptr && offset < 0) { + const OrderedMessage *cur = d->ordered_messages.get(); while (cur->left != nullptr) { cur = cur->left.get(); } @@ -21159,8 +21167,8 @@ tl_object_ptr MessagesManager::get_dialog_history(DialogId dia vector> messages; if (*p != nullptr && offset == 0) { while (*p != nullptr && messages.size() < static_cast(limit)) { - messages.push_back(get_message_object(dialog_id, *p, "get_dialog_history")); from_message_id = (*p)->message_id; + messages.push_back(get_message_object(dialog_id, get_message(d, from_message_id), "get_dialog_history")); from_the_end = false; --p; } @@ -22839,8 +22847,9 @@ int64 MessagesManager::get_dialog_message_by_date(DialogId dialog_id, int32 date } while (random_id == 0 || get_dialog_message_by_date_results_.count(random_id) > 0); get_dialog_message_by_date_results_[random_id]; // reserve place for result - auto message_id = find_message_by_date(d->messages.get(), date); - if (message_id.is_valid() && (message_id == d->last_message_id || get_message(d, message_id)->have_next)) { + auto message_id = find_message_by_date(d, d->ordered_messages.get(), date); + if (message_id.is_valid() && + (message_id == d->last_message_id || (*MessagesConstIterator(d, message_id))->have_next)) { get_dialog_message_by_date_results_[random_id] = {dialog_id, message_id}; promise.set_value(Unit()); return random_id; @@ -22906,37 +22915,41 @@ void MessagesManager::on_get_affected_history(DialogId dialog_id, AffectedHistor } } -MessageId MessagesManager::find_message_by_date(const Message *m, int32 date) { - if (m == nullptr) { +MessageId MessagesManager::find_message_by_date(const Dialog *d, const OrderedMessage *ordered_message, int32 date) { + if (ordered_message == nullptr) { return MessageId(); } + const Message *m = get_message(d, ordered_message->message_id); + CHECK(m != nullptr); if (m->date > date) { - return find_message_by_date(m->left.get(), date); + return find_message_by_date(d, ordered_message->left.get(), date); } - auto message_id = find_message_by_date(m->right.get(), date); + auto message_id = find_message_by_date(d, ordered_message->right.get(), date); if (message_id.is_valid()) { return message_id; } - return m->message_id; + return ordered_message->message_id; } -void MessagesManager::find_messages_by_date(const Message *m, int32 min_date, int32 max_date, - vector &message_ids) { - if (m == nullptr) { +void MessagesManager::find_messages_by_date(const Dialog *d, const OrderedMessage *ordered_message, int32 min_date, + int32 max_date, vector &message_ids) { + if (ordered_message == nullptr) { return; } + const Message *m = get_message(d, ordered_message->message_id); + CHECK(m != nullptr); if (m->date >= min_date) { - find_messages_by_date(m->left.get(), min_date, max_date, message_ids); + find_messages_by_date(d, ordered_message->left.get(), min_date, max_date, message_ids); if (m->date <= max_date) { message_ids.push_back(m->message_id); } } if (m->date <= max_date) { - find_messages_by_date(m->right.get(), min_date, max_date, message_ids); + find_messages_by_date(d, ordered_message->right.get(), min_date, max_date, message_ids); } } @@ -22950,7 +22963,7 @@ void MessagesManager::on_get_dialog_message_by_date_from_database(DialogId dialo if (result.is_ok()) { Message *m = on_get_message_from_database(d, result.ok(), false, "on_get_dialog_message_by_date_from_database"); if (m != nullptr) { - auto message_id = find_message_by_date(d->messages.get(), date); + auto message_id = find_message_by_date(d, d->ordered_messages.get(), date); if (!message_id.is_valid()) { LOG(ERROR) << "Failed to find " << m->message_id << " in " << dialog_id << " by date " << date; message_id = m->message_id; @@ -22974,7 +22987,7 @@ void MessagesManager::get_dialog_message_by_date_from_server(const Dialog *d, in return promise.set_value(Unit()); } - auto message_id = find_message_by_date(d->messages.get(), date); + auto message_id = find_message_by_date(d, d->ordered_messages.get(), date); if (message_id.is_valid()) { get_dialog_message_by_date_results_[random_id] = {d->dialog_id, message_id}; } @@ -23012,7 +23025,7 @@ void MessagesManager::on_get_dialog_message_by_date_success(DialogId dialog_id, if (result != FullMessageId()) { const Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); - auto message_id = find_message_by_date(d->messages.get(), date); + auto message_id = find_message_by_date(d, d->ordered_messages.get(), date); if (!message_id.is_valid()) { LOG(ERROR) << "Failed to find " << result.get_message_id() << " in " << dialog_id << " by date " << date; message_id = result.get_message_id(); @@ -23390,7 +23403,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId return; } - if (messages.empty() && from_the_end && d->messages == nullptr) { + if (messages.empty() && from_the_end && d->messages.empty()) { if (d->have_full_history) { set_dialog_is_empty(d, "on_get_history_from_database empty"); } else if (d->last_database_message_id.is_valid()) { @@ -26653,7 +26666,7 @@ bool MessagesManager::is_deleted_secret_chat(const Dialog *d) const { return false; } - if (d->order != DEFAULT_ORDER || d->messages != nullptr) { + if (d->order != DEFAULT_ORDER || !d->messages.empty()) { return false; } @@ -30411,7 +30424,7 @@ void MessagesManager::send_update_delete_messages(DialogId dialog_id, vectormessages == nullptr); + CHECK(d->messages.empty()); if ((d->dialog_id.get_type() == DialogType::User || d->dialog_id.get_type() == DialogType::SecretChat) && td_->auth_manager_->is_bot()) { (void)get_dialog_photo(d->dialog_id); // to apply pending user photo @@ -32686,10 +32699,12 @@ void MessagesManager::on_dialog_linked_channel_updated(DialogId dialog_id, Chann } vector message_ids; - find_messages(d->messages.get(), message_ids, [old_linked_channel_id, new_linked_channel_id](const Message *m) { - return !m->reply_info.is_empty() && m->reply_info.channel_id_.is_valid() && - (m->reply_info.channel_id_ == old_linked_channel_id || m->reply_info.channel_id_ == new_linked_channel_id); - }); + find_messages(d, d->ordered_messages.get(), message_ids, + [old_linked_channel_id, new_linked_channel_id](const Message *m) { + return !m->reply_info.is_empty() && m->reply_info.channel_id_.is_valid() && + (m->reply_info.channel_id_ == old_linked_channel_id || + m->reply_info.channel_id_ == new_linked_channel_id); + }); LOG(INFO) << "Found discussion messages " << message_ids; for (auto message_id : message_ids) { send_update_message_interaction_info(dialog_id, get_message(d, message_id)); @@ -34155,7 +34170,7 @@ void MessagesManager::unpin_all_dialog_messages(DialogId dialog_id, MessageId to if (!td_->auth_manager_->is_bot()) { vector message_ids; - find_messages(d->messages.get(), message_ids, [top_thread_message_id](const Message *m) { + find_messages(d, d->ordered_messages.get(), message_ids, [top_thread_message_id](const Message *m) { return m->is_pinned && (!top_thread_message_id.is_valid() || (m->is_topic_message && m->top_thread_message_id == top_thread_message_id)); }); @@ -34226,13 +34241,8 @@ void MessagesManager::unpin_all_dialog_messages_on_server(DialogId dialog_id, ui get_erase_log_event_promise(log_event_id, std::move(promise))); } -unique_ptr *MessagesManager::treap_find_message(unique_ptr *v, - MessageId message_id) { - return const_cast *>(treap_find_message(static_cast *>(v), message_id)); -} - -const unique_ptr *MessagesManager::treap_find_message(const unique_ptr *v, - MessageId message_id) { +unique_ptr *MessagesManager::treap_find_message(unique_ptr *v, + MessageId message_id) { while (*v != nullptr) { if ((*v)->message_id.get() < message_id.get()) { v = &(*v)->right; @@ -34245,7 +34255,8 @@ const unique_ptr *MessagesManager::treap_find_message( return v; } -MessagesManager::Message *MessagesManager::treap_insert_message(unique_ptr *v, unique_ptr message) { +MessagesManager::OrderedMessage *MessagesManager::treap_insert_message(unique_ptr *v, + unique_ptr message) { auto message_id = message->message_id; while (*v != nullptr && (*v)->random_y >= message->random_y) { if ((*v)->message_id.get() < message_id.get()) { @@ -34257,10 +34268,10 @@ MessagesManager::Message *MessagesManager::treap_insert_message(unique_ptr *left = &message->left; - unique_ptr *right = &message->right; + unique_ptr *left = &message->left; + unique_ptr *right = &message->right; - unique_ptr cur = std::move(*v); + unique_ptr cur = std::move(*v); while (cur != nullptr) { if (cur->message_id.get() < message_id.get()) { *left = std::move(cur); @@ -34278,10 +34289,11 @@ MessagesManager::Message *MessagesManager::treap_insert_message(unique_ptrget(); } -unique_ptr MessagesManager::treap_delete_message(unique_ptr *v) { - unique_ptr result = std::move(*v); - unique_ptr left = std::move(result->left); - unique_ptr right = std::move(result->right); +unique_ptr MessagesManager::treap_delete_message(unique_ptr *v) { + unique_ptr result = std::move(*v); + CHECK(result != nullptr); + unique_ptr left = std::move(result->left); + unique_ptr right = std::move(result->right); while (left != nullptr || right != nullptr) { if (left == nullptr || (right != nullptr && right->random_y > left->random_y)) { @@ -34323,11 +34335,9 @@ const MessagesManager::Message *MessagesManager::get_message(const Dialog *d, Me } } } else { - if (message_id.is_valid()) { - result = treap_find_message(&d->messages, message_id)->get(); - if (result != nullptr) { - result->last_access_date = G()->unix_time_cached(); - } + result = d->messages.get_pointer(message_id); + if (result != nullptr) { + result->last_access_date = G()->unix_time_cached(); } } LOG(INFO) << "Search for " << message_id << " in " << d->dialog_id << " found " << result; @@ -34455,13 +34465,15 @@ MessagesManager::Message *MessagesManager::on_get_message_from_database(Dialog * return result; } -int32 MessagesManager::get_random_y(MessageId message_id) { - return static_cast(static_cast(message_id.get() * 2101234567u)); +unique_ptr MessagesManager::create_ordered_message(MessageId message_id) { + auto result = make_unique(); + result->message_id = message_id; + result->random_y = static_cast(static_cast(message_id.get() * 2101234567u)); + return result; } void MessagesManager::set_message_id(unique_ptr &message, MessageId message_id) { message->message_id = message_id; - message->random_y = get_random_y(message_id); } MessagesManager::Message *MessagesManager::add_message_to_dialog(DialogId dialog_id, unique_ptr message, @@ -34859,7 +34871,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq on_dialog_updated(dialog_id, "drop have_full_history"); } - if (d->open_count == 0 && d->messages != nullptr && is_message_unload_enabled() && !d->has_unload_timeout) { + if (d->open_count == 0 && !d->messages.empty() && is_message_unload_enabled() && !d->has_unload_timeout) { LOG(INFO) << "Schedule unload of " << dialog_id; pending_unload_dialog_timeout_.add_timeout_in(dialog_id.get(), get_next_unload_dialog_delay(d)); d->has_unload_timeout = true; @@ -34965,7 +34977,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq bool is_attached = false; if (auto_attach) { auto it = MessagesIterator(d, message_id); - Message *previous_message = *it; + OrderedMessage *previous_message = *it; if (previous_message != nullptr) { auto previous_message_id = previous_message->message_id; CHECK(previous_message_id < message_id); @@ -34993,8 +35005,8 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } if (!is_attached && !message_id.is_yet_unsent()) { // message may be attached to the next message if there is no previous message - Message *cur = d->messages.get(); - Message *next_message = nullptr; + OrderedMessage *cur = d->ordered_messages.get(); + OrderedMessage *next_message = nullptr; while (cur != nullptr) { if (cur->message_id < message_id) { cur = cur->right.get(); @@ -35221,7 +35233,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq cancel_dialog_action(dialog_id, m); update_has_outgoing_messages(dialog_id, m); - if (!td_->auth_manager_->is_bot() && d->messages == nullptr && !m->is_outgoing && dialog_id != get_my_dialog_id()) { + if (!td_->auth_manager_->is_bot() && d->messages.empty() && !m->is_outgoing && dialog_id != get_my_dialog_id()) { switch (dialog_type) { case DialogType::User: td_->contacts_manager_->invalidate_user_full(dialog_id.get_user_id()); @@ -35250,21 +35262,20 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq td_->forum_topic_manager_->on_topic_message_count_changed(dialog_id, m->top_thread_message_id, +1); } - Message *result_message = treap_insert_message(&d->messages, std::move(message)); - CHECK(result_message != nullptr); - CHECK(result_message == m); - CHECK(d->messages != nullptr); + Message *result_message = message.get(); + d->messages.set(message_id, std::move(message)); + OrderedMessage *ordered_message = treap_insert_message(&d->ordered_messages, create_ordered_message(message_id)); if (!is_attached) { if (have_next) { CHECK(!have_previous); - attach_message_to_next(d, m->message_id, source); + attach_message_to_next(d, message_id, source); } else if (have_previous) { - attach_message_to_previous(d, m->message_id, source); + attach_message_to_previous(d, message_id, source); } } else { - result_message->have_previous = have_previous; - result_message->have_next = have_next; + ordered_message->have_previous = have_previous; + ordered_message->have_next = have_next; } if (m->message_id.is_yet_unsent() && !m->message_id.is_scheduled() && m->top_thread_message_id.is_valid() && @@ -35877,7 +35888,7 @@ void MessagesManager::attach_message_to_previous(Dialog *d, MessageId message_id CHECK(d != nullptr); CHECK(message_id.is_valid()); MessagesIterator it(d, message_id); - Message *m = *it; + OrderedMessage *m = *it; CHECK(m != nullptr); CHECK(m->message_id == message_id); if (m->have_previous) { @@ -35899,7 +35910,7 @@ void MessagesManager::attach_message_to_next(Dialog *d, MessageId message_id, co CHECK(d != nullptr); CHECK(message_id.is_valid()); MessagesIterator it(d, message_id); - Message *m = *it; + OrderedMessage *m = *it; CHECK(m != nullptr); CHECK(m->message_id == message_id); if (m->have_next) { @@ -35925,7 +35936,6 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr LOG_CHECK(old_message->message_id == new_message->message_id) << d->dialog_id << ' ' << old_message->message_id << ' ' << new_message->message_id << ' ' << is_message_in_dialog; - CHECK(old_message->random_y == new_message->random_y); CHECK(need_update_dialog_pos != nullptr); DialogId dialog_id = d->dialog_id; @@ -36792,7 +36802,14 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&di d->is_channel_difference_finished = true; } - unique_ptr last_database_message = std::move(d->messages); + unique_ptr last_database_message; + if (!d->messages.empty()) { + d->messages.foreach([&](const MessageId &message_id, unique_ptr &message) { + CHECK(last_database_message == nullptr); + last_database_message = std::move(message); + }); + d->messages = {}; + } MessageId last_database_message_id = d->last_database_message_id; d->last_database_message_id = MessageId(); int64 order = d->order; @@ -36862,9 +36879,7 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&di being_added_new_dialog_id_ = DialogId(); - LOG_CHECK(d->messages == nullptr) << d->messages->message_id << ' ' << d->last_message_id << ' ' - << d->last_database_message_id << ' ' - << d->debug_set_dialog_last_database_message_id << ' ' << d->messages->debug_source; + CHECK(d->messages.empty()); fix_new_dialog(d, std::move(last_database_message), last_database_message_id, order, last_clear_history_date, last_clear_history_message_id, default_join_group_call_as_dialog_id, default_send_message_as_dialog_id, @@ -37233,24 +37248,13 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab << ", max_notification_message_id = " << d->notification_info->max_notification_message_id_; } - if (d->messages != nullptr) { - if (d->messages->message_id != last_message_id || d->messages->left != nullptr || d->messages->right != nullptr) { - auto common_data = PSTRING() << ' ' << last_message_id << ' ' << d->last_message_id << ' ' - << d->last_database_message_id << ' ' << d->debug_set_dialog_last_database_message_id - << ' ' << d->messages->debug_source << ' ' << is_loaded_from_database << ' ' - << source << ' ' << being_added_dialog_id_ << ' ' << being_added_new_dialog_id_ - << ' ' << dialog_id << ' ' << d->is_channel_difference_finished << ' ' - << debug_last_get_channel_difference_dialog_id_ << ' ' - << debug_last_get_channel_difference_source_ << ' ' << G()->use_message_database(); - LOG_CHECK(d->messages->message_id == last_message_id) << d->messages->message_id << common_data; - LOG_CHECK(d->messages->left == nullptr) - << d->messages->left->message_id << ' ' << d->messages->message_id << ' ' << d->messages->left->message_id - << ' ' << d->messages->left->debug_source << common_data; - LOG_CHECK(d->messages->right == nullptr) - << d->messages->right->message_id << ' ' << d->messages->message_id << ' ' << d->messages->right->message_id - << ' ' << d->messages->right->debug_source << common_data; - } - } + LOG_CHECK(d->messages.calc_size() <= 1) + << d->messages.calc_size() << ' ' << last_message_id << ' ' << d->last_message_id << ' ' + << d->last_database_message_id << ' ' << d->debug_set_dialog_last_database_message_id << ' ' + << is_loaded_from_database << ' ' << source << ' ' << being_added_dialog_id_ << ' ' << being_added_new_dialog_id_ + << ' ' << dialog_id << ' ' << d->is_channel_difference_finished << ' ' + << debug_last_get_channel_difference_dialog_id_ << ' ' << debug_last_get_channel_difference_source_ << ' ' + << G()->use_message_database(); // must be after update_dialog_pos, because uses d->order // must be after checks that dialog has at most one message, because read_history_inbox can load @@ -37295,8 +37299,6 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab bool MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message) { CHECK(d != nullptr); CHECK(last_database_message != nullptr); - CHECK(last_database_message->left == nullptr); - CHECK(last_database_message->right == nullptr); auto dialog_id = d->dialog_id; auto message_id = last_database_message->message_id; @@ -37978,9 +37980,9 @@ unique_ptr MessagesManager::parse_dialog(DialogId dialo if (d->default_send_message_as_dialog_id != dialog_id) { dependencies.add_message_sender_dependencies(d->default_send_message_as_dialog_id); } - if (d->messages != nullptr) { - add_message_dependencies(dependencies, d->messages.get()); - } + d->messages.foreach([&](const MessageId &message_id, const unique_ptr &message) { + add_message_dependencies(dependencies, message.get()); + }); if (d->draft_message != nullptr) { add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text); } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index a928e8810..e20424960 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1139,10 +1139,20 @@ class MessagesManager final : public Actor { } }; - // Do not forget to update MessagesManager::update_message and all make_unique when this class is changed - struct Message { + struct OrderedMessage { int32 random_y = 0; + bool have_previous = false; + bool have_next = false; + + MessageId message_id; + + unique_ptr left; + unique_ptr right; + }; + + // Do not forget to update MessagesManager::update_message and all make_unique when this class is changed + struct Message { MessageId message_id; UserId sender_user_id; DialogId sender_dialog_id; @@ -1195,8 +1205,6 @@ class MessagesManager final : public Actor { bool hide_via_bot = false; // for resend_message bool is_bot_start_message = false; // for resend_message - bool have_previous = false; - bool have_next = false; bool from_database = false; bool has_get_message_views_query = false; @@ -1250,9 +1258,6 @@ class MessagesManager final : public Actor { const char *debug_source = "null"; - unique_ptr left; - unique_ptr right; - mutable int32 last_access_date = 0; mutable bool is_update_sent = false; // whether the message is known to the app @@ -1447,7 +1452,8 @@ class MessagesManager final : public Actor { string client_data; - unique_ptr messages; + WaitFreeHashMap, MessageIdHash> messages; + unique_ptr ordered_messages; unique_ptr scheduled_messages; @@ -1579,13 +1585,13 @@ class MessagesManager final : public Actor { }; class MessagesIteratorBase { - vector stack_; + vector stack_; protected: MessagesIteratorBase() = default; // points iterator to message with greatest identifier which is less or equal than message_id - MessagesIteratorBase(const Message *root, MessageId message_id) { + MessagesIteratorBase(const OrderedMessage *root, MessageId message_id) { CHECK(!message_id.is_scheduled()); size_t last_right_pos = 0; @@ -1604,7 +1610,7 @@ class MessagesManager final : public Actor { stack_.resize(last_right_pos); } - const Message *operator*() const { + const OrderedMessage *operator*() const { return stack_.empty() ? nullptr : stack_.back(); } @@ -1621,7 +1627,7 @@ class MessagesManager final : public Actor { return; } - const Message *cur = stack_.back(); + const OrderedMessage *cur = stack_.back(); if (!cur->have_next) { stack_.clear(); return; @@ -1632,7 +1638,7 @@ class MessagesManager final : public Actor { if (stack_.empty()) { return; } - const Message *new_cur = stack_.back(); + const OrderedMessage *new_cur = stack_.back(); if (new_cur->left.get() == cur) { return; } @@ -1652,7 +1658,7 @@ class MessagesManager final : public Actor { return; } - const Message *cur = stack_.back(); + const OrderedMessage *cur = stack_.back(); if (!cur->have_previous) { stack_.clear(); return; @@ -1663,7 +1669,7 @@ class MessagesManager final : public Actor { if (stack_.empty()) { return; } - const Message *new_cur = stack_.back(); + const OrderedMessage *new_cur = stack_.back(); if (new_cur->right.get() == cur) { return; } @@ -1683,11 +1689,11 @@ class MessagesManager final : public Actor { public: MessagesIterator() = default; - MessagesIterator(Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { + MessagesIterator(Dialog *d, MessageId message_id) : MessagesIteratorBase(d->ordered_messages.get(), message_id) { } - Message *operator*() const { - return const_cast(MessagesIteratorBase::operator*()); + OrderedMessage *operator*() const { + return const_cast(MessagesIteratorBase::operator*()); } }; @@ -1695,10 +1701,11 @@ class MessagesManager final : public Actor { public: MessagesConstIterator() = default; - MessagesConstIterator(const Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { + MessagesConstIterator(const Dialog *d, MessageId message_id) + : MessagesIteratorBase(d->ordered_messages.get(), message_id) { } - const Message *operator*() const { + const OrderedMessage *operator*() const { return MessagesIteratorBase::operator*(); } }; @@ -2138,8 +2145,7 @@ class MessagesManager final : public Actor { void delete_all_dialog_messages(Dialog *d, bool remove_from_dialog_list, bool is_permanently_deleted); - void do_delete_all_dialog_messages(Dialog *d, unique_ptr &message, bool is_permanently_deleted, - vector &deleted_message_ids); + void do_delete_all_dialog_messages(Dialog *d, bool is_permanently_deleted, vector &deleted_message_ids); void erase_delete_messages_log_event(uint64 log_event_id); @@ -2183,18 +2189,21 @@ class MessagesManager final : public Actor { void on_get_affected_history(DialogId dialog_id, AffectedHistoryQuery query, bool get_affected_messages, AffectedHistory affected_history, Promise &&promise); - static MessageId find_message_by_date(const Message *m, int32 date); + static MessageId find_message_by_date(const Dialog *d, const OrderedMessage *ordered_message, int32 date); - static void find_messages_by_date(const Message *m, int32 min_date, int32 max_date, vector &message_ids); + static void find_messages_by_date(const Dialog *d, const OrderedMessage *ordered_message, int32 min_date, + int32 max_date, vector &message_ids); - static void find_messages(const Message *m, vector &message_ids, + static void find_messages(const Dialog *d, const OrderedMessage *ordered_message, vector &message_ids, const std::function &condition); - static void find_old_messages(const Message *m, MessageId max_message_id, vector &message_ids); + static void find_old_messages(const OrderedMessage *ordered_message, MessageId max_message_id, + vector &message_ids); - static void find_newer_messages(const Message *m, MessageId min_message_id, vector &message_ids); + static void find_newer_messages(const OrderedMessage *ordered_message, MessageId min_message_id, + vector &message_ids); - void find_unloadable_messages(const Dialog *d, int32 unload_before_date, const Message *m, + void find_unloadable_messages(const Dialog *d, int32 unload_before_date, const OrderedMessage *ordered_message, vector &message_ids, bool &has_left_to_unload_messages) const; void on_pending_message_views_timeout(DialogId dialog_id); @@ -2329,7 +2338,7 @@ class MessagesManager final : public Actor { void on_get_scheduled_messages_from_database(DialogId dialog_id, vector &&messages); - static int32 get_random_y(MessageId message_id); + static unique_ptr create_ordered_message(MessageId message_id); static void set_message_id(unique_ptr &message, MessageId message_id); @@ -2863,11 +2872,11 @@ class MessagesManager final : public Actor { DialogFolder *get_dialog_folder(FolderId folder_id); const DialogFolder *get_dialog_folder(FolderId folder_id) const; - static unique_ptr *treap_find_message(unique_ptr *v, MessageId message_id); - static const unique_ptr *treap_find_message(const unique_ptr *v, MessageId message_id); + static unique_ptr *treap_find_message(unique_ptr *v, MessageId message_id); - static Message *treap_insert_message(unique_ptr *v, unique_ptr message); - static unique_ptr treap_delete_message(unique_ptr *v); + static OrderedMessage *treap_insert_message(unique_ptr *v, unique_ptr message); + + static unique_ptr treap_delete_message(unique_ptr *v); static Message *get_message(Dialog *d, MessageId message_id); static const Message *get_message(const Dialog *d, MessageId message_id);