main.cpp 21.7 KB
Newer Older
Q
qinzuoyan 已提交
1 2 3 4 5
// Copyright (c) 2017, Xiaomi, Inc.  All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <pegasus/version.h>
6
#include <dsn/utility/strings.h>
Q
qinzuoyan 已提交
7 8 9 10 11 12
#include <setjmp.h>
#include <signal.h>
#include <algorithm>
#include "args.h"
#include "command_executor.h"
#include "commands.h"
13
#include "base/pegasus_const.h"
Q
qinzuoyan 已提交
14

15 16 17 18
std::map<std::string, command_executor *> s_commands_map;
shell_context s_global_context;
size_t s_max_name_length = 0;
size_t s_option_width = 70;
Q
qinzuoyan 已提交
19

20 21 22 23 24 25 26
void print_help();
bool help_info(command_executor *e, shell_context *sc, arguments args)
{
    print_help();
    return true;
}

27
static command_executor commands[] = {
28 29 30
    {
        "help", "print help info", "", help_info,
    },
Q
qinzuoyan 已提交
31 32 33 34
    {
        "version", "get the shell version", "", version,
    },
    {
35 36 37 38
        "cluster_info",
        "get the information of the cluster",
        "[-r|--resolve_ip] [-o|--output file_name] [-j|--json]",
        query_cluster_info,
Q
qinzuoyan 已提交
39 40 41 42
    },
    {
        "app",
        "get the partition information for some specific app",
43
        "<app_name> [-d|--detailed] [-r|--resolve_ip] [-o|--output file_name] [-j|--json]",
Q
qinzuoyan 已提交
44 45 46 47 48
        query_app,
    },
    {
        "app_disk",
        "get the disk usage information for some specific app",
49
        "<app_name> [-d|--detailed] [-j|--json] [-o|--output file_name]",
Q
qinzuoyan 已提交
50 51 52 53 54
        app_disk,
    },
    {
        "ls",
        "list all apps",
55
        "[-a|-all] [-d|--detailed] [-j|--json] [-o|--output file_name]"
56
        "[-s|--status all|available|creating|dropping|dropped]",
Q
qinzuoyan 已提交
57 58 59 60 61
        ls_apps,
    },
    {
        "nodes",
        "get the node status for this cluster",
62
        "[-d|--detailed] [-j|--json] [-r|--resolve_ip] [-u|--resource_usage]"
63
        "[-o|--output file_name] [-s|--status all|alive|unalive] [-q|--qps]",
Q
qinzuoyan 已提交
64 65 66 67 68
        ls_nodes,
    },
    {
        "create",
        "create an app",
69 70
        "<app_name> [-p|--partition_count num] [-r|--replica_count num] "
        "[-e|--envs k1=v1,k2=v2...]",
Q
qinzuoyan 已提交
71 72 73
        create_app,
    },
    {
74
        "drop", "drop an app", "<app_name> [-r|--reserve_seconds num]", drop_app,
Q
qinzuoyan 已提交
75 76 77 78 79 80 81
    },
    {
        "recall", "recall an app", "<app_id> [new_app_name]", recall_app,
    },
    {
        "set_meta_level",
        "set the meta function level: stopped, blind, freezed, steady, lively",
82
        "<stopped|blind|freezed|steady|lively>",
Q
qinzuoyan 已提交
83 84 85 86 87 88 89 90
        set_meta_level,
    },
    {
        "get_meta_level", "get the meta function level", "", get_meta_level,
    },
    {
        "balance",
        "send explicit balancer request for the cluster",
91 92
        "<-g|--gpid appid.pidx> <-p|--type move_pri|copy_pri|copy_sec> <-f|--from from_address> "
        "<-t|--to to_address>",
Q
qinzuoyan 已提交
93 94 95 96 97 98
        balance,
    },
    {
        "propose",
        "send configuration proposals to cluster",
        "[-f|--force] "
99 100
        "<-g|--gpid appid.pidx> <-p|--type ASSIGN_PRIMARY|ADD_SECONDARY|DOWNGRADE_TO_INACTIVE...> "
        "<-t|--target node_to_exec_command> <-n|--node node_to_be_affected> ",
Q
qinzuoyan 已提交
101 102 103 104 105 106 107 108
        propose,
    },
    {
        "use",
        "set the current app used for the data access commands",
        "[app_name]",
        use_app_as_current,
    },
W
Wu Tao 已提交
109
    {
110
        "cc", "change to the specified cluster", "[cluster_name]", cc_command,
W
Wu Tao 已提交
111
    },
Q
qinzuoyan 已提交
112 113 114 115 116 117
    {
        "escape_all",
        "if escape all characters when printing key/value bytes",
        "[true|false]",
        process_escape_all,
    },
118 119 120 121 122 123
    {
        "timeout",
        "default timeout in milliseconds for read/write operations",
        "[time_in_ms]",
        process_timeout,
    },
Q
qinzuoyan 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    {
        "hash",
        "calculate the hash result for some hash key",
        "<hash_key> <sort_key>",
        calculate_hash_value,
    },
    {
        "set", "set value", "<hash_key> <sort_key> <value> [ttl_in_seconds]", data_operations,
    },
    {
        "multi_set",
        "set multiple values for a single hash key",
        "<hash_key> <sort_key> <value> [sort_key value...]",
        data_operations,
    },
    {
        "get", "get value", "<hash_key> <sort_key>", data_operations,
    },
    {
        "multi_get",
        "get multiple values for a single hash key",
        "<hash_key> [sort_key...]",
        data_operations,
    },
148 149 150 151
    {
        "multi_get_range",
        "get multiple values under sort key range for a single hash key",
        "<hash_key> <start_sort_key> <stop_sort_key> "
152 153 154 155
        "[-a|--start_inclusive true|false] [-b|--stop_inclusive true|false] "
        "[-s|--sort_key_filter_type anywhere|prefix|postfix] "
        "[-y|--sort_key_filter_pattern str] "
        "[-n|--max_count num] [-i|--no_value] [-r|--reverse]",
156 157
        data_operations,
    },
Q
qinzuoyan 已提交
158 159 160 161 162 163 164
    {
        "multi_get_sortkeys",
        "get multiple sort keys for a single hash key",
        "<hash_key>",
        data_operations,
    },
    {
165
        "del", "delete a key", "<hash_key> <sort_key>", data_operations,
Q
qinzuoyan 已提交
166 167 168 169 170 171 172
    },
    {
        "multi_del",
        "delete multiple values for a single hash key",
        "<hash_key> <sort_key> [sort_key...]",
        data_operations,
    },
173 174 175 176
    {
        "multi_del_range",
        "delete multiple values under sort key range for a single hash key",
        "<hash_key> <start_sort_key> <stop_sort_key> "
177 178 179 180
        "[-a|--start_inclusive true|false] [-b|--stop_inclusive true|false] "
        "[-s|--sort_key_filter_type anywhere|prefix|postfix] "
        "[-y|--sort_key_filter_pattern str] "
        "[-o|--output file_name] [-i|--silent]",
181 182
        data_operations,
    },
Q
QinZuoyan 已提交
183
    {
Q
QinZuoyan 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        "incr",
        "atomically increment value of a key",
        "<hash_key> <sort_key> [increment]",
        data_operations,
    },
    {
        "check_and_set",
        "atomically check and set value",
        "<hash_key> "
        "[-c|--check_sort_key str] "
        "[-t|--check_type not_exist|not_exist_or_empty|exist|not_empty] "
        "[match_anywhere|match_prefix|match_postfix] "
        "[bytes_less|bytes_less_or_equal|bytes_equal|bytes_greater_or_equal|bytes_greater] "
        "[int_less|int_less_or_equal|int_equal|int_greater_or_equal|int_greater] "
        "[-o|--check_operand str] "
        "[-s|--set_sort_key str] "
        "[-v|--set_value str] "
        "[-l|--set_value_ttl_seconds num] "
        "[-r|--return_check_value]",
        data_operations,
Q
QinZuoyan 已提交
204
    },
205 206 207 208 209 210 211 212 213 214 215 216 217
    {
        "check_and_mutate",
        "atomically check and mutate",
        "<hash_key> "
        "[-c|--check_sort_key str] "
        "[-t|--check_type not_exist|not_exist_or_empty|exist|not_empty] "
        "[match_anywhere|match_prefix|match_postfix] "
        "[bytes_less|bytes_less_or_equal|bytes_equal|bytes_greater_or_equal|bytes_greater] "
        "[int_less|int_less_or_equal|int_equal|int_greater_or_equal|int_greater] "
        "[-o|--check_operand str] "
        "[-r|--return_check_value]",
        data_operations,
    },
Q
qinzuoyan 已提交
218 219 220 221 222 223 224 225 226 227
    {
        "exist", "check value exist", "<hash_key> <sort_key>", data_operations,
    },
    {
        "count", "get sort key count for a single hash key", "<hash_key>", data_operations,
    },
    {
        "ttl", "query ttl for a specific key", "<hash_key> <sort_key>", data_operations,
    },
    {
228
        "hash_scan",
Q
qinzuoyan 已提交
229
        "scan all sorted keys for a single hash key",
230 231 232 233
        "<hash_key> <start_sort_key> <stop_sort_key> "
        "[-a|--start_inclusive true|false] [-b|--stop_inclusive true|false] "
        "[-s|--sort_key_filter_type anywhere|prefix|postfix] "
        "[-y|--sort_key_filter_pattern str] "
234 235 236 237
        "[-v|--value_filter_type anywhere|prefix|postfix|exact] "
        "[-z|--value_filter_pattern str] "
        "[-o|--output file_name] [-n|--max_count num] [-t|--timeout_ms num] "
        "[-d|--detailed] [-i|--no_value]",
Q
qinzuoyan 已提交
238 239 240
        data_operations,
    },
    {
241 242
        "full_scan",
        "scan all hash keys",
243 244
        "[-h|--hash_key_filter_type anywhere|prefix|postfix] "
        "[-x|--hash_key_filter_pattern str] "
245
        "[-s|--sort_key_filter_type anywhere|prefix|postfix|exact] "
246
        "[-y|--sort_key_filter_pattern str] "
247 248 249 250
        "[-v|--value_filter_type anywhere|prefix|postfix|exact] "
        "[-z|--value_filter_pattern str] "
        "[-o|--output file_name] [-n|--max_count num] [-t|--timeout_ms num] "
        "[-d|--detailed] [-i|--no_value] [-p|--partition num]",
Q
qinzuoyan 已提交
251 252 253 254 255
        data_operations,
    },
    {
        "copy_data",
        "copy app data",
256
        "<-c|--target_cluster_name str> <-a|--target_app_name str> "
257
        "[-p|--partition num] [-b|--max_batch_count num] [-t|--timeout_ms num] "
258 259
        "[-h|--hash_key_filter_type anywhere|prefix|postfix] "
        "[-x|--hash_key_filter_pattern str] "
260
        "[-s|--sort_key_filter_type anywhere|prefix|postfix|exact] "
261
        "[-y|--sort_key_filter_pattern str] "
262
        "[-v|--value_filter_type anywhere|prefix|postfix|exact] "
263
        "[-z|--value_filter_pattern str] "
264
        "[-n|--no_overwrite] [-i|--no_value] [-g|--geo_data]",
Q
qinzuoyan 已提交
265 266 267 268 269
        data_operations,
    },
    {
        "clear_data",
        "clear app data",
270 271 272
        "[-p|--partition num] [-b|--max_batch_count num] [-t|--timeout_ms num] "
        "[-h|--hash_key_filter_type anywhere|prefix|postfix] "
        "[-x|--hash_key_filter_pattern str] "
273
        "[-s|--sort_key_filter_type anywhere|prefix|postfix|exact] "
274
        "[-y|--sort_key_filter_pattern str] "
275
        "[-v|--value_filter_type anywhere|prefix|postfix|exact] "
276 277
        "[-z|--value_filter_pattern str] "
        "[-f|--force]",
Q
qinzuoyan 已提交
278 279 280 281 282
        data_operations,
    },
    {
        "count_data",
        "get app row count",
283 284 285
        "[-p|--partition num] [-b|--max_batch_count num] [-t|--timeout_ms num] "
        "[-h|--hash_key_filter_type anywhere|prefix|postfix] "
        "[-x|--hash_key_filter_pattern str] "
286
        "[-s|--sort_key_filter_type anywhere|prefix|postfix|exact] "
287
        "[-y|--sort_key_filter_pattern str] "
288
        "[-v|--value_filter_type anywhere|prefix|postfix|exact] "
289 290
        "[-z|--value_filter_pattern str] "
        "[-d|--diff_hash_key] [-a|--stat_size] [-n|--top_count num] [-r|--run_seconds num]",
Q
qinzuoyan 已提交
291 292 293 294 295
        data_operations,
    },
    {
        "remote_command",
        "send remote command to servers",
296 297
        "[-t all|meta-server|replica-server] [-l ip:port,ip:port...] "
        "<command> [arguments...]",
Q
qinzuoyan 已提交
298 299 300 301 302
        remote_command,
    },
    {
        "server_info",
        "get info of servers",
303
        "[-t all|meta-server|replica-server] [-l ip:port,ip:port...]",
Q
qinzuoyan 已提交
304 305 306 307 308
        server_info,
    },
    {
        "server_stat",
        "get stat of servers",
309
        "[-t all|meta-server|replica-server] [-l ip:port,ip:port...]",
Q
qinzuoyan 已提交
310 311 312
        server_stat,
    },
    {
313 314
        "app_stat",
        "get stat of apps",
315 316
        "[-a|--app_name str] [-q|--only_qps] [-u|--only_usage] [-j|--json] "
        "[-o|--output file_name]",
317
        app_stat,
Q
qinzuoyan 已提交
318 319 320 321
    },
    {
        "flush_log",
        "flush log of servers",
322
        "[-t all|meta-server|replica-server] [-l ip:port,ip:port...]",
Q
qinzuoyan 已提交
323 324 325 326 327
        flush_log,
    },
    {
        "local_get", "get value from local db", "<db_path> <hash_key> <sort_key>", local_get,
    },
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
    {
        "rdb_key_str2hex",
        "transform the given hashkey and sortkey to rocksdb raw key in hex representation",
        "<hash_key> <sort_key>",
        rdb_key_str2hex,
    },
    {
        "rdb_key_hex2str",
        "transform the given rocksdb raw key in hex representation to hash key and sort key",
        "<rdb_key_in_hex>",
        rdb_key_hex2str,
    },
    {
        "rdb_value_hex2str",
        "parse the given rocksdb raw value in hex representation",
        "<value_in_hex>",
        rdb_value_hex2str,
    },
Q
qinzuoyan 已提交
346 347 348
    {
        "sst_dump",
        "dump sstable dir or files",
349
        "[--command=check|scan|none|raw] <--file=data_dir_OR_sst_file> "
350
        "[--from=user_key] [--to=user_key] [--read_num=num] [--show_properties] [--pegasus_data]",
Q
qinzuoyan 已提交
351 352 353 354 355
        sst_dump,
    },
    {
        "mlog_dump",
        "dump mutation log dir",
356
        "<-i|--input log_dir> [-o|--output file_name] [-d|--detailed]",
Q
qinzuoyan 已提交
357 358 359 360 361
        mlog_dump,
    },
    {
        "recover",
        "control the meta to recover the system from given nodes",
362 363 364
        "[-f|--node_list_file file_name] [-s|--node_list_str str] "
        "[-w|--wait_seconds num] "
        "[-b|--skip_bad_nodes] [-l|--skip_lost_partitions] [-o|--output file_name]",
Q
qinzuoyan 已提交
365 366
        recover,
    },
C
cailiuyang 已提交
367 368 369
    {
        "add_backup_policy",
        "add new cold backup policy",
370 371 372
        "<-p|--policy_name str> <-b|--backup_provider_type str> <-a|--app_ids 1,2...> "
        "<-i|--backup_interval_seconds num> <-s|--start_time hour:minute> "
        "<-c|--backup_history_cnt num>",
C
cailiuyang 已提交
373 374
        add_backup_policy,
    },
375
    {"ls_backup_policy", "list the names of the subsistent backup policies", "", ls_backup_policy},
C
cailiuyang 已提交
376 377
    {
        "query_backup_policy",
378
        "query subsistent backup policy and last backup infos",
379
        "<-p|--policy_name p1,p2...> [-b|--backup_info_cnt num]",
C
cailiuyang 已提交
380 381 382 383 384
        query_backup_policy,
    },
    {
        "modify_backup_policy",
        "modify the backup policy",
385 386
        "<-p|--policy_name str> [-a|--add_app 1,2...] [-r|--remove_app 1,2...] "
        "[-i|--backup_interval_seconds num] [-c|--backup_history_count num] "
C
cailiuyang 已提交
387
        "[-s|--start_time hour:minute]",
C
cailiuyang 已提交
388 389 390 391 392
        modify_backup_policy,
    },
    {
        "disable_backup_policy",
        "stop policy continue backup",
393
        "<-p|--policy_name str>",
C
cailiuyang 已提交
394 395 396 397 398
        disable_backup_policy,
    },
    {
        "enable_backup_policy",
        "start backup policy to backup again",
399
        "<-p|--policy_name str>",
C
cailiuyang 已提交
400 401 402 403 404
        enable_backup_policy,
    },
    {
        "restore_app",
        "restore app from backup media",
405
        "<-c|--old_cluster_name str> <-p|--old_policy_name str> <-a|--old_app_name str> "
C
cailiuyang 已提交
406
        "<-i|--old_app_id id> <-t|--timestamp/backup_id timestamp> "
407
        "<-b|--backup_provider_type str> [-n|--new_app_name str] [-s|--skip_bad_partition]",
C
cailiuyang 已提交
408 409 410
        restore,
    },
    {
411 412
        "query_restore_status",
        "query restore status",
C
cailiuyang 已提交
413
        "<restore_app_id> [-d|--detailed]",
414
        query_restore_status,
C
cailiuyang 已提交
415
    },
416
    {
417
        "get_app_envs", "get current app envs", "[-j|--json]", get_app_envs,
418
    },
419
    {
420
        "set_app_envs", "set current app envs", "<key> <value> [key value...]", set_app_envs,
421 422
    },
    {
423
        "del_app_envs", "delete current app envs", "<key> [key...]", del_app_envs,
424 425
    },
    {
426 427 428 429 430 431 432 433
        "clear_app_envs", "clear current app envs", "[-a|--all] [-p|--prefix str]", clear_app_envs,
    },
    {
        "ddd_diagnose",
        "diagnose three-dead partitions",
        "[-g|--gpid appid|appid.pidx] [-d|--diagnose] [-a|--auto_diagnose] "
        "[-s|--skip_prompt] [-o|--output file_name]",
        ddd_diagnose,
434
    },
Q
qinzuoyan 已提交
435 436 437 438 439 440 441
    {
        "exit", "exit shell", "", exit_shell,
    },
    {
        nullptr, nullptr, nullptr, nullptr,
    }};

442
void print_help(command_executor *e, size_t name_width, size_t option_width)
Q
qinzuoyan 已提交
443
{
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
    std::vector<std::string> lines;
    std::string options(e->option_usage);
    int line_start = 0;
    int line_end = -1;
    int i;
    for (i = 0; i < options.size(); i++) {
        if (i - line_start >= option_width && line_end >= line_start) {
            std::string s = options.substr(line_start, line_end - line_start + 1);
            std::string r = dsn::utils::trim_string((char *)s.c_str());
            if (!r.empty())
                lines.push_back(r);
            line_start = line_end + 2;
        }
        if ((options[i] == ']' || options[i] == '>') && i < options.size() - 1 &&
            options[i + 1] == ' ') {
            line_end = i;
        }
    }
    line_end = i - 1;
    if (line_end >= line_start) {
        std::string s = options.substr(line_start, line_end - line_start + 1);
        std::string r = dsn::utils::trim_string((char *)s.c_str());
        if (!r.empty())
            lines.push_back(r);
    }

    std::cout << "\t" << e->name << std::string(name_width + 2 - strlen(e->name), ' ');
    if (lines.empty()) {
        std::cout << std::endl;
    } else {
        for (int k = 0; k < lines.size(); k++) {
            if (k != 0)
                std::cout << "\t" << std::string(name_width + 2, ' ');
            std::cout << lines[k] << std::endl;
        }
    }
Q
qinzuoyan 已提交
480 481 482 483 484 485
}

void print_help()
{
    std::cout << "Usage:" << std::endl;
    for (int i = 0; commands[i].name != nullptr; ++i) {
486
        print_help(&commands[i], s_max_name_length, s_option_width);
Q
qinzuoyan 已提交
487 488 489 490 491 492
    }
}

void register_all_commands()
{
    for (int i = 0; commands[i].name != nullptr; ++i) {
493
        auto pr = s_commands_map.emplace(commands[i].name, &commands[i]);
Q
qinzuoyan 已提交
494
        dassert(pr.second, "the command '%s' is already registered!!!", commands[i].name);
495
        s_max_name_length = std::max(s_max_name_length, strlen(commands[i].name));
Q
qinzuoyan 已提交
496 497 498
    }
}

499
void execute_command(command_executor *e, int argc, sds *str_args)
Q
qinzuoyan 已提交
500
{
501
    if (!e->exec(e, &s_global_context, {argc, str_args})) {
Q
qinzuoyan 已提交
502
        printf("USAGE: ");
503
        print_help(e, s_max_name_length, s_option_width);
Q
qinzuoyan 已提交
504 505 506
    }
}

507 508
/* Linenoise completion callback. */
static void completionCallback(const char *buf, linenoiseCompletions *lc)
Q
qinzuoyan 已提交
509
{
510 511 512 513 514 515 516
    for (int i = 0; commands[i].name != nullptr; ++i) {
        const command_executor &c = commands[i];

        size_t matchlen = strlen(buf);
        if (strncasecmp(buf, c.name, matchlen) == 0) {
            linenoiseAddCompletion(lc, c.name);
        }
Q
qinzuoyan 已提交
517 518 519
    }
}

520 521
/* Linenoise hints callback. */
static char *hintsCallback(const char *buf, int *color, int *bold)
Q
qinzuoyan 已提交
522
{
523 524 525 526 527 528
    int argc;
    sds *argv = sdssplitargs(buf, &argc);
    auto cleanup = dsn::defer([argc, argv]() { sdsfreesplitres(argv, argc); });

    /* Check if the argument list is empty and return ASAP. */
    if (argc == 0) {
Q
QinZuoyan 已提交
529
        return nullptr;
Q
qinzuoyan 已提交
530 531
    }

532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
    size_t buflen = strlen(buf);
    bool endWithSpace = buflen && isspace(buf[buflen - 1]);

    for (int i = 0; commands[i].name != nullptr; ++i) {
        if (strcasecmp(argv[0], commands[i].name) == 0) {
            *color = 90;
            *bold = 0;
            sds hint = sdsnew(commands[i].option_usage);

            /* Add an initial space if needed. */
            if (!endWithSpace) {
                sds newhint = sdsnewlen(" ", 1);
                newhint = sdscatsds(newhint, hint);
                sdsfree(hint);
                hint = newhint;
            }

            return hint;
        }
    }
Q
QinZuoyan 已提交
552
    return nullptr;
553 554 555 556 557
}

/* Linenoise free hints callback. */
static void freeHintsCallback(void *ptr) { sdsfree((sds)ptr); }

W
Wu Tao 已提交
558
/*extern*/ void check_in_cluster(std::string cluster_name)
559
{
560
    s_global_context.current_cluster_name = cluster_name;
561 562 563 564 565
    std::string server_list =
        dsn_config_get_value_string(pegasus::PEGASUS_CLUSTER_SECTION_NAME.c_str(),
                                    s_global_context.current_cluster_name.c_str(),
                                    "",
                                    "");
Q
qinzuoyan 已提交
566 567

    dsn::replication::replica_helper::load_meta_servers(
568 569 570
        s_global_context.meta_list,
        pegasus::PEGASUS_CLUSTER_SECTION_NAME.c_str(),
        cluster_name.c_str());
W
Wu Tao 已提交
571 572
    s_global_context.ddl_client =
        dsn::make_unique<dsn::replication::replication_ddl_client>(s_global_context.meta_list);
Q
qinzuoyan 已提交
573

574 575 576 577 578 579 580 581
    // get real cluster name from zk
    std::string name;
    ::dsn::error_code err = s_global_context.ddl_client->cluster_name(1000, name);
    if (err == dsn::ERR_OK) {
        cluster_name = name;
    }
    std::cout << "The cluster name is: " << cluster_name << std::endl;
    std::cout << "The cluster meta list is: " << server_list << std::endl;
W
Wu Tao 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
}

void initialize(int argc, char **argv)
{
    std::cout << "Pegasus Shell " << PEGASUS_VERSION << std::endl;
    std::cout << "Type \"help\" for more information." << std::endl;
    std::cout << "Type \"Ctrl-D\" or \"Ctrl-C\" to exit the shell." << std::endl;
    std::cout << std::endl;

    std::string config_file = argc > 1 ? argv[1] : "config.ini";
    if (!pegasus::pegasus_client_factory::initialize(config_file.c_str())) {
        std::cout << "ERROR: init pegasus failed: " << config_file << std::endl;
        dsn_exit(-1);
    } else {
        std::cout << "The config file is: " << config_file << std::endl;
    }

    std::string cluster_name = argc > 2 ? argv[2] : "mycluster";
    check_in_cluster(cluster_name);
601

602 603 604 605 606 607
    linenoiseSetMultiLine(1);
    linenoiseSetCompletionCallback(completionCallback);
    linenoiseSetHintsCallback(hintsCallback);
    linenoiseSetFreeHintsCallback(freeHintsCallback);
    linenoiseHistoryLoad(".shell-history");

Q
qinzuoyan 已提交
608 609 610 611 612 613
    register_all_commands();
}

void run()
{
    while (true) {
614 615 616 617
        int arg_count = 0;
        sds *args = scanfCommand(&arg_count);
        auto cleanup = dsn::defer([args, arg_count] { sdsfreesplitres(args, arg_count); });

Q
QinZuoyan 已提交
618
        if (args == nullptr) {
619 620 621 622
            printf("Invalid argument(s)\n");
            continue;
        }

Q
qinzuoyan 已提交
623
        if (arg_count > 0) {
624 625
            auto iter = s_commands_map.find(args[0]);
            if (iter != s_commands_map.end()) {
626 627 628
                // command executions(e.g. check_and_mutate) may have the different hints, so cancel
                // the commands hints temporarily
                linenoiseSetHintsCallback(nullptr);
Q
qinzuoyan 已提交
629
                execute_command(iter->second, arg_count, args);
630
                linenoiseSetHintsCallback(hintsCallback);
Q
qinzuoyan 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
            } else {
                std::cout << "ERROR: invalid subcommand '" << args[0] << "'" << std::endl;
                print_help();
            }
        }
    }
}

int main(int argc, char **argv)
{
    initialize(argc, argv);
    run();
    return 0;
}

#include <dsn/git_commit.h>
#include <dsn/version.h>
#include <pegasus/git_commit.h>
#include <pegasus/version.h>
static char const rcsid[] =
    "$Version: Pegasus Shell " PEGASUS_VERSION " (" PEGASUS_GIT_COMMIT ")"
#if defined(DSN_BUILD_TYPE)
    " " STR(DSN_BUILD_TYPE)
#endif
        ", built with rDSN " DSN_CORE_VERSION " (" DSN_GIT_COMMIT ")"
        ", built by gcc " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
#if defined(DSN_BUILD_HOSTNAME)
            ", built on " STR(DSN_BUILD_HOSTNAME)
#endif
                ", built at " __DATE__ " " __TIME__ " $";
const char *pegasus_shell_rcsid() { return rcsid; }