bool run()

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;
}