zoukankan      html  css  js  c++  java
  • Redis源码分析(三十三)--- redis-cli.c客户端命令行接口的实现(2)

             今天学习完了命令行客户端的后续内容,整体感觉就是围绕着2个东西转,config和mode。为什么我会这么说呢,请继续往下看,客户端中的配置结构体和之前我们所学习的配置结构体,不是指的同一个概念,cli中的结构体除了基本的ip,Port端口号,还有就是各种mode的配置了。

    /* Redis配置结构体 */
    static struct config {
        char *hostip;
        int hostport;
        char *hostsocket;
        long repeat;
        long interval;
        int dbnum;
        int interactive;
        int shutdown;
        int monitor_mode;
        int pubsub_mode;
        int latency_mode;
        int latency_history;
        int cluster_mode;
        int cluster_reissue_command;
        int slave_mode;
        int pipe_mode;
        int pipe_timeout;
        int getrdb_mode;
        int stat_mode;
        int scan_mode;
        int intrinsic_latency_mode;
        int intrinsic_latency_duration;
        char *pattern;
        char *rdb_filename;
        int bigkeys;
        int stdinarg; /* get last arg from stdin. (-x option) */
        char *auth;
        int output; /* output mode, see OUTPUT_* defines */
        sds mb_delim;
        char prompt[128];
        char *eval;
        int last_cmd_type;
    } config;
    里面少说也有10个mode模式了吧。我们先倒过来,看看cli的主程序运行的流程,也就是main函数的执行步骤:

    /*main函数主程序操作*/
    int main(int argc, char **argv) {
        int firstarg;
    	
    	//首先初始化客户端配置操作
        config.hostip = sdsnew("127.0.0.1");
        config.hostport = 6379;
        config.hostsocket = NULL;
        config.repeat = 1;
        config.interval = 0;
        config.dbnum = 0;
        config.interactive = 0;
        config.shutdown = 0;
        config.monitor_mode = 0;
        config.pubsub_mode = 0;
        config.latency_mode = 0;
        config.latency_history = 0;
        config.cluster_mode = 0;
        config.slave_mode = 0;
        config.getrdb_mode = 0;
        config.stat_mode = 0;
        config.scan_mode = 0;
        config.intrinsic_latency_mode = 0;
        config.pattern = NULL;
        config.rdb_filename = NULL;
        config.pipe_mode = 0;
        config.pipe_timeout = REDIS_CLI_DEFAULT_PIPE_TIMEOUT;
        config.bigkeys = 0;
        config.stdinarg = 0;
        config.auth = NULL;
        config.eval = NULL;
        config.last_cmd_type = -1;
    
        if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == NULL))
            config.output = OUTPUT_RAW;
        else
            config.output = OUTPUT_STANDARD;
        config.mb_delim = sdsnew("
    ");
        cliInitHelp();
    	
    	//根据用户输入的参数,配置config
        firstarg = parseOptions(argc,argv);
        argc -= firstarg;
        argv += firstarg;
    
    	//配置设置完毕,根据配置中的模式设置,调用相应的mode方法
        /* Latency mode */
        if (config.latency_mode) {
            if (cliConnect(0) == REDIS_ERR) exit(1);
            latencyMode();
        }
    
        /* Slave mode */
        if (config.slave_mode) {
            if (cliConnect(0) == REDIS_ERR) exit(1);
            slaveMode();
        }
    	....
    
    后面的代码与此相同,所以就省略了,步骤简单来说,就是设置配置,根据配置启动相应的模式,下面说说,里面的主要几种模式

    1.statMode:

    /* statMode主要输出一些读取数据统计的一些信息 */
    static void statMode(void) {
        redisReply *reply;
        long aux, requests = 0;
        int i = 0;
    
        while(1) {
            char buf[64];
            int j;
    
            reply = reconnectingInfo();
            if (reply->type == REDIS_REPLY_ERROR) {
                printf("ERROR: %s
    ", reply->str);
                exit(1);
            }
    
            if ((i++ % 20) == 0) {
                printf(
    "------- data ------ --------------------- load -------------------- - child -
    "
    "keys       mem      clients blocked requests            connections          
    ");
            }
    
            /* Keys */
            aux = 0;
            for (j = 0; j < 20; j++) {
                long k;
    
                sprintf(buf,"db%d:keys",j);
                k = getLongInfoField(reply->str,buf);
                if (k == LONG_MIN) continue;
                aux += k;
            }
            sprintf(buf,"%ld",aux);
            printf("%-11s",buf);
    
            /* Used memory */
            aux = getLongInfoField(reply->str,"used_memory");
            bytesToHuman(buf,aux);
            printf("%-8s",buf);
    
            /* Clients */
            aux = getLongInfoField(reply->str,"connected_clients");
            sprintf(buf,"%ld",aux);
            printf(" %-8s",buf);
    
            /* Blocked (BLPOPPING) Clients */
            aux = getLongInfoField(reply->str,"blocked_clients");
            sprintf(buf,"%ld",aux);
            printf("%-8s",buf);
    		....
    客户端当前的数据统计信息。

    2.latencyMode中会用到的测试硬件计算性能的方法:

    /* This is just some computation the compiler can't optimize out.
     * Should run in less than 100-200 microseconds even using very
     * slow hardware. Runs in less than 10 microseconds in modern HW. */
    /* 普通的计算操作,测试硬件计算的速度快慢 */
    unsigned long compute_something_fast(void) {
        unsigned char s[256], i, j, t;
        int count = 1000, k;
        unsigned long output = 0;
    
        for (k = 0; k < 256; k++) s[k] = k;
    
        i = 0;
        j = 0;
        while(count--) {
            i++;
            j = j + s[i];
            t = s[i];
            s[i] = s[j];
            s[j] = t;
            output += s[(s[i]+s[j])&255];
        }
        return output;
    }
    帮助命令的输出文档是由下面的函数输出的:

    /* 帮助命令的输出文档 */
    static void usage(void) {
        sds version = cliVersion();
        fprintf(stderr,
    "redis-cli %s
    "
    "
    "
    "Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
    "
    "  -h <hostname>      Server hostname (default: 127.0.0.1).
    "
    "  -p <port>          Server port (default: 6379).
    "
    "  -s <socket>        Server socket (overrides hostname and port).
    "
    "  -a <password>      Password to use when connecting to the server.
    "
    "  -r <repeat>        Execute specified command N times.
    "
    "  -i <interval>      When -r is used, waits <interval> seconds per command.
    "
    "                     It is possible to specify sub-second times like -i 0.1.
    "
    "  -n <db>            Database number.
    "
    "  -x                 Read last argument from STDIN.
    "
    "  -d <delimiter>     Multi-bulk delimiter in for raw formatting (default: \n).
    "
    "  -c                 Enable cluster mode (follow -ASK and -MOVED redirections).
    "
    "  --raw              Use raw formatting for replies (default when STDOUT is
    "
    "                     not a tty).
    "
    "  --no-raw           Force formatted output even when STDOUT is not a tty.
    "
    "  --csv              Output in CSV format.
    "
    "  --latency          Enter a special mode continuously sampling latency.
    "
    "  --latency-history  Like --latency but tracking latency changes over time.
    "
    "                     Default time interval is 15 sec. Change it using -i.
    "
    "  --slave            Simulate a slave showing commands received from the master.
    "
    "  --rdb <filename>   Transfer an RDB dump from remote server to local file.
    "
    "  --pipe             Transfer raw Redis protocol from stdin to server.
    "
    "  --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.
    "
    "                     no reply is received within <n> seconds.
    "
    "                     Default timeout: %d. Use 0 to wait forever.
    "
    "  --bigkeys          Sample Redis keys looking for big keys.
    "
    "  --scan             List all keys using the SCAN command.
    "
    "  --pattern <pat>    Useful with --scan to specify a SCAN pattern.
    "
    "  --intrinsic-latency <sec> Run a test to measure intrinsic system latency.
    "
    "                     The test will run for the specified amount of seconds.
    "
    "  --eval <file>      Send an EVAL command using the Lua script at <file>.
    "
    "  --help             Output this help and exit.
    "
    "  --version          Output version and exit.
    "
    "
    "
    "Examples:
    "
    "  cat /etc/passwd | redis-cli -x set mypasswd
    "
    "  redis-cli get mypasswd
    "
    "  redis-cli -r 100 lpush mylist x
    "
    "  redis-cli -r 100 -i 1 info | grep used_memory_human:
    "
    "  redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3
    "
    "  redis-cli --scan --pattern '*:12345*'
    "
    "
    "
    "  (Note: when using --eval the comma separates KEYS[] from ARGV[] items)
    "
    "
    "
    "When no command is given, redis-cli starts in interactive mode.
    "
    "Type "help" in interactive mode for information on available commands.
    "
    "
    ",
            version, REDIS_CLI_DEFAULT_PIPE_TIMEOUT);
        sdsfree(version);
        exit(1);
    }
    在命令里面,会由于2个概念,1个叫一般性的Command命令还有一个是CommandGroup命令组的概念,举个例子,比如list,set等经常会用到的一些命令,后面可以接好多种参数的命令,属性命令组命令,一般CONFIG GET,这种功能非常单一的命令我们就叫他为普通的命令,Dump,Exist啊等等这些命令都是普通的命令,CommandGroup的命令不是很多就下面这么几个:

    /* 所有的命令组 */
    static char *commandGroups[] = {
        "generic",
        "string",
        "list",
        "set",
        "sorted_set",
        "hash",
        "pubsub",
        "transactions",
        "connection",
        "server",
        "scripting",
        "hyperloglog"
    };
    也是最最常用的命令,在redis的系统中。
  • 相关阅读:
    use paramiko to connect remote server and execute command
    protect golang source code
    adjust jedi vim to python2 and python3
    install vim plugin local file offline
    add swap file if you only have 1G RAM
    datatables hyperlink in td
    django rest framework custom json format
    【JAVA基础】网络编程
    【JAVA基础】多线程
    【JAVA基础】String类的概述和使用
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184188.html
Copyright © 2011-2022 走看看