diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index b7d7d3f8..f4422e7f 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -48,6 +48,8 @@ #include #include +#define FILE_TTL 20 + namespace td { namespace { constexpr int64 MAX_FILE_SIZE = 1500 * (1 << 20) /* 1500MB */; @@ -982,8 +984,6 @@ bool FileManager::try_fix_partial_local_location(FileNodePtr node) { FileManager::FileIdInfo *FileManager::get_file_id_info(FileId file_id) { file_id.set_time(); - LOG_CHECK(0 <= file_id.get() && file_id.get() < static_cast(file_id_info_.size())) - << file_id << " " << file_id_info_.size(); return &file_id_info_[file_id.get()]; } @@ -1019,7 +1019,7 @@ void FileManager::try_forget_file_id(FileId file_id) { bool is_removed = td::remove(file_node->file_ids_, file_id); CHECK(is_removed); *info = FileIdInfo(); - empty_file_ids_.push_back(file_id.get()); + file_id_info_.erase(file_id.get()); } FileId FileManager::register_empty(FileType type) { @@ -1805,7 +1805,7 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local } FileNode *FileManager::get_file_node_raw(FileId file_id, FileNodeId *file_node_id) { - if (file_id.get() <= 0 || file_id.get() >= static_cast(file_id_info_.size())) { + if (file_id.get() <= 0) { return nullptr; } FileNodeId node_id = file_id_info_[file_id.get()].node_id_; @@ -3192,30 +3192,16 @@ string FileManager::extract_file_reference(const tl_object_ptr(id), 0); - file_id_info_.push_back({}); + file_id_info_[id] = {}; res.set_time(); return res; } FileManager::FileNodeId FileManager::next_file_node_id() { - if (!empty_node_ids_.empty()) { - auto res = empty_node_ids_.back(); - empty_node_ids_.pop_back(); - return static_cast(res); - } - - auto res = static_cast(file_nodes_.size()); - file_nodes_.emplace_back(nullptr); + auto res = static_cast(file_node_seqno++); + file_nodes_[res] = nullptr; return res; } @@ -3735,102 +3721,91 @@ void FileManager::destroy_query(int32 file_id) { void FileManager::memory_cleanup() { - is_closed_ = true; - auto time = std::time(nullptr); + /* DESTROY OLD file_id_info_ */ + { + auto it = file_id_info_.begin(); + auto time = std::time(nullptr); + std::vector file_to_be_deleted = {}; - for (unsigned int i = 0; i < file_id_info_.size(); i++) { - auto main_node_id = file_id_info_[i].node_id_; - if (main_node_id != 0) { - auto &node = file_nodes_[main_node_id]; + while (it != file_id_info_.end()) { + if (it->second.node_id_ != 0) { + auto &node = file_nodes_[it->second.node_id_]; - if (node != nullptr && - node->download_priority_ == 0 && - ((int32) i) == node->main_file_id_.fast_get()) { - if (time - node->main_file_id_.get_time() > 120 /* MAIN FILE TTL */) { - node->main_file_id_.reset_time(); + if (node != nullptr && time - node->main_file_id_.get_time() > FILE_TTL) { + auto can_reset = node->download_priority_ == 0; + can_reset &= node->generate_download_priority_ == 0; + can_reset &= node->download_id_ == 0; - for (auto &file_id : node->file_ids_) { - /* DESTROY ASSOCIATED QUERIES */ - destroy_query(file_id.fast_get()); + if (can_reset) { + auto file_ids_it = node->file_ids_.begin(); - /* DESTROY ASSOCIATED NODE */ - auto &ref_node_id = file_id_info_[file_id.fast_get()].node_id_; - if (ref_node_id != 0 && ref_node_id != main_node_id) { - auto &ref_node = file_nodes_[ref_node_id]; - if (ref_node != nullptr) { - context_->destroy_file_source(file_id); - ref_node.reset(); - } - empty_node_ids_.push_back(ref_node_id); - file_nodes_[ref_node_id] = nullptr; + while (file_ids_it != node->file_ids_.end() && can_reset) { + auto &file = file_id_info_[file_ids_it->fast_get()]; + can_reset &= file.download_priority_ == 0; + can_reset &= time - file_ids_it->get_time() > FILE_TTL; + ++file_ids_it; } - - /* DESTROY ASSOCIATED FILE */ - empty_file_ids_.push_back(file_id.fast_get()); - file_id_info_[file_id.fast_get()] = FileIdInfo(); } - /* DESTROY MAIN QUERY */ - destroy_query(i); + if (can_reset) { + node->main_file_id_.reset_time(); - /* DESTROY FILE REFERENCE */ - context_->destroy_file_source(node->main_file_id_); + for (auto &file_id : node->file_ids_) { + file_id.reset_time(); - /* DESTROY MAIN FILE */ - empty_file_ids_.push_back(i); - file_id_info_[i] = FileIdInfo(); + /* DESTROY ASSOCIATED QUERIES */ + destroy_query(file_id.fast_get()); - /* DESTROY MAIN NODE */ - node.reset(); - file_nodes_[main_node_id] = nullptr; - empty_node_ids_.push_back(main_node_id); + /* DESTROY ASSOCIATED LATE */ + file_to_be_deleted.push_back(file_id.fast_get()); + + /* DESTROY REF NODE */ + auto ref_node_id = file_id_info_[file_id.fast_get()].node_id_; + if (it->second.node_id_ != ref_node_id) { + file_nodes_[ref_node_id].reset(); + file_nodes_.erase(ref_node_id); + } + } + + /* DESTROY MAIN QUERY */ + destroy_query(it->first); + + /* DESTROY FILE REFERENCE */ + context_->destroy_file_source(node->main_file_id_); + + /* DESTROY MAIN NODE */ + node.reset(); + file_nodes_.erase(it->first); + + /* DESTROY MAIN FILE LATE */ + file_to_be_deleted.push_back(it->first); + } } } + + ++it; + } + + for (auto file_id : file_to_be_deleted) { + file_id_info_.erase(file_id); } } /* DESTROY INVALID FILES */ - for (unsigned int i = 0; i < file_id_info_.size(); i++) { - auto &file = file_id_info_[i]; - - if (file.node_id_ != 0) { - auto &node = file_nodes_[file.node_id_]; - - if (node == nullptr) { - destroy_query(i); - context_->destroy_file_source({(int32) i, 0}); - empty_file_ids_.push_back(i); - file_id_info_[i] = FileIdInfo(); - } - } - } - - /* DESTROY INVALID NODES */ - for (unsigned int i = 0; i < file_nodes_.size(); i++) { - auto &node = file_nodes_[i]; - - if (node != nullptr) { - auto invalid = file_id_info_[node->main_file_id_.fast_get()].node_id_ != ((int32) i); - - if (!invalid) { - for (auto &file : node->file_ids_) { - if (file_id_info_[file.fast_get()].node_id_ != ((int32) i)) { - invalid = true; - break; - } + { + auto it = file_id_info_.begin(); + while (it != file_id_info_.end()) { + if (it->second.node_id_ != 0) { + auto &node = file_nodes_[it->second.node_id_]; + if (node == nullptr) { + destroy_query(it->first); + context_->destroy_file_source({it->first, 0}); + file_id_info_.erase(it++); + } else { + ++it; } - } - - if (invalid) { - for (auto &file : node->file_ids_) { - destroy_query(file.fast_get()); - context_->destroy_file_source(file); - empty_file_ids_.push_back(file.fast_get()); - file_id_info_[file.fast_get()] = FileIdInfo(); - } - - empty_node_ids_.push_back(i); - file_nodes_[i] = nullptr; + } else { + ++it; } } } @@ -3889,13 +3864,23 @@ void FileManager::memory_cleanup() { } } - file_hash_to_file_id_.rehash(0); - file_id_info_.shrink_to_fit(); - empty_file_ids_.shrink_to_fit(); - empty_node_ids_.shrink_to_fit(); + /* DESTROY NULL file_id_info_ */ + { + auto it = file_id_info_.begin(); + while (it != file_id_info_.end()) { + if (&it->second == nullptr || file_nodes_[it->second.node_id_] == nullptr) { + file_id_info_.erase(it++); + } else { + ++it; + } + } + } - LOG(ERROR) << empty_file_ids_.size() << " empty ids and " << queries_container_.size() << " running queries"; - is_closed_ = false; + file_nodes_.rehash(0); + file_hash_to_file_id_.rehash(0); + file_id_info_.rehash(0); + + LOG(ERROR) << "registered ids: " << file_id_info_.size() << " registered nodes: " << file_nodes_.size(); } void FileManager::tear_down() { diff --git a/td/telegram/files/FileManager.h b/td/telegram/files/FileManager.h index 4beb5d0b..3998f26d 100644 --- a/td/telegram/files/FileManager.h +++ b/td/telegram/files/FileManager.h @@ -554,16 +554,17 @@ class FileManager : public FileLoadManager::Callback { }; Enumerator remote_location_info_; + FileNodeId file_node_seqno = 0; + int32 file_id_seqno = 0; + std::unordered_map file_hash_to_file_id_; std::map local_location_to_file_id_; std::map generate_location_to_file_id_; std::map pmc_id_to_file_node_id_; - std::vector file_id_info_; - vector empty_file_ids_; - vector empty_node_ids_; - vector> file_nodes_; + std::unordered_map file_id_info_; + std::unordered_map> file_nodes_; ActorOwn file_load_manager_; ActorOwn file_generate_manager_;