Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-10-15 22:50:34 +02:00
commit 982b994332
63 changed files with 1084 additions and 1128 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX)

View File

@ -803,8 +803,8 @@ foundMessages total_count:int32 messages:vector<message> next_offset:string = Fo
//@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier
//@start_parameter Parameter for the bot start message if the sponsored chat is a chat with a bot @content Content of the message
sponsoredMessage id:int32 sponsor_chat_id:int53 start_parameter:string content:MessageContent = SponsoredMessage;
//@link An internal link to be opened when the sponsored message is clicked; may be null. If null, the sponsor chat needs to be opened instead @content Content of the message
sponsoredMessage id:int32 sponsor_chat_id:int53 link:InternalLinkType content:MessageContent = SponsoredMessage;
//@description Contains a list of sponsored messages @messages List of sponsored messages
sponsoredMessages messages:vector<sponsoredMessage> = SponsoredMessages;
@ -1479,11 +1479,11 @@ date day:int32 month:int32 year:int32 = Date;
//@birthdate Birthdate of the user @gender Gender of the user, "male" or "female" @country_code A two-letter ISO 3166-1 alpha-2 country code of the user's country @residence_country_code A two-letter ISO 3166-1 alpha-2 country code of the user's residence country
personalDetails first_name:string middle_name:string last_name:string native_first_name:string native_middle_name:string native_last_name:string birthdate:date gender:string country_code:string residence_country_code:string = PersonalDetails;
//@description An identity document @number Document number; 1-24 characters @expiry_date Document expiry date; may be null @front_side Front side of the document
//@description An identity document @number Document number; 1-24 characters @expiry_date Document expiry date; may be null if not applicable @front_side Front side of the document
//@reverse_side Reverse side of the document; only for driver license and identity card; may be null @selfie Selfie with the document; may be null @translation List of files containing a certified English translation of the document
identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile translation:vector<datedFile> = IdentityDocument;
//@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date, if available @front_side Front side of the document
//@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date; pass null if not applicable @front_side Front side of the document
//@reverse_side Reverse side of the document; only for driver license and identity card; pass null otherwise @selfie Selfie with the document; pass null if unavailable @translation List of files containing a certified English translation of the document
inputIdentityDocument number:string expiry_date:date front_side:InputFile reverse_side:InputFile selfie:InputFile translation:vector<InputFile> = InputIdentityDocument;

View File

@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
if (POLICY CMP0065)
# do not export symbols from executables
# affects compiler checks in project(), so must be set before it
cmake_policy(SET CMP0065 NEW)
endif()
project(tl-parser LANGUAGES C)
set(SOURCES crc32.h crc32.c tlc.c tl-parser.c tl-parser.h tl-parser-tree.h tl-tl.h portable_endian.h)

View File

@ -703,9 +703,7 @@ void AnimationsManager::add_saved_animation(const tl_object_ptr<td_api::InputFil
}
void AnimationsManager::send_save_gif_query(FileId animation_id, bool unsave, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
// TODO invokeAfter and log event
auto file_view = td_->file_manager_->get_file_view(animation_id);

View File

@ -472,9 +472,8 @@ Result<string> BackgroundManager::get_background_url(const string &name,
void BackgroundManager::reload_background_from_server(
BackgroundId background_id, const string &background_name,
telegram_api::object_ptr<telegram_api::InputWallPaper> &&input_wallpaper, Promise<Unit> &&promise) const {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<GetBackgroundQuery>(std::move(promise))
->send(background_id, background_name, std::move(input_wallpaper));
}

View File

@ -840,7 +840,7 @@ void CallActor::send_with_promise(NetQueryPtr query, Promise<NetQueryPtr> promis
void CallActor::hangup() {
container_.for_each(
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Status::Error(500, "Request aborted")); });
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
stop();
}

View File

@ -274,9 +274,7 @@ void CallbackQueriesManager::send_get_callback_answer_query(
FullMessageId full_message_id, tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password,
Promise<td_api::object_ptr<td_api::callbackQueryAnswer>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto dialog_id = full_message_id.get_dialog_id();
if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {

View File

@ -956,9 +956,7 @@ void ConfigManager::lazy_request_config() {
}
void ConfigManager::get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto auth_manager = G()->td().get_actor_unsafe()->auth_manager_.get();
if (auth_manager != nullptr && auth_manager->is_bot()) {
@ -974,9 +972,7 @@ void ConfigManager::get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>
}
void ConfigManager::get_content_settings(Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto auth_manager = G()->td().get_actor_unsafe()->auth_manager_.get();
if (auth_manager == nullptr || !auth_manager->is_authorized() || auth_manager->is_bot()) {
@ -991,9 +987,7 @@ void ConfigManager::get_content_settings(Promise<Unit> &&promise) {
}
void ConfigManager::set_content_settings(bool ignore_sensitive_content_restrictions, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
last_set_content_settings_ = ignore_sensitive_content_restrictions;
auto &queries = set_content_settings_queries_[ignore_sensitive_content_restrictions];
@ -1011,9 +1005,7 @@ void ConfigManager::set_content_settings(bool ignore_sensitive_content_restricti
}
void ConfigManager::get_global_privacy_settings(Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto auth_manager = G()->td().get_actor_unsafe()->auth_manager_.get();
if (auth_manager == nullptr || !auth_manager->is_authorized() || auth_manager->is_bot()) {
@ -1028,9 +1020,8 @@ void ConfigManager::get_global_privacy_settings(Promise<Unit> &&promise) {
}
void ConfigManager::set_archive_and_mute(bool archive_and_mute, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
if (archive_and_mute) {
remove_suggested_action(suggested_actions_, SuggestedAction{SuggestedAction::Type::EnableArchiveAndMuteNewChats});
}

View File

@ -1185,13 +1185,11 @@ class TogglePrehistoryHiddenQuery final : public Td::ResultHandler {
td->updates_manager_->on_get_updates(
std::move(ptr),
PromiseCreator::lambda([promise = std::move(promise_), channel_id = channel_id_,
PromiseCreator::lambda([actor_id = G()->contacts_manager(), promise = std::move(promise_),
channel_id = channel_id_,
is_all_history_available = is_all_history_available_](Unit result) mutable {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
send_closure(G()->contacts_manager(), &ContactsManager::on_update_channel_is_all_history_available,
channel_id, is_all_history_available, std::move(promise));
send_closure(actor_id, &ContactsManager::on_update_channel_is_all_history_available, channel_id,
is_all_history_available, std::move(promise));
}));
}
@ -1417,13 +1415,11 @@ class ToggleSlowModeQuery final : public Td::ResultHandler {
LOG(INFO) << "Receive result for ToggleSlowModeQuery: " << to_string(ptr);
td->updates_manager_->on_get_updates(
std::move(ptr), PromiseCreator::lambda([promise = std::move(promise_), channel_id = channel_id_,
slow_mode_delay = slow_mode_delay_](Unit result) mutable {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
send_closure(G()->contacts_manager(), &ContactsManager::on_update_channel_slow_mode_delay, channel_id,
slow_mode_delay, std::move(promise));
std::move(ptr),
PromiseCreator::lambda([actor_id = G()->contacts_manager(), promise = std::move(promise_),
channel_id = channel_id_, slow_mode_delay = slow_mode_delay_](Unit result) mutable {
send_closure(actor_id, &ContactsManager::on_update_channel_slow_mode_delay, channel_id, slow_mode_delay,
std::move(promise));
}));
}
@ -5327,9 +5323,7 @@ void ContactsManager::reload_contacts(bool force) {
}
void ContactsManager::add_contact(Contact contact, bool share_phone_number, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
if (!are_contacts_loaded_) {
load_contacts(PromiseCreator::lambda([actor_id = actor_id(this), contact = std::move(contact), share_phone_number,
@ -5475,11 +5469,12 @@ void ContactsManager::on_load_imported_contacts_from_database(string value) {
LOG(INFO) << "Successfully loaded " << all_imported_contacts_.size() << " imported contacts from database";
}
load_imported_contact_users_multipromise_.add_promise(PromiseCreator::lambda([](Result<> result) {
if (result.is_ok()) {
send_closure_later(G()->contacts_manager(), &ContactsManager::on_load_imported_contacts_finished);
}
}));
load_imported_contact_users_multipromise_.add_promise(
PromiseCreator::lambda([actor_id = actor_id(this)](Result<Unit> result) {
if (result.is_ok()) {
send_closure_later(actor_id, &ContactsManager::on_load_imported_contacts_finished);
}
}));
auto lock_promise = load_imported_contact_users_multipromise_.get_promise();
@ -5729,9 +5724,7 @@ std::pair<int32, vector<UserId>> ContactsManager::search_contacts(const string &
}
void ContactsManager::share_phone_number(UserId user_id, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
if (!are_contacts_loaded_) {
load_contacts(PromiseCreator::lambda(
@ -6185,7 +6178,8 @@ void ContactsManager::upload_profile_photo(FileId file_id, bool is_animation, do
CHECK(uploaded_profile_photos_.find(file_id) == uploaded_profile_photos_.end());
uploaded_profile_photos_.emplace(
file_id, UploadedProfilePhoto{main_frame_timestamp, is_animation, reupload_count, std::move(promise)});
LOG(INFO) << "Ask to upload profile photo " << file_id << " with bad parts " << bad_parts;
LOG(INFO) << "Ask to upload " << (is_animation ? "animated" : "static") << " profile photo " << file_id
<< " with bad parts " << bad_parts;
// TODO use force_reupload if reupload_count >= 1, replace reupload_count with is_reupload
td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_profile_photo_callback_, 32, 0);
}
@ -6584,9 +6578,7 @@ void ContactsManager::get_channel_statistics_dc_id(DialogId dialog_id, bool for_
void ContactsManager::get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics,
Promise<DcId> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto channel_full = get_channel_full(channel_id, false, "get_channel_statistics_dc_id_impl");
if (channel_full == nullptr) {
@ -6615,9 +6607,8 @@ void ContactsManager::get_channel_statistics(DialogId dialog_id, bool is_dark,
void ContactsManager::send_get_channel_stats_query(DcId dc_id, ChannelId channel_id, bool is_dark,
Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
const Channel *c = get_channel(channel_id);
CHECK(c != nullptr);
if (c->is_megagroup) {
@ -6666,9 +6657,7 @@ void ContactsManager::get_channel_message_statistics(FullMessageId full_message_
void ContactsManager::send_get_channel_message_stats_query(
DcId dc_id, FullMessageId full_message_id, bool is_dark,
Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto dialog_id = full_message_id.get_dialog_id();
if (!td_->messages_manager_->have_message_force(full_message_id, "send_get_channel_message_stats_query")) {
@ -6697,9 +6686,7 @@ void ContactsManager::load_statistics_graph(DialogId dialog_id, const string &to
void ContactsManager::send_load_async_graph_query(DcId dc_id, string token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<LoadAsyncGraphQuery>(std::move(promise))->send(token, x, dc_id);
}
@ -7218,9 +7205,7 @@ void ContactsManager::transfer_dialog_ownership(DialogId dialog_id, UserId user_
void ContactsManager::transfer_channel_ownership(
ChannelId channel_id, UserId user_id, tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<EditChannelCreatorQuery>(std::move(promise))
->send(channel_id, user_id, std::move(input_check_password));
@ -7285,10 +7270,7 @@ void ContactsManager::export_dialog_invite_link(DialogId dialog_id, int32 expire
void ContactsManager::export_dialog_invite_link_impl(DialogId dialog_id, int32 expire_date, int32 usage_limit,
bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
td_->create_handler<ExportChatInviteQuery>(std::move(promise))
@ -7479,6 +7461,8 @@ void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, bo
void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
DialogParticipantStatus status, DialogParticipantStatus old_status,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
<< status;
const Channel *c = get_channel(channel_id);
@ -7536,22 +7520,22 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
if (old_status.is_member() && !status.is_member() && !status.is_banned()) {
// we can't make participant Left without kicking it first
auto on_result_promise = PromiseCreator::lambda([channel_id, participant_dialog_id, status,
promise = std::move(promise)](Result<> result) mutable {
auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id,
status, promise = std::move(promise)](Result<> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
create_actor<SleepActor>("RestrictChannelParticipantSleepActor", 1.0,
PromiseCreator::lambda([channel_id, participant_dialog_id, status,
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, status,
promise = std::move(promise)](Result<> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(G()->contacts_manager(), &ContactsManager::restrict_channel_participant,
channel_id, participant_dialog_id, status,
DialogParticipantStatus::Banned(0), std::move(promise));
send_closure(actor_id, &ContactsManager::restrict_channel_participant, channel_id,
participant_dialog_id, status, DialogParticipantStatus::Banned(0),
std::move(promise));
}))
.release();
});
@ -7969,10 +7953,10 @@ void ContactsManager::on_load_contacts_from_database(string value) {
LOG(INFO) << "Successfully loaded " << user_ids.size() << " contacts from database";
load_contact_users_multipromise_.add_promise(
PromiseCreator::lambda([expected_contact_count = user_ids.size()](Result<> result) {
load_contact_users_multipromise_.add_promise(PromiseCreator::lambda(
[actor_id = actor_id(this), expected_contact_count = user_ids.size()](Result<Unit> result) {
if (result.is_ok()) {
send_closure(G()->contacts_manager(), &ContactsManager::on_get_contacts_finished, expected_contact_count);
send_closure(actor_id, &ContactsManager::on_get_contacts_finished, expected_contact_count);
}
}));
@ -9693,18 +9677,18 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
}
}
if (u->is_name_changed) {
td_->messages_manager_->on_dialog_title_updated(DialogId(user_id));
for_each_secret_chat_with_user(user_id,
[messages_manager = td_->messages_manager_.get()](SecretChatId secret_chat_id) {
messages_manager->on_dialog_title_updated(DialogId(secret_chat_id));
});
auto messages_manager = td_->messages_manager_.get();
messages_manager->on_dialog_title_updated(DialogId(user_id));
for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) {
messages_manager->on_dialog_title_updated(DialogId(secret_chat_id));
});
}
if (u->is_photo_changed) {
td_->messages_manager_->on_dialog_photo_updated(DialogId(user_id));
for_each_secret_chat_with_user(user_id,
[messages_manager = td_->messages_manager_.get()](SecretChatId secret_chat_id) {
messages_manager->on_dialog_photo_updated(DialogId(secret_chat_id));
});
auto messages_manager = td_->messages_manager_.get();
messages_manager->on_dialog_photo_updated(DialogId(user_id));
for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) {
messages_manager->on_dialog_photo_updated(DialogId(secret_chat_id));
});
}
if (u->is_status_changed && user_id != get_my_id()) {
auto left_time = get_user_was_online(u, user_id) - G()->server_time_cached();
@ -10437,7 +10421,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
if (chat->groupcall_default_join_as_ != nullptr) {
default_join_group_call_as_dialog_id = DialogId(chat->groupcall_default_join_as_);
}
// use send closure later to not crete synchronously default_join_group_call_as_dialog_id
// use send closure later to not create synchronously default_join_group_call_as_dialog_id
send_closure_later(G()->messages_manager(),
&MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(chat_id),
default_join_group_call_as_dialog_id, false);
@ -10653,7 +10637,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
if (channel->groupcall_default_join_as_ != nullptr) {
default_join_group_call_as_dialog_id = DialogId(channel->groupcall_default_join_as_);
}
// use send closure later to not crete synchronously default_join_group_call_as_dialog_id
// use send closure later to not create synchronously default_join_group_call_as_dialog_id
send_closure_later(G()->messages_manager(),
&MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id),
default_join_group_call_as_dialog_id, false);
@ -11701,9 +11685,7 @@ void ContactsManager::on_get_channel_participants(
ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset, int32 limit, string additional_query,
int32 additional_limit, tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
Promise<DialogParticipants> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
on_get_users(std::move(channel_participants->users_), "on_get_channel_participants");
on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants");
@ -13331,9 +13313,8 @@ void ContactsManager::on_update_channel_location(ChannelId channel_id, const Dia
void ContactsManager::on_update_channel_slow_mode_delay(ChannelId channel_id, int32 slow_mode_delay,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_slow_mode_delay");
if (channel_full != nullptr) {
on_update_channel_full_slow_mode_delay(channel_full, channel_id, slow_mode_delay, 0);
@ -13380,9 +13361,7 @@ void ContactsManager::on_update_channel_full_bot_user_ids(ChannelFull *channel_f
void ContactsManager::on_update_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
CHECK(channel_id.is_valid());
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_is_all_history_available");
if (channel_full != nullptr && channel_full->is_all_history_available != is_all_history_available) {
@ -14766,9 +14745,7 @@ void ContactsManager::get_dialog_participant(DialogId dialog_id,
void ContactsManager::finish_get_dialog_participant(DialogParticipant &&dialog_participant,
Promise<td_api::object_ptr<td_api::chatMember>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto participant_dialog_id = dialog_participant.dialog_id;
bool is_user = participant_dialog_id.get_type() == DialogType::User;
@ -14979,9 +14956,7 @@ void ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id, Promi
void ContactsManager::finish_get_chat_participant(ChatId chat_id, UserId user_id,
Promise<DialogParticipant> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
const auto *participant = get_chat_participant(chat_id, user_id);
if (participant == nullptr) {
@ -15012,9 +14987,7 @@ void ContactsManager::search_chat_participants(ChatId chat_id, const string &que
void ContactsManager::do_search_chat_participants(ChatId chat_id, const string &query, int32 limit,
DialogParticipantsFilter filter,
Promise<DialogParticipants> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto chat_full = get_chat_full(chat_id);
if (chat_full == nullptr) {
@ -15087,9 +15060,7 @@ void ContactsManager::get_channel_participant(ChannelId channel_id, DialogId par
void ContactsManager::finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
Promise<DialogParticipant> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
LOG(INFO) << "Receive a member " << dialog_participant.dialog_id << " of a channel " << channel_id;
@ -15218,8 +15189,9 @@ void ContactsManager::on_load_dialog_administrators_from_database(DialogId dialo
MultiPromiseActorSafe load_users_multipromise{"LoadUsersMultiPromiseActor"};
load_users_multipromise.add_promise(
PromiseCreator::lambda([dialog_id, administrators, promise = std::move(promise)](Result<> result) mutable {
send_closure(G()->contacts_manager(), &ContactsManager::on_load_administrator_users_finished, dialog_id,
PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, administrators,
promise = std::move(promise)](Result<Unit> result) mutable {
send_closure(actor_id, &ContactsManager::on_load_administrator_users_finished, dialog_id,
std::move(administrators), std::move(result), std::move(promise));
}));
@ -15235,7 +15207,7 @@ void ContactsManager::on_load_dialog_administrators_from_database(DialogId dialo
void ContactsManager::on_load_administrator_users_finished(DialogId dialog_id,
vector<DialogAdministrator> administrators, Result<> result,
Promise<Unit> promise) {
if (result.is_ok()) {
if (!G()->close_flag() && result.is_ok()) {
dialog_administrators_.emplace(dialog_id, std::move(administrators));
}
promise.set_value(Unit());
@ -15761,8 +15733,6 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
}
void ContactsManager::on_upload_profile_photo(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) {
LOG(INFO) << "File " << file_id << " has been uploaded";
auto it = uploaded_profile_photos_.find(file_id);
CHECK(it != uploaded_profile_photos_.end());
@ -15773,6 +15743,8 @@ void ContactsManager::on_upload_profile_photo(FileId file_id, tl_object_ptr<tele
uploaded_profile_photos_.erase(it);
LOG(INFO) << "Uploaded " << (is_animation ? "animated" : "static") << " profile photo " << file_id
<< " with reupload_count = " << reupload_count;
FileView file_view = td_->file_manager_->get_file_view(file_id);
if (file_view.has_remote_location() && input_file == nullptr) {
if (file_view.main_remote_location().is_web()) {
@ -15785,8 +15757,10 @@ void ContactsManager::on_upload_profile_photo(FileId file_id, tl_object_ptr<tele
// delete file reference and forcely reupload the file
if (is_animation) {
CHECK(file_view.get_type() == FileType::Animation);
LOG_CHECK(file_view.main_remote_location().is_common()) << file_view.main_remote_location();
} else {
CHECK(file_view.get_type() == FileType::Photo);
LOG_CHECK(file_view.main_remote_location().is_photo()) << file_view.main_remote_location();
}
auto file_reference =
is_animation ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_document())

View File

@ -59,7 +59,7 @@ void DelayDispatcher::tear_down() {
while (!queue_.empty()) {
auto query = std::move(queue_.front());
queue_.pop();
query.net_query->set_error(Status::Error(500, "Request aborted"));
query.net_query->set_error(Global::request_aborted_error());
send_closure(std::move(query.callback), &NetQueryCallback::on_result, std::move(query.net_query));
}
parent_.reset();

View File

@ -288,8 +288,11 @@ class DialogDbImpl final : public DialogDbSyncInterface {
return std::move(notification_groups);
}
Status begin_transaction() final {
return db_.begin_transaction();
Status begin_read_transaction() final {
return db_.begin_read_transaction();
}
Status begin_write_transaction() final {
return db_.begin_write_transaction();
}
Status commit_transaction() final {
return db_.commit_transaction();
@ -463,7 +466,7 @@ class DialogDbAsync final : public DialogDbAsyncInterface {
if (pending_writes_.empty()) {
return;
}
sync_db_->begin_transaction().ensure();
sync_db_->begin_write_transaction().ensure();
for (auto &query : pending_writes_) {
query.set_value(Unit());
}

View File

@ -55,7 +55,8 @@ class DialogDbSyncInterface {
virtual Result<int32> get_secret_chat_count(FolderId folder_id) = 0;
virtual Status begin_transaction() = 0;
virtual Status begin_read_transaction() = 0;
virtual Status begin_write_transaction() = 0;
virtual Status commit_transaction() = 0;
};

View File

@ -227,28 +227,17 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source
auto &node = nodes_[dest.node_id];
node.query->active_queries++;
auto promise = PromiseCreator::lambda([dest, file_source_id, file_reference_manager = G()->file_reference_manager(),
file_manager = G()->file_manager()](Result<Unit> result) {
if (G()->close_flag()) {
VLOG(file_references) << "Ignore file reference repair from " << file_source_id << " during closing";
return;
}
auto new_promise = PromiseCreator::lambda([dest, file_source_id, file_reference_manager](Result<Unit> result) {
if (G()->close_flag()) {
VLOG(file_references) << "Ignore file reference repair from " << file_source_id << " during closing";
return;
}
auto promise = PromiseCreator::lambda([dest, file_source_id, actor_id = actor_id(this),
file_manager_actor_id = G()->file_manager()](Result<Unit> result) {
auto new_promise = PromiseCreator::lambda([dest, file_source_id, actor_id](Result<Unit> result) {
Status status;
if (result.is_error()) {
status = result.move_as_error();
}
send_closure(file_reference_manager, &FileReferenceManager::on_query_result, dest, file_source_id,
std::move(status), 0);
send_closure(actor_id, &FileReferenceManager::on_query_result, dest, file_source_id, std::move(status), 0);
});
send_closure(file_manager, &FileManager::on_file_reference_repaired, dest.node_id, file_source_id,
send_closure(file_manager_actor_id, &FileManager::on_file_reference_repaired, dest.node_id, file_source_id,
std::move(result), std::move(new_promise));
});
auto index = static_cast<size_t>(file_source_id.get()) - 1;
@ -272,7 +261,13 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source
[&](const FileSourceWallpapers &source) { promise.set_error(Status::Error("Can't repair old wallpapers")); },
[&](const FileSourceWebPage &source) {
send_closure_later(G()->web_pages_manager(), &WebPagesManager::reload_web_page_by_url, source.url,
std::move(promise));
PromiseCreator::lambda([promise = std::move(promise)](Result<WebPageId> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(Unit());
}
}));
},
[&](const FileSourceSavedAnimations &source) {
send_closure_later(G()->animations_manager(), &AnimationsManager::repair_saved_animations, std::move(promise));
@ -300,6 +295,11 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source
FileReferenceManager::Destination FileReferenceManager::on_query_result(Destination dest, FileSourceId file_source_id,
Status status, int32 sub) {
if (G()->close_flag()) {
VLOG(file_references) << "Ignore file reference repair from " << file_source_id << " during closing";
return dest;
}
VLOG(file_references) << "Receive result of file reference repair query for file " << dest.node_id
<< " with generation " << dest.generation << " from " << file_source_id << ": " << status << " "
<< sub;

View File

@ -383,6 +383,10 @@ class Global final : public ActorContext {
#endif
}
static Status request_aborted_error() {
return Status::Error(500, "Request aborted");
}
void set_close_flag() {
close_flag_ = true;
}
@ -390,6 +394,10 @@ class Global final : public ActorContext {
return close_flag_.load();
}
Status close_status() const {
return close_flag() ? request_aborted_error() : Status::OK();
}
bool is_expected_error(const Status &error) const {
CHECK(error.is_error());
if (error.code() == 401) {

View File

@ -1325,9 +1325,7 @@ void GroupCallManager::create_voice_chat(DialogId dialog_id, string title, int32
void GroupCallManager::on_voice_chat_created(DialogId dialog_id, InputGroupCallId input_group_call_id,
Promise<GroupCallId> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
if (!input_group_call_id.is_valid()) {
return promise.set_error(Status::Error(500, "Receive invalid group call identifier"));
}
@ -1404,7 +1402,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i
load_group_call_queries_.erase(it);
if (G()->close_flag()) {
result = Status::Error(500, "Request aborted");
result = Global::request_aborted_error();
}
if (result.is_ok()) {
@ -2351,10 +2349,7 @@ void GroupCallManager::get_group_call_stream_segment(GroupCallId group_call_id,
int32 channel_id,
td_api::object_ptr<td_api::GroupCallVideoQuality> quality,
Promise<string> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -2441,10 +2436,7 @@ void GroupCallManager::finish_get_group_call_stream_segment(InputGroupCallId inp
}
void GroupCallManager::start_scheduled_group_call(GroupCallId group_call_id, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -2852,10 +2844,7 @@ void GroupCallManager::process_group_call_after_join_requests(InputGroupCallId i
}
void GroupCallManager::set_group_call_title(GroupCallId group_call_id, string title, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -2929,10 +2918,7 @@ void GroupCallManager::on_edit_group_call_title(InputGroupCallId input_group_cal
void GroupCallManager::toggle_group_call_is_my_video_paused(GroupCallId group_call_id, bool is_my_video_paused,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3017,10 +3003,7 @@ void GroupCallManager::on_toggle_group_call_is_my_video_paused(InputGroupCallId
void GroupCallManager::toggle_group_call_is_my_video_enabled(GroupCallId group_call_id, bool is_my_video_enabled,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3108,10 +3091,7 @@ void GroupCallManager::on_toggle_group_call_is_my_video_enabled(InputGroupCallId
void GroupCallManager::toggle_group_call_is_my_presentation_paused(GroupCallId group_call_id,
bool is_my_presentation_paused,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3199,10 +3179,7 @@ void GroupCallManager::on_toggle_group_call_is_my_presentation_paused(InputGroup
void GroupCallManager::toggle_group_call_start_subscribed(GroupCallId group_call_id, bool start_subscribed,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3286,10 +3263,7 @@ void GroupCallManager::on_toggle_group_call_start_subscription(InputGroupCallId
void GroupCallManager::toggle_group_call_mute_new_participants(GroupCallId group_call_id, bool mute_new_participants,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3376,10 +3350,7 @@ void GroupCallManager::on_toggle_group_call_mute_new_participants(InputGroupCall
}
void GroupCallManager::revoke_group_call_invite_link(GroupCallId group_call_id, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3432,10 +3403,7 @@ void GroupCallManager::invite_group_call_participants(GroupCallId group_call_id,
void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, bool can_self_unmute,
Promise<string> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3467,10 +3435,7 @@ void GroupCallManager::get_group_call_invite_link(GroupCallId group_call_id, boo
void GroupCallManager::toggle_group_call_recording(GroupCallId group_call_id, bool is_enabled, string title,
bool record_video, bool use_portrait_orientation,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3560,10 +3525,7 @@ void GroupCallManager::on_toggle_group_call_recording(InputGroupCallId input_gro
void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_call_id, int32 audio_source,
bool is_speaking, Promise<Unit> &&promise, int32 date) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));
auto *group_call = get_group_call(input_group_call_id);
@ -3609,9 +3571,6 @@ void GroupCallManager::set_group_call_participant_is_speaking(GroupCallId group_
if (!is_recursive) {
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), group_call_id, audio_source, is_speaking,
promise = std::move(promise), date](Result<Unit> &&result) mutable {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
if (result.is_error()) {
promise.set_value(Unit());
} else {

View File

@ -1787,6 +1787,7 @@ bool InlineQueriesManager::load_recently_used_bots(Promise<Unit> &promise) {
resolve_recent_inline_bots_multipromise_.add_promise(std::move(promise));
if (recently_used_bots_loaded_ == 0) {
resolve_recent_inline_bots_multipromise_.set_ignore_errors(true);
auto lock = resolve_recent_inline_bots_multipromise_.get_promise();
if (!G()->parameters().use_chat_info_db) {
for (auto &bot_username : bot_usernames) {
td_->messages_manager_->search_public_dialog(bot_username, false,
@ -1798,6 +1799,7 @@ bool InlineQueriesManager::load_recently_used_bots(Promise<Unit> &promise) {
td_->contacts_manager_->get_user(user_id, 3, resolve_recent_inline_bots_multipromise_.get_promise());
}
}
lock.set_value(Unit());
recently_used_bots_loaded_ = 1;
}
return false;

View File

@ -1313,7 +1313,7 @@ void LanguagePackManager::save_strings_to_database(SqliteKeyValue *kv, int32 new
return;
}
kv->begin_transaction().ensure();
kv->begin_write_transaction().ensure();
for (auto str : strings) {
if (!is_valid_key(str.first)) {
LOG(ERROR) << "Have invalid key \"" << str.first << '"';
@ -1873,7 +1873,7 @@ void LanguagePackManager::send_with_promise(NetQueryPtr query, Promise<NetQueryP
void LanguagePackManager::hangup() {
container_.for_each(
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Status::Error(500, "Request aborted")); });
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
stop();
}

View File

@ -3987,16 +3987,16 @@ unique_ptr<MessageContent> get_secret_message_content(
}
auto url = r_http_url.ok().get_url();
auto web_page_id = td->web_pages_manager_->get_web_page_by_url(url, load_data_multipromise.get_promise());
auto result = make_unique<MessageText>(FormattedText{std::move(message_text), std::move(entities)}, web_page_id);
if (!result->web_page_id.is_valid()) {
load_data_multipromise.add_promise(
PromiseCreator::lambda([td, url, &web_page_id = result->web_page_id](Result<Unit> result) {
if (result.is_ok()) {
web_page_id = td->web_pages_manager_->get_web_page_by_url(url);
}
}));
}
auto result = make_unique<MessageText>(FormattedText{std::move(message_text), std::move(entities)}, WebPageId());
td->web_pages_manager_->get_web_page_by_url(
url,
PromiseCreator::lambda([&web_page_id = result->web_page_id, promise = load_data_multipromise.get_promise()](
Result<WebPageId> r_web_page_id) mutable {
if (r_web_page_id.is_ok()) {
web_page_id = r_web_page_id.move_as_ok();
}
promise.set_value(Unit());
}));
return std::move(result);
}
case secret_api::decryptedMessageMediaExternalDocument::ID: {

View File

@ -809,8 +809,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return std::move(result);
}
Status begin_transaction() final {
return db_.begin_transaction();
Status begin_write_transaction() final {
return db_.begin_write_transaction();
}
Status commit_transaction() final {
return db_.commit_transaction();
@ -1176,7 +1176,7 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
if (pending_writes_.empty()) {
return;
}
sync_db_->begin_transaction().ensure();
sync_db_->begin_write_transaction().ensure();
for (auto &query : pending_writes_) {
query.set_value(Unit());
}

View File

@ -100,7 +100,7 @@ class MessagesDbSyncInterface {
virtual Result<MessagesDbCallsResult> get_calls(MessagesDbCallsQuery query) = 0;
virtual Result<MessagesDbFtsResult> get_messages_fts(MessagesDbFtsQuery query) = 0;
virtual Status begin_transaction() = 0;
virtual Status begin_write_transaction() = 0;
virtual Status commit_transaction() = 0;
};

File diff suppressed because it is too large Load Diff

View File

@ -189,7 +189,7 @@ class MessagesManager final : public Actor {
int32 total_count = 0;
bool is_channel_messages = false;
};
MessagesInfo on_get_messages(tl_object_ptr<telegram_api::messages_Messages> &&messages_ptr, const char *source);
MessagesInfo get_messages_info(tl_object_ptr<telegram_api::messages_Messages> &&messages_ptr, const char *source);
void get_channel_difference_if_needed(DialogId dialog_id, MessagesInfo &&messages_info,
Promise<MessagesInfo> &&promise);
@ -197,7 +197,7 @@ class MessagesManager final : public Actor {
void get_channel_differences_if_needed(MessagesInfo &&messages_info, Promise<MessagesInfo> &&promise);
void on_get_messages(vector<tl_object_ptr<telegram_api::Message>> &&messages, bool is_channel_message,
bool is_scheduled, const char *source);
bool is_scheduled, Promise<Unit> &&promise, const char *source);
void on_get_history(DialogId dialog_id, MessageId from_message_id, MessageId old_last_new_message_id, int32 offset,
int32 limit, bool from_the_end, vector<tl_object_ptr<telegram_api::Message>> &&messages,
@ -211,7 +211,8 @@ class MessagesManager final : public Actor {
MessageId from_message_id, int32 offset, int32 limit,
MessageSearchFilter filter, MessageId top_thread_message_id,
int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
vector<tl_object_ptr<telegram_api::Message>> &&messages,
Promise<Unit> &&promise);
void on_failed_dialog_messages_search(DialogId dialog_id, int64 random_id);
void on_get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, int32 total_count,
@ -220,7 +221,7 @@ class MessagesManager final : public Actor {
void on_get_messages_search_result(const string &query, int32 offset_date, DialogId offset_dialog_id,
MessageId offset_message_id, int32 limit, MessageSearchFilter filter,
int32 min_date, int32 max_date, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
vector<tl_object_ptr<telegram_api::Message>> &&messages, Promise<Unit> &&promise);
void on_failed_messages_search(int64 random_id);
void on_get_scheduled_server_messages(DialogId dialog_id, uint32 generation,
@ -547,13 +548,11 @@ class MessagesManager final : public Actor {
void block_message_sender_from_replies(MessageId message_id, bool delete_message, bool delete_all_messages,
bool report_spam, Promise<Unit> &&promise);
std::pair<int32, vector<DialogId>> get_blocked_dialogs(int32 offset, int32 limit, int64 &random_id,
Promise<Unit> &&promise);
void get_blocked_dialogs(int32 offset, int32 limit, Promise<td_api::object_ptr<td_api::messageSenders>> &&promise);
void on_get_blocked_dialogs(int32 offset, int32 limit, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::peerBlocked>> &&blocked_peers);
void on_failed_get_blocked_dialogs(int64 random_id);
void on_get_blocked_dialogs(int32 offset, int32 limit, int32 total_count,
vector<tl_object_ptr<telegram_api::peerBlocked>> &&blocked_peers,
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise);
bool can_get_message_statistics(FullMessageId full_message_id);
@ -728,7 +727,8 @@ class MessagesManager final : public Actor {
int64 get_dialog_message_by_date(DialogId dialog_id, int32 date, Promise<Unit> &&promise);
void on_get_dialog_message_by_date_success(DialogId dialog_id, int32 date, int64 random_id,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
vector<tl_object_ptr<telegram_api::Message>> &&messages,
Promise<Unit> &&promise);
void on_get_dialog_message_by_date_fail(int64 random_id);
@ -1743,6 +1743,8 @@ class MessagesManager final : public Actor {
void add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message, Promise<Unit> lock_promise = Auto());
void on_add_secret_message_ready(int64 token);
void finish_add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message);
void finish_delete_secret_messages(DialogId dialog_id, std::vector<int64> random_ids, Promise<> promise);
@ -2133,7 +2135,7 @@ class MessagesManager final : public Actor {
void load_folder_dialog_list(FolderId folder_id, int32 limit, bool only_local);
void on_load_folder_dialog_list_fail(FolderId folder_id, Status error);
void on_load_folder_dialog_list(FolderId folder_id, Result<Unit> &&result);
void load_folder_dialog_list_from_database(FolderId folder_id, int32 limit, Promise<Unit> &&promise);
@ -2376,7 +2378,7 @@ class MessagesManager final : public Actor {
void on_get_secret_chat_total_count(DialogListId dialog_list_id, int32 total_count);
void recalc_unread_count(DialogListId dialog_list_id, int32 old_dialog_total_count = -1);
void recalc_unread_count(DialogListId dialog_list_id, int32 old_dialog_total_count, bool force);
td_api::object_ptr<td_api::updateChatFilters> get_update_chat_filters_object() const;
@ -3273,9 +3275,6 @@ class MessagesManager final : public Actor {
};
std::unordered_map<UserId, CommonDialogs, UserIdHash> found_common_dialogs_;
std::unordered_map<int64, std::pair<int32, vector<DialogId>>>
found_blocked_dialogs_; // random_id -> [total_count, [dialog_id]...]
std::unordered_map<int64, FullMessageId> get_dialog_message_by_date_results_;
std::unordered_map<int64, std::pair<int32, vector<MessageId>>>

View File

@ -839,7 +839,7 @@ void PasswordManager::start_up() {
void PasswordManager::hangup() {
container_.for_each(
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Status::Error(500, "Request aborted")); });
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
stop();
}

View File

@ -561,7 +561,7 @@ void PrivacyManager::send_with_promise(NetQueryPtr query, Promise<NetQueryPtr> p
void PrivacyManager::hangup() {
container_.for_each(
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Status::Error(500, "Request aborted")); });
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
stop();
}

View File

@ -129,6 +129,13 @@ void RecentDialogList::on_load_dialogs(vector<string> &&found_dialogs) {
auto promises = std::move(load_list_queries_);
CHECK(!promises.empty());
if (G()->close_flag()) {
for (auto &promise : promises) {
promise.set_error(Global::request_aborted_error());
}
return;
}
auto newly_found_dialogs = std::move(dialog_ids_);
reset_to_empty(dialog_ids_);

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/AuthManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/Td.h"
#include "td/telegram/td_api.h"
@ -127,7 +128,7 @@ class RequestActor : public Actor {
}
void hangup() final {
do_send_error(Status::Error(500, "Request aborted"));
do_send_error(Global::request_aborted_error());
stop();
}

View File

@ -1304,16 +1304,6 @@ Status SecretChatActor::do_inbound_message_decrypted(unique_ptr<log_event::Inbou
decrypted_message_service->random_id_, std::move(save_message_finish));
break;
default:
/*
decryptedMessageActionResend#511110b0 start_seq_no:int end_seq_no:int = DecryptedMessageAction;
decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction;
decryptedMessageActionTyping#ccb27641 action:SendMessageAction = DecryptedMessageAction;
decryptedMessageActionRequestKey#f3c9611b exchange_id:long g_a:bytes = DecryptedMessageAction;
decryptedMessageActionAcceptKey#6fe1735b exchange_id:long g_b:bytes key_fingerprint:long = DecryptedMessageAction;
decryptedMessageActionAbortKey#dd05ec6b exchange_id:long = DecryptedMessageAction;
decryptedMessageActionCommitKey#ec2e0b9b exchange_id:long key_fingerprint:long = DecryptedMessageAction;
decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction;
*/
save_message_finish.set_value(Unit());
break;
}
@ -1379,7 +1369,7 @@ void SecretChatActor::on_save_changes_start(ChangesProcessor<StateChange>::Id sa
}
void SecretChatActor::on_inbound_save_message_finish(uint64 state_id) {
if (close_flag_) {
if (close_flag_ || context_->close_flag()) {
return;
}
auto *state = inbound_message_states_.get(state_id);

View File

@ -582,7 +582,7 @@ void SetSecureValue::loop() {
}
void SetSecureValue::hangup() {
on_error(Status::Error(406, "Request aborted"));
on_error(Status::Error(406, "Request canceled"));
}
void SetSecureValue::tear_down() {
@ -1294,7 +1294,7 @@ void SecureManager::get_preferred_country_language(string country_code,
void SecureManager::hangup() {
container_.for_each(
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Status::Error(500, "Request aborted")); });
[](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
dec_refcnt();
}

View File

@ -226,7 +226,7 @@ void SequenceDispatcher::tear_down() {
continue;
}
data.state_ = State::Dummy;
data.query_->set_error(Status::Error(500, "Request aborted"));
data.query_->set_error(Global::request_aborted_error());
do_finish(data);
}
}

View File

@ -148,8 +148,25 @@ void SponsoredMessageManager::delete_cached_sponsored_messages(DialogId dialog_i
td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponsored_message_object(
DialogId dialog_id, const SponsoredMessage &sponsored_message) const {
td_api::object_ptr<td_api::InternalLinkType> link;
switch (sponsored_message.sponsor_dialog_id.get_type()) {
case DialogType::User: {
auto user_id = sponsored_message.sponsor_dialog_id.get_user_id();
if (!td_->contacts_manager_->is_user_bot(user_id)) {
break;
}
auto bot_username = td_->contacts_manager_->get_user_username(user_id);
if (bot_username.empty()) {
break;
}
link = td_api::make_object<td_api::internalLinkTypeBotStart>(bot_username, sponsored_message.start_param);
break;
}
default:
break;
}
return td_api::make_object<td_api::sponsoredMessage>(
sponsored_message.local_id, sponsored_message.sponsor_dialog_id.get(), sponsored_message.start_param,
sponsored_message.local_id, sponsored_message.sponsor_dialog_id.get(), std::move(link),
get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1));
}
@ -201,7 +218,7 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
CHECK(messages->message_random_ids.empty());
if (result.is_ok() && G()->close_flag()) {
result = Status::Error(500, "Request aborted");
result = Global::request_aborted_error();
}
if (result.is_error()) {
dialog_sponsored_messages_.erase(dialog_id);

View File

@ -2293,11 +2293,12 @@ StickerSetId StickersManager::on_get_input_sticker_set(FileId sticker_file_id,
}
auto set_id = search_sticker_set(set->short_name_, load_data_multipromise_ptr->get_promise());
if (!set_id.is_valid()) {
load_data_multipromise_ptr->add_promise(
PromiseCreator::lambda([td = td_, sticker_file_id, short_name = set->short_name_](Result<Unit> result) {
load_data_multipromise_ptr->add_promise(PromiseCreator::lambda(
[actor_id = actor_id(this), sticker_file_id, short_name = set->short_name_](Result<Unit> result) {
if (result.is_ok()) {
// just in case
td->stickers_manager_->on_resolve_sticker_set_short_name(sticker_file_id, short_name);
send_closure(actor_id, &StickersManager::on_resolve_sticker_set_short_name, sticker_file_id,
short_name);
}
}));
}
@ -2317,6 +2318,10 @@ StickerSetId StickersManager::on_get_input_sticker_set(FileId sticker_file_id,
}
void StickersManager::on_resolve_sticker_set_short_name(FileId sticker_file_id, const string &short_name) {
if (G()->close_flag()) {
return;
}
LOG(INFO) << "Resolve sticker " << sticker_file_id << " set to " << short_name;
StickerSetId set_id = search_sticker_set(short_name, Auto());
if (set_id.is_valid()) {
@ -3841,9 +3846,7 @@ void StickersManager::reload_sticker_set(StickerSetId sticker_set_id, int64 acce
void StickersManager::do_reload_sticker_set(StickerSetId sticker_set_id,
tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set,
Promise<Unit> &&promise) const {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<GetStickerSetQuery>(std::move(promise))->send(sticker_set_id, std::move(input_sticker_set));
}
@ -3911,7 +3914,12 @@ void StickersManager::on_update_dice_emojis() {
for (auto &emoji : new_dice_emojis) {
if (!td::contains(dice_emojis_, emoji)) {
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_dice(emoji));
CHECK(!special_sticker_set.id_.is_valid());
if (special_sticker_set.id_.is_valid()) {
// drop information about the sticker set to reload it
special_sticker_set.id_ = StickerSetId();
special_sticker_set.access_hash_ = 0;
special_sticker_set.short_name_.clear();
}
if (G()->parameters().use_file_db) {
LOG(INFO) << "Load new dice sticker set for emoji " << emoji;
@ -4149,9 +4157,7 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic
void StickersManager::send_click_animated_emoji_message_response(
FileId sticker_id, Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
promise.set_value(get_sticker_object(sticker_id));
}
@ -5308,9 +5314,8 @@ void StickersManager::create_new_sticker_set(UserId user_id, string &title, stri
} while (random_id == 0 || pending_new_sticker_sets_.find(random_id) != pending_new_sticker_sets_.end());
pending_new_sticker_sets_[random_id] = std::move(pending_new_sticker_set);
multipromise.add_promise(PromiseCreator::lambda([random_id](Result<Unit> result) {
send_closure_later(G()->stickers_manager(), &StickersManager::on_new_stickers_uploaded, random_id,
std::move(result));
multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), random_id](Result<Unit> result) {
send_closure_later(actor_id, &StickersManager::on_new_stickers_uploaded, random_id, std::move(result));
}));
auto lock_promise = multipromise.get_promise();
@ -5448,6 +5453,9 @@ void StickersManager::on_new_stickers_uploaded(int64 random_id, Result<Unit> res
pending_new_sticker_sets_.erase(it);
if (G()->close_flag()) {
result = Global::request_aborted_error();
}
if (result.is_error()) {
pending_new_sticker_set->promise.set_error(result.move_as_error());
return;
@ -5584,9 +5592,7 @@ void StickersManager::set_sticker_set_thumbnail(UserId user_id, string &short_na
void StickersManager::do_set_sticker_set_thumbnail(UserId user_id, string short_name,
tl_object_ptr<td_api::InputFile> &&thumbnail,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
auto it = short_name_to_sticker_set_id_.find(short_name);
const StickerSet *sticker_set = it == short_name_to_sticker_set_id_.end() ? nullptr : get_sticker_set(it->second);
@ -6009,9 +6015,7 @@ void StickersManager::add_recent_sticker(bool is_attached, const tl_object_ptr<t
void StickersManager::send_save_recent_sticker_query(bool is_attached, FileId sticker_id, bool unsave,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
// TODO invokeAfter and log event
auto file_view = td_->file_manager_->get_file_view(sticker_id);
@ -6404,9 +6408,7 @@ void StickersManager::add_favorite_sticker(const tl_object_ptr<td_api::InputFile
}
void StickersManager::send_fave_sticker_query(FileId sticker_id, bool unsave, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
// TODO invokeAfter and log event
auto file_view = td_->file_manager_->get_file_view(sticker_id);
@ -6806,8 +6808,8 @@ void StickersManager::on_get_emoji_keywords(
const string &language_code, Result<telegram_api::object_ptr<telegram_api::emojiKeywordsDifference>> &&result) {
auto it = load_emoji_keywords_queries_.find(language_code);
CHECK(it != load_emoji_keywords_queries_.end());
CHECK(!it->second.empty());
auto promises = std::move(it->second);
CHECK(!promises.empty());
load_emoji_keywords_queries_.erase(it);
if (result.is_error()) {
@ -6919,8 +6921,7 @@ void StickersManager::on_get_emoji_keywords_difference(
}
version = keywords->version_;
auto *pmc = G()->td_db()->get_sqlite_sync_pmc();
pmc->begin_transaction().ensure();
// set must be the first operation to start a write transaction
pmc->begin_write_transaction().ensure();
pmc->set(get_emoji_language_code_version_database_key(language_code), to_string(version));
pmc->set(get_emoji_language_code_last_difference_time_database_key(language_code), to_string(G()->unix_time()));
for (auto &keyword_ptr : keywords->keywords_) {

View File

@ -63,8 +63,7 @@ void StorageManager::on_new_file(int64 size, int64 real_size, int32 cnt) {
void StorageManager::get_storage_stats(bool need_all_files, int32 dialog_limit, Promise<FileStats> promise) {
if (is_closed_) {
promise.set_error(Status::Error(500, "Request aborted"));
return;
return promise.set_error(Global::request_aborted_error());
}
if (pending_storage_stats_.size() != 0) {
if (stats_dialog_limit_ == dialog_limit && need_all_files == stats_need_all_files_) {
@ -111,7 +110,7 @@ void StorageManager::update_use_storage_optimizer() {
void StorageManager::run_gc(FileGcParameters parameters, bool return_deleted_file_statistics,
Promise<FileStats> promise) {
if (is_closed_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
if (!pending_run_gc_[0].empty() || !pending_run_gc_[1].empty()) {
close_gc_worker();
@ -126,7 +125,7 @@ void StorageManager::run_gc(FileGcParameters parameters, bool return_deleted_fil
std::move(file_stats));
}));
//NB: get_storage_stats will cancel all gc queries, so promise needs to be added after the call
//NB: get_storage_stats will cancel all garbage collection queries, so promise needs to be added after the call
pending_run_gc_[return_deleted_file_statistics].push_back(std::move(promise));
}
@ -158,7 +157,7 @@ void StorageManager::create_stats_worker() {
void StorageManager::on_all_files(FileGcParameters gc_parameters, Result<FileStats> r_file_stats) {
int32 dialog_limit = gc_parameters.dialog_limit;
if (is_closed_ && r_file_stats.is_ok()) {
r_file_stats = Status::Error(500, "Request aborted");
r_file_stats = Global::request_aborted_error();
}
if (r_file_stats.is_error()) {
return on_gc_finished(dialog_limit, r_file_stats.move_as_error());
@ -291,7 +290,7 @@ void StorageManager::close_stats_worker() {
auto promises = std::move(pending_storage_stats_);
pending_storage_stats_.clear();
for (auto &promise : promises) {
promise.set_error(Status::Error(500, "Request aborted"));
promise.set_error(Global::request_aborted_error());
}
stats_generation_++;
stats_worker_.reset();
@ -304,7 +303,7 @@ void StorageManager::close_gc_worker() {
pending_run_gc_[0].clear();
pending_run_gc_[1].clear();
for (auto &promise : promises) {
promise.set_error(Status::Error(500, "Request aborted"));
promise.set_error(Global::request_aborted_error());
}
gc_worker_.reset();
gc_cancellation_token_source_.cancel();
@ -332,7 +331,7 @@ void StorageManager::schedule_next_gc() {
!G()->parameters().enable_storage_optimizer) {
next_gc_at_ = 0;
cancel_timeout();
LOG(INFO) << "No next file gc is scheduled";
LOG(INFO) << "No next file clean up is scheduled";
return;
}
auto sys_time = static_cast<uint32>(Clocks::system());
@ -348,7 +347,7 @@ void StorageManager::schedule_next_gc() {
CHECK(next_gc_at >= sys_time);
auto next_gc_in = next_gc_at - sys_time;
LOG(INFO) << "Schedule next file gc in " << next_gc_in;
LOG(INFO) << "Schedule next file clean up in " << next_gc_in;
next_gc_at_ = Time::now() + next_gc_in;
set_timeout_at(next_gc_at_);
}
@ -364,7 +363,7 @@ void StorageManager::timeout_expired() {
next_gc_at_ = 0;
run_gc({}, false, PromiseCreator::lambda([actor_id = actor_id(this)](Result<FileStats> r_stats) {
if (!r_stats.is_error() || r_stats.error().code() != 500) {
// do not save gc timestamp if request was canceled
// do not save garbage collection timestamp if request was canceled
send_closure(actor_id, &StorageManager::save_last_gc_timestamp);
}
send_closure(actor_id, &StorageManager::schedule_next_gc);

View File

@ -1596,15 +1596,22 @@ class GetWebPagePreviewRequest final : public RequestOnceActor {
}
};
class GetWebPageInstantViewRequest final : public RequestActor<> {
class GetWebPageInstantViewRequest final : public RequestActor<WebPageId> {
string url_;
bool force_full_;
WebPageId web_page_id_;
void do_run(Promise<Unit> &&promise) final {
web_page_id_ =
td->web_pages_manager_->get_web_page_instant_view(url_, force_full_, get_tries() < 3, std::move(promise));
void do_run(Promise<WebPageId> &&promise) final {
if (get_tries() < 2) {
promise.set_value(std::move(web_page_id_));
return;
}
td->web_pages_manager_->get_web_page_instant_view(url_, force_full_, std::move(promise));
}
void do_set_result(WebPageId &&result) final {
web_page_id_ = result;
}
void do_send_result() final {
@ -1614,7 +1621,6 @@ class GetWebPageInstantViewRequest final : public RequestActor<> {
public:
GetWebPageInstantViewRequest(ActorShared<Td> td, uint64 request_id, string url, bool force_full)
: RequestActor(std::move(td), request_id), url_(std::move(url)), force_full_(force_full) {
set_tries(3);
}
};
@ -1856,31 +1862,6 @@ class GetChatEventLogRequest final : public RequestOnceActor {
}
};
class GetBlockedMessageSendersRequest final : public RequestActor<> {
int32 offset_;
int32 limit_;
int64 random_id_;
std::pair<int32, vector<DialogId>> message_senders_;
void do_run(Promise<Unit> &&promise) final {
message_senders_ = td->messages_manager_->get_blocked_dialogs(offset_, limit_, random_id_, std::move(promise));
}
void do_send_result() final {
auto senders =
transform(message_senders_.second, [messages_manager = td->messages_manager_.get()](DialogId dialog_id) {
return messages_manager->get_message_sender_object(dialog_id, "GetBlockedMessageSendersRequest");
});
send_result(td_api::make_object<td_api::messageSenders>(message_senders_.first, std::move(senders)));
}
public:
GetBlockedMessageSendersRequest(ActorShared<Td> td, uint64 request_id, int32 offset, int32 limit)
: RequestActor(std::move(td), request_id), offset_(offset), limit_(limit), random_id_(0) {
}
};
class ImportContactsRequest final : public RequestActor<> {
vector<Contact> contacts_;
int64 random_id_;
@ -6633,7 +6614,8 @@ void Td::on_request(uint64 id, const td_api::blockMessageSenderFromReplies &requ
void Td::on_request(uint64 id, const td_api::getBlockedMessageSenders &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetBlockedMessageSendersRequest, request.offset_, request.limit_);
CREATE_REQUEST_PROMISE();
messages_manager_->get_blocked_dialogs(request.offset_, request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::addContact &request) {

View File

@ -277,6 +277,8 @@ void TdDb::do_close(Promise<> on_finished, bool destroy_flag) {
}
binlog_.reset();
}
lock.set_value(Unit());
}
Status TdDb::init_sqlite(int32 scheduler_id, const TdParameters &parameters, DbKey key, DbKey old_key,

View File

@ -1656,7 +1656,9 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
}
MultiPromiseActorSafe mpas{"OnPendingUpdatesMultiPromiseActor"};
mpas.add_promise(std::move(promise));
mpas.add_promise([actor_id = actor_id(this), promise = std::move(promise)](Result<Unit> &&result) mutable {
send_closure(actor_id, &UpdatesManager::on_pending_updates_processed, std::move(result), std::move(promise));
});
auto lock = mpas.get_promise();
for (auto &update : updates) {
@ -1775,6 +1777,10 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
lock.set_value(Unit());
}
void UpdatesManager::on_pending_updates_processed(Result<Unit> &&result, Promise<Unit> &&promise) {
promise.set_result(std::move(result));
}
void UpdatesManager::add_pending_qts_update(tl_object_ptr<telegram_api::Update> &&update, int32 qts,
Promise<Unit> &&promise) {
CHECK(update != nullptr);

View File

@ -267,6 +267,8 @@ class UpdatesManager final : public Actor {
void on_pending_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, int32 seq_begin, int32 seq_end,
int32 date, double receive_time, Promise<Unit> &&promise, const char *source);
void on_pending_updates_processed(Result<Unit> &&result, Promise<Unit> &&promise);
void process_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, bool force_apply,
Promise<Unit> &&promise);

View File

@ -94,12 +94,12 @@ class GetWebPagePreviewQuery final : public Td::ResultHandler {
};
class GetWebPageQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
Promise<WebPageId> promise_;
WebPageId web_page_id_;
string url_;
public:
explicit GetWebPageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
explicit GetWebPageQuery(Promise<WebPageId> &&promise) : promise_(std::move(promise)) {
}
void send(WebPageId web_page_id, const string &url, int32 hash) {
@ -123,15 +123,15 @@ class GetWebPageQuery final : public Td::ResultHandler {
? web_page->cached_page_views_
: 0;
td->web_pages_manager_->on_get_web_page_instant_view_view_count(web_page_id_, view_count);
return promise_.set_value(std::move(web_page_id_));
} else {
LOG(ERROR) << "Receive webPageNotModified for " << url_;
return on_error(id, Status::Error(500, "Receive webPageNotModified"));
}
} else {
auto web_page_id = td->web_pages_manager_->on_get_web_page(std::move(ptr), DialogId());
td->web_pages_manager_->on_get_web_page_by_url(url_, web_page_id, false);
}
promise_.set_value(Unit());
auto web_page_id = td->web_pages_manager_->on_get_web_page(std::move(ptr), DialogId());
td->web_pages_manager_->on_get_web_page_by_url(url_, web_page_id, false);
promise_.set_value(std::move(web_page_id));
}
void on_error(uint64 id, Status status) final {
@ -832,50 +832,44 @@ tl_object_ptr<td_api::webPage> WebPagesManager::get_web_page_preview_result(int6
return get_web_page_object(web_page_id);
}
WebPageId WebPagesManager::get_web_page_instant_view(const string &url, bool force_full, bool force,
Promise<Unit> &&promise) {
void WebPagesManager::get_web_page_instant_view(const string &url, bool force_full, Promise<WebPageId> &&promise) {
LOG(INFO) << "Trying to get web page instant view for the url \"" << url << '"';
auto it = url_to_web_page_id_.find(url);
if (it != url_to_web_page_id_.end()) {
if (it->second == WebPageId() && !force) {
if (it->second == WebPageId()) {
// ignore negative caching
reload_web_page_by_url(url, std::move(promise));
return WebPageId();
return reload_web_page_by_url(url, std::move(promise));
}
return get_web_page_instant_view(it->second, force_full, std::move(promise));
}
load_web_page_by_url(url, std::move(promise));
return WebPageId();
}
WebPageId WebPagesManager::get_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<Unit> &&promise) {
void WebPagesManager::get_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<WebPageId> &&promise) {
LOG(INFO) << "Trying to get web page instant view for " << web_page_id;
const WebPageInstantView *web_page_instant_view = get_web_page_instant_view(web_page_id);
if (web_page_instant_view == nullptr) {
promise.set_value(Unit());
return WebPageId();
return promise.set_value(WebPageId());
}
if (!web_page_instant_view->is_loaded || (force_full && !web_page_instant_view->is_full)) {
load_web_page_instant_view(web_page_id, force_full, std::move(promise));
return WebPageId();
return load_web_page_instant_view(web_page_id, force_full, std::move(promise));
}
if (force_full) {
reload_web_page_instant_view(web_page_id);
}
promise.set_value(Unit());
return web_page_id;
promise.set_value(std::move(web_page_id));
}
string WebPagesManager::get_web_page_instant_view_database_key(WebPageId web_page_id) {
return PSTRING() << "wpiv" << web_page_id.get();
}
void WebPagesManager::load_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<Unit> &&promise) {
void WebPagesManager::load_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<WebPageId> &&promise) {
auto &load_web_page_instant_view_queries = load_web_page_instant_view_queries_[web_page_id];
auto previous_queries =
load_web_page_instant_view_queries.partial.size() + load_web_page_instant_view_queries.full.size();
@ -892,9 +886,10 @@ void WebPagesManager::load_web_page_instant_view(WebPageId web_page_id, bool for
if (G()->parameters().use_message_db && !web_page_instant_view->was_loaded_from_database) {
LOG(INFO) << "Trying to load " << web_page_id << " instant view from database";
G()->td_db()->get_sqlite_pmc()->get(
get_web_page_instant_view_database_key(web_page_id), PromiseCreator::lambda([web_page_id](string value) {
send_closure(G()->web_pages_manager(), &WebPagesManager::on_load_web_page_instant_view_from_database,
web_page_id, std::move(value));
get_web_page_instant_view_database_key(web_page_id),
PromiseCreator::lambda([actor_id = actor_id(this), web_page_id](string value) {
send_closure(actor_id, &WebPagesManager::on_load_web_page_instant_view_from_database, web_page_id,
std::move(value));
}));
} else {
reload_web_page_instant_view(web_page_id);
@ -907,14 +902,12 @@ void WebPagesManager::reload_web_page_instant_view(WebPageId web_page_id) {
const WebPage *web_page = get_web_page(web_page_id);
CHECK(web_page != nullptr && !web_page->instant_view.is_empty);
auto promise = PromiseCreator::lambda([web_page_id](Result<> result) {
send_closure(G()->web_pages_manager(), &WebPagesManager::update_web_page_instant_view_load_requests, web_page_id,
true, std::move(result));
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), web_page_id](Result<WebPageId> result) {
send_closure(actor_id, &WebPagesManager::update_web_page_instant_view_load_requests, web_page_id, true,
std::move(result));
});
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<GetWebPageQuery>(std::move(promise))
->send(web_page_id, web_page->url, web_page->instant_view.is_full ? web_page->instant_view.hash : 0);
@ -927,7 +920,7 @@ void WebPagesManager::on_load_web_page_instant_view_from_database(WebPageId web_
CHECK(G()->parameters().use_message_db);
LOG(INFO) << "Successfully loaded " << web_page_id << " instant view of size " << value.size() << " from database";
// G()->td_db()->get_sqlite_pmc()->erase(get_web_page_instant_view_database_key(web_page_id), Auto());
// return;
// value.clear();
auto web_page_it = web_pages_.find(web_page_id);
if (web_page_it == web_pages_.end() || web_page_it->second->instant_view.is_empty) {
@ -936,7 +929,7 @@ void WebPagesManager::on_load_web_page_instant_view_from_database(WebPageId web_
if (!value.empty()) {
G()->td_db()->get_sqlite_pmc()->erase(get_web_page_instant_view_database_key(web_page_id), Auto());
}
update_web_page_instant_view_load_requests(web_page_id, true, Unit());
update_web_page_instant_view_load_requests(web_page_id, true, web_page_id);
return;
}
WebPage *web_page = web_page_it->second.get();
@ -966,41 +959,42 @@ void WebPagesManager::on_load_web_page_instant_view_from_database(WebPageId web_
td_->file_manager_->change_files_source(get_web_page_file_source_id(web_page), old_file_ids, new_file_ids);
}
update_web_page_instant_view_load_requests(web_page_id, false, Unit());
update_web_page_instant_view_load_requests(web_page_id, false, web_page_id);
}
void WebPagesManager::update_web_page_instant_view_load_requests(WebPageId web_page_id, bool force_update,
Result<> result) {
if (G()->close_flag() && result.is_error()) {
result = Status::Error(500, "Request aborted");
Result<WebPageId> r_web_page_id) {
if (G()->close_flag()) {
r_web_page_id = Global::request_aborted_error();
}
LOG(INFO) << "Update load requests for " << web_page_id;
auto it = load_web_page_instant_view_queries_.find(web_page_id);
if (it == load_web_page_instant_view_queries_.end()) {
return;
}
vector<Promise<Unit>> promises[2];
vector<Promise<WebPageId>> promises[2];
promises[0] = std::move(it->second.partial);
promises[1] = std::move(it->second.full);
reset_to_empty(it->second.partial);
reset_to_empty(it->second.full);
load_web_page_instant_view_queries_.erase(it);
if (result.is_error()) {
LOG(INFO) << "Receive error " << result.error() << " for load " << web_page_id;
if (r_web_page_id.is_error()) {
LOG(INFO) << "Receive error " << r_web_page_id.error() << " for load " << web_page_id;
combine(promises[0], std::move(promises[1]));
for (auto &promise : promises[0]) {
promise.set_error(result.error().clone());
promise.set_error(r_web_page_id.error().clone());
}
return;
}
LOG(INFO) << "Successfully loaded web page " << web_page_id;
const WebPageInstantView *web_page_instant_view = get_web_page_instant_view(web_page_id);
auto new_web_page_id = r_web_page_id.move_as_ok();
LOG(INFO) << "Successfully loaded web page " << web_page_id << " as " << new_web_page_id;
const WebPageInstantView *web_page_instant_view = get_web_page_instant_view(new_web_page_id);
if (web_page_instant_view == nullptr) {
combine(promises[0], std::move(promises[1]));
for (auto &promise : promises[0]) {
promise.set_value(Unit());
promise.set_value(WebPageId());
}
return;
}
@ -1010,26 +1004,27 @@ void WebPagesManager::update_web_page_instant_view_load_requests(WebPageId web_p
}
for (auto &promise : promises[0]) {
promise.set_value(Unit());
promise.set_value(WebPageId(new_web_page_id));
}
reset_to_empty(promises[0]);
}
if (!promises[0].empty() || !promises[1].empty()) {
if (force_update) {
// protection from cycles
LOG(ERROR) << "Expected to receive " << web_page_id << " from the server, but didn't receive it";
LOG(ERROR) << "Expected to receive " << web_page_id << '/' << new_web_page_id
<< " from the server, but didn't receive it";
combine(promises[0], std::move(promises[1]));
for (auto &promise : promises[0]) {
promise.set_value(Unit());
promise.set_value(WebPageId());
}
return;
}
auto &load_queries = load_web_page_instant_view_queries_[web_page_id];
auto &load_queries = load_web_page_instant_view_queries_[new_web_page_id];
auto old_size = load_queries.partial.size() + load_queries.full.size();
combine(load_queries.partial, std::move(promises[0]));
combine(load_queries.full, std::move(promises[1]));
if (old_size == 0) {
reload_web_page_instant_view(web_page_id);
reload_web_page_instant_view(new_web_page_id);
}
}
}
@ -1049,48 +1044,42 @@ WebPageId WebPagesManager::get_web_page_by_url(const string &url) const {
return WebPageId();
}
WebPageId WebPagesManager::get_web_page_by_url(const string &url, Promise<Unit> &&promise) {
void WebPagesManager::get_web_page_by_url(const string &url, Promise<WebPageId> &&promise) {
LOG(INFO) << "Trying to get web page identifier for the url \"" << url << '"';
auto it = url_to_web_page_id_.find(url);
if (it != url_to_web_page_id_.end()) {
promise.set_value(Unit());
return it->second;
return promise.set_value(WebPageId(it->second));
}
load_web_page_by_url(url, std::move(promise));
return WebPageId();
}
void WebPagesManager::load_web_page_by_url(const string &url, Promise<Unit> &&promise) {
void WebPagesManager::load_web_page_by_url(const string &url, Promise<WebPageId> &&promise) {
if (!G()->parameters().use_message_db) {
reload_web_page_by_url(url, std::move(promise));
return;
return reload_web_page_by_url(url, std::move(promise));
}
LOG(INFO) << "Load \"" << url << '"';
G()->td_db()->get_sqlite_pmc()->get(get_web_page_url_database_key(url),
PromiseCreator::lambda([url, promise = std::move(promise)](string value) mutable {
send_closure(G()->web_pages_manager(),
&WebPagesManager::on_load_web_page_id_by_url_from_database, url,
value, std::move(promise));
}));
G()->td_db()->get_sqlite_pmc()->get(
get_web_page_url_database_key(url),
PromiseCreator::lambda([actor_id = actor_id(this), url, promise = std::move(promise)](string value) mutable {
send_closure(actor_id, &WebPagesManager::on_load_web_page_id_by_url_from_database, std::move(url),
std::move(value), std::move(promise));
}));
}
void WebPagesManager::on_load_web_page_id_by_url_from_database(const string &url, string value,
Promise<Unit> &&promise) {
if (G()->close_flag()) {
return;
}
void WebPagesManager::on_load_web_page_id_by_url_from_database(string url, string value, Promise<WebPageId> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
LOG(INFO) << "Successfully loaded url \"" << url << "\" of size " << value.size() << " from database";
// G()->td_db()->get_sqlite_pmc()->erase(get_web_page_url_database_key(web_page_id), Auto());
// return;
// value.clear();
auto it = url_to_web_page_id_.find(url);
if (it != url_to_web_page_id_.end()) {
// URL web page has already been loaded
promise.set_value(Unit());
return;
return promise.set_value(WebPageId(it->second));
}
if (!value.empty()) {
auto web_page_id = WebPageId(to_integer<int64>(value));
@ -1098,16 +1087,16 @@ void WebPagesManager::on_load_web_page_id_by_url_from_database(const string &url
if (have_web_page(web_page_id)) {
// URL web page has already been loaded
on_get_web_page_by_url(url, web_page_id, true);
promise.set_value(Unit());
promise.set_value(WebPageId(web_page_id));
return;
}
load_web_page_from_database(
web_page_id,
PromiseCreator::lambda([web_page_id, url, promise = std::move(promise)](Result<> result) mutable {
send_closure(G()->web_pages_manager(), &WebPagesManager::on_load_web_page_by_url_from_database, web_page_id,
url, std::move(promise), std::move(result));
}));
load_web_page_from_database(web_page_id,
PromiseCreator::lambda([actor_id = actor_id(this), web_page_id, url = std::move(url),
promise = std::move(promise)](Result<Unit> result) mutable {
send_closure(actor_id, &WebPagesManager::on_load_web_page_by_url_from_database,
web_page_id, std::move(url), std::move(promise), std::move(result));
}));
return;
} else {
LOG(ERROR) << "Receive invalid " << web_page_id;
@ -1117,33 +1106,27 @@ void WebPagesManager::on_load_web_page_id_by_url_from_database(const string &url
reload_web_page_by_url(url, std::move(promise));
}
void WebPagesManager::on_load_web_page_by_url_from_database(WebPageId web_page_id, const string &url,
Promise<Unit> &&promise, Result<> result) {
void WebPagesManager::on_load_web_page_by_url_from_database(WebPageId web_page_id, string url,
Promise<WebPageId> &&promise, Result<Unit> &&result) {
if (result.is_error()) {
CHECK(G()->close_flag());
promise.set_error(Status::Error(500, "Request aborted"));
return;
return promise.set_error(Global::request_aborted_error());
}
const WebPage *web_page = get_web_page(web_page_id);
if (web_page == nullptr) {
reload_web_page_by_url(url, std::move(promise));
return;
return reload_web_page_by_url(url, std::move(promise));
}
if (web_page->url != url) {
on_get_web_page_by_url(url, web_page_id, true);
}
promise.set_value(Unit());
promise.set_value(WebPageId(web_page_id));
}
void WebPagesManager::reload_web_page_by_url(const string &url, Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
LOG(INFO) << "Reload url \"" << url << '"';
void WebPagesManager::reload_web_page_by_url(const string &url, Promise<WebPageId> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<GetWebPageQuery>(std::move(promise))->send(WebPageId(), url, 0);
}
@ -1528,9 +1511,8 @@ void WebPagesManager::save_web_page(const WebPage *web_page, WebPageId web_page_
LOG(INFO) << "Save " << web_page_id << " to database";
G()->td_db()->get_sqlite_pmc()->set(
get_web_page_database_key(web_page_id), log_event_store(*web_page).as_slice().str(),
PromiseCreator::lambda([web_page_id](Result<> result) {
send_closure(G()->web_pages_manager(), &WebPagesManager::on_save_web_page_to_database, web_page_id,
result.is_ok());
PromiseCreator::lambda([actor_id = actor_id(this), web_page_id](Result<> result) {
send_closure(actor_id, &WebPagesManager::on_save_web_page_to_database, web_page_id, result.is_ok());
}));
}
@ -1594,11 +1576,11 @@ void WebPagesManager::load_web_page_from_database(WebPageId web_page_id, Promise
auto &load_web_page_queries = load_web_page_from_database_queries_[web_page_id];
load_web_page_queries.push_back(std::move(promise));
if (load_web_page_queries.size() == 1u) {
G()->td_db()->get_sqlite_pmc()->get(
get_web_page_database_key(web_page_id), PromiseCreator::lambda([web_page_id](string value) {
send_closure(G()->web_pages_manager(), &WebPagesManager::on_load_web_page_from_database, web_page_id,
std::move(value));
}));
G()->td_db()->get_sqlite_pmc()->get(get_web_page_database_key(web_page_id),
PromiseCreator::lambda([actor_id = actor_id(this), web_page_id](string value) {
send_closure(actor_id, &WebPagesManager::on_load_web_page_from_database,
web_page_id, std::move(value));
}));
}
}
@ -1620,7 +1602,7 @@ void WebPagesManager::on_load_web_page_from_database(WebPageId web_page_id, stri
LOG(INFO) << "Successfully loaded " << web_page_id << " of size " << value.size() << " from database";
// G()->td_db()->get_sqlite_pmc()->erase(get_web_page_database_key(web_page_id), Auto());
// return;
// value.clear();
if (!have_web_page(web_page_id)) {
if (!value.empty()) {

View File

@ -67,13 +67,13 @@ class WebPagesManager final : public Actor {
tl_object_ptr<td_api::webPage> get_web_page_preview_result(int64 request_id);
WebPageId get_web_page_instant_view(const string &url, bool force_full, bool force, Promise<Unit> &&promise);
void get_web_page_instant_view(const string &url, bool force_full, Promise<WebPageId> &&promise);
WebPageId get_web_page_by_url(const string &url) const;
WebPageId get_web_page_by_url(const string &url, Promise<Unit> &&promise);
void get_web_page_by_url(const string &url, Promise<WebPageId> &&promise);
void reload_web_page_by_url(const string &url, Promise<Unit> &&promise);
void reload_web_page_by_url(const string &url, Promise<WebPageId> &&promise);
void on_get_web_page_preview_success(int64 request_id, const string &url,
tl_object_ptr<telegram_api::MessageMedia> &&message_media_ptr,
@ -125,7 +125,7 @@ class WebPagesManager final : public Actor {
const WebPageInstantView *get_web_page_instant_view(WebPageId web_page_id) const;
WebPageId get_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<Unit> &&promise);
void get_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<WebPageId> &&promise);
tl_object_ptr<td_api::webPageInstantView> get_web_page_instant_view_object(
WebPageId web_page_id, const WebPageInstantView *web_page_instant_view) const;
@ -153,22 +153,23 @@ class WebPagesManager final : public Actor {
static string get_web_page_instant_view_database_key(WebPageId web_page_id);
void load_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<Unit> &&promise);
void load_web_page_instant_view(WebPageId web_page_id, bool force_full, Promise<WebPageId> &&promise);
void on_load_web_page_instant_view_from_database(WebPageId web_page_id, string value);
void reload_web_page_instant_view(WebPageId web_page_id);
void update_web_page_instant_view_load_requests(WebPageId web_page_id, bool force_update, Result<> result);
void update_web_page_instant_view_load_requests(WebPageId web_page_id, bool force_update,
Result<WebPageId> r_web_page_id);
static string get_web_page_url_database_key(const string &url);
void load_web_page_by_url(const string &url, Promise<Unit> &&promise);
void load_web_page_by_url(const string &url, Promise<WebPageId> &&promise);
void on_load_web_page_id_by_url_from_database(const string &url, string value, Promise<Unit> &&promise);
void on_load_web_page_id_by_url_from_database(string url, string value, Promise<WebPageId> &&promise);
void on_load_web_page_by_url_from_database(WebPageId web_page_id, const string &url, Promise<Unit> &&promise,
Result<> result);
void on_load_web_page_by_url_from_database(WebPageId web_page_id, string url, Promise<WebPageId> &&promise,
Result<Unit> &&result);
void tear_down() final;
@ -186,8 +187,8 @@ class WebPagesManager final : public Actor {
std::unordered_set<WebPageId, WebPageIdHash> loaded_from_database_web_pages_;
struct PendingWebPageInstantViewQueries {
vector<Promise<Unit>> partial;
vector<Promise<Unit>> full;
vector<Promise<WebPageId>> partial;
vector<Promise<WebPageId>> full;
};
std::unordered_map<WebPageId, PendingWebPageInstantViewQueries, WebPageIdHash> load_web_page_instant_view_queries_;

View File

@ -23,7 +23,6 @@
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Slice.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Status.h"
@ -78,10 +77,7 @@ class FileDb final : public FileDbInterface {
void clear_file_data(FileDbId id, const string &remote_key, const string &local_key, const string &generate_key) {
auto &pmc = file_pmc();
pmc.begin_transaction().ensure();
SCOPE_EXIT {
pmc.commit_transaction().ensure();
};
pmc.begin_write_transaction().ensure();
if (id > current_pmc_id_) {
pmc.set("file_id", to_string(id.get()));
@ -89,27 +85,26 @@ class FileDb final : public FileDbInterface {
}
pmc.erase(PSTRING() << "file" << id.get());
LOG(DEBUG) << "ERASE " << format::as_hex_dump<4>(Slice(PSLICE() << "file" << id.get()));
// LOG(DEBUG) << "ERASE " << format::as_hex_dump<4>(Slice(PSLICE() << "file" << id.get()));
if (!remote_key.empty()) {
pmc.erase(remote_key);
LOG(DEBUG) << "ERASE remote " << format::as_hex_dump<4>(Slice(remote_key));
// LOG(DEBUG) << "ERASE remote " << format::as_hex_dump<4>(Slice(remote_key));
}
if (!local_key.empty()) {
pmc.erase(local_key);
LOG(DEBUG) << "ERASE local " << format::as_hex_dump<4>(Slice(local_key));
// LOG(DEBUG) << "ERASE local " << format::as_hex_dump<4>(Slice(local_key));
}
if (!generate_key.empty()) {
pmc.erase(generate_key);
}
pmc.commit_transaction().ensure();
}
void store_file_data(FileDbId id, const string &file_data, const string &remote_key, const string &local_key,
const string &generate_key) {
auto &pmc = file_pmc();
pmc.begin_transaction().ensure();
SCOPE_EXIT {
pmc.commit_transaction().ensure();
};
pmc.begin_write_transaction().ensure();
if (id > current_pmc_id_) {
pmc.set("file_id", to_string(id.get()));
@ -127,13 +122,12 @@ class FileDb final : public FileDbInterface {
if (!generate_key.empty()) {
pmc.set(generate_key, to_string(id.get()));
}
pmc.commit_transaction().ensure();
}
void store_file_data_ref(FileDbId id, FileDbId new_id) {
auto &pmc = file_pmc();
pmc.begin_transaction().ensure();
SCOPE_EXIT {
pmc.commit_transaction().ensure();
};
pmc.begin_write_transaction().ensure();
if (id > current_pmc_id_) {
pmc.set("file_id", to_string(id.get()));
@ -141,18 +135,18 @@ class FileDb final : public FileDbInterface {
}
do_store_file_data_ref(id, new_id);
pmc.commit_transaction().ensure();
}
void optimize_refs(const std::vector<FileDbId> ids, FileDbId main_id) {
LOG(INFO) << "Optimize " << ids.size() << " ids in file database to " << main_id.get();
auto &pmc = file_pmc();
pmc.begin_transaction().ensure();
SCOPE_EXIT {
pmc.commit_transaction().ensure();
};
pmc.begin_write_transaction().ensure();
for (size_t i = 0; i + 1 < ids.size(); i++) {
do_store_file_data_ref(ids[i], main_id);
}
pmc.commit_transaction().ensure();
}
private:
@ -221,10 +215,10 @@ class FileDb final : public FileDbInterface {
if (file_data.generate_ != nullptr && new_generate) {
generate_key = as_key(*file_data.generate_);
}
LOG(DEBUG) << "SAVE " << id.get() << " -> " << file_data << " "
<< tag("remote_key", format::as_hex_dump<4>(Slice(remote_key)))
<< tag("local_key", format::as_hex_dump<4>(Slice(local_key)))
<< tag("generate_key", format::as_hex_dump<4>(Slice(generate_key)));
// LOG(DEBUG) << "SAVE " << id.get() << " -> " << file_data << " "
// << tag("remote_key", format::as_hex_dump<4>(Slice(remote_key)))
// << tag("local_key", format::as_hex_dump<4>(Slice(local_key)))
// << tag("generate_key", format::as_hex_dump<4>(Slice(generate_key)));
send_closure(file_db_actor_, &FileDbActor::store_file_data, id, serialize(file_data), remote_key, local_key,
generate_key);
}
@ -243,7 +237,7 @@ class FileDb final : public FileDbInterface {
static Result<FileData> load_file_data_impl(ActorId<FileDbActor> file_db_actor_id, SqliteKeyValue &pmc,
const string &key, FileDbId current_pmc_id) {
//LOG(DEBUG) << "Load by key " << format::as_hex_dump<4>(Slice(key));
// LOG(DEBUG) << "Load by key " << format::as_hex_dump<4>(Slice(key));
TRY_RESULT(id, get_id(pmc, key));
vector<FileDbId> ids;
@ -270,8 +264,8 @@ class FileDb final : public FileDbInterface {
if (ids.size() > 1) {
send_closure(file_db_actor_id, &FileDbActor::optimize_refs, std::move(ids), id);
}
//LOG(DEBUG) << "By ID " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str));
//LOG(INFO) << attempt_count;
// LOG(DEBUG) << "By ID " << id.get() << " found data " << format::as_hex_dump<4>(Slice(data_str));
// LOG(INFO) << attempt_count;
log_event::WithVersion<TlParser> parser(data_str);
parser.set_version(static_cast<int32>(Version::Initial));
@ -287,7 +281,7 @@ class FileDb final : public FileDbInterface {
static Result<FileDbId> get_id(SqliteKeyValue &pmc, const string &key) TD_WARN_UNUSED_RESULT {
auto id_str = pmc.get(key);
//LOG(DEBUG) << "Found ID " << id_str << " by key " << format::as_hex_dump<4>(Slice(key));
// LOG(DEBUG) << "Found ID " << id_str << " by key " << format::as_hex_dump<4>(Slice(key));
if (id_str.empty()) {
return Status::Error("There is no such a key in database");
}

View File

@ -132,7 +132,7 @@ void FileGcWorker::run_gc(const FileGcParameters &parameters, std::vector<FullFi
return false;
});
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
// sort by max(atime, mtime)
@ -152,7 +152,7 @@ void FileGcWorker::run_gc(const FileGcParameters &parameters, std::vector<FullFi
size_t pos = 0;
while (pos < files.size() && (remove_count > 0 || remove_size > 0)) {
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
if (remove_count > 0) {
remove_by_count_cnt++;

View File

@ -1746,6 +1746,8 @@ void FileManager::change_files_source(FileSourceId file_source_id, const vector<
void FileManager::on_file_reference_repaired(FileId file_id, FileSourceId file_source_id, Result<Unit> &&result,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
auto file_view = get_file_view(file_id);
CHECK(!file_view.empty());
if (result.is_ok() &&
@ -2030,9 +2032,7 @@ void FileManager::get_content(FileId file_id, Promise<BufferSlice> promise) {
void FileManager::read_file_part(FileId file_id, int32 offset, int32 count, int left_tries,
Promise<td_api::object_ptr<td_api::filePart>> promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
TRY_STATUS_PROMISE(promise, G()->close_status());
if (!file_id.is_valid()) {
return promise.set_error(Status::Error(400, "File identifier is invalid"));
@ -2224,8 +2224,8 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
if (priority == 0) {
node->set_download_priority(priority);
LOG(INFO) << "Cancel downloading of file " << node->main_file_id_;
if (old_priority != 0) {
LOG(INFO) << "Cancel downloading of file " << node->main_file_id_;
do_cancel_download(node);
}
return;
@ -2640,7 +2640,7 @@ void FileManager::run_generate(FileNodePtr node) {
}
FileView file_view(node);
if (!file_view.can_generate()) {
LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " can't be generated";
// LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " can't be generated";
return;
}
if (file_view.has_local_location()) {
@ -2732,8 +2732,6 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
if (old_priority != 0) {
LOG(INFO) << "Cancel file " << file_id << " uploading";
do_cancel_upload(node);
} else {
LOG(INFO) << "File " << file_id << " upload priority is still 0";
}
return;
}
@ -3872,7 +3870,7 @@ void FileManager::hangup() {
while (!queries_container_.empty()) {
auto ids = queries_container_.ids();
for (auto id : ids) {
on_error(id, Status::Error(500, "Request aborted"));
on_error(id, Global::request_aborted_error());
}
}
is_closed_ = true;

View File

@ -161,7 +161,7 @@ void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_
auto passed = Time::now() - start;
LOG_IF(INFO, passed > 0.5) << "Get file stats took: " << format::as_time(passed);
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
promise.set_value(std::move(file_stats));
} else {
@ -182,7 +182,7 @@ void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_
});
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
std::unordered_map<size_t, size_t> hash_to_pos;
@ -191,7 +191,7 @@ void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_
hash_to_pos[std::hash<std::string>()(full_info.path)] = pos;
pos++;
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
}
scan_db(token_, [&](DbFileInfo &db_info) {
@ -203,14 +203,14 @@ void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_
full_infos[it->second].owner_dialog_id = db_info.owner_dialog_id;
});
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
FileStats file_stats(need_all_files, split_by_owner_dialog_id);
for (auto &full_info : full_infos) {
file_stats.add(std::move(full_info));
if (token_) {
return promise.set_error(Status::Error(500, "Request aborted"));
return promise.set_error(Global::request_aborted_error());
}
}
auto passed = Time::now() - start;

View File

@ -6,6 +6,7 @@
//
#pragma once
#include "td/telegram/Global.h"
#include "td/telegram/net/NetQuery.h"
#include "td/actor/actor.h"
@ -40,7 +41,7 @@ class NetActor : public NetQueryCallback {
class NetActorOnce : public NetActor {
void hangup() override {
on_error(0, Status::Error(500, "Request aborted"));
on_error(0, Global::request_aborted_error());
stop();
}

View File

@ -116,7 +116,7 @@ void NetQueryDelayer::on_slot_event(uint64 id) {
void NetQueryDelayer::tear_down() {
container_.for_each([](auto id, auto &query_slot) {
query_slot.query_->set_error(Status::Error(500, "Request aborted"));
query_slot.query_->set_error(Global::request_aborted_error());
G()->net_query_dispatcher().dispatch(std::move(query_slot.query_));
});
}

View File

@ -6,6 +6,8 @@
//
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/AuthDataShared.h"
#include "td/telegram/net/DcAuthManager.h"
#include "td/telegram/net/NetQuery.h"
@ -13,9 +15,6 @@
#include "td/telegram/net/PublicRsaKeyShared.h"
#include "td/telegram/net/PublicRsaKeyWatchdog.h"
#include "td/telegram/net/SessionMultiProxy.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Global.h"
#include "td/telegram/Td.h"
#include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.h"
@ -44,7 +43,7 @@ void NetQueryDispatcher::complete_net_query(NetQueryPtr net_query) {
void NetQueryDispatcher::dispatch(NetQueryPtr net_query) {
// net_query->debug("dispatch");
if (stop_flag_.load(std::memory_order_relaxed)) {
net_query->set_error(Status::Error(500, "Request aborted"));
net_query->set_error(Global::request_aborted_error());
return complete_net_query(std::move(net_query));
}
if (G()->shared_config().get_option_boolean("test_flood_wait")) {

View File

@ -75,6 +75,7 @@ class Actor : public ObserverBase {
void do_migrate(int32 sched_id);
uint64 get_link_token();
std::weak_ptr<ActorContext> get_context_weak_ptr() const;
std::shared_ptr<ActorContext> set_context(std::shared_ptr<ActorContext> context);
string set_tag(string tag);

View File

@ -79,18 +79,26 @@ std::enable_if_t<std::is_base_of<Actor, ActorType>::value> start_migrate(ActorTy
Scheduler::instance()->start_migrate_actor(&obj, sched_id);
}
}
template <class ActorType>
std::enable_if_t<std::is_base_of<Actor, ActorType>::value> finish_migrate(ActorType &obj) {
if (!obj.empty()) {
Scheduler::instance()->finish_migrate_actor(&obj);
}
}
inline uint64 Actor::get_link_token() {
return Scheduler::instance()->get_link_token(this);
}
inline std::weak_ptr<ActorContext> Actor::get_context_weak_ptr() const {
return info_->get_context_weak_ptr();
}
inline std::shared_ptr<ActorContext> Actor::set_context(std::shared_ptr<ActorContext> context) {
return info_->set_context(std::move(context));
}
inline string Actor::set_tag(string tag) {
auto *ctx = info_->get_context();
string old_tag;
@ -105,12 +113,14 @@ inline string Actor::set_tag(string tag) {
inline void Actor::init(ObjectPool<ActorInfo>::OwnerPtr &&info) {
info_ = std::move(info);
}
inline ActorInfo *Actor::get_info() {
return &*info_;
}
inline const ActorInfo *Actor::get_info() const {
return &*info_;
}
inline ObjectPool<ActorInfo>::OwnerPtr Actor::clear() {
return std::move(info_);
}

View File

@ -86,6 +86,7 @@ class ActorInfo final
const Actor *get_actor_unsafe() const;
std::shared_ptr<ActorContext> set_context(std::shared_ptr<ActorContext> context);
std::weak_ptr<ActorContext> get_context_weak_ptr() const;
ActorContext *get_context();
const ActorContext *get_context() const;
CSlice get_name() const;

View File

@ -156,6 +156,11 @@ inline std::shared_ptr<ActorContext> ActorInfo::set_context(std::shared_ptr<Acto
Scheduler::on_context_updated();
return context;
}
inline std::weak_ptr<ActorContext> ActorInfo::get_context_weak_ptr() const {
return context_;
}
inline const ActorContext *ActorInfo::get_context() const {
return context_.get();
}

View File

@ -13,31 +13,29 @@
#include "td/utils/Random.h"
#include "td/utils/tests.h"
using namespace td;
TEST(MultiTimeout, bug) {
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 0;
sched.init(threads_n);
sched.start();
unique_ptr<MultiTimeout> multi_timeout;
td::unique_ptr<td::MultiTimeout> multi_timeout;
struct Data {
MultiTimeout *multi_timeout;
td::MultiTimeout *multi_timeout;
};
Data data;
{
auto guard = sched.get_main_guard();
multi_timeout = make_unique<MultiTimeout>("MultiTimeout");
multi_timeout = td::make_unique<td::MultiTimeout>("MultiTimeout");
data.multi_timeout = multi_timeout.get();
multi_timeout->set_callback([](void *void_data, int64 key) {
multi_timeout->set_callback([](void *void_data, td::int64 key) {
auto &data = *static_cast<Data *>(void_data);
if (key == 1) {
data.multi_timeout->cancel_timeout(key + 1);
data.multi_timeout->set_timeout_in(key + 2, 1);
} else {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
});
multi_timeout->set_callback_data(&data);
@ -51,9 +49,9 @@ TEST(MultiTimeout, bug) {
sched.finish();
}
class TimeoutManager final : public Actor {
class TimeoutManager final : public td::Actor {
public:
static int32 count;
static td::int32 count;
TimeoutManager() {
count++;
@ -70,7 +68,7 @@ class TimeoutManager final : public Actor {
LOG(INFO) << "Destroy TimeoutManager";
}
static void on_test_timeout_callback(void *timeout_manager_ptr, int64 id) {
static void on_test_timeout_callback(void *timeout_manager_ptr, td::int64 id) {
CHECK(count >= 0);
if (count == 0) {
LOG(ERROR) << "Receive timeout after manager was closed";
@ -84,21 +82,21 @@ class TimeoutManager final : public Actor {
void test_timeout() {
CHECK(count > 0);
// we must yield scheduler, so run_main breaks immediately, if timeouts are handled immediately
Scheduler::instance()->yield();
td::Scheduler::instance()->yield();
}
MultiTimeout test_timeout_{"TestTimeout"};
td::MultiTimeout test_timeout_{"TestTimeout"};
};
int32 TimeoutManager::count;
td::int32 TimeoutManager::count;
TEST(MultiTimeout, Destroy) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 0;
sched.init(threads_n);
ActorOwn<TimeoutManager> timeout_manager = sched.create_actor_unsafe<TimeoutManager>(0, "TimeoutManager");
auto timeout_manager = sched.create_actor_unsafe<TimeoutManager>(0, "TimeoutManager");
TimeoutManager *manager = timeout_manager.get().get_actor_unsafe();
sched.start();
int cnt = 100;
@ -107,12 +105,12 @@ TEST(MultiTimeout, Destroy) {
cnt--;
if (cnt > 0) {
for (int i = 0; i < 2; i++) {
manager->test_timeout_.set_timeout_in(Random::fast(0, 1000000000), Random::fast(2, 5) / 1000.0);
manager->test_timeout_.set_timeout_in(td::Random::fast(0, 1000000000), td::Random::fast(2, 5) / 1000.0);
}
} else if (cnt == 0) {
timeout_manager.reset();
} else if (cnt == -10) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
}
sched.finish();

View File

@ -19,18 +19,16 @@
#include <memory>
#include <utility>
using namespace td;
namespace {
template <class ContainerT>
static typename ContainerT::value_type &rand_elem(ContainerT &cont) {
CHECK(0 < cont.size() && cont.size() <= static_cast<size_t>(std::numeric_limits<int>::max()));
return cont[Random::fast(0, static_cast<int>(cont.size()) - 1)];
return cont[td::Random::fast(0, static_cast<int>(cont.size()) - 1)];
}
static uint32 fast_pow_mod_uint32(uint32 x, uint32 p) {
uint32 res = 1;
static td::uint32 fast_pow_mod_uint32(td::uint32 x, td::uint32 p) {
td::uint32 res = 1;
while (p) {
if (p & 1) {
res *= x;
@ -41,18 +39,18 @@ static uint32 fast_pow_mod_uint32(uint32 x, uint32 p) {
return res;
}
static uint32 slow_pow_mod_uint32(uint32 x, uint32 p) {
uint32 res = 1;
for (uint32 i = 0; i < p; i++) {
static td::uint32 slow_pow_mod_uint32(td::uint32 x, td::uint32 p) {
td::uint32 res = 1;
for (td::uint32 i = 0; i < p; i++) {
res *= x;
}
return res;
}
struct Query {
uint32 query_id{};
uint32 result{};
std::vector<int> todo;
td::uint32 query_id{};
td::uint32 result{};
td::vector<int> todo;
Query() = default;
Query(const Query &) = delete;
Query &operator=(const Query &) = delete;
@ -72,25 +70,25 @@ struct Query {
}
};
static uint32 fast_calc(Query &q) {
uint32 result = q.result;
static td::uint32 fast_calc(Query &q) {
td::uint32 result = q.result;
for (auto x : q.todo) {
result = fast_pow_mod_uint32(result, x);
}
return result;
}
class Worker final : public Actor {
class Worker final : public td::Actor {
public:
explicit Worker(int threads_n) : threads_n_(threads_n) {
}
void query(PromiseActor<uint32> &&promise, uint32 x, uint32 p) {
uint32 result = slow_pow_mod_uint32(x, p);
void query(td::PromiseActor<td::uint32> &&promise, td::uint32 x, td::uint32 p) {
td::uint32 result = slow_pow_mod_uint32(x, p);
promise.set_value(std::move(result));
(void)threads_n_;
// if (threads_n_ > 1 && Random::fast(0, 9) == 0) {
// migrate(Random::fast(2, threads_n));
// if (threads_n_ > 1 && td::Random::fast(0, 9) == 0) {
// migrate(td::Random::fast(2, threads_n));
//}
}
@ -98,7 +96,7 @@ class Worker final : public Actor {
int threads_n_;
};
class QueryActor final : public Actor {
class QueryActor final : public td::Actor {
public:
class Callback {
public:
@ -115,39 +113,39 @@ class QueryActor final : public Actor {
explicit QueryActor(int threads_n) : threads_n_(threads_n) {
}
void set_callback(unique_ptr<Callback> callback) {
void set_callback(td::unique_ptr<Callback> callback) {
callback_ = std::move(callback);
}
void set_workers(std::vector<ActorId<Worker>> workers) {
void set_workers(td::vector<td::ActorId<Worker>> workers) {
workers_ = std::move(workers);
}
void query(Query &&query) {
uint32 x = query.result;
uint32 p = query.next_pow();
if (Random::fast(0, 3) && (p <= 1000 || workers_.empty())) {
td::uint32 x = query.result;
td::uint32 p = query.next_pow();
if (td::Random::fast(0, 3) && (p <= 1000 || workers_.empty())) {
query.result = slow_pow_mod_uint32(x, p);
callback_->on_result(std::move(query));
} else {
auto future = Random::fast(0, 3) == 0
? send_promise<ActorSendType::Immediate>(rand_elem(workers_), &Worker::query, x, p)
: send_promise<ActorSendType::Later>(rand_elem(workers_), &Worker::query, x, p);
auto future = td::Random::fast(0, 3) == 0
? td::send_promise<td::ActorSendType::Immediate>(rand_elem(workers_), &Worker::query, x, p)
: td::send_promise<td::ActorSendType::Later>(rand_elem(workers_), &Worker::query, x, p);
if (future.is_ready()) {
query.result = future.move_as_ok();
callback_->on_result(std::move(query));
} else {
future.set_event(EventCreator::raw(actor_id(), query.query_id));
future.set_event(td::EventCreator::raw(actor_id(), query.query_id));
auto query_id = query.query_id;
pending_.emplace(query_id, std::make_pair(std::move(future), std::move(query)));
}
}
if (threads_n_ > 1 && Random::fast(0, 9) == 0) {
migrate(Random::fast(2, threads_n_));
if (threads_n_ > 1 && td::Random::fast(0, 9) == 0) {
migrate(td::Random::fast(2, threads_n_));
}
}
void raw_event(const Event::Raw &event) final {
uint32 id = event.u32;
void raw_event(const td::Event::Raw &event) final {
td::uint32 id = event.u32;
auto it = pending_.find(id);
auto future = std::move(it->second.first);
auto query = std::move(it->second.second);
@ -162,7 +160,7 @@ class QueryActor final : public Actor {
stop();
}
void on_start_migrate(int32 sched_id) final {
void on_start_migrate(td::int32 sched_id) final {
for (auto &it : pending_) {
start_migrate(it.second.first, sched_id);
}
@ -174,13 +172,13 @@ class QueryActor final : public Actor {
}
private:
unique_ptr<Callback> callback_;
std::map<uint32, std::pair<FutureActor<uint32>, Query>> pending_;
std::vector<ActorId<Worker>> workers_;
td::unique_ptr<Callback> callback_;
std::map<td::uint32, std::pair<td::FutureActor<td::uint32>, Query>> pending_;
td::vector<td::ActorId<Worker>> workers_;
int threads_n_;
};
class MainQueryActor final : public Actor {
class MainQueryActor final : public td::Actor {
class QueryActorCallback final : public QueryActor::Callback {
public:
void on_result(Query &&query) final {
@ -193,13 +191,13 @@ class MainQueryActor final : public Actor {
void on_closed() final {
send_closure(parent_id_, &MainQueryActor::on_closed);
}
QueryActorCallback(ActorId<MainQueryActor> parent_id, ActorId<QueryActor> next_solver)
QueryActorCallback(td::ActorId<MainQueryActor> parent_id, td::ActorId<QueryActor> next_solver)
: parent_id_(parent_id), next_solver_(next_solver) {
}
private:
ActorId<MainQueryActor> parent_id_;
ActorId<QueryActor> next_solver_;
td::ActorId<MainQueryActor> parent_id_;
td::ActorId<QueryActor> next_solver_;
};
const int ACTORS_CNT = 10;
@ -212,22 +210,22 @@ class MainQueryActor final : public Actor {
void start_up() final {
actors_.resize(ACTORS_CNT);
for (auto &actor : actors_) {
auto actor_ptr = make_unique<QueryActor>(threads_n_);
actor = register_actor("QueryActor", std::move(actor_ptr), threads_n_ > 1 ? Random::fast(2, threads_n_) : 0)
auto actor_ptr = td::make_unique<QueryActor>(threads_n_);
actor = register_actor("QueryActor", std::move(actor_ptr), threads_n_ > 1 ? td::Random::fast(2, threads_n_) : 0)
.release();
}
workers_.resize(WORKERS_CNT);
for (auto &worker : workers_) {
auto actor_ptr = make_unique<Worker>(threads_n_);
worker =
register_actor("Worker", std::move(actor_ptr), threads_n_ > 1 ? Random::fast(2, threads_n_) : 0).release();
auto actor_ptr = td::make_unique<Worker>(threads_n_);
worker = register_actor("Worker", std::move(actor_ptr), threads_n_ > 1 ? td::Random::fast(2, threads_n_) : 0)
.release();
}
for (int i = 0; i < ACTORS_CNT; i++) {
ref_cnt_++;
send_closure(actors_[i], &QueryActor::set_callback,
make_unique<QueryActorCallback>(actor_id(this), actors_[(i + 1) % ACTORS_CNT]));
td::make_unique<QueryActorCallback>(actor_id(this), actors_[(i + 1) % ACTORS_CNT]));
send_closure(actors_[i], &QueryActor::set_workers, workers_);
}
yield();
@ -252,14 +250,14 @@ class MainQueryActor final : public Actor {
void on_closed() {
ref_cnt_--;
if (ref_cnt_ == 0) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
}
void wakeup() final {
int cnt = 100000;
while (out_cnt_ < in_cnt_ + 100 && out_cnt_ < cnt) {
if (Random::fast_bool()) {
if (td::Random::fast_bool()) {
send_closure(rand_elem(actors_), &QueryActor::query, create_query());
} else {
send_closure_later(rand_elem(actors_), &QueryActor::query, create_query());
@ -276,9 +274,9 @@ class MainQueryActor final : public Actor {
}
private:
std::map<uint32, uint32> expected_;
std::vector<ActorId<QueryActor>> actors_;
std::vector<ActorId<Worker>> workers_;
std::map<td::uint32, td::uint32> expected_;
td::vector<td::ActorId<QueryActor>> actors_;
td::vector<td::ActorId<Worker>> workers_;
int out_cnt_ = 0;
int in_cnt_ = 0;
int query_id_ = 1;
@ -286,46 +284,47 @@ class MainQueryActor final : public Actor {
int threads_n_;
};
class SimpleActor final : public Actor {
class SimpleActor final : public td::Actor {
public:
explicit SimpleActor(int32 threads_n) : threads_n_(threads_n) {
explicit SimpleActor(td::int32 threads_n) : threads_n_(threads_n) {
}
void start_up() final {
auto actor_ptr = make_unique<Worker>(threads_n_);
auto actor_ptr = td::make_unique<Worker>(threads_n_);
worker_ =
register_actor("Worker", std::move(actor_ptr), threads_n_ > 1 ? Random::fast(2, threads_n_) : 0).release();
register_actor("Worker", std::move(actor_ptr), threads_n_ > 1 ? td::Random::fast(2, threads_n_) : 0).release();
yield();
}
void wakeup() final {
if (q_ == 100000) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
stop();
return;
}
q_++;
p_ = Random::fast_bool() ? 1 : 10000;
auto future = Random::fast(0, 3) == 0 ? send_promise<ActorSendType::Immediate>(worker_, &Worker::query, q_, p_)
: send_promise<ActorSendType::Later>(worker_, &Worker::query, q_, p_);
p_ = td::Random::fast_bool() ? 1 : 10000;
auto future = td::Random::fast(0, 3) == 0
? td::send_promise<td::ActorSendType::Immediate>(worker_, &Worker::query, q_, p_)
: td::send_promise<td::ActorSendType::Later>(worker_, &Worker::query, q_, p_);
if (future.is_ready()) {
auto result = future.move_as_ok();
CHECK(result == fast_pow_mod_uint32(q_, p_));
yield();
} else {
future.set_event(EventCreator::raw(actor_id(), nullptr));
future.set_event(td::EventCreator::raw(actor_id(), nullptr));
future_ = std::move(future);
}
// if (threads_n_ > 1 && Random::fast(0, 2) == 0) {
// migrate(Random::fast(1, threads_n));
// if (threads_n_ > 1 && td::Random::fast(0, 2) == 0) {
// migrate(td::Random::fast(1, threads_n));
//}
}
void raw_event(const Event::Raw &event) final {
void raw_event(const td::Event::Raw &event) final {
auto result = future_.move_as_ok();
CHECK(result == fast_pow_mod_uint32(q_, p_));
yield();
}
void on_start_migrate(int32 sched_id) final {
void on_start_migrate(td::int32 sched_id) final {
start_migrate(future_, sched_id);
}
void on_finish_migrate() final {
@ -333,25 +332,26 @@ class SimpleActor final : public Actor {
}
private:
int32 threads_n_;
ActorId<Worker> worker_;
FutureActor<uint32> future_;
uint32 q_ = 1;
uint32 p_ = 0;
td::int32 threads_n_;
td::ActorId<Worker> worker_;
td::FutureActor<td::uint32> future_;
td::uint32 q_ = 1;
td::uint32 p_ = 0;
};
} // namespace
class SendToDead final : public Actor {
class SendToDead final : public td::Actor {
public:
class Parent final : public Actor {
class Parent final : public td::Actor {
public:
explicit Parent(ActorShared<> parent, int ttl = 3) : parent_(std::move(parent)), ttl_(ttl) {
explicit Parent(td::ActorShared<> parent, int ttl = 3) : parent_(std::move(parent)), ttl_(ttl) {
}
void start_up() final {
set_timeout_in(Random::fast_uint32() % 3 * 0.001);
set_timeout_in(td::Random::fast_uint32() % 3 * 0.001);
if (ttl_ != 0) {
child_ = create_actor_on_scheduler<Parent>(
"Child", Random::fast_uint32() % Scheduler::instance()->sched_count(), actor_shared(this), ttl_ - 1);
child_ = td::create_actor_on_scheduler<Parent>(
"Child", td::Random::fast_uint32() % td::Scheduler::instance()->sched_count(), actor_shared(this),
ttl_ - 1);
}
}
void timeout_expired() final {
@ -359,29 +359,30 @@ class SendToDead final : public Actor {
}
private:
ActorOwn<Parent> child_;
ActorShared<> parent_;
td::ActorOwn<Parent> child_;
td::ActorShared<> parent_;
int ttl_;
};
void start_up() final {
for (int i = 0; i < 2000; i++) {
create_actor_on_scheduler<Parent>("Parent", Random::fast_uint32() % Scheduler::instance()->sched_count(),
create_reference(), 4)
td::create_actor_on_scheduler<Parent>(
"Parent", td::Random::fast_uint32() % td::Scheduler::instance()->sched_count(), create_reference(), 4)
.release();
}
}
ActorShared<> create_reference() {
td::ActorShared<> create_reference() {
ref_cnt_++;
return actor_shared(this);
}
void hangup_shared() final {
ref_cnt_--;
if (ref_cnt_ == 0) {
ttl_--;
if (ttl_ <= 0) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
stop();
} else {
start_up();
@ -389,14 +390,14 @@ class SendToDead final : public Actor {
}
}
uint32 ttl_{50};
uint32 ref_cnt_{0};
td::uint32 ttl_{50};
td::uint32 ref_cnt_{0};
};
TEST(Actors, send_to_dead) {
//TODO: fix CHECK(storage_count_.load() == 0)
return;
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 5;
sched.init(threads_n);
@ -409,9 +410,7 @@ TEST(Actors, send_to_dead) {
}
TEST(Actors, main_simple) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 3;
sched.init(threads_n);
@ -424,9 +423,7 @@ TEST(Actors, main_simple) {
}
TEST(Actors, main) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 9;
sched.init(threads_n);
@ -438,23 +435,21 @@ TEST(Actors, main) {
sched.finish();
}
class DoAfterStop final : public Actor {
class DoAfterStop final : public td::Actor {
public:
void loop() final {
ptr = make_unique<int>(10);
ptr = td::make_unique<int>(10);
stop();
CHECK(*ptr == 10);
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
private:
unique_ptr<int> ptr;
td::unique_ptr<int> ptr;
};
TEST(Actors, do_after_stop) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 0;
sched.init(threads_n);
@ -466,9 +461,9 @@ TEST(Actors, do_after_stop) {
sched.finish();
}
class XContext final : public ActorContext {
class XContext final : public td::ActorContext {
public:
int32 get_id() const final {
td::int32 get_id() const final {
return 123456789;
}
@ -481,12 +476,12 @@ class XContext final : public ActorContext {
int x = 1234;
};
class WithXContext final : public Actor {
class WithXContext final : public td::Actor {
public:
void start_up() final {
auto old_context = set_context(std::make_shared<XContext>());
}
void f(unique_ptr<Guard> guard) {
void f(td::unique_ptr<td::Guard> guard) {
}
void close() {
stop();
@ -494,25 +489,23 @@ class WithXContext final : public Actor {
};
static void check_context() {
auto ptr = static_cast<XContext *>(Scheduler::context());
CHECK(ptr);
auto ptr = static_cast<XContext *>(td::Scheduler::context());
CHECK(ptr != nullptr);
ptr->validate();
}
TEST(Actors, context_during_destruction) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
int threads_n = 0;
sched.init(threads_n);
{
auto guard = sched.get_main_guard();
auto with_context = create_actor<WithXContext>("WithXContext").release();
send_closure(with_context, &WithXContext::f, create_lambda_guard([] { check_context(); }));
auto with_context = td::create_actor<WithXContext>("WithXContext").release();
send_closure(with_context, &WithXContext::f, td::create_lambda_guard([] { check_context(); }));
send_closure_later(with_context, &WithXContext::close);
send_closure(with_context, &WithXContext::f, create_lambda_guard([] { check_context(); }));
send_closure(with_context, &WithXContext::f, create_lambda_guard([] { Scheduler::instance()->finish(); }));
send_closure(with_context, &WithXContext::f, td::create_lambda_guard([] { check_context(); }));
send_closure(with_context, &WithXContext::f, td::create_lambda_guard([] { td::Scheduler::instance()->finish(); }));
}
sched.start();
while (sched.run_main(10)) {

View File

@ -28,40 +28,38 @@
#include <tuple>
namespace {
using namespace td;
static const size_t BUF_SIZE = 1024 * 1024;
static char buf[BUF_SIZE];
static char buf2[BUF_SIZE];
static StringBuilder sb(MutableSlice(buf, BUF_SIZE - 1));
static StringBuilder sb2(MutableSlice(buf2, BUF_SIZE - 1));
static td::StringBuilder sb(td::MutableSlice(buf, BUF_SIZE - 1));
static td::StringBuilder sb2(td::MutableSlice(buf2, BUF_SIZE - 1));
static auto create_queue() {
auto res = std::make_shared<MpscPollableQueue<EventFull>>();
static std::shared_ptr<td::MpscPollableQueue<td::EventFull>> create_queue() {
auto res = std::make_shared<td::MpscPollableQueue<td::EventFull>>();
res->init();
return res;
}
TEST(Actors, SendLater) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
sb.clear();
Scheduler scheduler;
td::Scheduler scheduler;
scheduler.init(0, {create_queue()}, nullptr);
auto guard = scheduler.get_guard();
class Worker final : public Actor {
class Worker final : public td::Actor {
public:
void f() {
sb << "A";
}
};
auto id = create_actor<Worker>("Worker");
scheduler.run_no_guard(Timestamp::now());
send_closure(id, &Worker::f);
send_closure_later(id, &Worker::f);
send_closure(id, &Worker::f);
auto id = td::create_actor<Worker>("Worker");
scheduler.run_no_guard(td::Timestamp::in(1));
td::send_closure(id, &Worker::f);
td::send_closure_later(id, &Worker::f);
td::send_closure(id, &Worker::f);
ASSERT_STREQ("A", sb.as_cslice().c_str());
scheduler.run_no_guard(Timestamp::now());
scheduler.run_no_guard(td::Timestamp::in(1));
ASSERT_STREQ("AAA", sb.as_cslice().c_str());
}
@ -87,7 +85,7 @@ class X {
~X() = default;
};
class XReceiver final : public Actor {
class XReceiver final : public td::Actor {
public:
void by_const_ref(const X &) {
sb << "[by_const_ref]";
@ -101,13 +99,12 @@ class XReceiver final : public Actor {
};
TEST(Actors, simple_pass_event_arguments) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
Scheduler scheduler;
td::Scheduler scheduler;
scheduler.init(0, {create_queue()}, nullptr);
auto guard = scheduler.get_guard();
auto id = create_actor<XReceiver>("XR").release();
scheduler.run_no_guard(Timestamp::now());
auto id = td::create_actor<XReceiver>("XR").release();
scheduler.run_no_guard(td::Timestamp::in(1));
X x;
@ -122,47 +119,47 @@ TEST(Actors, simple_pass_event_arguments) {
// Tmp-->ConstRef
sb.clear();
send_closure(id, &XReceiver::by_const_ref, X());
td::send_closure(id, &XReceiver::by_const_ref, X());
ASSERT_STREQ("[cnstr_default][by_const_ref]", sb.as_cslice().c_str());
// Tmp-->ConstRef (Delayed)
sb.clear();
send_closure_later(id, &XReceiver::by_const_ref, X());
scheduler.run_no_guard(Timestamp::now());
td::send_closure_later(id, &XReceiver::by_const_ref, X());
scheduler.run_no_guard(td::Timestamp::in(1));
// LOG(ERROR) << sb.as_cslice();
ASSERT_STREQ("[cnstr_default][cnstr_move][by_const_ref]", sb.as_cslice().c_str());
// Tmp-->LvalueRef
sb.clear();
send_closure(id, &XReceiver::by_lvalue_ref, X());
td::send_closure(id, &XReceiver::by_lvalue_ref, X());
ASSERT_STREQ("[cnstr_default][by_lvalue_ref]", sb.as_cslice().c_str());
// Tmp-->LvalueRef (Delayed)
sb.clear();
send_closure_later(id, &XReceiver::by_lvalue_ref, X());
scheduler.run_no_guard(Timestamp::now());
td::send_closure_later(id, &XReceiver::by_lvalue_ref, X());
scheduler.run_no_guard(td::Timestamp::in(1));
ASSERT_STREQ("[cnstr_default][cnstr_move][by_lvalue_ref]", sb.as_cslice().c_str());
// Tmp-->Value
sb.clear();
send_closure(id, &XReceiver::by_value, X());
td::send_closure(id, &XReceiver::by_value, X());
ASSERT_STREQ("[cnstr_default][cnstr_move][by_value]", sb.as_cslice().c_str());
// Tmp-->Value (Delayed)
sb.clear();
send_closure_later(id, &XReceiver::by_value, X());
scheduler.run_no_guard(Timestamp::now());
td::send_closure_later(id, &XReceiver::by_value, X());
scheduler.run_no_guard(td::Timestamp::in(1));
ASSERT_STREQ("[cnstr_default][cnstr_move][cnstr_move][by_value]", sb.as_cslice().c_str());
// Var-->ConstRef
sb.clear();
send_closure(id, &XReceiver::by_const_ref, x);
td::send_closure(id, &XReceiver::by_const_ref, x);
ASSERT_STREQ("[by_const_ref]", sb.as_cslice().c_str());
// Var-->ConstRef (Delayed)
sb.clear();
send_closure_later(id, &XReceiver::by_const_ref, x);
scheduler.run_no_guard(Timestamp::now());
td::send_closure_later(id, &XReceiver::by_const_ref, x);
scheduler.run_no_guard(td::Timestamp::in(1));
ASSERT_STREQ("[cnstr_copy][by_const_ref]", sb.as_cslice().c_str());
// Var-->LvalueRef
@ -171,17 +168,17 @@ TEST(Actors, simple_pass_event_arguments) {
// Var-->Value
sb.clear();
send_closure(id, &XReceiver::by_value, x);
td::send_closure(id, &XReceiver::by_value, x);
ASSERT_STREQ("[cnstr_copy][by_value]", sb.as_cslice().c_str());
// Var-->Value (Delayed)
sb.clear();
send_closure_later(id, &XReceiver::by_value, x);
scheduler.run_no_guard(Timestamp::now());
td::send_closure_later(id, &XReceiver::by_value, x);
scheduler.run_no_guard(td::Timestamp::in(1));
ASSERT_STREQ("[cnstr_copy][cnstr_move][by_value]", sb.as_cslice().c_str());
}
class PrintChar final : public Actor {
class PrintChar final : public td::Actor {
public:
PrintChar(char c, int cnt) : char_(c), cnt_(cnt) {
}
@ -208,19 +205,18 @@ class PrintChar final : public Actor {
// Yield must add actor to the end of queue
//
TEST(Actors, simple_hand_yield) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
Scheduler scheduler;
td::Scheduler scheduler;
scheduler.init(0, {create_queue()}, nullptr);
sb.clear();
int cnt = 1000;
{
auto guard = scheduler.get_guard();
create_actor<PrintChar>("PrintA", 'A', cnt).release();
create_actor<PrintChar>("PrintB", 'B', cnt).release();
create_actor<PrintChar>("PrintC", 'C', cnt).release();
td::create_actor<PrintChar>("PrintA", 'A', cnt).release();
td::create_actor<PrintChar>("PrintB", 'B', cnt).release();
td::create_actor<PrintChar>("PrintC", 'C', cnt).release();
}
scheduler.run(Timestamp::now());
std::string expected;
scheduler.run(td::Timestamp::in(1));
td::string expected;
for (int i = 0; i < cnt; i++) {
expected += "ABC";
}
@ -229,7 +225,7 @@ TEST(Actors, simple_hand_yield) {
class Ball {
public:
friend void start_migrate(Ball &ball, int32 sched_id) {
friend void start_migrate(Ball &ball, td::int32 sched_id) {
sb << "start";
}
friend void finish_migrate(Ball &ball) {
@ -237,30 +233,30 @@ class Ball {
}
};
class Pong final : public Actor {
class Pong final : public td::Actor {
public:
void pong(Ball ball) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
};
class Ping final : public Actor {
class Ping final : public td::Actor {
public:
explicit Ping(ActorId<Pong> pong) : pong_(pong) {
explicit Ping(td::ActorId<Pong> pong) : pong_(pong) {
}
void start_up() final {
send_closure(pong_, &Pong::pong, Ball());
td::send_closure(pong_, &Pong::pong, Ball());
}
private:
ActorId<Pong> pong_;
td::ActorId<Pong> pong_;
};
TEST(Actors, simple_migrate) {
sb.clear();
sb2.clear();
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(2);
auto pong = scheduler.create_actor_unsafe<Pong>(2, "Pong").release();
scheduler.create_actor_unsafe<Ping>(1, "Ping", pong).release();
@ -277,7 +273,7 @@ TEST(Actors, simple_migrate) {
#endif
}
class OpenClose final : public Actor {
class OpenClose final : public td::Actor {
public:
explicit OpenClose(int cnt) : cnt_(cnt) {
}
@ -285,17 +281,17 @@ class OpenClose final : public Actor {
yield();
}
void wakeup() final {
ObserverBase *observer = reinterpret_cast<ObserverBase *>(123);
auto observer = reinterpret_cast<td::ObserverBase *>(123);
if (cnt_ > 0) {
auto r_file_fd = FileFd::open("server", FileFd::Read | FileFd::Create);
auto r_file_fd = td::FileFd::open("server", td::FileFd::Read | td::FileFd::Create);
LOG_CHECK(r_file_fd.is_ok()) << r_file_fd.error();
auto file_fd = r_file_fd.move_as_ok();
{ PollableFd pollable_fd = file_fd.get_poll_info().extract_pollable_fd(observer); }
{ auto pollable_fd = file_fd.get_poll_info().extract_pollable_fd(observer); }
file_fd.close();
cnt_--;
yield();
} else {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
}
@ -304,8 +300,7 @@ class OpenClose final : public Actor {
};
TEST(Actors, open_close) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(2);
int cnt = 1000000;
#if TD_WINDOWS || TD_ANDROID
@ -321,18 +316,18 @@ TEST(Actors, open_close) {
}
namespace {
class MsgActor : public Actor {
class MsgActor : public td::Actor {
public:
virtual void msg() = 0;
};
class Slave final : public Actor {
class Slave final : public td::Actor {
public:
ActorId<MsgActor> msg;
explicit Slave(ActorId<MsgActor> msg) : msg(msg) {
td::ActorId<MsgActor> msg;
explicit Slave(td::ActorId<MsgActor> msg) : msg(msg) {
}
void hangup() final {
send_closure(msg, &MsgActor::msg);
td::send_closure(msg, &MsgActor::msg);
}
};
@ -340,10 +335,10 @@ class MasterActor final : public MsgActor {
public:
void loop() final {
alive_ = true;
slave = create_actor<Slave>("slave", static_cast<ActorId<MsgActor>>(actor_id(this)));
slave = td::create_actor<Slave>("slave", static_cast<td::ActorId<MsgActor>>(actor_id(this)));
stop();
}
ActorOwn<Slave> slave;
td::ActorOwn<Slave> slave;
MasterActor() = default;
MasterActor(const MasterActor &) = delete;
@ -356,26 +351,25 @@ class MasterActor final : public MsgActor {
void msg() final {
CHECK(alive_ == 123456789);
}
uint64 alive_ = 123456789;
td::uint64 alive_ = 123456789;
};
} // namespace
TEST(Actors, call_after_destruct) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
Scheduler scheduler;
td::Scheduler scheduler;
scheduler.init(0, {create_queue()}, nullptr);
{
auto guard = scheduler.get_guard();
create_actor<MasterActor>("Master").release();
td::create_actor<MasterActor>("Master").release();
}
scheduler.run(Timestamp::now());
scheduler.run(td::Timestamp::in(1));
}
class LinkTokenSlave final : public Actor {
class LinkTokenSlave final : public td::Actor {
public:
explicit LinkTokenSlave(ActorShared<> parent) : parent_(std::move(parent)) {
explicit LinkTokenSlave(td::ActorShared<> parent) : parent_(std::move(parent)) {
}
void add(uint64 link_token) {
void add(td::uint64 link_token) {
CHECK(link_token == get_link_token());
}
void close() {
@ -383,42 +377,43 @@ class LinkTokenSlave final : public Actor {
}
private:
ActorShared<> parent_;
td::ActorShared<> parent_;
};
class LinkTokenMasterActor final : public Actor {
class LinkTokenMasterActor final : public td::Actor {
public:
explicit LinkTokenMasterActor(int cnt) : cnt_(cnt) {
}
void start_up() final {
child_ = create_actor<LinkTokenSlave>("Slave", actor_shared(this, 123)).release();
child_ = td::create_actor<LinkTokenSlave>("Slave", actor_shared(this, 123)).release();
yield();
}
void loop() final {
for (int i = 0; i < 100 && cnt_ > 0; cnt_--, i++) {
auto token = static_cast<uint64>(cnt_) + 1;
auto token = static_cast<td::uint64>(cnt_) + 1;
switch (i % 4) {
case 0: {
send_closure(ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token);
td::send_closure(td::ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token);
break;
}
case 1: {
send_closure_later(ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token);
td::send_closure_later(td::ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token);
break;
}
case 2: {
EventCreator::closure(ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token).try_emit();
td::EventCreator::closure(td::ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token)
.try_emit();
break;
}
case 3: {
EventCreator::closure(ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token)
td::EventCreator::closure(td::ActorShared<LinkTokenSlave>(child_, token), &LinkTokenSlave::add, token)
.try_emit_later();
break;
}
}
}
if (cnt_ == 0) {
send_closure(child_, &LinkTokenSlave::close);
td::send_closure(child_, &LinkTokenSlave::close);
} else {
yield();
}
@ -426,18 +421,17 @@ class LinkTokenMasterActor final : public Actor {
void hangup_shared() final {
CHECK(get_link_token() == 123);
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
stop();
}
private:
int cnt_;
ActorId<LinkTokenSlave> child_;
td::ActorId<LinkTokenSlave> child_;
};
TEST(Actors, link_token) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
auto cnt = 100000;
scheduler.create_actor_unsafe<LinkTokenMasterActor>(0, "A", cnt).release();
@ -449,25 +443,25 @@ TEST(Actors, link_token) {
TEST(Actors, promise) {
int value = -1;
Promise<int> p1 = PromiseCreator::lambda([&](int x) { value = x; });
p1.set_error(Status::Error("Test error"));
td::Promise<int> p1 = td::PromiseCreator::lambda([&](int x) { value = x; });
p1.set_error(td::Status::Error("Test error"));
ASSERT_EQ(0, value);
Promise<int32> p2 = PromiseCreator::lambda([&](Result<int32> x) { value = 1; });
p2.set_error(Status::Error("Test error"));
td::Promise<td::int32> p2 = td::PromiseCreator::lambda([&](td::Result<td::int32> x) { value = 1; });
p2.set_error(td::Status::Error("Test error"));
ASSERT_EQ(1, value);
}
class LaterSlave final : public Actor {
class LaterSlave final : public td::Actor {
public:
explicit LaterSlave(ActorShared<> parent) : parent_(std::move(parent)) {
explicit LaterSlave(td::ActorShared<> parent) : parent_(std::move(parent)) {
}
private:
ActorShared<> parent_;
td::ActorShared<> parent_;
void hangup() final {
sb << "A";
send_closure(actor_id(this), &LaterSlave::finish);
td::send_closure(actor_id(this), &LaterSlave::finish);
}
void finish() {
sb << "B";
@ -475,12 +469,12 @@ class LaterSlave final : public Actor {
}
};
class LaterMasterActor final : public Actor {
class LaterMasterActor final : public td::Actor {
int cnt_ = 3;
std::vector<ActorOwn<LaterSlave>> children_;
td::vector<td::ActorOwn<LaterSlave>> children_;
void start_up() final {
for (int i = 0; i < cnt_; i++) {
children_.push_back(create_actor<LaterSlave>("B", actor_shared(this)));
children_.push_back(td::create_actor<LaterSlave>("B", actor_shared(this)));
}
yield();
}
@ -489,16 +483,15 @@ class LaterMasterActor final : public Actor {
}
void hangup_shared() final {
if (!--cnt_) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
stop();
}
}
};
TEST(Actors, later) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
sb.clear();
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<LaterMasterActor>(0, "A").release();
scheduler.start();
@ -508,38 +501,36 @@ TEST(Actors, later) {
ASSERT_STREQ(sb.as_cslice().c_str(), "AAABBB");
}
class MultiPromise2 final : public Actor {
class MultiPromise2 final : public td::Actor {
public:
void start_up() final {
auto promise = PromiseCreator::lambda([](Result<Unit> result) {
auto promise = td::PromiseCreator::lambda([](td::Result<td::Unit> result) {
result.ensure();
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
});
MultiPromiseActorSafe multi_promise{"MultiPromiseActor2"};
td::MultiPromiseActorSafe multi_promise{"MultiPromiseActor2"};
multi_promise.add_promise(std::move(promise));
for (int i = 0; i < 10; i++) {
create_actor<SleepActor>("Sleep", 0.1, multi_promise.get_promise()).release();
td::create_actor<td::SleepActor>("Sleep", 0.1, multi_promise.get_promise()).release();
}
}
};
class MultiPromise1 final : public Actor {
class MultiPromise1 final : public td::Actor {
public:
void start_up() final {
auto promise = PromiseCreator::lambda([](Result<Unit> result) {
auto promise = td::PromiseCreator::lambda([](td::Result<td::Unit> result) {
CHECK(result.is_error());
create_actor<MultiPromise2>("B").release();
td::create_actor<MultiPromise2>("B").release();
});
MultiPromiseActorSafe multi_promise{"MultiPromiseActor1"};
td::MultiPromiseActorSafe multi_promise{"MultiPromiseActor1"};
multi_promise.add_promise(std::move(promise));
}
};
TEST(Actors, MultiPromise) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
sb.clear();
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<MultiPromise1>(0, "A").release();
scheduler.start();
@ -548,22 +539,20 @@ TEST(Actors, MultiPromise) {
scheduler.finish();
}
class FastPromise final : public Actor {
class FastPromise final : public td::Actor {
public:
void start_up() final {
PromiseFuture<int> pf;
td::PromiseFuture<int> pf;
auto promise = pf.move_promise();
auto future = pf.move_future();
promise.set_value(123);
CHECK(future.move_as_ok() == 123);
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
};
TEST(Actors, FastPromise) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
sb.clear();
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<FastPromise>(0, "A").release();
scheduler.start();
@ -572,20 +561,18 @@ TEST(Actors, FastPromise) {
scheduler.finish();
}
class StopInTeardown final : public Actor {
class StopInTeardown final : public td::Actor {
void loop() final {
stop();
}
void tear_down() final {
stop();
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
};
TEST(Actors, stop_in_teardown) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
sb.clear();
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<StopInTeardown>(0, "A").release();
scheduler.start();
@ -594,34 +581,33 @@ TEST(Actors, stop_in_teardown) {
scheduler.finish();
}
class AlwaysWaitForMailbox final : public Actor {
class AlwaysWaitForMailbox final : public td::Actor {
public:
void start_up() final {
always_wait_for_mailbox();
create_actor<SleepActor>("Sleep", 0.1, PromiseCreator::lambda([actor_id = actor_id(this), ptr = this](Unit) {
send_closure(actor_id, &AlwaysWaitForMailbox::g);
send_closure(actor_id, &AlwaysWaitForMailbox::g);
CHECK(!ptr->was_f_);
}))
td::create_actor<td::SleepActor>("Sleep", 0.1,
td::PromiseCreator::lambda([actor_id = actor_id(this), ptr = this](td::Unit) {
td::send_closure(actor_id, &AlwaysWaitForMailbox::g);
td::send_closure(actor_id, &AlwaysWaitForMailbox::g);
CHECK(!ptr->was_f_);
}))
.release();
}
void f() {
was_f_ = true;
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
void g() {
send_closure(actor_id(this), &AlwaysWaitForMailbox::f);
td::send_closure(actor_id(this), &AlwaysWaitForMailbox::f);
}
private:
Timeout timeout_;
bool was_f_{false};
};
TEST(Actors, always_wait_for_mailbox) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<AlwaysWaitForMailbox>(0, "A").release();
scheduler.start();
@ -632,17 +618,16 @@ TEST(Actors, always_wait_for_mailbox) {
#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED
TEST(Actors, send_from_other_threads) {
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
ConcurrentScheduler scheduler;
td::ConcurrentScheduler scheduler;
scheduler.init(1);
int thread_n = 10;
class Listener final : public Actor {
class Listener final : public td::Actor {
public:
explicit Listener(int cnt) : cnt_(cnt) {
}
void dec() {
if (--cnt_ == 0) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
}
}
@ -652,11 +637,11 @@ TEST(Actors, send_from_other_threads) {
auto A = scheduler.create_actor_unsafe<Listener>(1, "A", thread_n).release();
scheduler.start();
std::vector<td::thread> threads(thread_n);
td::vector<td::thread> threads(thread_n);
for (auto &thread : threads) {
thread = td::thread([&A, &scheduler] {
auto guard = scheduler.get_send_guard();
send_closure(A, &Listener::dec);
td::send_closure(A, &Listener::dec);
});
}
while (scheduler.run_main(10)) {
@ -667,3 +652,45 @@ TEST(Actors, send_from_other_threads) {
scheduler.finish();
}
#endif
class DelayedCall final : public td::Actor {
public:
void on_called(int *order) {
CHECK(*order == 0);
*order = 1;
}
};
class MultiPromiseSendClosureLaterTest final : public td::Actor {
public:
void start_up() final {
delayed_call_ = td::create_actor<DelayedCall>("DelayedCall").release();
mpa_.add_promise(td::PromiseCreator::lambda([this](td::Unit) {
CHECK(order_ == 1);
order_++;
td::Scheduler::instance()->finish();
}));
auto lock = mpa_.get_promise();
td::send_closure_later(delayed_call_, &DelayedCall::on_called, &order_);
lock.set_value(td::Unit());
}
void tear_down() final {
CHECK(order_ == 2);
}
private:
int order_ = 0;
td::MultiPromiseActor mpa_{"MultiPromiseActor"};
td::ActorId<DelayedCall> delayed_call_;
};
TEST(Actors, MultiPromiseSendClosureLater) {
td::ConcurrentScheduler scheduler;
scheduler.init(0);
scheduler.create_actor_unsafe<MultiPromiseSendClosureLaterTest>(0, "MultiPromiseSendClosureLaterTest").release();
scheduler.start();
while (scheduler.run_main(1)) {
}
scheduler.finish();
}

View File

@ -12,9 +12,7 @@
namespace {
using namespace td;
class PowerWorker final : public Actor {
class PowerWorker final : public td::Actor {
public:
class Callback {
public:
@ -27,12 +25,12 @@ class PowerWorker final : public Actor {
virtual void on_ready(int query, int res) = 0;
virtual void on_closed() = 0;
};
void set_callback(unique_ptr<Callback> callback) {
void set_callback(td::unique_ptr<Callback> callback) {
callback_ = std::move(callback);
}
void task(uint32 x, uint32 p) {
uint32 res = 1;
for (uint32 i = 0; i < p; i++) {
void task(td::uint32 x, td::uint32 p) {
td::uint32 res = 1;
for (td::uint32 i = 0; i < p; i++) {
res *= x;
}
callback_->on_ready(x, res);
@ -43,12 +41,12 @@ class PowerWorker final : public Actor {
}
private:
unique_ptr<Callback> callback_;
td::unique_ptr<Callback> callback_;
};
class Manager final : public Actor {
class Manager final : public td::Actor {
public:
Manager(int queries_n, int query_size, std::vector<ActorId<PowerWorker>> workers)
Manager(int queries_n, int query_size, td::vector<td::ActorId<PowerWorker>> workers)
: workers_(std::move(workers))
, ref_cnt_(static_cast<int>(workers_.size()))
, left_query_(queries_n)
@ -57,17 +55,17 @@ class Manager final : public Actor {
class Callback final : public PowerWorker::Callback {
public:
Callback(ActorId<Manager> actor_id, int worker_id) : actor_id_(actor_id), worker_id_(worker_id) {
Callback(td::ActorId<Manager> actor_id, int worker_id) : actor_id_(actor_id), worker_id_(worker_id) {
}
void on_ready(int query, int result) final {
send_closure(actor_id_, &Manager::on_ready, worker_id_, query, result);
td::send_closure(actor_id_, &Manager::on_ready, worker_id_, query, result);
}
void on_closed() final {
send_closure_later(actor_id_, &Manager::on_closed, worker_id_);
td::send_closure_later(actor_id_, &Manager::on_closed, worker_id_);
}
private:
ActorId<Manager> actor_id_;
td::ActorId<Manager> actor_id_;
int worker_id_;
};
@ -75,9 +73,9 @@ class Manager final : public Actor {
int i = 0;
for (auto &worker : workers_) {
ref_cnt_++;
send_closure_later(worker, &PowerWorker::set_callback, make_unique<Callback>(actor_id(this), i));
td::send_closure_later(worker, &PowerWorker::set_callback, td::make_unique<Callback>(actor_id(this), i));
i++;
send_closure_later(worker, &PowerWorker::task, 3, query_size_);
td::send_closure_later(worker, &PowerWorker::task, 3, query_size_);
left_query_--;
}
}
@ -85,10 +83,10 @@ class Manager final : public Actor {
void on_ready(int worker_id, int query, int res) {
ref_cnt_--;
if (left_query_ == 0) {
send_closure(workers_[worker_id], &PowerWorker::close);
td::send_closure(workers_[worker_id], &PowerWorker::close);
} else {
ref_cnt_++;
send_closure(workers_[worker_id], &PowerWorker::task, 3, query_size_);
td::send_closure(workers_[worker_id], &PowerWorker::task, 3, query_size_);
left_query_--;
}
}
@ -96,23 +94,23 @@ class Manager final : public Actor {
void on_closed(int worker_id) {
ref_cnt_--;
if (ref_cnt_ == 0) {
Scheduler::instance()->finish();
td::Scheduler::instance()->finish();
stop();
}
}
private:
std::vector<ActorId<PowerWorker>> workers_;
td::vector<td::ActorId<PowerWorker>> workers_;
int ref_cnt_;
int left_query_;
int query_size_;
};
static void test_workers(int threads_n, int workers_n, int queries_n, int query_size) {
ConcurrentScheduler sched;
td::ConcurrentScheduler sched;
sched.init(threads_n);
std::vector<ActorId<PowerWorker>> workers;
td::vector<td::ActorId<PowerWorker>> workers;
for (int i = 0; i < workers_n; i++) {
int thread_id = threads_n ? i % (threads_n - 1) + 2 : 0;
workers.push_back(sched.create_actor_unsafe<PowerWorker>(thread_id, PSLICE() << "worker" << i).release());

View File

@ -175,13 +175,20 @@ Status SqliteDb::set_user_version(int32 version) {
return exec(PSLICE() << "PRAGMA user_version = " << version);
}
Status SqliteDb::begin_transaction() {
Status SqliteDb::begin_read_transaction() {
if (raw_->on_begin()) {
return exec("BEGIN");
}
return Status::OK();
}
Status SqliteDb::begin_write_transaction() {
if (raw_->on_begin()) {
return exec("BEGIN IMMEDIATE");
}
return Status::OK();
}
Status SqliteDb::commit_transaction() {
TRY_RESULT(need_commit, raw_->on_commit());
if (need_commit) {

View File

@ -46,7 +46,9 @@ class SqliteDb {
Result<bool> has_table(Slice table);
Result<string> get_pragma(Slice name);
Result<string> get_pragma_string(Slice name);
Status begin_transaction() TD_WARN_UNUSED_RESULT;
Status begin_read_transaction() TD_WARN_UNUSED_RESULT;
Status begin_write_transaction() TD_WARN_UNUSED_RESULT;
Status commit_transaction() TD_WARN_UNUSED_RESULT;
Result<int32> user_version();

View File

@ -51,8 +51,11 @@ class SqliteKeyValue {
SeqNo erase(Slice key);
Status begin_transaction() TD_WARN_UNUSED_RESULT {
return db_.begin_transaction();
Status begin_read_transaction() TD_WARN_UNUSED_RESULT {
return db_.begin_read_transaction();
}
Status begin_write_transaction() TD_WARN_UNUSED_RESULT {
return db_.begin_write_transaction();
}
Status commit_transaction() TD_WARN_UNUSED_RESULT {
return db_.commit_transaction();

View File

@ -121,7 +121,7 @@ class SqliteKeyValueAsync final : public SqliteKeyValueAsyncInterface {
wakeup_at_ = 0;
cnt_ = 0;
kv_->begin_transaction().ensure();
kv_->begin_write_transaction().ensure();
for (auto &it : buffer_) {
if (it.second) {
kv_->set(it.first, it.second.value());

View File

@ -150,7 +150,9 @@ Slice get_operating_system_version() {
}
var clientStrings = [
{s:'Windows 10', r:/(Windows 10.0|Windows NT 10.0)/},
{s:'Windows 11', r:/(Windows 11|Windows NT 11)/},
// there is no way to distinguish Windows 10 from newer versions, so report it as just Windows.
// {s:'Windows 10 or later', r:/(Windows 10|Windows NT 10)/},
{s:'Windows 8.1', r:/(Windows 8.1|Windows NT 6.3)/},
{s:'Windows 8', r:/(Windows 8|Windows NT 6.2)/},
{s:'Windows 7', r:/(Windows 7|Windows NT 6.1)/},
@ -242,7 +244,18 @@ Slice get_operating_system_version() {
if (major == 10) {
if (is_server) {
return os_version_info.dwBuildNumber >= 17623 ? "Windows Server 2019" : "Windows Server 2016";
if (os_version_info.dwBuildNumber >= 20201) {
// https://techcommunity.microsoft.com/t5/windows-server-insiders/announcing/m-p/1614436
return "Windows Server 2022";
}
if (os_version_info.dwBuildNumber >= 17623) {
// https://techcommunity.microsoft.com/t5/windows-server-insiders/announcing/m-p/173715
return "Windows Server 2019";
}
return "Windows Server 2016";
}
if (os_version_info.dwBuildNumber >= 21900) { // build numbers between 21391 and 21999 aren't used
return "Windows 11";
}
return "Windows 10";
}

View File

@ -58,7 +58,7 @@ TEST(EpochBaseMemoryReclamation, stress) {
for (auto &thread : threads) {
thread.join();
}
LOG(ERROR) << "Undeleted pointers: " << ebmr.to_delete_size_unsafe();
LOG(INFO) << "Undeleted pointers: " << ebmr.to_delete_size_unsafe();
//CHECK(static_cast<int>(ebmr.to_delete_size_unsafe()) <= threads_n * threads_n);
for (int i = 0; i < threads_n; i++) {
ebmr.get_locker(i).retire_sync();

View File

@ -50,7 +50,7 @@ TEST(HazardPointers, stress) {
for (auto &thread : threads) {
thread.join();
}
LOG(ERROR) << "Undeleted pointers: " << hazard_pointers.to_delete_size_unsafe();
LOG(INFO) << "Undeleted pointers: " << hazard_pointers.to_delete_size_unsafe();
CHECK(static_cast<int>(hazard_pointers.to_delete_size_unsafe()) <= threads_n * threads_n);
for (int i = 0; i < threads_n; i++) {
hazard_pointers.retire(i);

View File

@ -9,47 +9,45 @@
#include "td/utils/buffer.h"
#include "td/utils/Random.h"
using namespace td;
TEST(Buffer, buffer_builder) {
{
BufferBuilder builder;
td::BufferBuilder builder;
builder.append("b");
builder.prepend("a");
builder.append("c");
ASSERT_EQ(builder.extract().as_slice(), "abc");
}
{
BufferBuilder builder{"hello", 0, 0};
td::BufferBuilder builder{"hello", 0, 0};
ASSERT_EQ(builder.extract().as_slice(), "hello");
}
{
BufferBuilder builder{"hello", 1, 1};
td::BufferBuilder builder{"hello", 1, 1};
builder.prepend("A ");
builder.append(" B");
ASSERT_EQ(builder.extract().as_slice(), "A hello B");
}
{
std::string str = rand_string('a', 'z', 10000);
auto splitted_str = rand_split(str);
auto str = td::rand_string('a', 'z', 10000);
auto splitted_str = td::rand_split(str);
int l = Random::fast(0, static_cast<int32>(splitted_str.size() - 1));
int l = td::Random::fast(0, static_cast<int>(splitted_str.size() - 1));
int r = l;
BufferBuilder builder(splitted_str[l], 123, 1000);
while (l != 0 || r != static_cast<int32>(splitted_str.size()) - 1) {
if (l == 0 || (Random::fast_bool() && r != static_cast<int32>(splitted_str.size() - 1))) {
td::BufferBuilder builder(splitted_str[l], 123, 1000);
while (l != 0 || r != static_cast<int>(splitted_str.size()) - 1) {
if (l == 0 || (td::Random::fast_bool() && r != static_cast<int>(splitted_str.size() - 1))) {
r++;
if (Random::fast_bool()) {
if (td::Random::fast_bool()) {
builder.append(splitted_str[r]);
} else {
builder.append(BufferSlice(splitted_str[r]));
builder.append(td::BufferSlice(splitted_str[r]));
}
} else {
l--;
if (Random::fast_bool()) {
if (td::Random::fast_bool()) {
builder.prepend(splitted_str[l]);
} else {
builder.prepend(BufferSlice(splitted_str[l]));
builder.prepend(td::BufferSlice(splitted_str[l]));
}
}
}

View File

@ -12,17 +12,15 @@
#include <utility>
using namespace td;
static void decode_encode(string str, string result = "") {
static void decode_encode(td::string str, td::string result = "") {
auto str_copy = str;
auto r_value = json_decode(str_copy);
auto r_value = td::json_decode(str_copy);
ASSERT_TRUE(r_value.is_ok());
if (r_value.is_error()) {
LOG(INFO) << r_value.error();
return;
}
auto new_str = json_encode<string>(r_value.ok());
auto new_str = td::json_encode<td::string>(r_value.ok());
if (result.empty()) {
result = str;
}
@ -31,18 +29,19 @@ static void decode_encode(string str, string result = "") {
TEST(JSON, array) {
char tmp[1000];
StringBuilder sb(MutableSlice{tmp, sizeof(tmp)});
JsonBuilder jb(std::move(sb));
td::StringBuilder sb(td::MutableSlice{tmp, sizeof(tmp)});
td::JsonBuilder jb(std::move(sb));
jb.enter_value().enter_array() << "Hello" << -123;
ASSERT_EQ(jb.string_builder().is_error(), false);
auto encoded = jb.string_builder().as_cslice().str();
ASSERT_EQ("[\"Hello\",-123]", encoded);
decode_encode(encoded);
}
TEST(JSON, object) {
char tmp[1000];
StringBuilder sb(MutableSlice{tmp, sizeof(tmp)});
JsonBuilder jb(std::move(sb));
td::StringBuilder sb(td::MutableSlice{tmp, sizeof(tmp)});
td::JsonBuilder jb(std::move(sb));
auto c = jb.enter_object();
c("key", "value");
c("1", 2);
@ -55,8 +54,8 @@ TEST(JSON, object) {
TEST(JSON, nested) {
char tmp[1000];
StringBuilder sb(MutableSlice{tmp, sizeof(tmp)});
JsonBuilder jb(std::move(sb));
td::StringBuilder sb(td::MutableSlice{tmp, sizeof(tmp)});
td::JsonBuilder jb(std::move(sb));
{
auto a = jb.enter_array();
a << 1;

View File

@ -18,11 +18,9 @@
#include <limits>
#include <utility>
using namespace td;
#if TD_HAVE_OPENSSL
static bool is_prime(uint64 x) {
for (uint64 d = 2; d < x && d * d <= x; d++) {
static bool is_prime(td::uint64 x) {
for (td::uint64 d = 2; d < x && d * d <= x; d++) {
if (x % d == 0) {
return false;
}
@ -30,8 +28,8 @@ static bool is_prime(uint64 x) {
return true;
}
static std::vector<uint64> gen_primes(uint64 L, uint64 R, int limit = 0) {
std::vector<uint64> res;
static td::vector<td::uint64> gen_primes(td::uint64 L, td::uint64 R, int limit = 0) {
td::vector<td::uint64> res;
for (auto x = L; x <= R && (limit <= 0 || res.size() < static_cast<std::size_t>(limit)); x++) {
if (is_prime(x)) {
res.push_back(x);
@ -40,21 +38,23 @@ static std::vector<uint64> gen_primes(uint64 L, uint64 R, int limit = 0) {
return res;
}
static std::vector<uint64> gen_primes() {
std::vector<uint64> result;
append(result, gen_primes(1, 100));
append(result, gen_primes((1ull << 31) - 500000, std::numeric_limits<uint64>::max(), 5));
append(result, gen_primes((1ull << 32) - 500000, std::numeric_limits<uint64>::max(), 5));
append(result, gen_primes((1ull << 39) - 500000, std::numeric_limits<uint64>::max(), 1));
static td::vector<td::uint64> gen_primes() {
td::vector<td::uint64> result;
td::append(result, gen_primes(1, 100));
td::append(result, gen_primes((1ull << 31) - 500000, std::numeric_limits<td::uint64>::max(), 5));
td::append(result, gen_primes((1ull << 32) - 500000, std::numeric_limits<td::uint64>::max(), 5));
td::append(result, gen_primes((1ull << 39) - 500000, std::numeric_limits<td::uint64>::max(), 1));
return result;
}
using PqQuery = std::pair<uint64, uint64>;
using PqQuery = std::pair<td::uint64, td::uint64>;
static bool cmp(const PqQuery &a, const PqQuery &b) {
return a.first * a.second < b.first * b.second;
}
static std::vector<PqQuery> gen_pq_queries() {
std::vector<PqQuery> res;
static td::vector<PqQuery> gen_pq_queries() {
td::vector<PqQuery> res;
auto primes = gen_primes();
for (auto q : primes) {
for (auto p : primes) {
@ -68,21 +68,21 @@ static std::vector<PqQuery> gen_pq_queries() {
return res;
}
static void test_pq(uint64 first, uint64 second) {
BigNum p = BigNum::from_decimal(PSLICE() << first).move_as_ok();
BigNum q = BigNum::from_decimal(PSLICE() << second).move_as_ok();
static void test_pq(td::uint64 first, td::uint64 second) {
td::BigNum p = td::BigNum::from_decimal(PSLICE() << first).move_as_ok();
td::BigNum q = td::BigNum::from_decimal(PSLICE() << second).move_as_ok();
BigNum pq;
BigNumContext context;
BigNum::mul(pq, p, q, context);
std::string pq_str = pq.to_binary();
td::BigNum pq;
td::BigNumContext context;
td::BigNum::mul(pq, p, q, context);
td::string pq_str = pq.to_binary();
std::string p_str, q_str;
td::string p_str, q_str;
int err = td::pq_factorize(pq_str, &p_str, &q_str);
LOG_CHECK(err == 0) << first << " * " << second;
BigNum p_res = BigNum::from_binary(p_str);
BigNum q_res = BigNum::from_binary(q_str);
td::BigNum p_res = td::BigNum::from_binary(p_str);
td::BigNum q_res = td::BigNum::from_binary(q_str);
LOG_CHECK(p_str == p.to_binary()) << td::tag("got", p_res.to_decimal()) << td::tag("expected", first);
LOG_CHECK(q_str == q.to_binary()) << td::tag("got", q_res.to_decimal()) << td::tag("expected", second);