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的系统中。
  • 相关阅读:
    Cocos2d-x 2.x项目创建
    Mac OS 使用Git
    Android Studio And Gradle
    Mac OS环境变量配置(Android Studio之Gradle)
    【Android UI】 Shape详解
    JS-OC通信之Cordova简介
    python类的定义和使用
    Android屏幕适配常识
    Python面试315题
    第十五篇 Python之文件处理
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184188.html
Copyright © 2011-2022 走看看