void replica_stub::register_ctrl_command()

in src/replica/replica_stub.cpp [2502:2683]


void replica_stub::register_ctrl_command()
{
    /// In simple_kv test, three replica apps are created, which means that three replica_stubs are
    /// initialized in simple_kv test. If we don't use std::call_once, these command are registered
    /// for three times. And in command_manager, one same command is not allowed to be registered
    /// more than twice times. That is why we use std::call_once here. Same situation in
    /// failure_detector::register_ctrl_commands and nfs_client_impl::register_cli_commands
    static std::once_flag flag;
    std::call_once(flag, [&]() {
        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.kill_partition"},
            "replica.kill_partition [app_id [partition_index]]",
            "replica.kill_partition: kill partitions by (all, one app, one partition)",
            [this](const std::vector<std::string> &args) {
                dsn::gpid pid;
                if (args.size() == 0) {
                    pid.set_app_id(-1);
                    pid.set_partition_index(-1);
                } else if (args.size() == 1) {
                    pid.set_app_id(atoi(args[0].c_str()));
                    pid.set_partition_index(-1);
                } else if (args.size() == 2) {
                    pid.set_app_id(atoi(args[0].c_str()));
                    pid.set_partition_index(atoi(args[1].c_str()));
                } else {
                    return std::string(ERR_INVALID_PARAMETERS.to_string());
                }
                dsn::error_code e = this->on_kill_replica(pid);
                return std::string(e.to_string());
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.deny-client"},
            "replica.deny-client <true|false>",
            "replica.deny-client - control if deny client read & write request",
            [this](const std::vector<std::string> &args) {
                return remote_command_set_bool_flag(_deny_client, "deny-client", args);
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.verbose-client-log"},
            "replica.verbose-client-log <true|false>",
            "replica.verbose-client-log - control if print verbose error log when reply read & "
            "write request",
            [this](const std::vector<std::string> &args) {
                return remote_command_set_bool_flag(
                    _verbose_client_log, "verbose-client-log", args);
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.verbose-commit-log"},
            "replica.verbose-commit-log <true|false>",
            "replica.verbose-commit-log - control if print verbose log when commit mutation",
            [this](const std::vector<std::string> &args) {
                return remote_command_set_bool_flag(
                    _verbose_commit_log, "verbose-commit-log", args);
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.trigger-checkpoint"},
            "replica.trigger-checkpoint [id1,id2,...] (where id is 'app_id' or "
            "'app_id.partition_id')",
            "replica.trigger-checkpoint - trigger replicas to do checkpoint",
            [this](const std::vector<std::string> &args) {
                return exec_command_on_replica(args, true, [this](const replica_ptr &rep) {
                    tasking::enqueue(LPC_PER_REPLICA_CHECKPOINT_TIMER,
                                     rep->tracker(),
                                     std::bind(&replica_stub::trigger_checkpoint, this, rep, true),
                                     rep->get_gpid().thread_hash());
                    return std::string("triggered");
                });
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.query-compact"},
            "replica.query-compact [id1,id2,...] (where id is 'app_id' or 'app_id.partition_id')",
            "replica.query-compact - query full compact status on the underlying storage engine",
            [this](const std::vector<std::string> &args) {
                return exec_command_on_replica(args, true, [](const replica_ptr &rep) {
                    return rep->query_manual_compact_state();
                });
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.query-app-envs"},
            "replica.query-app-envs [id1,id2,...] (where id is 'app_id' or 'app_id.partition_id')",
            "replica.query-app-envs - query app envs on the underlying storage engine",
            [this](const std::vector<std::string> &args) {
                return exec_command_on_replica(args, true, [](const replica_ptr &rep) {
                    std::map<std::string, std::string> kv_map;
                    rep->query_app_envs(kv_map);
                    return dsn::utils::kv_map_to_string(kv_map, ',', '=');
                });
            }));

#ifdef DSN_ENABLE_GPERF
        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.release-tcmalloc-memory"},
            "replica.release-tcmalloc-memory <true|false>",
            "replica.release-tcmalloc-memory - control if try to release tcmalloc memory",
            [this](const std::vector<std::string> &args) {
                return remote_command_set_bool_flag(
                    _release_tcmalloc_memory, "release-tcmalloc-memory", args);
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.get-tcmalloc-status"},
            "replica.get-tcmalloc-status - get status of tcmalloc",
            "get status of tcmalloc",
            [](const std::vector<std::string> &args) {
                char buf[4096];
                MallocExtension::instance()->GetStats(buf, 4096);
                return std::string(buf);
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.mem-release-max-reserved-percentage"},
            "replica.mem-release-max-reserved-percentage [num | DEFAULT]",
            "control tcmalloc max reserved but not-used memory percentage",
            [this](const std::vector<std::string> &args) {
                std::string result("OK");
                if (args.empty()) {
                    // show current value
                    result = "mem-release-max-reserved-percentage = " +
                             std::to_string(_mem_release_max_reserved_mem_percentage);
                    return result;
                }
                if (args[0] == "DEFAULT") {
                    // set to default value
                    _mem_release_max_reserved_mem_percentage =
                        FLAGS_mem_release_max_reserved_mem_percentage;
                    return result;
                }
                int32_t percentage = 0;
                if (!dsn::buf2int32(args[0], percentage) || percentage <= 0 || percentage > 100) {
                    result = std::string("ERR: invalid arguments");
                } else {
                    _mem_release_max_reserved_mem_percentage = percentage;
                }
                return result;
            }));

        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.release-all-reserved-memory"},
            "replica.release-all-reserved-memory - release tcmalloc all reserved-not-used memory",
            "release tcmalloc all reserverd not-used memory back to operating system",
            [this](const std::vector<std::string> &args) {
                auto release_bytes = gc_tcmalloc_memory(true);
                return "OK, release_bytes=" + std::to_string(release_bytes);
            }));
#elif defined(DSN_USE_JEMALLOC)
        register_jemalloc_ctrl_command();
#endif
        // TODO(yingchun): use http
        _cmds.emplace_back(::dsn::command_manager::instance().register_command(
            {"replica.max-concurrent-bulk-load-downloading-count"},
            "replica.max-concurrent-bulk-load-downloading-count [num | DEFAULT]",
            "control stub max_concurrent_bulk_load_downloading_count",
            [this](const std::vector<std::string> &args) {
                std::string result("OK");
                if (args.empty()) {
                    result = "max_concurrent_bulk_load_downloading_count=" +
                             std::to_string(_max_concurrent_bulk_load_downloading_count);
                    return result;
                }

                if (args[0] == "DEFAULT") {
                    _max_concurrent_bulk_load_downloading_count =
                        _options.max_concurrent_bulk_load_downloading_count;
                    return result;
                }

                int32_t count = 0;
                if (!dsn::buf2int32(args[0], count) || count <= 0) {
                    result = std::string("ERR: invalid arguments");
                } else {
                    _max_concurrent_bulk_load_downloading_count = count;
                }
                return result;
            }));
    });
}