zoukankan      html  css  js  c++  java
  • redis源码笔记 rediscli.c

    这份代码是redis的client接口,其和server端的交互使用了deps目录下的hiredis c库,同时,在这部分代码中,应用了linenoise库完成类似history命令查询、自动补全等终端控制功能。

      1 #include "fmacros.h"       //用于mac下的兼容性处理
      2 #include "version.h"       //版本信息头文件,当前版本是2.4.10
      3 
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <stdlib.h>
      7 #include <unistd.h>
      8 #include <ctype.h>
      9 #include <errno.h>
     10 #include <sys/stat.h>
     11 #include <sys/time.h>
     12 #include <assert.h>
     13 
     14 #include "hiredis.h"        //redis 客户端库的头文件
     15 #include "sds.h"
     16 #include "zmalloc.h"
     17 #include "linenoise.h"      //终端控制库的头文件
     18 #include "help.h"           //当前所有的命令文件汇总,用于tab自动补全功能的源数据
    /* help entry的结构如下:

    struct commandHelp {
    20 char *name;          //命令名字
    21 char *params;        //参数格式
    22 char *summary;       //简单的解释信息
    23 int group;           //命令类型(当前版本共分10种不同类型的命令)
    24 char *since;         //从哪个版本开始支持此命令
    25 } */

     19 
     20 #define REDIS_NOTUSED(V) ((void) V)
     21 
     22 static redisContext *context;            //维护client和server端的连接信息,包括文件描述符,错误信息等,参见deps/hiredis/hiredis.h
     23 static struct config {
     24     char *hostip;
     25     int hostport;
     26     char *hostsocket;
     27     long repeat;                         //命令重复执行次数
     28     long interval;                       //命令重复执行间隔
     29     int dbnum;                           // db no.
     30     int interactive;                     //交互模式 or 命令模式
     31     int shutdown;
     32     int monitor_mode;                    //监控模式
     33     int pubsub_mode;                     //pub sub模式
     34     int latency_mode;                    //该模式测试cli到server执行ping命令的时间间隔(应用层ping)
     35     int stdinarg; /* get last arg from stdin. (-x option) */
     36     char *auth;                          //需要鉴权时的密码信息
     37     int raw_output; /* output mode per command */      //选择该模式,将不会添加类似(interger),参见http://blog.sina.com.cn/s/blog_6262a50e0100zw83.html
     38     sds mb_delim;
     39     char prompt[128];           
     40 } config;
     41 
     42 static void usage();
     43 char *redisGitSHA1(void);
     44 char *redisGitDirty(void);
     45 
     46 /*------------------------------------------------------------------------------
     47  * Utility functions
     48  *--------------------------------------------------------------------------- */
     49 
     50 static long long mstime(void) {
     51     struct timeval tv;
     52     long long mst;
     53 
     54     gettimeofday(&tv, NULL);
     55     mst = ((long)tv.tv_sec)*1000;
     56     mst += tv.tv_usec/1000;
     57     return mst;
     58 }
     59 
     60 static void cliRefreshPrompt(void) {
     61     int len;
     62 
     63     if (config.hostsocket != NULL)
     64         len = snprintf(config.prompt,sizeof(config.prompt),"redis %s",
     65                        config.hostsocket);
     66     else
     67         len = snprintf(config.prompt,sizeof(config.prompt),"redis %s:%d",
     68                        config.hostip, config.hostport);
     69     /* Add [dbnum] if needed */
     70     if (config.dbnum != 0)
     71         len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",
     72             config.dbnum);
     73     snprintf(config.prompt+len,sizeof(config.prompt)-len,"> ");
     74 }
     75 
     76 /*------------------------------------------------------------------------------
     77  * Help functions
     78  *--------------------------------------------------------------------------- */
     79 
     80 #define CLI_HELP_COMMAND 1
     81 #define CLI_HELP_GROUP 2
     82 
     83 typedef struct {
     84     int type;
     85     int argc;
     86     sds *argv;
     87     sds full;
     88 
     89     /* Only used for help on commands */
     90     struct commandHelp *org;
     91 } helpEntry;
     92 
     93 static helpEntry *helpEntries;
     94 static int helpEntriesLen;
     95 
     96 static sds cliVersion() {
     97     sds version;
     98     version = sdscatprintf(sdsempty(), "%s", REDIS_VERSION);
     99 
    100     /* Add git commit and working tree status when available */
    101     if (strtoll(redisGitSHA1(),NULL,16)) {
    102         version = sdscatprintf(version, " (git:%s", redisGitSHA1());
    103         if (strtoll(redisGitDirty(),NULL,10))
    104             version = sdscatprintf(version, "-dirty");
    105         version = sdscat(version, ")");
    106     }
    107     return version;
    108 }
    109 
    110 static void cliInitHelp() {
    111     int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
    112     int groupslen = sizeof(commandGroups)/sizeof(char*);
    113     int i, len, pos = 0;
    114     helpEntry tmp;
    115 
    116     helpEntriesLen = len = commandslen+groupslen;
    117     helpEntries = malloc(sizeof(helpEntry)*len);
    118 
    119     for (i = 0; i < groupslen; i++) {
    120         tmp.argc = 1;
    121         tmp.argv = malloc(sizeof(sds));
    122         tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]);
    123         tmp.full = tmp.argv[0];
    124         tmp.type = CLI_HELP_GROUP;
    125         tmp.org = NULL;
    126         helpEntries[pos++] = tmp;
    127     }
    128 
    129     for (i = 0; i < commandslen; i++) {
    130         tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc);
    131         tmp.full = sdsnew(commandHelp[i].name);
    132         tmp.type = CLI_HELP_COMMAND;
    133         tmp.org = &commandHelp[i];
    134         helpEntries[pos++] = tmp;
    135     }
    136 }
    137 
    138 /* Output command help to stdout. */
    139 static void cliOutputCommandHelp(struct commandHelp *help, int group) {
    140     printf("\r\n  \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params);
    141     printf("  \x1b[33msummary:\x1b[0m %s\r\n", help->summary);
    142     printf("  \x1b[33msince:\x1b[0m %s\r\n", help->since);
    143     if (group) {
    144         printf("  \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);
    145     }
    146 }
    147 
    148 /* Print generic help. */
    149 static void cliOutputGenericHelp() {
    150     sds version = cliVersion();
    151     printf(
    152         "redis-cli %s\r\n"
    153         "Type: \"help @<group>\" to get a list of commands in <group>\r\n"
    154         "      \"help <command>\" for help on <command>\r\n"
    155         "      \"help <tab>\" to get a list of possible help topics\r\n"
    156         "      \"quit\" to exit\r\n",
    157         version
    158     );
    159     sdsfree(version);
    160 }
    161 
    162 /* Output all command help, filtering by group or command name. */
    163 static void cliOutputHelp(int argc, char **argv) {
    164     int i, j, len;
    165     int group = -1;
    166     helpEntry *entry;
    167     struct commandHelp *help;
    168 
    169     if (argc == 0) {
    170         cliOutputGenericHelp();
    171         return;
    172     } else if (argc > 0 && argv[0][0] == '@') {
    173         len = sizeof(commandGroups)/sizeof(char*);
    174         for (i = 0; i < len; i++) {
    175             if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {
    176                 group = i;
    177                 break;
    178             }
    179         }
    180     }
    181 
    182     assert(argc > 0);
    183     for (i = 0; i < helpEntriesLen; i++) {
    184         entry = &helpEntries[i];
    185         if (entry->type != CLI_HELP_COMMAND) continue;
    186 
    187         help = entry->org;
    188         if (group == -1) {
    189             /* Compare all arguments */
    190             if (argc == entry->argc) {
    191                 for (j = 0; j < argc; j++) {
    192                     if (strcasecmp(argv[j],entry->argv[j]) != 0) break;
    193                 }
    194                 if (j == argc) {
    195                     cliOutputCommandHelp(help,1);
    196                 }
    197             }
    198         } else {
    199             if (group == help->group) {
    200                 cliOutputCommandHelp(help,0);
    201             }
    202         }
    203     }
    204     printf("\r\n");
    205 }
    206 
    207 static void completionCallback(const char *buf, linenoiseCompletions *lc) {
    208     size_t startpos = 0;
    209     int mask;
    210     int i;
    211     size_t matchlen;
    212     sds tmp;
    213 
    214     if (strncasecmp(buf,"help ",5) == 0) {
    215         startpos = 5;
    216         while (isspace(buf[startpos])) startpos++;
    217         mask = CLI_HELP_COMMAND | CLI_HELP_GROUP;
    218     } else {
    219         mask = CLI_HELP_COMMAND;
    220     }
    221 
    222     for (i = 0; i < helpEntriesLen; i++) {
    223         if (!(helpEntries[i].type & mask)) continue;
    224 
    225         matchlen = strlen(buf+startpos);
    226         if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) {
    227             tmp = sdsnewlen(buf,startpos);
    228             tmp = sdscat(tmp,helpEntries[i].full);
    229             linenoiseAddCompletion(lc,tmp);
    230             sdsfree(tmp);
    231         }
    232     }
    233 }
    234 
    235 /*------------------------------------------------------------------------------
    236  * Networking / parsing
    237  *--------------------------------------------------------------------------- */
    238 
    239 /* Send AUTH command to the server */
    240 static int cliAuth() {
    241     redisReply *reply;
    242     if (config.auth == NULL) return REDIS_OK;
    243 
    244     reply = redisCommand(context,"AUTH %s",config.auth);
    245     if (reply != NULL) {
    246         freeReplyObject(reply);
    247         return REDIS_OK;
    248     }
    249     return REDIS_ERR;
    250 }
    251 
    252 /* Send SELECT dbnum to the server */
    253 static int cliSelect() {
    254     redisReply *reply;
    255     if (config.dbnum == 0) return REDIS_OK;
    256 
    257     reply = redisCommand(context,"SELECT %d",config.dbnum);
    258     if (reply != NULL) {
    259         freeReplyObject(reply);
    260         return REDIS_OK;
    261     }
    262     return REDIS_ERR;
    263 }
    264 
    265 /* Connect to the client. If force is not zero the connection is performed
    266  * even if there is already a connected socket. */
    267 static int cliConnect(int force) {
    268     if (context == NULL || force) {
    269         if (context != NULL)
    270             redisFree(context);
    271 
    272         if (config.hostsocket == NULL) {
    273             context = redisConnect(config.hostip,config.hostport);
    274         } else {
    275             context = redisConnectUnix(config.hostsocket);
    276         }
    277 
    278         if (context->err) {
    279             fprintf(stderr,"Could not connect to Redis at ");
    280             if (config.hostsocket == NULL)
    281                 fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr);
    282             else
    283                 fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr);
    284             redisFree(context);
    285             context = NULL;
    286             return REDIS_ERR;
    287         }
    288 
    289         /* Do AUTH and select the right DB. */
    290         if (cliAuth() != REDIS_OK)
    291             return REDIS_ERR;
    292         if (cliSelect() != REDIS_OK)
    293             return REDIS_ERR;
    294     }
    295     return REDIS_OK;
    296 }
    297 
    298 static void cliPrintContextError() {
    299     if (context == NULL) return;
    300     fprintf(stderr,"Error: %s\n",context->errstr);
    301 }
    302 
    303 static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
    304     sds out = sdsempty();
    305     switch (r->type) {
    306     case REDIS_REPLY_ERROR:
    307         out = sdscatprintf(out,"(error) %s\n", r->str);
    308     break;
    309     case REDIS_REPLY_STATUS:
    310         out = sdscat(out,r->str);
    311         out = sdscat(out,"\n");
    312     break;
    313     case REDIS_REPLY_INTEGER:
    314         out = sdscatprintf(out,"(integer) %lld\n",r->integer);
    315     break;
    316     case REDIS_REPLY_STRING:
    317         /* If you are producing output for the standard output we want
    318         * a more interesting output with quoted characters and so forth */
    319         out = sdscatrepr(out,r->str,r->len);
    320         out = sdscat(out,"\n");
    321     break;
    322     case REDIS_REPLY_NIL:
    323         out = sdscat(out,"(nil)\n");
    324     break;
    325     case REDIS_REPLY_ARRAY:
    326         if (r->elements == 0) {
    327             out = sdscat(out,"(empty list or set)\n");
    328         } else {
    329             unsigned int i, idxlen = 0;
    330             char _prefixlen[16];
    331             char _prefixfmt[16];
    332             sds _prefix;
    333             sds tmp;
    334 
    335             /* Calculate chars needed to represent the largest index */
    336             i = r->elements;
    337             do {
    338                 idxlen++;
    339                 i /= 10;
    340             } while(i);
    341 
    342             /* Prefix for nested multi bulks should grow with idxlen+2 spaces */
    343             memset(_prefixlen,' ',idxlen+2);
    344             _prefixlen[idxlen+2] = '\0';
    345             _prefix = sdscat(sdsnew(prefix),_prefixlen);
    346 
    347             /* Setup prefix format for every entry */
    348             snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%dd) ",idxlen);
    349 
    350             for (i = 0; i < r->elements; i++) {
    351                 /* Don't use the prefix for the first element, as the parent
    352                  * caller already prepended the index number. */
    353                 out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1);
    354 
    355                 /* Format the multi bulk entry */
    356                 tmp = cliFormatReplyTTY(r->element[i],_prefix);
    357                 out = sdscatlen(out,tmp,sdslen(tmp));
    358                 sdsfree(tmp);
    359             }
    360             sdsfree(_prefix);
    361         }
    362     break;
    363     default:
    364         fprintf(stderr,"Unknown reply type: %d\n", r->type);
    365         exit(1);
    366     }
    367     return out;
    368 }
    369 
    370 static sds cliFormatReplyRaw(redisReply *r) {
    371     sds out = sdsempty(), tmp;
    372     size_t i;
    373 
    374     switch (r->type) {
    375     case REDIS_REPLY_NIL:
    376         /* Nothing... */
    377         break;
    378     case REDIS_REPLY_ERROR:
    379         out = sdscatlen(out,r->str,r->len);
    380         out = sdscatlen(out,"\n",1);
    381         break;
    382     case REDIS_REPLY_STATUS:
    383     case REDIS_REPLY_STRING:
    384         out = sdscatlen(out,r->str,r->len);
    385         break;
    386     case REDIS_REPLY_INTEGER:
    387         out = sdscatprintf(out,"%lld",r->integer);
    388         break;
    389     case REDIS_REPLY_ARRAY:
    390         for (i = 0; i < r->elements; i++) {
    391             if (i > 0) out = sdscat(out,config.mb_delim);
    392             tmp = cliFormatReplyRaw(r->element[i]);
    393             out = sdscatlen(out,tmp,sdslen(tmp));
    394             sdsfree(tmp);
    395         }
    396         break;
    397     default:
    398         fprintf(stderr,"Unknown reply type: %d\n", r->type);
    399         exit(1);
    400     }
    401     return out;
    402 }
    403 
    404 static int cliReadReply(int output_raw_strings) {
    405     void *_reply;
    406     redisReply *reply;
    407     sds out;
    408 
    409     if (redisGetReply(context,&_reply) != REDIS_OK) {
    410         if (config.shutdown)
    411             return REDIS_OK;
    412         if (config.interactive) {
    413             /* Filter cases where we should reconnect */
    414             if (context->err == REDIS_ERR_IO && errno == ECONNRESET)
    415                 return REDIS_ERR;
    416             if (context->err == REDIS_ERR_EOF)
    417                 return REDIS_ERR;
    418         }
    419         cliPrintContextError();
    420         exit(1);
    421         return REDIS_ERR; /* avoid compiler warning */
    422     }
    423 
    424     reply = (redisReply*)_reply;
    425     if (output_raw_strings) {
    426         out = cliFormatReplyRaw(reply);
    427     } else {
    428         if (config.raw_output) {
    429             out = cliFormatReplyRaw(reply);
    430             out = sdscat(out,"\n");
    431         } else {
    432             out = cliFormatReplyTTY(reply,"");
    433         }
    434     }
    435     fwrite(out,sdslen(out),1,stdout);
    436     sdsfree(out);
    437     freeReplyObject(reply);
    438     return REDIS_OK;
    439 }
    440 
    441 static int cliSendCommand(int argc, char **argv, int repeat) {
    442     char *command = argv[0];
    443     size_t *argvlen;
    444     int j, output_raw;
    445 
    446     if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) {
    447         cliOutputHelp(--argc, ++argv);
    448         return REDIS_OK;
    449     }
    450 
    451     if (context == NULL) return REDIS_ERR;
    452 
    453     output_raw = 0;
    454     if (!strcasecmp(command,"info") ||
    455         (argc == 2 && !strcasecmp(command,"client") &&
    456                        !strcasecmp(argv[1],"list")))
    457 
    458     {
    459         output_raw = 1;
    460     }
    461 
    462     if (!strcasecmp(command,"shutdown")) config.shutdown = 1;
    463     if (!strcasecmp(command,"monitor")) config.monitor_mode = 1;
    464     if (!strcasecmp(command,"subscribe") ||
    465         !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1;
    466 
    467     /* Setup argument length */
    468     argvlen = malloc(argc*sizeof(size_t));
    469     for (j = 0; j < argc; j++)
    470         argvlen[j] = sdslen(argv[j]);
    471 
    472     while(repeat--) {
    473         redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);
    474         while (config.monitor_mode) {
    475             if (cliReadReply(output_raw) != REDIS_OK) exit(1);
    476             fflush(stdout);
    477         }
    478 
    479         if (config.pubsub_mode) {
    480             if (!config.raw_output)
    481                 printf("Reading messages... (press Ctrl-C to quit)\n");
    482             while (1) {
    483                 if (cliReadReply(output_raw) != REDIS_OK) exit(1);
    484             }
    485         }
    486 
    487         if (cliReadReply(output_raw) != REDIS_OK) {
    488             free(argvlen);
    489             return REDIS_ERR;
    490         } else {
    491             /* Store database number when SELECT was successfully executed. */
    492             if (!strcasecmp(command,"select") && argc == 2) {
    493                 config.dbnum = atoi(argv[1]);
    494                 cliRefreshPrompt();
    495             }
    496         }
    497         if (config.interval) usleep(config.interval);
    498         fflush(stdout); /* Make it grep friendly */
    499     }
    500 
    501     free(argvlen);
    502     return REDIS_OK;
    503 }
    504 
    505 /*------------------------------------------------------------------------------
    506  * User interface
    507  *--------------------------------------------------------------------------- */
    508 
    509 static int parseOptions(int argc, char **argv) {
    510     int i;
    511 
    512     for (i = 1; i < argc; i++) {
    513         int lastarg = i==argc-1;
    514 
    515         if (!strcmp(argv[i],"-h") && !lastarg) {
    516             sdsfree(config.hostip);
    517             config.hostip = sdsnew(argv[i+1]);
    518             i++;
    519         } else if (!strcmp(argv[i],"-h") && lastarg) {
    520             usage();
    521         } else if (!strcmp(argv[i],"--help")) {
    522             usage();
    523         } else if (!strcmp(argv[i],"-x")) {
    524             config.stdinarg = 1;
    525         } else if (!strcmp(argv[i],"-p") && !lastarg) {
    526             config.hostport = atoi(argv[i+1]);
    527             i++;
    528         } else if (!strcmp(argv[i],"-s") && !lastarg) {
    529             config.hostsocket = argv[i+1];
    530             i++;
    531         } else if (!strcmp(argv[i],"-r") && !lastarg) {
    532             config.repeat = strtoll(argv[i+1],NULL,10);
    533             i++;
    534         } else if (!strcmp(argv[i],"-i") && !lastarg) {
    535             double seconds = atof(argv[i+1]);
    536             config.interval = seconds*1000000;
    537             i++;
    538         } else if (!strcmp(argv[i],"-n") && !lastarg) {
    539             config.dbnum = atoi(argv[i+1]);
    540             i++;
    541         } else if (!strcmp(argv[i],"-a") && !lastarg) {
    542             config.auth = argv[i+1];
    543             i++;
    544         } else if (!strcmp(argv[i],"--raw")) {
    545             config.raw_output = 1;
    546         } else if (!strcmp(argv[i],"--latency")) {
    547             config.latency_mode = 1;
    548         } else if (!strcmp(argv[i],"-d") && !lastarg) {
    549             sdsfree(config.mb_delim);
    550             config.mb_delim = sdsnew(argv[i+1]);
    551             i++;
    552         } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {
    553             sds version = cliVersion();
    554             printf("redis-cli %s\n", version);
    555             sdsfree(version);
    556             exit(0);
    557         } else {
    558             break;
    559         }
    560     }
    561     return i;
    562 }
    563 
    564 static sds readArgFromStdin(void) {
    565     char buf[1024];
    566     sds arg = sdsempty();
    567 
    568     while(1) {
    569         int nread = read(fileno(stdin),buf,1024);
    570 
    571         if (nread == 0) break;
    572         else if (nread == -1) {
    573             perror("Reading from standard input");
    574             exit(1);
    575         }
    576         arg = sdscatlen(arg,buf,nread);
    577     }
    578     return arg;
    579 }
    580 
    581 static void usage() {
    582     sds version = cliVersion();
    583     fprintf(stderr,
    584 "redis-cli %s\n"
    585 "\n"
    586 "Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n"
    587 "  -h <hostname>    Server hostname (default: 127.0.0.1)\n"
    588 "  -p <port>        Server port (default: 6379)\n"
    589 "  -s <socket>      Server socket (overrides hostname and port)\n"
    590 "  -a <password>    Password to use when connecting to the server\n"
    591 "  -r <repeat>      Execute specified command N times\n"
    592 "  -i <interval>    When -r is used, waits <interval> seconds per command.\n"
    593 "                   It is possible to specify sub-second times like -i 0.1.\n"
    594 "  -n <db>          Database number\n"
    595 "  -x               Read last argument from STDIN\n"
    596 "  -d <delimiter>   Multi-bulk delimiter in for raw formatting (default: \\n)\n"
    597 "  --raw            Use raw formatting for replies (default when STDOUT is not a tty)\n"
    598 "  --latency        Enter a special mode continuously sampling latency.\n"
    599 "  --help           Output this help and exit\n"
    600 "  --version        Output version and exit\n"
    601 "\n"
    602 "Examples:\n"
    603 "  cat /etc/passwd | redis-cli -x set mypasswd\n"
    604 "  redis-cli get mypasswd\n"
    605 "  redis-cli -r 100 lpush mylist x\n"
    606 "  redis-cli -r 100 -i 1 info | grep used_memory_human:\n"
    607 "\n"
    608 "When no command is given, redis-cli starts in interactive mode.\n"
    609 "Type \"help\" in interactive mode for information on available commands.\n"
    610 "\n",
    611         version);
    612     sdsfree(version);
    613     exit(1);
    614 }
    615 
    616 /* Turn the plain C strings into Sds strings */
    617 static char **convertToSds(int count, char** args) {
    618   int j;
    619   char **sds = zmalloc(sizeof(char*)*count);
    620 
    621   for(j = 0; j < count; j++)
    622     sds[j] = sdsnew(args[j]);
    623 
    624   return sds;
    625 }
    626 
    627 #define LINE_BUFLEN 4096
    628 static void repl() {
    629     sds historyfile = NULL;
    630     int history = 0;
    631     char *line;
    632     int argc;
    633     sds *argv;
    634 
    635     config.interactive = 1;
    636     linenoiseSetCompletionCallback(completionCallback);
    637 
    638     /* Only use history when stdin is a tty. */
    639     if (isatty(fileno(stdin))) {
    640         history = 1;
    641 
    642         if (getenv("HOME") != NULL) {
    643             historyfile = sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME"));
    644             linenoiseHistoryLoad(historyfile);
    645         }
    646     }
    647 
    648     cliRefreshPrompt();
    649     while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
    650         if (line[0] != '\0') {
    651             argv = sdssplitargs(line,&argc);
    652             if (history) linenoiseHistoryAdd(line);
    653             if (historyfile) linenoiseHistorySave(historyfile);
    654 
    655             if (argv == NULL) {
    656                 printf("Invalid argument(s)\n");
    657                 free(line);
    658                 continue;
    659             } else if (argc > 0) {
    660                 if (strcasecmp(argv[0],"quit") == 0 ||
    661                     strcasecmp(argv[0],"exit") == 0)
    662                 {
    663                     exit(0);
    664                 } else if (argc == 3 && !strcasecmp(argv[0],"connect")) {
    665                     sdsfree(config.hostip);
    666                     config.hostip = sdsnew(argv[1]);
    667                     config.hostport = atoi(argv[2]);
    668                     cliConnect(1);
    669                 } else if (argc == 1 && !strcasecmp(argv[0],"clear")) {
    670                     linenoiseClearScreen();
    671                 } else {
    672                     long long start_time = mstime(), elapsed;
    673                     int repeat, skipargs = 0;
    674 
    675                     repeat = atoi(argv[0]);
    676                     if (argc > 1 && repeat) {
    677                         skipargs = 1;
    678                     } else {
    679                         repeat = 1;
    680                     }
    681 
    682                     if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)
    683                         != REDIS_OK)
    684                     {
    685                         cliConnect(1);
    686 
    687                         /* If we still cannot send the command print error.
    688                          * We'll try to reconnect the next time. */
    689                         if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)
    690                             != REDIS_OK)
    691                             cliPrintContextError();
    692                     }
    693                     elapsed = mstime()-start_time;
    694                     if (elapsed >= 500) {
    695                         printf("(%.2fs)\n",(double)elapsed/1000);
    696                     }
    697                 }
    698             }
    699             /* Free the argument vector */
    700             while(argc--) sdsfree(argv[argc]);
    701             zfree(argv);
    702         }
    703         /* linenoise() returns malloc-ed lines like readline() */
    704         free(line);
    705     }
    706     exit(0);
    707 }
    708 
    709 static int noninteractive(int argc, char **argv) {
    710     int retval = 0;
    711     if (config.stdinarg) {
    712         argv = zrealloc(argv, (argc+1)*sizeof(char*));
    713         argv[argc] = readArgFromStdin();
    714         retval = cliSendCommand(argc+1, argv, config.repeat);
    715     } else {
    716         /* stdin is probably a tty, can be tested with S_ISCHR(s.st_mode) */
    717         retval = cliSendCommand(argc, argv, config.repeat);
    718     }
    719     return retval;
    720 }
    721 
    722 static void latencyMode(void) {
    723     redisReply *reply;
    724     long long start, latency, min, max, tot, count = 0;
    725     double avg;
    726 
    727     if (!context) exit(1);
    728     while(1) {
    729         start = mstime();
    730         reply = redisCommand(context,"PING");
    731         if (reply == NULL) {
    732             fprintf(stderr,"\nI/O error\n");
    733             exit(1);
    734         }
    735         latency = mstime()-start;
    736         freeReplyObject(reply);
    737         count++;
    738         if (count == 1) {
    739             min = max = tot = latency;
    740             avg = (double) latency;
    741         } else {
    742             if (latency < min) min = latency;
    743             if (latency > max) max = latency;
    744             tot += latency;
    745             avg = (double) tot/count;
    746         }
    747         printf("\x1b[0G\x1b[2Kmin: %lld, max: %lld, avg: %.2f (%lld samples)",
    748             min, max, avg, count);
    749         fflush(stdout);
    750         usleep(10000);
    751     }
    752 }
    753 
    754 int main(int argc, char **argv) {
    755     int firstarg;
    756 
    757     config.hostip = sdsnew("127.0.0.1");
    758     config.hostport = 6379;
    759     config.hostsocket = NULL;
    760     config.repeat = 1;
    761     config.interval = 0;
    762     config.dbnum = 0;
    763     config.interactive = 0;
    764     config.shutdown = 0;
    765     config.monitor_mode = 0;
    766     config.pubsub_mode = 0;
    767     config.latency_mode = 0;
    768     config.stdinarg = 0;
    769     config.auth = NULL;
    770     config.raw_output = !isatty(fileno(stdout)) && (getenv("FAKETTY") == NULL);
    771     config.mb_delim = sdsnew("\n");
    772     cliInitHelp();
    773 
    774     firstarg = parseOptions(argc,argv);
    775     argc -= firstarg;
    776     argv += firstarg;
    777 
    778     /* Start in latency mode if appropriate */
    779     if (config.latency_mode) {
    780         cliConnect(0);
    781         latencyMode();
    782     }
    783 
    784     /* Start interactive mode when no command is provided */
    785     if (argc == 0) {
    786         /* Note that in repl mode we don't abort on connection error.
    787          * A new attempt will be performed for every command send. */
    788         cliConnect(0);
    789         repl();
    790     }
    791 
    792     /* Otherwise, we have some arguments to execute */
    793     if (cliConnect(0) != REDIS_OK) exit(1);
    794     return noninteractive(argc,convertToSds(argc,argv));
    795 }
  • 相关阅读:
    web测试方法总结
    APP测试点总结
    函数初识
    字符编码及文件操作
    简单购物车程序(Python)
    基本数据类型(列表,元祖,字典,集合)
    python基础
    基本数据类型(数字和字符串)
    Python入门
    操作系统
  • 原文地址:https://www.cnblogs.com/liuhao/p/2509628.html
Copyright © 2011-2022 走看看