micromax 发表于 2015-7-20 08:55:04

redis源码笔记

  这份代码是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;         
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 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 = sdscatprintf(sdsempty(),"@%s",commandGroups);
123         tmp.full = tmp.argv;
124         tmp.type = CLI_HELP_GROUP;
125         tmp.org = NULL;
126         helpEntries = 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 = 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);
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 == '@') {
173         len = sizeof(commandGroups)/sizeof(char*);
174         for (i = 0; i < len; i++) {
175             if (strcasecmp(argv+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,entry->argv) != 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++;
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;
331             char _prefixfmt;
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 = '\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;
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,"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 = sdslen(argv);
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);
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);
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);
527             i++;
528         } else if (!strcmp(argv,"-s") && !lastarg) {
529             config.hostsocket = argv;
530             i++;
531         } else if (!strcmp(argv,"-r") && !lastarg) {
532             config.repeat = strtoll(argv,NULL,10);
533             i++;
534         } else if (!strcmp(argv,"-i") && !lastarg) {
535             double seconds = atof(argv);
536             config.interval = seconds*1000000;
537             i++;
538         } else if (!strcmp(argv,"-n") && !lastarg) {
539             config.dbnum = atoi(argv);
540             i++;
541         } else if (!strcmp(argv,"-a") && !lastarg) {
542             config.auth = argv;
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);
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;
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 ]]\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, waitsseconds 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 = sdsnew(args);
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') {
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,"quit") == 0 ||
661                     strcasecmp(argv,"exit") == 0)
662               {
663                     exit(0);
664               } else if (argc == 3 && !strcasecmp(argv,"connect")) {
665                     sdsfree(config.hostip);
666                     config.hostip = sdsnew(argv);
667                     config.hostport = atoi(argv);
668                     cliConnect(1);
669               } else if (argc == 1 && !strcasecmp(argv,"clear")) {
670                     linenoiseClearScreen();
671               } else {
672                     long long start_time = mstime(), elapsed;
673                     int repeat, skipargs = 0;
674
675                     repeat = atoi(argv);
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);
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 = 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]
查看完整版本: redis源码笔记