in src/runtime/service_api_c.cpp [373:604]
bool run(const char *config_file,
const char *config_arguments,
bool is_server,
std::string &app_list)
{
// We put the loading of configuration at the beginning of this func.
// Because in dsn_global_init(), it calls perf_counters::instance(), which calls
// shared_io_service::instance(). And in the cstor of shared_io_service, it calls
// dsn_config_get_value_uint64() to load the corresponding configs. That will make
// dsn_config_get_value_uint64() get wrong value if we put dsn_config_load at behind of
// dsn_global_init()
if (!dsn_config_load(config_file, config_arguments)) {
printf("Fail to load config file %s\n", config_file);
return false;
}
dsn::flags_initialize();
dsn_global_init();
dsn_core_init();
::dsn::task::set_tls_dsn_context(nullptr, nullptr);
dsn_all.engine_ready = false;
dsn_all.config_completed = false;
dsn_all.tool = nullptr;
dsn_all.engine = &::dsn::service_engine::instance();
dsn_all.magic = 0xdeadbeef;
// pause when necessary
if (FLAGS_pause_on_start) {
printf("\nPause for debugging (pid = %d)...\n", static_cast<int>(getpid()));
getchar();
}
for (int i = 0; i <= dsn::task_code::max(); i++) {
dsn_all.task_specs.push_back(::dsn::task_spec::get(i));
}
// initialize global specification from config file
::dsn::service_spec spec;
if (!spec.init()) {
printf("error in config file %s, exit ...\n", config_file);
return false;
}
dsn_all.config_completed = true;
// setup data dir
auto &data_dir = spec.data_dir;
CHECK(!dsn::utils::filesystem::file_exists(data_dir), "{} should not be a file.", data_dir);
if (!dsn::utils::filesystem::directory_exists(data_dir)) {
CHECK(dsn::utils::filesystem::create_directory(data_dir), "Fail to create {}", data_dir);
}
std::string cdir;
CHECK(dsn::utils::filesystem::get_absolute_path(data_dir, cdir),
"Fail to get absolute path from {}",
data_dir);
spec.data_dir = cdir;
::dsn::utils::coredump::init();
// Setup log directory.
// If log_dir is not set, use data_dir/log instead.
if (spec.log_dir.empty()) {
spec.log_dir = ::dsn::utils::filesystem::path_combine(spec.data_dir, "log");
fmt::print(stdout, "log_dir is not set, use '{}' instead\n", spec.log_dir);
}
// Validate log_dir.
if (!dsn::utils::filesystem::is_absolute_path(spec.log_dir)) {
fmt::print(stderr, "log_dir({}) should be set with an absolute path\n", spec.log_dir);
return false;
}
dsn::utils::filesystem::create_directory(spec.log_dir);
// Initialize tools.
dsn_all.tool.reset(::dsn::utils::factory_store<::dsn::tools::tool_app>::create(
spec.tool.c_str(), ::dsn::PROVIDER_TYPE_MAIN, spec.tool.c_str()));
dsn_all.tool->install(spec);
// Initialize app specs.
if (!spec.init_app_specs()) {
fmt::print(stderr, "error in config file {}, exit ...\n", config_file);
return false;
}
#ifdef DSN_ENABLE_GPERF
::MallocExtension::instance()->SetMemoryReleaseRate(FLAGS_tcmalloc_release_rate);
#endif
// Extract app_names.
std::list<std::string> app_names_and_indexes;
::dsn::utils::split_args(app_list.c_str(), app_names_and_indexes, ';');
std::vector<std::string> app_names;
for (const auto &app_name_and_index : app_names_and_indexes) {
std::vector<std::string> name_and_index;
::dsn::utils::split_args(app_name_and_index.c_str(), name_and_index, '@');
if (name_and_index.empty()) {
fmt::print(stderr, "app_name should be specified in '{}'", app_name_and_index);
return false;
}
app_names.push_back(name_and_index[0]);
}
// Initialize logging.
dsn_log_init(spec.logging_factory_name,
spec.log_dir,
fmt::format("{}", fmt::join(app_names, ".")),
dsn_log_prefixed_message_func);
// Prepare the minimum necessary.
::dsn::service_engine::instance().init_before_toollets(spec);
LOG_INFO("process({}) start: {}, date: {}",
getpid(),
dsn::utils::process_start_millis(),
dsn::utils::process_start_date_time_mills());
// Initialize toollets.
for (const auto &toollet_name : spec.toollets) {
auto tlet = dsn::tools::internal_use_only::get_toollet(toollet_name.c_str(),
::dsn::PROVIDER_TYPE_MAIN);
CHECK_NOTNULL(tlet, "toolet not found");
tlet->install(spec);
}
// init provider specific system inits
dsn::tools::sys_init_before_app_created.execute();
// TODO: register sys_exit execution
// init runtime
::dsn::service_engine::instance().init_after_toollets();
dsn_all.engine_ready = true;
// init security if FLAGS_enable_auth == true
if (FLAGS_enable_auth) {
if (!dsn::security::init(is_server)) {
return false;
}
// if FLAGS_enable_auth is false but FLAGS_enable_zookeeper_kerberos, we should init
// kerberos for it separately
// include two steps:
// 1) apply kerberos ticket and keep it valid
// 2) complete sasl init for client(use FLAGS_sasl_plugin_path)
} else if (FLAGS_enable_zookeeper_kerberos && app_list == "meta") {
if (!dsn::security::init_for_zookeeper_client()) {
return false;
}
}
// init apps
for (auto &sp : spec.app_specs) {
if (!sp.run) {
continue;
}
bool create_it = false;
// create all apps
if (app_list.empty()) {
create_it = true;
} else {
for (const auto &app_name_and_index : app_names_and_indexes) {
std::vector<std::string> name_and_index;
::dsn::utils::split_args(app_name_and_index.c_str(), name_and_index, '@');
CHECK(!name_and_index.empty(),
"app_name should be specified in '{}'",
app_name_and_index);
if (std::string("apps.") + name_and_index.front() == sp.config_section) {
if (name_and_index.size() < 2) {
create_it = true;
} else {
int32_t index = 0;
const auto index_str = name_and_index.back();
CHECK(dsn::buf2int32(index_str, index),
"'{}' is not a valid index",
index_str);
create_it = (index == sp.index);
}
break;
}
}
}
if (create_it) {
::dsn::service_engine::instance().start_node(sp);
}
}
if (dsn::service_engine::instance().get_all_nodes().empty()) {
fmt::print(stderr,
"no app are created, usually because \n"
"app_name is not specified correctly, should be 'xxx' in [apps.xxx]\n"
"or app_index (1-based) is greater than specified count in config file\n");
exit(1);
}
dump_log_cmd = dsn::command_manager::instance().register_single_command(
"config-dump",
"Dump all configurations to a server local path or to stdout",
"[target_file]",
[](const std::vector<std::string> &args) {
std::ostringstream oss;
std::ofstream off;
std::ostream *os = &oss;
if (args.size() > 0) {
off.open(args[0]);
os = &off;
oss << "config dump to file " << args[0] << std::endl;
}
dsn_config_dump(*os);
return oss.str();
});
// invoke customized init after apps are created
dsn::tools::sys_init_after_app_created.execute();
// start the tool
dsn_all.tool->run();
if (is_server) {
while (true) {
std::this_thread::sleep_for(std::chrono::hours(1));
}
}
// add this to allow mimic app call from this thread.
memset((void *)&dsn::tls_dsn, 0, sizeof(dsn::tls_dsn));
return true;
}