Move directory creation and database check to another thread.
This commit is contained in:
parent
1528cfb9da
commit
ee926f86a3
@ -144,7 +144,6 @@
|
|||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
#include "td/utils/PathView.h"
|
#include "td/utils/PathView.h"
|
||||||
#include "td/utils/port/IPAddress.h"
|
#include "td/utils/port/IPAddress.h"
|
||||||
#include "td/utils/port/path.h"
|
|
||||||
#include "td/utils/port/SocketFd.h"
|
#include "td/utils/port/SocketFd.h"
|
||||||
#include "td/utils/port/uname.h"
|
#include "td/utils/port/uname.h"
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
@ -3042,6 +3041,10 @@ void Td::request(uint64 id, tl_object_ptr<td_api::Function> function) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Td::run_request(uint64 id, tl_object_ptr<td_api::Function> function) {
|
void Td::run_request(uint64 id, tl_object_ptr<td_api::Function> function) {
|
||||||
|
if (set_parameters_request_id_ > 0) {
|
||||||
|
pending_set_parameters_requests_.emplace_back(id, std::move(function));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (init_request_id_ > 0) {
|
if (init_request_id_ > 0) {
|
||||||
pending_init_requests_.emplace_back(id, std::move(function));
|
pending_init_requests_.emplace_back(id, std::move(function));
|
||||||
return;
|
return;
|
||||||
@ -3073,9 +3076,20 @@ void Td::run_request(uint64 id, tl_object_ptr<td_api::Function> function) {
|
|||||||
switch (state_) {
|
switch (state_) {
|
||||||
case State::WaitParameters: {
|
case State::WaitParameters: {
|
||||||
switch (function_id) {
|
switch (function_id) {
|
||||||
case td_api::setTdlibParameters::ID:
|
case td_api::setTdlibParameters::ID: {
|
||||||
return answer_ok_query(
|
auto status = set_parameters(std::move(move_tl_object_as<td_api::setTdlibParameters>(function)->parameters_));
|
||||||
id, set_parameters(std::move(move_tl_object_as<td_api::setTdlibParameters>(function)->parameters_)));
|
if (status.is_error()) {
|
||||||
|
return send_closure(actor_id(this), &Td::send_error, id, std::move(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
VLOG(td_init) << "Begin to check parameters";
|
||||||
|
set_parameters_request_id_ = id;
|
||||||
|
auto promise =
|
||||||
|
PromiseCreator::lambda([actor_id = actor_id(this)](Result<TdDb::CheckedParameters> r_checked_parameters) {
|
||||||
|
send_closure(actor_id, &Td::on_parameters_checked, std::move(r_checked_parameters));
|
||||||
|
});
|
||||||
|
return TdDb::check_parameters(get_database_scheduler_id(), parameters_, std::move(promise));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (is_preinitialization_request(function_id)) {
|
if (is_preinitialization_request(function_id)) {
|
||||||
break;
|
break;
|
||||||
@ -3653,6 +3667,45 @@ int32 Td::get_database_scheduler_id() {
|
|||||||
return min(current_scheduler_id + 1, scheduler_count - 1);
|
return min(current_scheduler_id + 1, scheduler_count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Td::on_parameters_checked(Result<TdDb::CheckedParameters> r_checked_parameters) {
|
||||||
|
CHECK(set_parameters_request_id_ != 0);
|
||||||
|
if (r_checked_parameters.is_error()) {
|
||||||
|
send_closure(actor_id(this), &Td::send_error, set_parameters_request_id_,
|
||||||
|
Status::Error(400, r_checked_parameters.error().message()));
|
||||||
|
return finish_set_parameters();
|
||||||
|
}
|
||||||
|
auto checked_parameters = r_checked_parameters.move_as_ok();
|
||||||
|
|
||||||
|
parameters_.database_directory = std::move(checked_parameters.database_directory);
|
||||||
|
parameters_.files_directory = std::move(checked_parameters.files_directory);
|
||||||
|
is_database_encrypted_ = checked_parameters.is_database_encrypted;
|
||||||
|
|
||||||
|
state_ = State::Decrypt;
|
||||||
|
VLOG(td_init) << "Send authorizationStateWaitEncryptionKey";
|
||||||
|
send_closure(actor_id(this), &Td::send_update,
|
||||||
|
td_api::make_object<td_api::updateAuthorizationState>(
|
||||||
|
td_api::make_object<td_api::authorizationStateWaitEncryptionKey>(is_database_encrypted_)));
|
||||||
|
VLOG(td_init) << "Finish set parameters";
|
||||||
|
send_closure(actor_id(this), &Td::send_result, set_parameters_request_id_, td_api::make_object<td_api::ok>());
|
||||||
|
return finish_set_parameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Td::finish_set_parameters() {
|
||||||
|
CHECK(set_parameters_request_id_ != 0);
|
||||||
|
set_parameters_request_id_ = 0;
|
||||||
|
|
||||||
|
if (pending_set_parameters_requests_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VLOG(td_init) << "Continue to execute " << pending_set_parameters_requests_.size() << " pending requests";
|
||||||
|
auto requests = std::move(pending_set_parameters_requests_);
|
||||||
|
for (auto &request : requests) {
|
||||||
|
run_request(request.first, std::move(request.second));
|
||||||
|
}
|
||||||
|
CHECK(pending_set_parameters_requests_.size() < requests.size());
|
||||||
|
}
|
||||||
|
|
||||||
void Td::start_init(uint64 id, string &&key) {
|
void Td::start_init(uint64 id, string &&key) {
|
||||||
VLOG(td_init) << "Begin to init database";
|
VLOG(td_init) << "Begin to init database";
|
||||||
init_request_id_ = id;
|
init_request_id_ = id;
|
||||||
@ -4213,35 +4266,6 @@ Status Td::fix_parameters(TdParameters ¶meters) {
|
|||||||
VLOG(td_init) << "Invalid api_hash";
|
VLOG(td_init) << "Invalid api_hash";
|
||||||
return Status::Error(400, "Valid api_hash must be provided. Can be obtained at https://my.telegram.org");
|
return Status::Error(400, "Valid api_hash must be provided. Can be obtained at https://my.telegram.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prepare_dir = [](string dir) -> Result<string> {
|
|
||||||
CHECK(!dir.empty());
|
|
||||||
if (dir.back() != TD_DIR_SLASH) {
|
|
||||||
dir += TD_DIR_SLASH;
|
|
||||||
}
|
|
||||||
TRY_STATUS(mkpath(dir, 0750));
|
|
||||||
TRY_RESULT(real_dir, realpath(dir, true));
|
|
||||||
if (dir.back() != TD_DIR_SLASH) {
|
|
||||||
dir += TD_DIR_SLASH;
|
|
||||||
}
|
|
||||||
return real_dir;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto r_database_directory = prepare_dir(parameters.database_directory);
|
|
||||||
if (r_database_directory.is_error()) {
|
|
||||||
VLOG(td_init) << "Invalid database_directory";
|
|
||||||
return Status::Error(400, PSLICE() << "Can't init database in the directory \"" << parameters.database_directory
|
|
||||||
<< "\": " << r_database_directory.error());
|
|
||||||
}
|
|
||||||
parameters.database_directory = r_database_directory.move_as_ok();
|
|
||||||
auto r_files_directory = prepare_dir(parameters.files_directory);
|
|
||||||
if (r_files_directory.is_error()) {
|
|
||||||
VLOG(td_init) << "Invalid files_directory";
|
|
||||||
return Status::Error(400, PSLICE() << "Can't init files directory \"" << parameters.files_directory
|
|
||||||
<< "\": " << r_files_directory.error());
|
|
||||||
}
|
|
||||||
parameters.files_directory = r_files_directory.move_as_ok();
|
|
||||||
|
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4252,8 +4276,8 @@ Status Td::set_parameters(td_api::object_ptr<td_api::tdlibParameters> parameters
|
|||||||
return Status::Error(400, "Parameters aren't specified");
|
return Status::Error(400, "Parameters aren't specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clean_input_string(parameters->api_hash_) && !clean_input_string(parameters->system_language_code_) &&
|
if (!clean_input_string(parameters->api_hash_) || !clean_input_string(parameters->system_language_code_) ||
|
||||||
!clean_input_string(parameters->device_model_) && !clean_input_string(parameters->system_version_) &&
|
!clean_input_string(parameters->device_model_) || !clean_input_string(parameters->system_version_) ||
|
||||||
!clean_input_string(parameters->application_version_)) {
|
!clean_input_string(parameters->application_version_)) {
|
||||||
VLOG(td_init) << "Wrong string encoding";
|
VLOG(td_init) << "Wrong string encoding";
|
||||||
return Status::Error(400, "Strings must be encoded in UTF-8");
|
return Status::Error(400, "Strings must be encoded in UTF-8");
|
||||||
@ -4271,11 +4295,7 @@ Status Td::set_parameters(td_api::object_ptr<td_api::tdlibParameters> parameters
|
|||||||
parameters_.use_chat_info_db = parameters->use_chat_info_database_;
|
parameters_.use_chat_info_db = parameters->use_chat_info_database_;
|
||||||
parameters_.use_message_db = parameters->use_message_database_;
|
parameters_.use_message_db = parameters->use_message_database_;
|
||||||
|
|
||||||
VLOG(td_init) << "Fix parameters...";
|
|
||||||
TRY_STATUS(fix_parameters(parameters_));
|
TRY_STATUS(fix_parameters(parameters_));
|
||||||
VLOG(td_init) << "Check binlog encryption...";
|
|
||||||
TRY_RESULT(encryption_info, TdDb::check_encryption(parameters_));
|
|
||||||
is_database_encrypted_ = encryption_info.is_encrypted;
|
|
||||||
|
|
||||||
VLOG(td_init) << "Create MtprotoHeader::Options";
|
VLOG(td_init) << "Create MtprotoHeader::Options";
|
||||||
options_.api_id = parameters->api_id_;
|
options_.api_id = parameters->api_id_;
|
||||||
@ -4306,12 +4326,6 @@ Status Td::set_parameters(td_api::object_ptr<td_api::tdlibParameters> parameters
|
|||||||
options_.is_emulator = false;
|
options_.is_emulator = false;
|
||||||
options_.proxy = Proxy();
|
options_.proxy = Proxy();
|
||||||
|
|
||||||
state_ = State::Decrypt;
|
|
||||||
VLOG(td_init) << "Send authorizationStateWaitEncryptionKey";
|
|
||||||
send_closure(actor_id(this), &Td::send_update,
|
|
||||||
td_api::make_object<td_api::updateAuthorizationState>(
|
|
||||||
td_api::make_object<td_api::authorizationStateWaitEncryptionKey>(is_database_encrypted_)));
|
|
||||||
VLOG(td_init) << "Finish set parameters";
|
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +296,7 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
enum class State : int32 { WaitParameters, Decrypt, Run, Close } state_ = State::WaitParameters;
|
enum class State : int32 { WaitParameters, Decrypt, Run, Close } state_ = State::WaitParameters;
|
||||||
uint64 init_request_id_ = 0;
|
uint64 init_request_id_ = 0;
|
||||||
|
uint64 set_parameters_request_id_ = 0;
|
||||||
bool is_database_encrypted_ = false;
|
bool is_database_encrypted_ = false;
|
||||||
|
|
||||||
FlatHashMap<uint64, std::shared_ptr<ResultHandler>> result_handlers_;
|
FlatHashMap<uint64, std::shared_ptr<ResultHandler>> result_handlers_;
|
||||||
@ -321,6 +322,7 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_preauthentication_requests_;
|
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_preauthentication_requests_;
|
||||||
|
|
||||||
|
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_set_parameters_requests_;
|
||||||
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_init_requests_;
|
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_init_requests_;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -1428,6 +1430,10 @@ class Td final : public Actor {
|
|||||||
|
|
||||||
static int32 get_database_scheduler_id();
|
static int32 get_database_scheduler_id();
|
||||||
|
|
||||||
|
void on_parameters_checked(Result<TdDb::CheckedParameters> r_checked_parameters);
|
||||||
|
|
||||||
|
void finish_set_parameters();
|
||||||
|
|
||||||
void start_init(uint64 id, string &&key);
|
void start_init(uint64 id, string &&key);
|
||||||
|
|
||||||
void init(Result<TdDb::OpenedDatabase> r_opened_database);
|
void init(Result<TdDb::OpenedDatabase> r_opened_database);
|
||||||
|
@ -51,19 +51,6 @@ std::string get_sqlite_path(const TdParameters ¶meters) {
|
|||||||
return parameters.database_directory + db_name + ".sqlite";
|
return parameters.database_directory + db_name + ".sqlite";
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<TdDb::EncryptionInfo> check_encryption(string path) {
|
|
||||||
Binlog binlog;
|
|
||||||
auto status = binlog.init(std::move(path), Binlog::Callback());
|
|
||||||
if (status.is_error() && status.code() != Binlog::Error::WrongPassword) {
|
|
||||||
LOG(WARNING) << "Failed to check binlog: " << status;
|
|
||||||
return Status::Error(400, status.message());
|
|
||||||
}
|
|
||||||
TdDb::EncryptionInfo info;
|
|
||||||
info.is_encrypted = binlog.get_info().wrong_password;
|
|
||||||
binlog.close(false /*need_sync*/).ensure();
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_pmc, BinlogKeyValue<Binlog> &config_pmc,
|
Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_pmc, BinlogKeyValue<Binlog> &config_pmc,
|
||||||
TdDb::OpenedDatabase &events, DbKey key) {
|
TdDb::OpenedDatabase &events, DbKey key) {
|
||||||
auto callback = [&](const BinlogEvent &event) {
|
auto callback = [&](const BinlogEvent &event) {
|
||||||
@ -495,8 +482,62 @@ void TdDb::open(int32 scheduler_id, TdParameters parameters, DbKey key, Promise<
|
|||||||
TdDb::TdDb() = default;
|
TdDb::TdDb() = default;
|
||||||
TdDb::~TdDb() = default;
|
TdDb::~TdDb() = default;
|
||||||
|
|
||||||
Result<TdDb::EncryptionInfo> TdDb::check_encryption(const TdParameters ¶meters) {
|
void TdDb::check_parameters(int32 scheduler_id, TdParameters parameters, Promise<CheckedParameters> promise) {
|
||||||
return ::td::check_encryption(get_binlog_path(parameters));
|
if (scheduler_id >= 0 && Scheduler::instance()->sched_id() != scheduler_id) {
|
||||||
|
class Worker final : public Actor {
|
||||||
|
public:
|
||||||
|
void run(TdParameters parameters, Promise<CheckedParameters> promise) {
|
||||||
|
TdDb::check_parameters(-1, std::move(parameters), std::move(promise));
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
send_closure(create_actor_on_scheduler<Worker>("Worker", scheduler_id), &Worker::run, std::move(parameters),
|
||||||
|
std::move(promise));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CheckedParameters result;
|
||||||
|
|
||||||
|
auto prepare_dir = [](string dir) -> Result<string> {
|
||||||
|
CHECK(!dir.empty());
|
||||||
|
if (dir.back() != TD_DIR_SLASH) {
|
||||||
|
dir += TD_DIR_SLASH;
|
||||||
|
}
|
||||||
|
TRY_STATUS(mkpath(dir, 0750));
|
||||||
|
TRY_RESULT(real_dir, realpath(dir, true));
|
||||||
|
if (dir.back() != TD_DIR_SLASH) {
|
||||||
|
dir += TD_DIR_SLASH;
|
||||||
|
}
|
||||||
|
return real_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto r_database_directory = prepare_dir(parameters.database_directory);
|
||||||
|
if (r_database_directory.is_error()) {
|
||||||
|
VLOG(td_init) << "Invalid database_directory";
|
||||||
|
return promise.set_error(Status::Error(PSLICE()
|
||||||
|
<< "Can't init database in the directory \"" << parameters.database_directory
|
||||||
|
<< "\": " << r_database_directory.error()));
|
||||||
|
}
|
||||||
|
result.database_directory = r_database_directory.move_as_ok();
|
||||||
|
parameters.database_directory = result.database_directory;
|
||||||
|
|
||||||
|
auto r_files_directory = prepare_dir(parameters.files_directory);
|
||||||
|
if (r_files_directory.is_error()) {
|
||||||
|
VLOG(td_init) << "Invalid files_directory";
|
||||||
|
return promise.set_error(Status::Error(PSLICE() << "Can't init files directory \"" << parameters.files_directory
|
||||||
|
<< "\": " << r_files_directory.error()));
|
||||||
|
}
|
||||||
|
result.files_directory = r_files_directory.move_as_ok();
|
||||||
|
|
||||||
|
Binlog binlog;
|
||||||
|
auto status = binlog.init(get_binlog_path(parameters), Binlog::Callback());
|
||||||
|
if (status.is_error() && status.code() != Binlog::Error::WrongPassword) {
|
||||||
|
LOG(WARNING) << "Failed to check binlog: " << status;
|
||||||
|
return promise.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
result.is_database_encrypted = binlog.get_info().wrong_password;
|
||||||
|
binlog.close(false /*need_sync*/).ensure();
|
||||||
|
|
||||||
|
promise.set_value(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TdDb::change_key(DbKey key, Promise<> promise) {
|
void TdDb::change_key(DbKey key, Promise<> promise) {
|
||||||
|
@ -48,6 +48,13 @@ class TdDb {
|
|||||||
TdDb &operator=(TdDb &&) = delete;
|
TdDb &operator=(TdDb &&) = delete;
|
||||||
~TdDb();
|
~TdDb();
|
||||||
|
|
||||||
|
struct CheckedParameters {
|
||||||
|
string database_directory;
|
||||||
|
string files_directory;
|
||||||
|
bool is_database_encrypted{false};
|
||||||
|
};
|
||||||
|
static void check_parameters(int32 scheduler_id, TdParameters parameters, Promise<CheckedParameters> promise);
|
||||||
|
|
||||||
struct OpenedDatabase {
|
struct OpenedDatabase {
|
||||||
unique_ptr<TdDb> database;
|
unique_ptr<TdDb> database;
|
||||||
|
|
||||||
@ -64,11 +71,6 @@ class TdDb {
|
|||||||
};
|
};
|
||||||
static void open(int32 scheduler_id, TdParameters parameters, DbKey key, Promise<OpenedDatabase> &&promise);
|
static void open(int32 scheduler_id, TdParameters parameters, DbKey key, Promise<OpenedDatabase> &&promise);
|
||||||
|
|
||||||
struct EncryptionInfo {
|
|
||||||
bool is_encrypted{false};
|
|
||||||
};
|
|
||||||
static Result<EncryptionInfo> check_encryption(const TdParameters ¶meters);
|
|
||||||
|
|
||||||
static Status destroy(const TdParameters ¶meters);
|
static Status destroy(const TdParameters ¶meters);
|
||||||
|
|
||||||
std::shared_ptr<FileDbInterface> get_file_db_shared();
|
std::shared_ptr<FileDbInterface> get_file_db_shared();
|
||||||
|
@ -440,7 +440,7 @@ class TestDownloadFile : public Task {
|
|||||||
begin = end;
|
begin = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::random_shuffle(as_mutable_span(ranges_), rnd);
|
random_shuffle(as_mutable_span(ranges_), rnd);
|
||||||
start_chunk();
|
start_chunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user