设为首页 收藏本站
查看: 562|回复: 0

[经验分享] redis源码笔记

[复制链接]

尚未签到

发表于 2015-7-20 08:55:04 | 显示全部楼层 |阅读模式
  这份代码是redis的client接口,其和server端的交互使用了deps目录下的hiredis c库,同时,在这部分代码中,应用了linenoise库完成类似history命令查询、自动补全等终端控制功能。



  1 #include "fmacros.h"       //用于mac下的兼容性处理
  2 #include "version.h"       //版本信息头文件,当前版本是2.4.10
  3
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include
10 #include
11 #include
12 #include
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);
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.name,&tmp.argc);
131         tmp.full = sdsnew(commandHelp.name);
132         tmp.type = CLI_HELP_COMMAND;
133         tmp.org = &commandHelp;
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 @\" to get a list of commands in \r\n"
154         "      \"help \" for help on \r\n"
155         "      \"help \" 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) == 0) {
176                 group = i;
177                 break;
178             }
179         }
180     }
181
182     assert(argc > 0);
183     for (i = 0; i < helpEntriesLen; i++) {
184         entry = &helpEntries;
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.type & mask)) continue;
224
225         matchlen = strlen(buf+startpos);
226         if (strncasecmp(buf+startpos,helpEntries.full,matchlen) == 0) {
227             tmp = sdsnewlen(buf,startpos);
228             tmp = sdscat(tmp,helpEntries.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,_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);
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,"-h") && !lastarg) {
516             sdsfree(config.hostip);
517             config.hostip = sdsnew(argv[i+1]);
518             i++;
519         } else if (!strcmp(argv,"-h") && lastarg) {
520             usage();
521         } else if (!strcmp(argv,"--help")) {
522             usage();
523         } else if (!strcmp(argv,"-x")) {
524             config.stdinarg = 1;
525         } else if (!strcmp(argv,"-p") && !lastarg) {
526             config.hostport = atoi(argv[i+1]);
527             i++;
528         } else if (!strcmp(argv,"-s") && !lastarg) {
529             config.hostsocket = argv[i+1];
530             i++;
531         } else if (!strcmp(argv,"-r") && !lastarg) {
532             config.repeat = strtoll(argv[i+1],NULL,10);
533             i++;
534         } else if (!strcmp(argv,"-i") && !lastarg) {
535             double seconds = atof(argv[i+1]);
536             config.interval = seconds*1000000;
537             i++;
538         } else if (!strcmp(argv,"-n") && !lastarg) {
539             config.dbnum = atoi(argv[i+1]);
540             i++;
541         } else if (!strcmp(argv,"-a") && !lastarg) {
542             config.auth = argv[i+1];
543             i++;
544         } else if (!strcmp(argv,"--raw")) {
545             config.raw_output = 1;
546         } else if (!strcmp(argv,"--latency")) {
547             config.latency_mode = 1;
548         } else if (!strcmp(argv,"-d") && !lastarg) {
549             sdsfree(config.mb_delim);
550             config.mb_delim = sdsnew(argv[i+1]);
551             i++;
552         } else if (!strcmp(argv,"-v") || !strcmp(argv, "--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     Server hostname (default: 127.0.0.1)\n"
588 "  -p         Server port (default: 6379)\n"
589 "  -s       Server socket (overrides hostname and port)\n"
590 "  -a     Password to use when connecting to the server\n"
591 "  -r       Execute specified command N times\n"
592 "  -i     When -r is used, waits  seconds per command.\n"
593 "                   It is possible to specify sub-second times like -i 0.1.\n"
594 "  -n           Database number\n"
595 "  -x               Read last argument from STDIN\n"
596 "  -d    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 }

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88430-1-1.html 上篇帖子: 深入剖析 redis 事件驱动 下篇帖子: ServiceStack.Redis 之 IRedisTypedClient<第四篇>
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表