Repair file_reference in SaveGifQuery.

GitOrigin-RevId: ae9fcc543795a659c51699af8ea0048a0b5f8fb5
This commit is contained in:
levlam 2019-01-23 22:20:48 +03:00
parent 6633b87d51
commit 0ac8c2d389
8 changed files with 87 additions and 34 deletions

View File

@ -64,13 +64,22 @@ class GetSavedGifsQuery : public Td::ResultHandler {
}; };
class SaveGifQuery : public Td::ResultHandler { class SaveGifQuery : public Td::ResultHandler {
FileId file_id_;
string file_reference_;
bool unsave_ = false;
Promise<Unit> promise_; Promise<Unit> promise_;
public: public:
explicit SaveGifQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit SaveGifQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(tl_object_ptr<telegram_api::InputDocument> &&input_document, bool unsave) { void send(FileId file_id, tl_object_ptr<telegram_api::inputDocument> &&input_document, bool unsave) {
CHECK(input_document != nullptr);
CHECK(file_id.is_valid());
file_id_ = file_id;
file_reference_ = input_document->file_reference_.as_slice().str();
unsave_ = unsave;
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
create_storer(telegram_api::messages_saveGif(std::move(input_document), unsave)))); create_storer(telegram_api::messages_saveGif(std::move(input_document), unsave))));
} }
@ -82,7 +91,7 @@ class SaveGifQuery : public Td::ResultHandler {
} }
bool result = result_ptr.move_as_ok(); bool result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for save gif: " << result; LOG(INFO) << "Receive result for save GIF: " << result;
if (!result) { if (!result) {
td->animations_manager_->reload_saved_animations(true); td->animations_manager_->reload_saved_animations(true);
} }
@ -91,7 +100,22 @@ class SaveGifQuery : public Td::ResultHandler {
} }
void on_error(uint64 id, Status status) override { void on_error(uint64 id, Status status) override {
LOG(ERROR) << "Receive error for save gif: " << status; if (FileReferenceManager::is_file_reference_error(status)) {
td->file_manager_->delete_file_reference(file_id_, file_reference_);
td->file_reference_manager_->repair_file_reference(
file_id_, PromiseCreator::lambda([animation_id = file_id_, unsave = unsave_,
promise = std::move(promise_)](Result<Unit> result) mutable {
if (result.is_error()) {
return promise.set_error(Status::Error(400, "Failed to find the animation"));
}
send_closure(G()->animations_manager(), &AnimationsManager::send_save_gif_query, animation_id, unsave,
std::move(promise));
}));
return;
}
LOG(ERROR) << "Receive error for save GIF: " << status;
td->animations_manager_->reload_saved_animations(true); td->animations_manager_->reload_saved_animations(true);
promise_.set_error(std::move(status)); promise_.set_error(std::move(status));
} }
@ -310,6 +334,7 @@ tl_object_ptr<telegram_api::InputMedia> AnimationsManager::get_input_media(
return nullptr; return nullptr;
} }
SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file_id, SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file_id,
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
const string &caption, BufferSlice thumbnail, const string &caption, BufferSlice thumbnail,
@ -511,7 +536,7 @@ void AnimationsManager::on_get_saved_animations(
for (auto &document_ptr : saved_animations->gifs_) { for (auto &document_ptr : saved_animations->gifs_) {
int32 document_constructor_id = document_ptr->get_id(); int32 document_constructor_id = document_ptr->get_id();
if (document_constructor_id == telegram_api::documentEmpty::ID) { if (document_constructor_id == telegram_api::documentEmpty::ID) {
LOG(ERROR) << "Empty gif document received"; LOG(ERROR) << "Empty saved animation document received";
continue; continue;
} }
CHECK(document_constructor_id == telegram_api::document::ID); CHECK(document_constructor_id == telegram_api::document::ID);
@ -588,11 +613,19 @@ void AnimationsManager::add_saved_animation(const tl_object_ptr<td_api::InputFil
add_saved_animation_inner(r_file_id.ok(), std::move(promise)); add_saved_animation_inner(r_file_id.ok(), std::move(promise));
} }
void AnimationsManager::add_saved_animation_inner(FileId animation_id, Promise<Unit> &&promise) { void AnimationsManager::send_save_gif_query(FileId animation_id, bool unsave, Promise<Unit> &&promise) {
if (add_saved_animation_impl(animation_id, promise)) {
// TODO invokeAfter and log event // TODO invokeAfter and log event
auto file_view = td_->file_manager_->get_file_view(animation_id); auto file_view = td_->file_manager_->get_file_view(animation_id);
td_->create_handler<SaveGifQuery>(std::move(promise))->send(file_view.remote_location().as_input_document(), false); CHECK(file_view.has_remote_location());
CHECK(file_view.remote_location().is_document()) << file_view.remote_location();
CHECK(!file_view.remote_location().is_web());
td_->create_handler<SaveGifQuery>(std::move(promise))
->send(animation_id, file_view.remote_location().as_input_document(), unsave);
}
void AnimationsManager::add_saved_animation_inner(FileId animation_id, Promise<Unit> &&promise) {
if (add_saved_animation_impl(animation_id, promise)) {
send_save_gif_query(animation_id, false, std::move(promise));
} }
} }
@ -697,12 +730,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptr<td_api::Input
return promise.set_error(Status::Error(7, "Animation not found")); return promise.set_error(Status::Error(7, "Animation not found"));
} }
// TODO invokeAfter send_save_gif_query(file_id, true, std::move(promise));
auto file_view = td_->file_manager_->get_file_view(file_id);
CHECK(file_view.has_remote_location());
CHECK(file_view.remote_location().is_document()) << file_view.remote_location();
CHECK(!file_view.remote_location().is_web());
td_->create_handler<SaveGifQuery>(std::move(promise))->send(file_view.remote_location().as_input_document(), true);
saved_animation_ids_.erase(it); saved_animation_ids_.erase(it);
@ -716,19 +744,22 @@ td_api::object_ptr<td_api::updateSavedAnimations> AnimationsManager::get_update_
void AnimationsManager::send_update_saved_animations(bool from_database) { void AnimationsManager::send_update_saved_animations(bool from_database) {
if (are_saved_animations_loaded_) { if (are_saved_animations_loaded_) {
if (!saved_animations_file_source_id_.is_valid() && !saved_animation_ids_.empty()) { vector<FileId> new_saved_animation_file_ids = saved_animation_ids_;
saved_animations_file_source_id_ = td_->file_reference_manager_->create_saved_animations_file_source();
}
for (auto &animation_id : saved_animation_ids_) { for (auto &animation_id : saved_animation_ids_) {
td_->file_manager_->add_file_source(animation_id, saved_animations_file_source_id_);
auto thumbnail_file_id = get_animation_thumbnail_file_id(animation_id); auto thumbnail_file_id = get_animation_thumbnail_file_id(animation_id);
if (thumbnail_file_id.is_valid()) { if (thumbnail_file_id.is_valid()) {
td_->file_manager_->add_file_source(thumbnail_file_id, saved_animations_file_source_id_); new_saved_animation_file_ids.push_back(thumbnail_file_id);
} }
} }
// there is no much reason to delete source from deleted saved animations, std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end());
// it will be automatically deleted after unsuccessfull try of file reference repairing if (new_saved_animation_file_ids != saved_animation_file_ids_) {
// moreover one thumbnail can belong to different animations, so removal should be careful if (!saved_animations_file_source_id_.is_valid()) {
saved_animations_file_source_id_ = td_->file_reference_manager_->create_saved_animations_file_source();
}
td_->file_manager_->change_files_source(saved_animations_file_source_id_, saved_animation_file_ids_,
new_saved_animation_file_ids);
saved_animation_file_ids_ = std::move(new_saved_animation_file_ids);
}
send_closure(G()->td(), &Td::send_update, get_update_saved_animations_object()); send_closure(G()->td(), &Td::send_update, get_update_saved_animations_object());

View File

@ -68,6 +68,8 @@ class AnimationsManager : public Actor {
vector<FileId> get_saved_animations(Promise<Unit> &&promise); vector<FileId> get_saved_animations(Promise<Unit> &&promise);
void send_save_gif_query(FileId animation_id, bool unsave, Promise<Unit> &&promise);
void add_saved_animation(const tl_object_ptr<td_api::InputFile> &input_file, Promise<Unit> &&promise); void add_saved_animation(const tl_object_ptr<td_api::InputFile> &input_file, Promise<Unit> &&promise);
void add_saved_animation_by_id(FileId animation_id); void add_saved_animation_by_id(FileId animation_id);
@ -133,6 +135,7 @@ class AnimationsManager : public Actor {
int32 saved_animations_limit_ = 200; int32 saved_animations_limit_ = 200;
vector<FileId> saved_animation_ids_; vector<FileId> saved_animation_ids_;
vector<FileId> saved_animation_file_ids_;
double next_saved_animations_load_time_ = 0; double next_saved_animations_load_time_ = 0;
bool are_saved_animations_loaded_ = false; bool are_saved_animations_loaded_ = false;
vector<Promise<Unit>> load_saved_animations_queries_; vector<Promise<Unit>> load_saved_animations_queries_;

View File

@ -128,14 +128,19 @@ void FileReferenceManager::run_node(NodeId node_id) {
if (node.query->active_queries != 0) { if (node.query->active_queries != 0) {
return; return;
} }
VLOG(file_references) << "Run file references repair for file " << node_id; VLOG(file_references) << "Trying to repair file reference for file " << node_id;
if (node.query->promises.empty()) { if (node.query->promises.empty()) {
node.query = {}; node.query = {};
return; return;
} }
if (!node.file_source_ids.has_next()) { if (!node.file_source_ids.has_next()) {
VLOG(file_references) << "Have no more file sources to repair file reference for file " << node_id;
for (auto &p : node.query->promises) { for (auto &p : node.query->promises) {
p.set_value(Unit()); if (node.file_source_ids.empty()) {
p.set_error(Status::Error(400, "File not found"));
} else {
p.set_error(Status::Error(429, "Too Many Requests: retry after 1"));
}
} }
node.query = {}; node.query = {};
return; return;
@ -253,7 +258,7 @@ void FileReferenceManager::repair_file_reference(NodeId node_id, Promise<> promi
node.query = make_unique<Query>(); node.query = make_unique<Query>();
node.query->generation = ++query_generation_; node.query->generation = ++query_generation_;
node.file_source_ids.reset_position(); node.file_source_ids.reset_position();
VLOG(file_references) << "new query " << query_generation_; VLOG(file_references) << "Create new file reference repair query with " << query_generation_;
} }
node.query->promises.push_back(std::move(promise)); node.query->promises.push_back(std::move(promise));
run_node(node_id); run_node(node_id);

View File

@ -42,8 +42,11 @@ class FileReferenceManager : public Actor {
using NodeId = FileId; using NodeId = FileId;
void repair_file_reference(NodeId node_id, Promise<> promise); void repair_file_reference(NodeId node_id, Promise<> promise);
void add_file_source(NodeId node_id, FileSourceId file_source_id); void add_file_source(NodeId node_id, FileSourceId file_source_id);
void remove_file_source(NodeId node_id, FileSourceId file_source_id); void remove_file_source(NodeId node_id, FileSourceId file_source_id);
void merge(NodeId to_node_id, NodeId from_node_id); void merge(NodeId to_node_id, NodeId from_node_id);
private: private:

View File

@ -77,6 +77,10 @@ class FastSetWithPosition {
return checked_.size() + not_checked_.size(); return checked_.size() + not_checked_.size();
} }
bool empty() const {
return size() == 0;
}
private: private:
std::set<T> checked_; std::set<T> checked_;
std::set<T> not_checked_; std::set<T> not_checked_;
@ -168,6 +172,13 @@ class SetWithPosition {
return static_cast<size_t>(has_value_); return static_cast<size_t>(has_value_);
} }
bool empty() const {
if (fast_) {
return false;
}
return !has_value_;
}
private: private:
T value_{}; T value_{};
bool has_value_{false}; bool has_value_{false};

View File

@ -241,7 +241,7 @@ class SaveRecentStickerQuery : public Td::ResultHandler {
explicit SaveRecentStickerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit SaveRecentStickerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(bool is_attached, tl_object_ptr<telegram_api::InputDocument> &&input_document, bool unsave) { void send(bool is_attached, tl_object_ptr<telegram_api::inputDocument> &&input_document, bool unsave) {
is_attached_ = is_attached; is_attached_ = is_attached;
int32 flags = 0; int32 flags = 0;
@ -347,7 +347,7 @@ class FaveStickerQuery : public Td::ResultHandler {
explicit FaveStickerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit FaveStickerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(tl_object_ptr<telegram_api::InputDocument> &&input_document, bool unsave) { void send(tl_object_ptr<telegram_api::inputDocument> &&input_document, bool unsave) {
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
create_storer(telegram_api::messages_faveSticker(std::move(input_document), unsave)))); create_storer(telegram_api::messages_faveSticker(std::move(input_document), unsave))));
} }
@ -666,7 +666,7 @@ class SetStickerPositionQuery : public Td::ResultHandler {
explicit SetStickerPositionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit SetStickerPositionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(tl_object_ptr<telegram_api::InputDocument> &&input_document, int32 position) { void send(tl_object_ptr<telegram_api::inputDocument> &&input_document, int32 position) {
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
create_storer(telegram_api::stickers_changeStickerPosition(std::move(input_document), position)))); create_storer(telegram_api::stickers_changeStickerPosition(std::move(input_document), position))));
} }
@ -695,7 +695,7 @@ class DeleteStickerFromSetQuery : public Td::ResultHandler {
explicit DeleteStickerFromSetQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit DeleteStickerFromSetQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(tl_object_ptr<telegram_api::InputDocument> &&input_document) { void send(tl_object_ptr<telegram_api::inputDocument> &&input_document) {
send_query(G()->net_query_creator().create( send_query(G()->net_query_creator().create(
create_storer(telegram_api::stickers_removeStickerFromSet(std::move(input_document))))); create_storer(telegram_api::stickers_removeStickerFromSet(std::move(input_document)))));
} }

View File

@ -480,7 +480,7 @@ class FullRemoteFileLocation {
} }
#define as_input_document() as_input_document_impl(__FILE__, __LINE__) #define as_input_document() as_input_document_impl(__FILE__, __LINE__)
tl_object_ptr<telegram_api::InputDocument> as_input_document_impl(const char *file, int line) const { tl_object_ptr<telegram_api::inputDocument> as_input_document_impl(const char *file, int line) const {
CHECK(is_common()) << file << ' ' << line; CHECK(is_common()) << file << ' ' << line;
CHECK(is_document()) << file << ' ' << line; CHECK(is_document()) << file << ' ' << line;
return make_tl_object<telegram_api::inputDocument>(common().id_, common().access_hash_, return make_tl_object<telegram_api::inputDocument>(common().id_, common().access_hash_,
@ -488,18 +488,18 @@ class FullRemoteFileLocation {
} }
#define as_input_photo() as_input_photo_impl(__FILE__, __LINE__) #define as_input_photo() as_input_photo_impl(__FILE__, __LINE__)
tl_object_ptr<telegram_api::InputPhoto> as_input_photo_impl(const char *file, int line) const { tl_object_ptr<telegram_api::inputPhoto> as_input_photo_impl(const char *file, int line) const {
CHECK(is_photo()) << file << ' ' << line; CHECK(is_photo()) << file << ' ' << line;
return make_tl_object<telegram_api::inputPhoto>(photo().id_, photo().access_hash_, BufferSlice(file_reference_)); return make_tl_object<telegram_api::inputPhoto>(photo().id_, photo().access_hash_, BufferSlice(file_reference_));
} }
tl_object_ptr<telegram_api::InputEncryptedFile> as_input_encrypted_file() const { tl_object_ptr<telegram_api::inputEncryptedFile> as_input_encrypted_file() const {
CHECK(is_encrypted_secret()); CHECK(is_encrypted_secret());
return make_tl_object<telegram_api::inputEncryptedFile>(common().id_, common().access_hash_); return make_tl_object<telegram_api::inputEncryptedFile>(common().id_, common().access_hash_);
} }
#define as_input_secure_file() as_input_secure_file_impl(__FILE__, __LINE__) #define as_input_secure_file() as_input_secure_file_impl(__FILE__, __LINE__)
tl_object_ptr<telegram_api::InputSecureFile> as_input_secure_file_impl(const char *file, int line) const { tl_object_ptr<telegram_api::inputSecureFile> as_input_secure_file_impl(const char *file, int line) const {
CHECK(is_secure()) << file << ' ' << line; CHECK(is_secure()) << file << ' ' << line;
return make_tl_object<telegram_api::inputSecureFile>(common().id_, common().access_hash_); return make_tl_object<telegram_api::inputSecureFile>(common().id_, common().access_hash_);
} }

View File

@ -164,7 +164,7 @@ void FileNode::set_remote_location(const RemoteFileLocation &remote, FileLocatio
void FileNode::delete_file_reference(Slice file_reference) { void FileNode::delete_file_reference(Slice file_reference) {
if (remote_.type() == RemoteFileLocation::Type::Full && remote_.full().delete_file_reference(file_reference)) { if (remote_.type() == RemoteFileLocation::Type::Full && remote_.full().delete_file_reference(file_reference)) {
VLOG(file_references) << "Delete file reference of file " << main_file_id_; VLOG(file_references) << "Do delete file reference of main file " << main_file_id_;
upload_was_update_file_reference_ = false; upload_was_update_file_reference_ = false;
download_was_update_file_reference_ = false; download_was_update_file_reference_ = false;
on_pmc_changed(); on_pmc_changed();
@ -1915,7 +1915,7 @@ bool FileManager::delete_partial_remote_location(FileId file_id) {
void FileManager::delete_file_reference(FileId file_id, string file_reference) { void FileManager::delete_file_reference(FileId file_id, string file_reference) {
VLOG(file_references) << "Delete file reference of file " << file_id << " " VLOG(file_references) << "Delete file reference of file " << file_id << " "
<< tag("reference", base64_encode(file_reference)); << tag("reference_base64", base64_encode(file_reference));
auto node = get_sync_file_node(file_id); auto node = get_sync_file_node(file_id);
if (!node) { if (!node) {
LOG(ERROR) << "Wrong file id " << file_id; LOG(ERROR) << "Wrong file id " << file_id;