Make country information static.

This commit is contained in:
levlam 2021-08-30 19:20:40 +03:00
parent 44556b3309
commit 8699d0aadb
2 changed files with 90 additions and 45 deletions

View File

@ -105,13 +105,13 @@ struct CountryInfoManager::CountryInfo {
}; };
struct CountryInfoManager::CountryList { struct CountryInfoManager::CountryList {
vector<CountryInfo> countries_; vector<CountryInfo> countries;
int32 hash = 0; int32 hash = 0;
double next_reload_time = 0.0; double next_reload_time = 0.0;
td_api::object_ptr<td_api::countries> get_countries_object() const { td_api::object_ptr<td_api::countries> get_countries_object() const {
return td_api::make_object<td_api::countries>( return td_api::make_object<td_api::countries>(
transform(countries_, [](const CountryInfo &info) { return info.get_country_info_object(); })); transform(countries, [](const CountryInfo &info) { return info.get_country_info_object(); }));
} }
}; };
@ -120,8 +120,20 @@ CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td),
CountryInfoManager::~CountryInfoManager() = default; CountryInfoManager::~CountryInfoManager() = default;
void CountryInfoManager::start_up() {
std::lock_guard<std::mutex> country_lock(country_mutex_);
manager_count_++;
}
void CountryInfoManager::tear_down() { void CountryInfoManager::tear_down() {
parent_.reset(); parent_.reset();
std::lock_guard<std::mutex> country_lock(country_mutex_);
manager_count_--;
if (manager_count_ == 0) {
LOG(INFO) << "Clear country info";
countries_.clear();
}
} }
string CountryInfoManager::get_main_language_code() { string CountryInfoManager::get_main_language_code() {
@ -141,23 +153,27 @@ void CountryInfoManager::do_get_countries(string language_code, bool is_recursiv
is_recursive = false; is_recursive = false;
} }
} }
auto list = get_country_list(language_code);
if (list == nullptr) { {
if (is_recursive) { std::lock_guard<std::mutex> country_lock(country_mutex_);
return promise.set_error(Status::Error(500, "Requested data is inaccessible")); auto list = get_country_list(this, language_code);
if (list != nullptr) {
return promise.set_value(list->get_countries_object());
} }
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code),
true, std::move(promise));
}));
} }
promise.set_value(list->get_countries_object()); if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code), true,
std::move(promise));
}));
} }
void CountryInfoManager::get_phone_number_info(string phone_number_prefix, void CountryInfoManager::get_phone_number_info(string phone_number_prefix,
@ -178,24 +194,26 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
is_recursive = false; is_recursive = false;
} }
} }
auto list = get_country_list(language_code); {
if (list == nullptr) { std::lock_guard<std::mutex> country_lock(country_mutex_);
if (is_recursive) { auto list = get_country_list(this, language_code);
return promise.set_error(Status::Error(500, "Requested data is inaccessible")); if (list != nullptr) {
return promise.set_value(get_phone_number_info_object(list, phone_number_prefix));
} }
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
std::move(phone_number_prefix), std::move(language_code), true,
std::move(promise));
}));
} }
promise.set_value(get_phone_number_info_object(list, phone_number_prefix)); if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
std::move(phone_number_prefix), std::move(language_code), true, std::move(promise));
}));
} }
td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_object(const CountryList *list, td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_object(const CountryList *list,
@ -205,7 +223,7 @@ td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number
const CallingCodeInfo *best_calling_code = nullptr; const CallingCodeInfo *best_calling_code = nullptr;
size_t best_length = 0; size_t best_length = 0;
bool is_prefix = false; // is phone number a prefix of a valid country_code + prefix bool is_prefix = false; // is phone number a prefix of a valid country_code + prefix
for (auto &country : list->countries_) { for (auto &country : list->countries) {
for (auto &calling_code : country.calling_codes) { for (auto &calling_code : country.calling_codes) {
if (begins_with(phone_number, calling_code.calling_code)) { if (begins_with(phone_number, calling_code.calling_code)) {
auto calling_code_size = calling_code.calling_code.size(); auto calling_code_size = calling_code.calling_code.size();
@ -315,9 +333,19 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
pending_load_country_queries_.erase(query_it); pending_load_country_queries_.erase(query_it);
if (r_country_list.is_error()) { if (r_country_list.is_error()) {
auto it = countries_.find(language_code); {
if (it != countries_.end()) { std::lock_guard<std::mutex> country_lock(country_mutex_);
it->second->next_reload_time = Time::now() + Random::fast(60, 120); auto it = countries_.find(language_code);
if (it != countries_.end()) {
// don't try to reload countries more often than once in 1-2 minutes
it->second->next_reload_time = max(Time::now() + Random::fast(60, 120), it->second->next_reload_time);
// if we have data for the language, then we don't need to fail promises
for (auto &promise : promises) {
promise.set_value(Unit());
}
return;
}
} }
for (auto &promise : promises) { for (auto &promise : promises) {
promise.set_error(r_country_list.error().clone()); promise.set_error(r_country_list.error().clone());
@ -325,7 +353,10 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
return; return;
} }
on_get_country_list_impl(language_code, r_country_list.move_as_ok()); {
std::lock_guard<std::mutex> country_lock(country_mutex_);
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
}
for (auto &promise : promises) { for (auto &promise : promises) {
promise.set_value(Unit()); promise.set_value(Unit());
@ -378,7 +409,7 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
continue; continue;
} }
countries->countries_.push_back(std::move(info)); countries->countries.push_back(std::move(info));
} }
countries->hash = list->hash_; countries->hash = list->hash_;
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400); countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
@ -389,7 +420,8 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
} }
} }
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) { const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(CountryInfoManager *manager,
const string &language_code) {
auto it = countries_.find(language_code); auto it = countries_.find(language_code);
if (it == countries_.end()) { if (it == countries_.end()) {
if (language_code == "en") { if (language_code == "en") {
@ -467,7 +499,9 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
it = countries_.find(language_code); it = countries_.find(language_code);
CHECK(it != countries_.end()) CHECK(it != countries_.end())
auto *country = it->second.get(); auto *country = it->second.get();
load_country_list(language_code, country->hash, Auto()); if (manager != nullptr) {
manager->load_country_list(language_code, country->hash, Auto());
}
return country; return country;
} }
return nullptr; return nullptr;
@ -475,11 +509,15 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
auto *country = it->second.get(); auto *country = it->second.get();
CHECK(country != nullptr); CHECK(country != nullptr);
if (country->next_reload_time < Time::now()) { if (manager != nullptr && country->next_reload_time < Time::now()) {
load_country_list(language_code, country->hash, Auto()); manager->load_country_list(language_code, country->hash, Auto());
} }
return country; return country;
} }
int32 CountryInfoManager::manager_count_ = 0;
std::mutex CountryInfoManager::country_mutex_;
std::unordered_map<string, unique_ptr<CountryInfoManager::CountryList>> CountryInfoManager::countries_;
} // namespace td } // namespace td

View File

@ -15,6 +15,7 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <mutex>
#include <unordered_map> #include <unordered_map>
namespace td { namespace td {
@ -39,6 +40,7 @@ class CountryInfoManager final : public Actor {
~CountryInfoManager() final; ~CountryInfoManager() final;
private: private:
void start_up() final;
void tear_down() final; void tear_down() final;
struct CallingCodeInfo; struct CallingCodeInfo;
@ -58,16 +60,21 @@ class CountryInfoManager final : public Actor {
void on_get_country_list(const string &language_code, void on_get_country_list(const string &language_code,
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list); Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
void on_get_country_list_impl(const string &language_code, static void on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list); tl_object_ptr<telegram_api::help_CountriesList> country_list);
const CountryList *get_country_list(const string &language_code); static const CountryList *get_country_list(CountryInfoManager *manager, const string &language_code);
static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_object(const CountryList *list, static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_object(const CountryList *list,
Slice phone_number); Slice phone_number);
static std::mutex country_mutex_;
static int32 manager_count_;
static std::unordered_map<string, unique_ptr<CountryList>> countries_;
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_; std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
std::unordered_map<string, unique_ptr<CountryList>> countries_;
Td *td_; Td *td_;
ActorShared<> parent_; ActorShared<> parent_;