1# 1 "src/redis-cli.c" 2# 1 "<built-in>" 3# 1 "<command-line>" 4# 1 "src/redis-cli.c" 5# 31 "src/redis-cli.c" 6# 1 "src/fmacros.h" 1 7# 32 "src/redis-cli.c" 2 8# 1 "src/version.h" 1 9# 33 "src/redis-cli.c" 2 10 11# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 12# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 13# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 14# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 15 16 17 18typedef int size_t; 19typedef int __builtin_va_list; 20typedef int __gnuc_va_list; 21typedef int va_list; 22typedef int __int8_t; 23typedef int __uint8_t; 24typedef int __int16_t; 25typedef int __uint16_t; 26typedef int __int_least16_t; 27typedef int __uint_least16_t; 28typedef int __int32_t; 29typedef int __uint32_t; 30typedef int __int64_t; 31typedef int __uint64_t; 32typedef int __int_least32_t; 33typedef int __uint_least32_t; 34typedef int __s8; 35typedef int __u8; 36typedef int __s16; 37typedef int __u16; 38typedef int __s32; 39typedef int __u32; 40typedef int __s64; 41typedef int __u64; 42typedef int _LOCK_T; 43typedef int _LOCK_RECURSIVE_T; 44typedef int _off_t; 45typedef int __dev_t; 46typedef int __uid_t; 47typedef int __gid_t; 48typedef int _off64_t; 49typedef int _fpos_t; 50typedef int _ssize_t; 51typedef int wint_t; 52typedef int _mbstate_t; 53typedef int _flock_t; 54typedef int _iconv_t; 55typedef int __ULong; 56typedef int __FILE; 57typedef int ptrdiff_t; 58typedef int wchar_t; 59typedef int __off_t; 60typedef int __pid_t; 61typedef int __loff_t; 62typedef int u_char; 63typedef int u_short; 64typedef int u_int; 65typedef int u_long; 66typedef int ushort; 67typedef int uint; 68typedef int clock_t; 69typedef int time_t; 70typedef int daddr_t; 71typedef int caddr_t; 72typedef int ino_t; 73typedef int off_t; 74typedef int dev_t; 75typedef int uid_t; 76typedef int gid_t; 77typedef int pid_t; 78typedef int key_t; 79typedef int ssize_t; 80typedef int mode_t; 81typedef int nlink_t; 82typedef int fd_mask; 83typedef int _types_fd_set; 84typedef int clockid_t; 85typedef int timer_t; 86typedef int useconds_t; 87typedef int suseconds_t; 88typedef int FILE; 89typedef int fpos_t; 90typedef int cookie_read_function_t; 91typedef int cookie_write_function_t; 92typedef int cookie_seek_function_t; 93typedef int cookie_close_function_t; 94typedef int cookie_io_functions_t; 95typedef int div_t; 96typedef int ldiv_t; 97typedef int lldiv_t; 98typedef int sigset_t; 99typedef int __sigset_t; 100typedef int _sig_func_ptr; 101typedef int sig_atomic_t; 102typedef int __tzrule_type; 103typedef int __tzinfo_type; 104typedef int mbstate_t; 105typedef int sem_t; 106typedef int pthread_t; 107typedef int pthread_attr_t; 108typedef int pthread_mutex_t; 109typedef int pthread_mutexattr_t; 110typedef int pthread_cond_t; 111typedef int pthread_condattr_t; 112typedef int pthread_key_t; 113typedef int pthread_once_t; 114typedef int pthread_rwlock_t; 115typedef int pthread_rwlockattr_t; 116typedef int pthread_spinlock_t; 117typedef int pthread_barrier_t; 118typedef int pthread_barrierattr_t; 119typedef int jmp_buf; 120typedef int rlim_t; 121typedef int sa_family_t; 122typedef int sigjmp_buf; 123typedef int stack_t; 124typedef int siginfo_t; 125typedef int z_stream; 126 127 128typedef int int8_t; 129typedef int uint8_t; 130typedef int int16_t; 131typedef int uint16_t; 132typedef int int32_t; 133typedef int uint32_t; 134typedef int int64_t; 135typedef int uint64_t; 136 137 138typedef int int_least8_t; 139typedef int uint_least8_t; 140typedef int int_least16_t; 141typedef int uint_least16_t; 142typedef int int_least32_t; 143typedef int uint_least32_t; 144typedef int int_least64_t; 145typedef int uint_least64_t; 146 147 148typedef int int_fast8_t; 149typedef int uint_fast8_t; 150typedef int int_fast16_t; 151typedef int uint_fast16_t; 152typedef int int_fast32_t; 153typedef int uint_fast32_t; 154typedef int int_fast64_t; 155typedef int uint_fast64_t; 156 157 158typedef int intptr_t; 159typedef int uintptr_t; 160 161 162typedef int intmax_t; 163typedef int uintmax_t; 164 165 166typedef _Bool bool; 167 168 169typedef void* MirEGLNativeWindowType; 170typedef void* MirEGLNativeDisplayType; 171typedef struct MirConnection MirConnection; 172typedef struct MirSurface MirSurface; 173typedef struct MirSurfaceSpec MirSurfaceSpec; 174typedef struct MirScreencast MirScreencast; 175typedef struct MirPromptSession MirPromptSession; 176typedef struct MirBufferStream MirBufferStream; 177typedef struct MirPersistentId MirPersistentId; 178typedef struct MirBlob MirBlob; 179typedef struct MirDisplayConfig MirDisplayConfig; 180 181 182typedef struct xcb_connection_t xcb_connection_t; 183typedef uint32_t xcb_window_t; 184typedef uint32_t xcb_visualid_t; 185# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 186# 35 "src/redis-cli.c" 2 187# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 188# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 189# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 190# 36 "src/redis-cli.c" 2 191# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 192# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 193# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 194# 37 "src/redis-cli.c" 2 195# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 1 196# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 197# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 2 198# 38 "src/redis-cli.c" 2 199# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1 200# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 201# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2 202# 39 "src/redis-cli.c" 2 203# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 204# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 205# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 206# 40 "src/redis-cli.c" 2 207# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 1 208# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 209# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 2 210# 41 "src/redis-cli.c" 2 211# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1 212# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 213# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2 214# 42 "src/redis-cli.c" 2 215# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 1 216# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 217# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 218# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 219# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 220# 43 "src/redis-cli.c" 2 221# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 222# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 223# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 224# 44 "src/redis-cli.c" 2 225# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 1 226# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 227# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 2 228# 45 "src/redis-cli.c" 2 229# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1 230# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 231# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2 232# 46 "src/redis-cli.c" 2 233# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 1 234# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 235# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 2 236# 47 "src/redis-cli.c" 2 237# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1 238# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 239# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2 240# 48 "src/redis-cli.c" 2 241 242# 1 "deps/hiredis/hiredis.h" 1 243# 36 "deps/hiredis/hiredis.h" 244# 1 "deps/hiredis/read.h" 1 245# 35 "deps/hiredis/read.h" 246# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 247# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 248# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 249# 36 "deps/hiredis/read.h" 2 250# 63 "deps/hiredis/read.h" 251typedef struct redisReadTask { 252 int type; 253 int elements; 254 int idx; 255 void *obj; 256 struct redisReadTask *parent; 257 void *privdata; 258} redisReadTask; 259 260typedef struct redisReplyObjectFunctions { 261 void *(*createString)(const redisReadTask*, char*, size_t); 262 void *(*createArray)(const redisReadTask*, int); 263 void *(*createInteger)(const redisReadTask*, long long); 264 void *(*createNil)(const redisReadTask*); 265 void (*freeObject)(void*); 266} redisReplyObjectFunctions; 267 268typedef struct redisReader { 269 int err; 270 char errstr[128]; 271 272 char *buf; 273 size_t pos; 274 size_t len; 275 size_t maxbuf; 276 277 redisReadTask rstack[9]; 278 int ridx; 279 void *reply; 280 281 redisReplyObjectFunctions *fn; 282 void *privdata; 283} redisReader; 284 285 286redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); 287void redisReaderFree(redisReader *r); 288int redisReaderFeed(redisReader *r, const char *buf, size_t len); 289int redisReaderGetReply(redisReader *r, void **reply); 290# 37 "deps/hiredis/hiredis.h" 2 291# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 292# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 293# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 294# 38 "deps/hiredis/hiredis.h" 2 295# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 296# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 297# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 298# 39 "deps/hiredis/hiredis.h" 2 299# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 300# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 301# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 302# 40 "deps/hiredis/hiredis.h" 2 303# 1 "deps/hiredis/sds.h" 1 304# 38 "deps/hiredis/sds.h" 305# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 306# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 307# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 308# 39 "deps/hiredis/sds.h" 2 309# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 310# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 311# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 312# 40 "deps/hiredis/sds.h" 2 313# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 314# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 315# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 316# 41 "deps/hiredis/sds.h" 2 317 318typedef char *sds; 319 320 321 322struct sdshdr5 { 323 unsigned char flags; 324 char buf[]; 325}; 326struct sdshdr8 { 327 uint8_t len; 328 uint8_t alloc; 329 unsigned char flags; 330 char buf[]; 331}; 332struct sdshdr16 { 333 uint16_t len; 334 uint16_t alloc; 335 unsigned char flags; 336 char buf[]; 337}; 338struct sdshdr32 { 339 uint32_t len; 340 uint32_t alloc; 341 unsigned char flags; 342 char buf[]; 343}; 344struct sdshdr64 { 345 uint64_t len; 346 uint64_t alloc; 347 unsigned char flags; 348 char buf[]; 349}; 350# 86 "deps/hiredis/sds.h" 351static inline size_t sdslen(const sds s) { 352 unsigned char flags = s[-1]; 353 switch(flags&7) { 354 case 0: 355 return ((flags)>>3); 356 case 1: 357 return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len; 358 case 2: 359 return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len; 360 case 3: 361 return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len; 362 case 4: 363 return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len; 364 } 365 return 0; 366} 367 368static inline size_t sdsavail(const sds s) { 369 unsigned char flags = s[-1]; 370 switch(flags&7) { 371 case 0: { 372 return 0; 373 } 374 case 1: { 375 struct sdshdr8 *sh = (struct sdshdr8 *)((s)-(sizeof(struct sdshdr8)));; 376 return sh->alloc - sh->len; 377 } 378 case 2: { 379 struct sdshdr16 *sh = (struct sdshdr16 *)((s)-(sizeof(struct sdshdr16)));; 380 return sh->alloc - sh->len; 381 } 382 case 3: { 383 struct sdshdr32 *sh = (struct sdshdr32 *)((s)-(sizeof(struct sdshdr32)));; 384 return sh->alloc - sh->len; 385 } 386 case 4: { 387 struct sdshdr64 *sh = (struct sdshdr64 *)((s)-(sizeof(struct sdshdr64)));; 388 return sh->alloc - sh->len; 389 } 390 } 391 return 0; 392} 393 394static inline void sdssetlen(sds s, size_t newlen) { 395 unsigned char flags = s[-1]; 396 switch(flags&7) { 397 case 0: 398 { 399 unsigned char *fp = ((unsigned char*)s)-1; 400 *fp = 0 | (newlen << 3); 401 } 402 break; 403 case 1: 404 ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len = newlen; 405 break; 406 case 2: 407 ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len = newlen; 408 break; 409 case 3: 410 ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len = newlen; 411 break; 412 case 4: 413 ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len = newlen; 414 break; 415 } 416} 417 418static inline void sdsinclen(sds s, size_t inc) { 419 unsigned char flags = s[-1]; 420 switch(flags&7) { 421 case 0: 422 { 423 unsigned char *fp = ((unsigned char*)s)-1; 424 unsigned char newlen = ((flags)>>3)+inc; 425 *fp = 0 | (newlen << 3); 426 } 427 break; 428 case 1: 429 ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len += inc; 430 break; 431 case 2: 432 ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len += inc; 433 break; 434 case 3: 435 ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len += inc; 436 break; 437 case 4: 438 ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len += inc; 439 break; 440 } 441} 442 443 444static inline size_t sdsalloc(const sds s) { 445 unsigned char flags = s[-1]; 446 switch(flags&7) { 447 case 0: 448 return ((flags)>>3); 449 case 1: 450 return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc; 451 case 2: 452 return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc; 453 case 3: 454 return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc; 455 case 4: 456 return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc; 457 } 458 return 0; 459} 460 461static inline void sdssetalloc(sds s, size_t newlen) { 462 unsigned char flags = s[-1]; 463 switch(flags&7) { 464 case 0: 465 466 break; 467 case 1: 468 ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc = newlen; 469 break; 470 case 2: 471 ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc = newlen; 472 break; 473 case 3: 474 ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc = newlen; 475 break; 476 case 4: 477 ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc = newlen; 478 break; 479 } 480} 481 482sds sdsnewlen(const void *init, size_t initlen); 483sds sdsnew(const char *init); 484sds sdsempty(void); 485sds sdsdup(const sds s); 486void sdsfree(sds s); 487sds sdsgrowzero(sds s, size_t len); 488sds sdscatlen(sds s, const void *t, size_t len); 489sds sdscat(sds s, const char *t); 490sds sdscatsds(sds s, const sds t); 491sds sdscpylen(sds s, const char *t, size_t len); 492sds sdscpy(sds s, const char *t); 493 494sds sdscatvprintf(sds s, const char *fmt, va_list ap); 495 496sds sdscatprintf(sds s, const char *fmt, ...) 497 ; 498 499 500 501 502sds sdscatfmt(sds s, char const *fmt, ...); 503sds sdstrim(sds s, const char *cset); 504void sdsrange(sds s, int start, int end); 505void sdsupdatelen(sds s); 506void sdsclear(sds s); 507int sdscmp(const sds s1, const sds s2); 508sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); 509void sdsfreesplitres(sds *tokens, int count); 510void sdstolower(sds s); 511void sdstoupper(sds s); 512sds sdsfromlonglong(long long value); 513sds sdscatrepr(sds s, const char *p, size_t len); 514sds *sdssplitargs(const char *line, int *argc); 515sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); 516sds sdsjoin(char **argv, int argc, char *sep); 517sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); 518 519 520sds sdsMakeRoomFor(sds s, size_t addlen); 521void sdsIncrLen(sds s, int incr); 522sds sdsRemoveFreeSpace(sds s); 523size_t sdsAllocSize(sds s); 524void *sdsAllocPtr(sds s); 525 526 527 528 529 530void *sds_malloc(size_t size); 531void *sds_realloc(void *ptr, size_t size); 532void sds_free(void *ptr); 533# 41 "deps/hiredis/hiredis.h" 2 534# 112 "deps/hiredis/hiredis.h" 535typedef struct redisReply { 536 int type; 537 long long integer; 538 size_t len; 539 char *str; 540 size_t elements; 541 struct redisReply **element; 542} redisReply; 543 544redisReader *redisReaderCreate(void); 545 546 547void freeReplyObject(void *reply); 548 549 550int redisvFormatCommand(char **target, const char *format, va_list ap); 551int redisFormatCommand(char **target, const char *format, ...); 552int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); 553int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); 554void redisFreeCommand(char *cmd); 555void redisFreeSdsCommand(sds cmd); 556 557enum redisConnectionType { 558 REDIS_CONN_TCP, 559 REDIS_CONN_UNIX 560}; 561 562 563typedef struct redisContext { 564 int err; 565 char errstr[128]; 566 int fd; 567 int flags; 568 char *obuf; 569 redisReader *reader; 570 571 enum redisConnectionType connection_type; 572 struct timeval *timeout; 573 574 struct { 575 char *host; 576 char *source_addr; 577 int port; 578 } tcp; 579 580 struct { 581 char *path; 582 } unix_sock; 583 584} redisContext; 585 586redisContext *redisConnect(const char *ip, int port); 587redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); 588redisContext *redisConnectNonBlock(const char *ip, int port); 589redisContext *redisConnectBindNonBlock(const char *ip, int port, 590 const char *source_addr); 591redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, 592 const char *source_addr); 593redisContext *redisConnectUnix(const char *path); 594redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); 595redisContext *redisConnectUnixNonBlock(const char *path); 596redisContext *redisConnectFd(int fd); 597# 184 "deps/hiredis/hiredis.h" 598int redisReconnect(redisContext *c); 599 600int redisSetTimeout(redisContext *c, const struct timeval tv); 601int redisEnableKeepAlive(redisContext *c); 602void redisFree(redisContext *c); 603int redisFreeKeepFd(redisContext *c); 604int redisBufferRead(redisContext *c); 605int redisBufferWrite(redisContext *c, int *done); 606 607 608 609 610 611int redisGetReply(redisContext *c, void **reply); 612int redisGetReplyFromReader(redisContext *c, void **reply); 613 614 615 616int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); 617 618 619 620int redisvAppendCommand(redisContext *c, const char *format, va_list ap); 621int redisAppendCommand(redisContext *c, const char *format, ...); 622int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 623 624 625 626 627 628 629void *redisvCommand(redisContext *c, const char *format, va_list ap); 630void *redisCommand(redisContext *c, const char *format, ...); 631void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 632# 50 "src/redis-cli.c" 2 633# 1 "src/sds.h" 1 634# 51 "src/redis-cli.c" 2 635# 1 "src/zmalloc.h" 1 636# 75 "src/zmalloc.h" 637void *zmalloc(size_t size); 638void *zcalloc(size_t size); 639void *zrealloc(void *ptr, size_t size); 640void zfree(void *ptr); 641char *zstrdup(const char *s); 642size_t zmalloc_used_memory(void); 643void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); 644float zmalloc_get_fragmentation_ratio(size_t rss); 645size_t zmalloc_get_rss(void); 646size_t zmalloc_get_private_dirty(long pid); 647size_t zmalloc_get_smap_bytes_by_field(char *field, long pid); 648size_t zmalloc_get_memory_size(void); 649void zlibc_free(void *ptr); 650 651 652 653 654 655 656 657size_t zmalloc_size(void *ptr); 658# 52 "src/redis-cli.c" 2 659# 1 "deps/linenoise/linenoise.h" 1 660# 46 "deps/linenoise/linenoise.h" 661typedef struct linenoiseCompletions { 662 size_t len; 663 char **cvec; 664} linenoiseCompletions; 665 666typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); 667typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); 668typedef void(linenoiseFreeHintsCallback)(void *); 669void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); 670void linenoiseSetHintsCallback(linenoiseHintsCallback *); 671void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); 672void linenoiseAddCompletion(linenoiseCompletions *, const char *); 673 674char *linenoise(const char *prompt); 675void linenoiseFree(void *ptr); 676int linenoiseHistoryAdd(const char *line); 677int linenoiseHistorySetMaxLen(int len); 678int linenoiseHistorySave(const char *filename); 679int linenoiseHistoryLoad(const char *filename); 680void linenoiseClearScreen(void); 681void linenoiseSetMultiLine(int ml); 682void linenoisePrintKeyCodes(void); 683# 53 "src/redis-cli.c" 2 684# 1 "src/help.h" 1 685 686 687 688 689 690static char *commandGroups[] = { 691 "generic", 692 "string", 693 "list", 694 "set", 695 "sorted_set", 696 "hash", 697 "pubsub", 698 "transactions", 699 "connection", 700 "server", 701 "scripting", 702 "hyperloglog", 703 "cluster", 704 "geo" 705}; 706 707struct commandHelp { 708 char *name; 709 char *params; 710 char *summary; 711 int group; 712 char *since; 713} commandHelp[] = { 714 { "APPEND", 715 "key value", 716 "Append a value to a key", 717 1, 718 "2.0.0" }, 719 { "AUTH", 720 "password", 721 "Authenticate to the server", 722 8, 723 "1.0.0" }, 724 { "BGREWRITEAOF", 725 "-", 726 "Asynchronously rewrite the append-only file", 727 9, 728 "1.0.0" }, 729 { "BGSAVE", 730 "-", 731 "Asynchronously save the dataset to disk", 732 9, 733 "1.0.0" }, 734 { "BITCOUNT", 735 "key [start end]", 736 "Count set bits in a string", 737 1, 738 "2.6.0" }, 739 { "BITFIELD", 740 "key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]", 741 "Perform arbitrary bitfield integer operations on strings", 742 1, 743 "3.2.0" }, 744 { "BITOP", 745 "operation destkey key [key ...]", 746 "Perform bitwise operations between strings", 747 1, 748 "2.6.0" }, 749 { "BITPOS", 750 "key bit [start] [end]", 751 "Find first bit set or clear in a string", 752 1, 753 "2.8.7" }, 754 { "BLPOP", 755 "key [key ...] timeout", 756 "Remove and get the first element in a list, or block until one is available", 757 2, 758 "2.0.0" }, 759 { "BRPOP", 760 "key [key ...] timeout", 761 "Remove and get the last element in a list, or block until one is available", 762 2, 763 "2.0.0" }, 764 { "BRPOPLPUSH", 765 "source destination timeout", 766 "Pop a value from a list, push it to another list and return it; or block until one is available", 767 2, 768 "2.2.0" }, 769 { "CLIENT GETNAME", 770 "-", 771 "Get the current connection name", 772 9, 773 "2.6.9" }, 774 { "CLIENT KILL", 775 "[ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]", 776 "Kill the connection of a client", 777 9, 778 "2.4.0" }, 779 { "CLIENT LIST", 780 "-", 781 "Get the list of client connections", 782 9, 783 "2.4.0" }, 784 { "CLIENT PAUSE", 785 "timeout", 786 "Stop processing commands from clients for some time", 787 9, 788 "2.9.50" }, 789 { "CLIENT REPLY", 790 "ON|OFF|SKIP", 791 "Instruct the server whether to reply to commands", 792 9, 793 "3.2" }, 794 { "CLIENT SETNAME", 795 "connection-name", 796 "Set the current connection name", 797 9, 798 "2.6.9" }, 799 { "CLUSTER ADDSLOTS", 800 "slot [slot ...]", 801 "Assign new hash slots to receiving node", 802 12, 803 "3.0.0" }, 804 { "CLUSTER COUNT-FAILURE-REPORTS", 805 "node-id", 806 "Return the number of failure reports active for a given node", 807 12, 808 "3.0.0" }, 809 { "CLUSTER COUNTKEYSINSLOT", 810 "slot", 811 "Return the number of local keys in the specified hash slot", 812 12, 813 "3.0.0" }, 814 { "CLUSTER DELSLOTS", 815 "slot [slot ...]", 816 "Set hash slots as unbound in receiving node", 817 12, 818 "3.0.0" }, 819 { "CLUSTER FAILOVER", 820 "[FORCE|TAKEOVER]", 821 "Forces a slave to perform a manual failover of its master.", 822 12, 823 "3.0.0" }, 824 { "CLUSTER FORGET", 825 "node-id", 826 "Remove a node from the nodes table", 827 12, 828 "3.0.0" }, 829 { "CLUSTER GETKEYSINSLOT", 830 "slot count", 831 "Return local key names in the specified hash slot", 832 12, 833 "3.0.0" }, 834 { "CLUSTER INFO", 835 "-", 836 "Provides info about Redis Cluster node state", 837 12, 838 "3.0.0" }, 839 { "CLUSTER KEYSLOT", 840 "key", 841 "Returns the hash slot of the specified key", 842 12, 843 "3.0.0" }, 844 { "CLUSTER MEET", 845 "ip port", 846 "Force a node cluster to handshake with another node", 847 12, 848 "3.0.0" }, 849 { "CLUSTER NODES", 850 "-", 851 "Get Cluster config for the node", 852 12, 853 "3.0.0" }, 854 { "CLUSTER REPLICATE", 855 "node-id", 856 "Reconfigure a node as a slave of the specified master node", 857 12, 858 "3.0.0" }, 859 { "CLUSTER RESET", 860 "[HARD|SOFT]", 861 "Reset a Redis Cluster node", 862 12, 863 "3.0.0" }, 864 { "CLUSTER SAVECONFIG", 865 "-", 866 "Forces the node to save cluster state on disk", 867 12, 868 "3.0.0" }, 869 { "CLUSTER SET-CONFIG-EPOCH", 870 "config-epoch", 871 "Set the configuration epoch in a new node", 872 12, 873 "3.0.0" }, 874 { "CLUSTER SETSLOT", 875 "slot IMPORTING|MIGRATING|STABLE|NODE [node-id]", 876 "Bind a hash slot to a specific node", 877 12, 878 "3.0.0" }, 879 { "CLUSTER SLAVES", 880 "node-id", 881 "List slave nodes of the specified master node", 882 12, 883 "3.0.0" }, 884 { "CLUSTER SLOTS", 885 "-", 886 "Get array of Cluster slot to node mappings", 887 12, 888 "3.0.0" }, 889 { "COMMAND", 890 "-", 891 "Get array of Redis command details", 892 9, 893 "2.8.13" }, 894 { "COMMAND COUNT", 895 "-", 896 "Get total number of Redis commands", 897 9, 898 "2.8.13" }, 899 { "COMMAND GETKEYS", 900 "-", 901 "Extract keys given a full Redis command", 902 9, 903 "2.8.13" }, 904 { "COMMAND INFO", 905 "command-name [command-name ...]", 906 "Get array of specific Redis command details", 907 9, 908 "2.8.13" }, 909 { "CONFIG GET", 910 "parameter", 911 "Get the value of a configuration parameter", 912 9, 913 "2.0.0" }, 914 { "CONFIG RESETSTAT", 915 "-", 916 "Reset the stats returned by INFO", 917 9, 918 "2.0.0" }, 919 { "CONFIG REWRITE", 920 "-", 921 "Rewrite the configuration file with the in memory configuration", 922 9, 923 "2.8.0" }, 924 { "CONFIG SET", 925 "parameter value", 926 "Set a configuration parameter to the given value", 927 9, 928 "2.0.0" }, 929 { "DBSIZE", 930 "-", 931 "Return the number of keys in the selected database", 932 9, 933 "1.0.0" }, 934 { "DEBUG OBJECT", 935 "key", 936 "Get debugging information about a key", 937 9, 938 "1.0.0" }, 939 { "DEBUG SEGFAULT", 940 "-", 941 "Make the server crash", 942 9, 943 "1.0.0" }, 944 { "DECR", 945 "key", 946 "Decrement the integer value of a key by one", 947 1, 948 "1.0.0" }, 949 { "DECRBY", 950 "key decrement", 951 "Decrement the integer value of a key by the given number", 952 1, 953 "1.0.0" }, 954 { "DEL", 955 "key [key ...]", 956 "Delete a key", 957 0, 958 "1.0.0" }, 959 { "DISCARD", 960 "-", 961 "Discard all commands issued after MULTI", 962 7, 963 "2.0.0" }, 964 { "DUMP", 965 "key", 966 "Return a serialized version of the value stored at the specified key.", 967 0, 968 "2.6.0" }, 969 { "ECHO", 970 "message", 971 "Echo the given string", 972 8, 973 "1.0.0" }, 974 { "EVAL", 975 "script numkeys key [key ...] arg [arg ...]", 976 "Execute a Lua script server side", 977 10, 978 "2.6.0" }, 979 { "EVALSHA", 980 "sha1 numkeys key [key ...] arg [arg ...]", 981 "Execute a Lua script server side", 982 10, 983 "2.6.0" }, 984 { "EXEC", 985 "-", 986 "Execute all commands issued after MULTI", 987 7, 988 "1.2.0" }, 989 { "EXISTS", 990 "key [key ...]", 991 "Determine if a key exists", 992 0, 993 "1.0.0" }, 994 { "EXPIRE", 995 "key seconds", 996 "Set a key's time to live in seconds", 997 0, 998 "1.0.0" }, 999 { "EXPIREAT", 1000 "key timestamp", 1001 "Set the expiration for a key as a UNIX timestamp", 1002 0, 1003 "1.2.0" }, 1004 { "FLUSHALL", 1005 "-", 1006 "Remove all keys from all databases", 1007 9, 1008 "1.0.0" }, 1009 { "FLUSHDB", 1010 "-", 1011 "Remove all keys from the current database", 1012 9, 1013 "1.0.0" }, 1014 { "GEOADD", 1015 "key longitude latitude member [longitude latitude member ...]", 1016 "Add one or more geospatial items in the geospatial index represented using a sorted set", 1017 13, 1018 "3.2.0" }, 1019 { "GEODIST", 1020 "key member1 member2 [unit]", 1021 "Returns the distance between two members of a geospatial index", 1022 13, 1023 "3.2.0" }, 1024 { "GEOHASH", 1025 "key member [member ...]", 1026 "Returns members of a geospatial index as standard geohash strings", 1027 13, 1028 "3.2.0" }, 1029 { "GEOPOS", 1030 "key member [member ...]", 1031 "Returns longitude and latitude of members of a geospatial index", 1032 13, 1033 "3.2.0" }, 1034 { "GEORADIUS", 1035 "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", 1036 "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", 1037 13, 1038 "3.2.0" }, 1039 { "GEORADIUSBYMEMBER", 1040 "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", 1041 "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", 1042 13, 1043 "3.2.0" }, 1044 { "GET", 1045 "key", 1046 "Get the value of a key", 1047 1, 1048 "1.0.0" }, 1049 { "GETBIT", 1050 "key offset", 1051 "Returns the bit value at offset in the string value stored at key", 1052 1, 1053 "2.2.0" }, 1054 { "GETRANGE", 1055 "key start end", 1056 "Get a substring of the string stored at a key", 1057 1, 1058 "2.4.0" }, 1059 { "GETSET", 1060 "key value", 1061 "Set the string value of a key and return its old value", 1062 1, 1063 "1.0.0" }, 1064 { "HDEL", 1065 "key field [field ...]", 1066 "Delete one or more hash fields", 1067 5, 1068 "2.0.0" }, 1069 { "HEXISTS", 1070 "key field", 1071 "Determine if a hash field exists", 1072 5, 1073 "2.0.0" }, 1074 { "HGET", 1075 "key field", 1076 "Get the value of a hash field", 1077 5, 1078 "2.0.0" }, 1079 { "HGETALL", 1080 "key", 1081 "Get all the fields and values in a hash", 1082 5, 1083 "2.0.0" }, 1084 { "HINCRBY", 1085 "key field increment", 1086 "Increment the integer value of a hash field by the given number", 1087 5, 1088 "2.0.0" }, 1089 { "HINCRBYFLOAT", 1090 "key field increment", 1091 "Increment the float value of a hash field by the given amount", 1092 5, 1093 "2.6.0" }, 1094 { "HKEYS", 1095 "key", 1096 "Get all the fields in a hash", 1097 5, 1098 "2.0.0" }, 1099 { "HLEN", 1100 "key", 1101 "Get the number of fields in a hash", 1102 5, 1103 "2.0.0" }, 1104 { "HMGET", 1105 "key field [field ...]", 1106 "Get the values of all the given hash fields", 1107 5, 1108 "2.0.0" }, 1109 { "HMSET", 1110 "key field value [field value ...]", 1111 "Set multiple hash fields to multiple values", 1112 5, 1113 "2.0.0" }, 1114 { "HSCAN", 1115 "key cursor [MATCH pattern] [COUNT count]", 1116 "Incrementally iterate hash fields and associated values", 1117 5, 1118 "2.8.0" }, 1119 { "HSET", 1120 "key field value", 1121 "Set the string value of a hash field", 1122 5, 1123 "2.0.0" }, 1124 { "HSETNX", 1125 "key field value", 1126 "Set the value of a hash field, only if the field does not exist", 1127 5, 1128 "2.0.0" }, 1129 { "HSTRLEN", 1130 "key field", 1131 "Get the length of the value of a hash field", 1132 5, 1133 "3.2.0" }, 1134 { "HVALS", 1135 "key", 1136 "Get all the values in a hash", 1137 5, 1138 "2.0.0" }, 1139 { "INCR", 1140 "key", 1141 "Increment the integer value of a key by one", 1142 1, 1143 "1.0.0" }, 1144 { "INCRBY", 1145 "key increment", 1146 "Increment the integer value of a key by the given amount", 1147 1, 1148 "1.0.0" }, 1149 { "INCRBYFLOAT", 1150 "key increment", 1151 "Increment the float value of a key by the given amount", 1152 1, 1153 "2.6.0" }, 1154 { "INFO", 1155 "[section]", 1156 "Get information and statistics about the server", 1157 9, 1158 "1.0.0" }, 1159 { "KEYS", 1160 "pattern", 1161 "Find all keys matching the given pattern", 1162 0, 1163 "1.0.0" }, 1164 { "LASTSAVE", 1165 "-", 1166 "Get the UNIX time stamp of the last successful save to disk", 1167 9, 1168 "1.0.0" }, 1169 { "LINDEX", 1170 "key index", 1171 "Get an element from a list by its index", 1172 2, 1173 "1.0.0" }, 1174 { "LINSERT", 1175 "key BEFORE|AFTER pivot value", 1176 "Insert an element before or after another element in a list", 1177 2, 1178 "2.2.0" }, 1179 { "LLEN", 1180 "key", 1181 "Get the length of a list", 1182 2, 1183 "1.0.0" }, 1184 { "LPOP", 1185 "key", 1186 "Remove and get the first element in a list", 1187 2, 1188 "1.0.0" }, 1189 { "LPUSH", 1190 "key value [value ...]", 1191 "Prepend one or multiple values to a list", 1192 2, 1193 "1.0.0" }, 1194 { "LPUSHX", 1195 "key value", 1196 "Prepend a value to a list, only if the list exists", 1197 2, 1198 "2.2.0" }, 1199 { "LRANGE", 1200 "key start stop", 1201 "Get a range of elements from a list", 1202 2, 1203 "1.0.0" }, 1204 { "LREM", 1205 "key count value", 1206 "Remove elements from a list", 1207 2, 1208 "1.0.0" }, 1209 { "LSET", 1210 "key index value", 1211 "Set the value of an element in a list by its index", 1212 2, 1213 "1.0.0" }, 1214 { "LTRIM", 1215 "key start stop", 1216 "Trim a list to the specified range", 1217 2, 1218 "1.0.0" }, 1219 { "MGET", 1220 "key [key ...]", 1221 "Get the values of all the given keys", 1222 1, 1223 "1.0.0" }, 1224 { "MIGRATE", 1225 "host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]", 1226 "Atomically transfer a key from a Redis instance to another one.", 1227 0, 1228 "2.6.0" }, 1229 { "MONITOR", 1230 "-", 1231 "Listen for all requests received by the server in real time", 1232 9, 1233 "1.0.0" }, 1234 { "MOVE", 1235 "key db", 1236 "Move a key to another database", 1237 0, 1238 "1.0.0" }, 1239 { "MSET", 1240 "key value [key value ...]", 1241 "Set multiple keys to multiple values", 1242 1, 1243 "1.0.1" }, 1244 { "MSETNX", 1245 "key value [key value ...]", 1246 "Set multiple keys to multiple values, only if none of the keys exist", 1247 1, 1248 "1.0.1" }, 1249 { "MULTI", 1250 "-", 1251 "Mark the start of a transaction block", 1252 7, 1253 "1.2.0" }, 1254 { "OBJECT", 1255 "subcommand [arguments [arguments ...]]", 1256 "Inspect the internals of Redis objects", 1257 0, 1258 "2.2.3" }, 1259 { "PERSIST", 1260 "key", 1261 "Remove the expiration from a key", 1262 0, 1263 "2.2.0" }, 1264 { "PEXPIRE", 1265 "key milliseconds", 1266 "Set a key's time to live in milliseconds", 1267 0, 1268 "2.6.0" }, 1269 { "PEXPIREAT", 1270 "key milliseconds-timestamp", 1271 "Set the expiration for a key as a UNIX timestamp specified in milliseconds", 1272 0, 1273 "2.6.0" }, 1274 { "PFADD", 1275 "key element [element ...]", 1276 "Adds the specified elements to the specified HyperLogLog.", 1277 11, 1278 "2.8.9" }, 1279 { "PFCOUNT", 1280 "key [key ...]", 1281 "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", 1282 11, 1283 "2.8.9" }, 1284 { "PFMERGE", 1285 "destkey sourcekey [sourcekey ...]", 1286 "Merge N different HyperLogLogs into a single one.", 1287 11, 1288 "2.8.9" }, 1289 { "PING", 1290 "[message]", 1291 "Ping the server", 1292 8, 1293 "1.0.0" }, 1294 { "PSETEX", 1295 "key milliseconds value", 1296 "Set the value and expiration in milliseconds of a key", 1297 1, 1298 "2.6.0" }, 1299 { "PSUBSCRIBE", 1300 "pattern [pattern ...]", 1301 "Listen for messages published to channels matching the given patterns", 1302 6, 1303 "2.0.0" }, 1304 { "PTTL", 1305 "key", 1306 "Get the time to live for a key in milliseconds", 1307 0, 1308 "2.6.0" }, 1309 { "PUBLISH", 1310 "channel message", 1311 "Post a message to a channel", 1312 6, 1313 "2.0.0" }, 1314 { "PUBSUB", 1315 "subcommand [argument [argument ...]]", 1316 "Inspect the state of the Pub/Sub subsystem", 1317 6, 1318 "2.8.0" }, 1319 { "PUNSUBSCRIBE", 1320 "[pattern [pattern ...]]", 1321 "Stop listening for messages posted to channels matching the given patterns", 1322 6, 1323 "2.0.0" }, 1324 { "QUIT", 1325 "-", 1326 "Close the connection", 1327 8, 1328 "1.0.0" }, 1329 { "RANDOMKEY", 1330 "-", 1331 "Return a random key from the keyspace", 1332 0, 1333 "1.0.0" }, 1334 { "READONLY", 1335 "-", 1336 "Enables read queries for a connection to a cluster slave node", 1337 12, 1338 "3.0.0" }, 1339 { "READWRITE", 1340 "-", 1341 "Disables read queries for a connection to a cluster slave node", 1342 12, 1343 "3.0.0" }, 1344 { "RENAME", 1345 "key newkey", 1346 "Rename a key", 1347 0, 1348 "1.0.0" }, 1349 { "RENAMENX", 1350 "key newkey", 1351 "Rename a key, only if the new key does not exist", 1352 0, 1353 "1.0.0" }, 1354 { "RESTORE", 1355 "key ttl serialized-value [REPLACE]", 1356 "Create a key using the provided serialized value, previously obtained using DUMP.", 1357 0, 1358 "2.6.0" }, 1359 { "ROLE", 1360 "-", 1361 "Return the role of the instance in the context of replication", 1362 9, 1363 "2.8.12" }, 1364 { "RPOP", 1365 "key", 1366 "Remove and get the last element in a list", 1367 2, 1368 "1.0.0" }, 1369 { "RPOPLPUSH", 1370 "source destination", 1371 "Remove the last element in a list, prepend it to another list and return it", 1372 2, 1373 "1.2.0" }, 1374 { "RPUSH", 1375 "key value [value ...]", 1376 "Append one or multiple values to a list", 1377 2, 1378 "1.0.0" }, 1379 { "RPUSHX", 1380 "key value", 1381 "Append a value to a list, only if the list exists", 1382 2, 1383 "2.2.0" }, 1384 { "SADD", 1385 "key member [member ...]", 1386 "Add one or more members to a set", 1387 3, 1388 "1.0.0" }, 1389 { "SAVE", 1390 "-", 1391 "Synchronously save the dataset to disk", 1392 9, 1393 "1.0.0" }, 1394 { "SCAN", 1395 "cursor [MATCH pattern] [COUNT count]", 1396 "Incrementally iterate the keys space", 1397 0, 1398 "2.8.0" }, 1399 { "SCARD", 1400 "key", 1401 "Get the number of members in a set", 1402 3, 1403 "1.0.0" }, 1404 { "SCRIPT DEBUG", 1405 "YES|SYNC|NO", 1406 "Set the debug mode for executed scripts.", 1407 10, 1408 "3.2.0" }, 1409 { "SCRIPT EXISTS", 1410 "script [script ...]", 1411 "Check existence of scripts in the script cache.", 1412 10, 1413 "2.6.0" }, 1414 { "SCRIPT FLUSH", 1415 "-", 1416 "Remove all the scripts from the script cache.", 1417 10, 1418 "2.6.0" }, 1419 { "SCRIPT KILL", 1420 "-", 1421 "Kill the script currently in execution.", 1422 10, 1423 "2.6.0" }, 1424 { "SCRIPT LOAD", 1425 "script", 1426 "Load the specified Lua script into the script cache.", 1427 10, 1428 "2.6.0" }, 1429 { "SDIFF", 1430 "key [key ...]", 1431 "Subtract multiple sets", 1432 3, 1433 "1.0.0" }, 1434 { "SDIFFSTORE", 1435 "destination key [key ...]", 1436 "Subtract multiple sets and store the resulting set in a key", 1437 3, 1438 "1.0.0" }, 1439 { "SELECT", 1440 "index", 1441 "Change the selected database for the current connection", 1442 8, 1443 "1.0.0" }, 1444 { "SET", 1445 "key value [EX seconds] [PX milliseconds] [NX|XX]", 1446 "Set the string value of a key", 1447 1, 1448 "1.0.0" }, 1449 { "SETBIT", 1450 "key offset value", 1451 "Sets or clears the bit at offset in the string value stored at key", 1452 1, 1453 "2.2.0" }, 1454 { "SETEX", 1455 "key seconds value", 1456 "Set the value and expiration of a key", 1457 1, 1458 "2.0.0" }, 1459 { "SETNX", 1460 "key value", 1461 "Set the value of a key, only if the key does not exist", 1462 1, 1463 "1.0.0" }, 1464 { "SETRANGE", 1465 "key offset value", 1466 "Overwrite part of a string at key starting at the specified offset", 1467 1, 1468 "2.2.0" }, 1469 { "SHUTDOWN", 1470 "[NOSAVE|SAVE]", 1471 "Synchronously save the dataset to disk and then shut down the server", 1472 9, 1473 "1.0.0" }, 1474 { "SINTER", 1475 "key [key ...]", 1476 "Intersect multiple sets", 1477 3, 1478 "1.0.0" }, 1479 { "SINTERSTORE", 1480 "destination key [key ...]", 1481 "Intersect multiple sets and store the resulting set in a key", 1482 3, 1483 "1.0.0" }, 1484 { "SISMEMBER", 1485 "key member", 1486 "Determine if a given value is a member of a set", 1487 3, 1488 "1.0.0" }, 1489 { "SLAVEOF", 1490 "host port", 1491 "Make the server a slave of another instance, or promote it as master", 1492 9, 1493 "1.0.0" }, 1494 { "SLOWLOG", 1495 "subcommand [argument]", 1496 "Manages the Redis slow queries log", 1497 9, 1498 "2.2.12" }, 1499 { "SMEMBERS", 1500 "key", 1501 "Get all the members in a set", 1502 3, 1503 "1.0.0" }, 1504 { "SMOVE", 1505 "source destination member", 1506 "Move a member from one set to another", 1507 3, 1508 "1.0.0" }, 1509 { "SORT", 1510 "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", 1511 "Sort the elements in a list, set or sorted set", 1512 0, 1513 "1.0.0" }, 1514 { "SPOP", 1515 "key [count]", 1516 "Remove and return one or multiple random members from a set", 1517 3, 1518 "1.0.0" }, 1519 { "SRANDMEMBER", 1520 "key [count]", 1521 "Get one or multiple random members from a set", 1522 3, 1523 "1.0.0" }, 1524 { "SREM", 1525 "key member [member ...]", 1526 "Remove one or more members from a set", 1527 3, 1528 "1.0.0" }, 1529 { "SSCAN", 1530 "key cursor [MATCH pattern] [COUNT count]", 1531 "Incrementally iterate Set elements", 1532 3, 1533 "2.8.0" }, 1534 { "STRLEN", 1535 "key", 1536 "Get the length of the value stored in a key", 1537 1, 1538 "2.2.0" }, 1539 { "SUBSCRIBE", 1540 "channel [channel ...]", 1541 "Listen for messages published to the given channels", 1542 6, 1543 "2.0.0" }, 1544 { "SUNION", 1545 "key [key ...]", 1546 "Add multiple sets", 1547 3, 1548 "1.0.0" }, 1549 { "SUNIONSTORE", 1550 "destination key [key ...]", 1551 "Add multiple sets and store the resulting set in a key", 1552 3, 1553 "1.0.0" }, 1554 { "SYNC", 1555 "-", 1556 "Internal command used for replication", 1557 9, 1558 "1.0.0" }, 1559 { "TIME", 1560 "-", 1561 "Return the current server time", 1562 9, 1563 "2.6.0" }, 1564 { "TTL", 1565 "key", 1566 "Get the time to live for a key", 1567 0, 1568 "1.0.0" }, 1569 { "TYPE", 1570 "key", 1571 "Determine the type stored at key", 1572 0, 1573 "1.0.0" }, 1574 { "UNSUBSCRIBE", 1575 "[channel [channel ...]]", 1576 "Stop listening for messages posted to the given channels", 1577 6, 1578 "2.0.0" }, 1579 { "UNWATCH", 1580 "-", 1581 "Forget about all watched keys", 1582 7, 1583 "2.2.0" }, 1584 { "WAIT", 1585 "numslaves timeout", 1586 "Wait for the synchronous replication of all the write commands sent in the context of the current connection", 1587 0, 1588 "3.0.0" }, 1589 { "WATCH", 1590 "key [key ...]", 1591 "Watch the given keys to determine execution of the MULTI/EXEC block", 1592 7, 1593 "2.2.0" }, 1594 { "ZADD", 1595 "key [NX|XX] [CH] [INCR] score member [score member ...]", 1596 "Add one or more members to a sorted set, or update its score if it already exists", 1597 4, 1598 "1.2.0" }, 1599 { "ZCARD", 1600 "key", 1601 "Get the number of members in a sorted set", 1602 4, 1603 "1.2.0" }, 1604 { "ZCOUNT", 1605 "key min max", 1606 "Count the members in a sorted set with scores within the given values", 1607 4, 1608 "2.0.0" }, 1609 { "ZINCRBY", 1610 "key increment member", 1611 "Increment the score of a member in a sorted set", 1612 4, 1613 "1.2.0" }, 1614 { "ZINTERSTORE", 1615 "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", 1616 "Intersect multiple sorted sets and store the resulting sorted set in a new key", 1617 4, 1618 "2.0.0" }, 1619 { "ZLEXCOUNT", 1620 "key min max", 1621 "Count the number of members in a sorted set between a given lexicographical range", 1622 4, 1623 "2.8.9" }, 1624 { "ZRANGE", 1625 "key start stop [WITHSCORES]", 1626 "Return a range of members in a sorted set, by index", 1627 4, 1628 "1.2.0" }, 1629 { "ZRANGEBYLEX", 1630 "key min max [LIMIT offset count]", 1631 "Return a range of members in a sorted set, by lexicographical range", 1632 4, 1633 "2.8.9" }, 1634 { "ZRANGEBYSCORE", 1635 "key min max [WITHSCORES] [LIMIT offset count]", 1636 "Return a range of members in a sorted set, by score", 1637 4, 1638 "1.0.5" }, 1639 { "ZRANK", 1640 "key member", 1641 "Determine the index of a member in a sorted set", 1642 4, 1643 "2.0.0" }, 1644 { "ZREM", 1645 "key member [member ...]", 1646 "Remove one or more members from a sorted set", 1647 4, 1648 "1.2.0" }, 1649 { "ZREMRANGEBYLEX", 1650 "key min max", 1651 "Remove all members in a sorted set between the given lexicographical range", 1652 4, 1653 "2.8.9" }, 1654 { "ZREMRANGEBYRANK", 1655 "key start stop", 1656 "Remove all members in a sorted set within the given indexes", 1657 4, 1658 "2.0.0" }, 1659 { "ZREMRANGEBYSCORE", 1660 "key min max", 1661 "Remove all members in a sorted set within the given scores", 1662 4, 1663 "1.2.0" }, 1664 { "ZREVRANGE", 1665 "key start stop [WITHSCORES]", 1666 "Return a range of members in a sorted set, by index, with scores ordered from high to low", 1667 4, 1668 "1.2.0" }, 1669 { "ZREVRANGEBYLEX", 1670 "key max min [LIMIT offset count]", 1671 "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", 1672 4, 1673 "2.8.9" }, 1674 { "ZREVRANGEBYSCORE", 1675 "key max min [WITHSCORES] [LIMIT offset count]", 1676 "Return a range of members in a sorted set, by score, with scores ordered from high to low", 1677 4, 1678 "2.2.0" }, 1679 { "ZREVRANK", 1680 "key member", 1681 "Determine the index of a member in a sorted set, with scores ordered from high to low", 1682 4, 1683 "2.0.0" }, 1684 { "ZSCAN", 1685 "key cursor [MATCH pattern] [COUNT count]", 1686 "Incrementally iterate sorted sets elements and associated scores", 1687 4, 1688 "2.8.0" }, 1689 { "ZSCORE", 1690 "key member", 1691 "Get the score associated with the given member in a sorted set", 1692 4, 1693 "1.2.0" }, 1694 { "ZUNIONSTORE", 1695 "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", 1696 "Add multiple sorted sets and store the resulting sorted set in a new key", 1697 4, 1698 "2.0.0" } 1699}; 1700# 54 "src/redis-cli.c" 2 1701# 1 "src/anet.h" 1 1702# 34 "src/anet.h" 1703# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 1704# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 1705# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 1706# 35 "src/anet.h" 2 1707# 52 "src/anet.h" 1708int anetTcpConnect(char *err, char *addr, int port); 1709int anetTcpNonBlockConnect(char *err, char *addr, int port); 1710int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr); 1711int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr); 1712int anetUnixConnect(char *err, char *path); 1713int anetUnixNonBlockConnect(char *err, char *path); 1714int anetRead(int fd, char *buf, int count); 1715int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len); 1716int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len); 1717int anetTcpServer(char *err, int port, char *bindaddr, int backlog); 1718int anetTcp6Server(char *err, int port, char *bindaddr, int backlog); 1719int anetUnixServer(char *err, char *path, mode_t perm, int backlog); 1720int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port); 1721int anetUnixAccept(char *err, int serversock); 1722int anetWrite(int fd, char *buf, int count); 1723int anetNonBlock(char *err, int fd); 1724int anetBlock(char *err, int fd); 1725int anetEnableTcpNoDelay(char *err, int fd); 1726int anetDisableTcpNoDelay(char *err, int fd); 1727int anetTcpKeepAlive(char *err, int fd); 1728int anetSendTimeout(char *err, int fd, long long ms); 1729int anetPeerToString(int fd, char *ip, size_t ip_len, int *port); 1730int anetKeepAlive(char *err, int fd, int interval); 1731int anetSockName(int fd, char *ip, size_t ip_len, int *port); 1732int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); 1733int anetFormatPeer(int fd, char *fmt, size_t fmt_len); 1734int anetFormatSock(int fd, char *fmt, size_t fmt_len); 1735# 55 "src/redis-cli.c" 2 1736# 1 "src/ae.h" 1 1737# 36 "src/ae.h" 1738# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 1739# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 1740# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 1741# 37 "src/ae.h" 2 1742# 57 "src/ae.h" 1743struct aeEventLoop; 1744 1745 1746typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); 1747typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); 1748typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); 1749typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); 1750 1751 1752typedef struct aeFileEvent { 1753 int mask; 1754 aeFileProc *rfileProc; 1755 aeFileProc *wfileProc; 1756 void *clientData; 1757} aeFileEvent; 1758 1759 1760typedef struct aeTimeEvent { 1761 long long id; 1762 long when_sec; 1763 long when_ms; 1764 aeTimeProc *timeProc; 1765 aeEventFinalizerProc *finalizerProc; 1766 void *clientData; 1767 struct aeTimeEvent *next; 1768} aeTimeEvent; 1769 1770 1771typedef struct aeFiredEvent { 1772 int fd; 1773 int mask; 1774} aeFiredEvent; 1775 1776 1777typedef struct aeEventLoop { 1778 int maxfd; 1779 int setsize; 1780 long long timeEventNextId; 1781 time_t lastTime; 1782 aeFileEvent *events; 1783 aeFiredEvent *fired; 1784 aeTimeEvent *timeEventHead; 1785 int stop; 1786 void *apidata; 1787 aeBeforeSleepProc *beforesleep; 1788 aeBeforeSleepProc *aftersleep; 1789} aeEventLoop; 1790 1791 1792aeEventLoop *aeCreateEventLoop(int setsize); 1793void aeDeleteEventLoop(aeEventLoop *eventLoop); 1794void aeStop(aeEventLoop *eventLoop); 1795int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, 1796 aeFileProc *proc, void *clientData); 1797void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); 1798int aeGetFileEvents(aeEventLoop *eventLoop, int fd); 1799long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, 1800 aeTimeProc *proc, void *clientData, 1801 aeEventFinalizerProc *finalizerProc); 1802int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); 1803int aeProcessEvents(aeEventLoop *eventLoop, int flags); 1804int aeWait(int fd, int mask, long long milliseconds); 1805void aeMain(aeEventLoop *eventLoop); 1806char *aeGetApiName(void); 1807void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); 1808void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep); 1809int aeGetSetSize(aeEventLoop *eventLoop); 1810int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); 1811# 56 "src/redis-cli.c" 2 1812# 70 "src/redis-cli.c" 1813int spectrum_palette_color_size = 19; 1814int spectrum_palette_color[] = {0,233,234,235,237,239,241,243,245,247,144,143,142,184,226,214,208,202,196}; 1815 1816int spectrum_palette_mono_size = 13; 1817int spectrum_palette_mono[] = {0,233,234,235,237,239,241,243,245,247,249,251,253}; 1818 1819 1820int *spectrum_palette; 1821int spectrum_palette_size; 1822 1823static redisContext *context; 1824static struct config { 1825 char *hostip; 1826 int hostport; 1827 char *hostsocket; 1828 long repeat; 1829 long interval; 1830 int dbnum; 1831 int interactive; 1832 int shutdown; 1833 int monitor_mode; 1834 int pubsub_mode; 1835 int latency_mode; 1836 int latency_dist_mode; 1837 int latency_history; 1838 int lru_test_mode; 1839 long long lru_test_sample_size; 1840 int cluster_mode; 1841 int cluster_reissue_command; 1842 int slave_mode; 1843 int pipe_mode; 1844 int pipe_timeout; 1845 int getrdb_mode; 1846 int stat_mode; 1847 int scan_mode; 1848 int intrinsic_latency_mode; 1849 int intrinsic_latency_duration; 1850 char *pattern; 1851 char *rdb_filename; 1852 int bigkeys; 1853 int hotkeys; 1854 int stdinarg; 1855 char *auth; 1856 int output; 1857 sds mb_delim; 1858 char prompt[128]; 1859 char *eval; 1860 int eval_ldb; 1861 int eval_ldb_sync; 1862 int eval_ldb_end; 1863 int enable_ldb_on_eval; 1864 int last_cmd_type; 1865} config; 1866 1867 1868static struct pref { 1869 int hints; 1870} pref; 1871 1872static volatile sig_atomic_t force_cancel_loop = 0; 1873static void usage(void); 1874static void slaveMode(void); 1875char *redisGitSHA1(void); 1876char *redisGitDirty(void); 1877static int cliConnect(int force); 1878 1879 1880 1881 1882 1883static long long ustime(void) { 1884 struct timeval tv; 1885 long long ust; 1886 1887 gettimeofday(&tv, 0); 1888 ust = ((long long)tv.tv_sec)*1000000; 1889 ust += tv.tv_usec; 1890 return ust; 1891} 1892 1893static long long mstime(void) { 1894 return ustime()/1000; 1895} 1896 1897static void cliRefreshPrompt(void) { 1898 int len; 1899 1900 if (config.eval_ldb) return; 1901 if (config.hostsocket != 0) 1902 len = snprintf(config.prompt,sizeof(config.prompt),"redis %s", 1903 config.hostsocket); 1904 else 1905 len = anetFormatAddr(config.prompt, sizeof(config.prompt), 1906 config.hostip, config.hostport); 1907 1908 if (config.dbnum != 0) 1909 len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]", 1910 config.dbnum); 1911 snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); 1912} 1913# 179 "src/redis-cli.c" 1914static sds getDotfilePath(char *envoverride, char *dotfilename) { 1915 char *path = 0; 1916 sds dotPath = 0; 1917 1918 1919 path = getenv(envoverride); 1920 if (path != 0 && *path != '\0') { 1921 if (!strcmp("/dev/null", path)) { 1922 return 0; 1923 } 1924 1925 1926 dotPath = sdsnew(path); 1927 } else { 1928 char *home = getenv("HOME"); 1929 if (home != 0 && *home != '\0') { 1930 1931 dotPath = sdscatprintf(sdsempty(), "%s/%s", home, dotfilename); 1932 } 1933 } 1934 return dotPath; 1935} 1936 1937 1938 1939 1940 1941 1942static sds percentDecode(const char *pe, size_t len) { 1943 const char *end = pe + len; 1944 sds ret = sdsempty(); 1945 const char *curr = pe; 1946 1947 while (curr < end) { 1948 if (*curr == '%') { 1949 if ((end - curr) < 2) { 1950 fprintf(stderr, "Incomplete URI encoding\n"); 1951 exit(1); 1952 } 1953 1954 char h = tolower(*(++curr)); 1955 char l = tolower(*(++curr)); 1956 if (!(isdigit(h) || (h >= 'a' && h <= 'f')) || !(isdigit(l) || (l >= 'a' && l <= 'f'))) { 1957 fprintf(stderr, "Illegal character in URI encoding\n"); 1958 exit(1); 1959 } 1960 char c = (((isdigit(h) ? h - '0' : h - 'a' + 10) << 4) + (isdigit(l) ? l - '0' : l - 'a' + 10)); 1961 ret = sdscatlen(ret, &c, 1); 1962 curr++; 1963 } else { 1964 ret = sdscatlen(ret, curr++, 1); 1965 } 1966 } 1967 1968 return ret; 1969} 1970# 244 "src/redis-cli.c" 1971static void parseRedisUri(const char *uri) { 1972 1973 const char *scheme = "redis://"; 1974 const char *curr = uri; 1975 const char *end = uri + strlen(uri); 1976 const char *userinfo, *username, *port, *host, *path; 1977 1978 1979 if (strncasecmp(scheme, curr, strlen(scheme))) { 1980 fprintf(stderr,"Invalid URI scheme\n"); 1981 exit(1); 1982 } 1983 curr += strlen(scheme); 1984 if (curr == end) return; 1985 1986 1987 if ((userinfo = strchr(curr,'@'))) { 1988 if ((username = strchr(curr, ':')) && username < userinfo) { 1989 1990 curr = username + 1; 1991 } 1992 1993 config.auth = percentDecode(curr, userinfo - curr); 1994 curr = userinfo + 1; 1995 } 1996 if (curr == end) return; 1997 1998 1999 path = strchr(curr, '/'); 2000 if (*curr != '/') { 2001 host = path ? path - 1 : end; 2002 if ((port = strchr(curr, ':'))) { 2003 config.hostport = atoi(port + 1); 2004 host = port - 1; 2005 } 2006 config.hostip = sdsnewlen(curr, host - curr + 1); 2007 } 2008 curr = path ? path + 1 : end; 2009 if (curr == end) return; 2010 2011 2012 config.dbnum = atoi(curr); 2013} 2014# 295 "src/redis-cli.c" 2015typedef struct { 2016 int type; 2017 int argc; 2018 sds *argv; 2019 sds full; 2020 2021 2022 struct commandHelp *org; 2023} helpEntry; 2024 2025static helpEntry *helpEntries; 2026static int helpEntriesLen; 2027 2028static sds cliVersion(void) { 2029 sds version; 2030 version = sdscatprintf(sdsempty(), "%s", "4.0.8"); 2031 2032 2033 if (strtoll(redisGitSHA1(),0,16)) { 2034 version = sdscatprintf(version, " (git:%s", redisGitSHA1()); 2035 if (strtoll(redisGitDirty(),0,10)) 2036 version = sdscatprintf(version, "-dirty"); 2037 version = sdscat(version, ")"); 2038 } 2039 return version; 2040} 2041 2042static void cliInitHelp(void) { 2043 int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp); 2044 int groupslen = sizeof(commandGroups)/sizeof(char*); 2045 int i, len, pos = 0; 2046 helpEntry tmp; 2047 2048 helpEntriesLen = len = commandslen+groupslen; 2049 helpEntries = zmalloc(sizeof(helpEntry)*len); 2050 2051 for (i = 0; i < groupslen; i++) { 2052 tmp.argc = 1; 2053 tmp.argv = zmalloc(sizeof(sds)); 2054 tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]); 2055 tmp.full = tmp.argv[0]; 2056 tmp.type = 2; 2057 tmp.org = 0; 2058 helpEntries[pos++] = tmp; 2059 } 2060 2061 for (i = 0; i < commandslen; i++) { 2062 tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc); 2063 tmp.full = sdsnew(commandHelp[i].name); 2064 tmp.type = 1; 2065 tmp.org = &commandHelp[i]; 2066 helpEntries[pos++] = tmp; 2067 } 2068} 2069 2070 2071 2072 2073 2074 2075static void cliIntegrateHelp(void) { 2076 if (cliConnect(0) == -1) return; 2077 2078 redisReply *reply = redisCommand(context, "COMMAND"); 2079 if(reply == 0 || reply->type != 2) return; 2080 2081 2082 2083 for (size_t j = 0; j < reply->elements; j++) { 2084 redisReply *entry = reply->element[j]; 2085 if (entry->type != 2 || entry->elements < 4 || 2086 entry->element[0]->type != 1 || 2087 entry->element[1]->type != 3 || 2088 entry->element[3]->type != 3) return; 2089 char *cmdname = entry->element[0]->str; 2090 int i; 2091 2092 for (i = 0; i < helpEntriesLen; i++) { 2093 helpEntry *he = helpEntries+i; 2094 if (!strcasecmp(he->argv[0],cmdname)) 2095 break; 2096 } 2097 if (i != helpEntriesLen) continue; 2098 2099 helpEntriesLen++; 2100 helpEntries = zrealloc(helpEntries,sizeof(helpEntry)*helpEntriesLen); 2101 helpEntry *new = helpEntries+(helpEntriesLen-1); 2102 2103 new->argc = 1; 2104 new->argv = zmalloc(sizeof(sds)); 2105 new->argv[0] = sdsnew(cmdname); 2106 new->full = new->argv[0]; 2107 new->type = 1; 2108 sdstoupper(new->argv[0]); 2109 2110 struct commandHelp *ch = zmalloc(sizeof(*ch)); 2111 ch->name = new->argv[0]; 2112 ch->params = sdsempty(); 2113 int args = llabs(entry->element[1]->integer); 2114 if (entry->element[3]->integer == 1) { 2115 ch->params = sdscat(ch->params,"key "); 2116 args--; 2117 } 2118 while(args--) ch->params = sdscat(ch->params,"arg "); 2119 if (entry->element[1]->integer < 0) 2120 ch->params = sdscat(ch->params,"...options..."); 2121 ch->summary = "Help not available"; 2122 ch->group = 0; 2123 ch->since = "not known"; 2124 new->org = ch; 2125 } 2126 freeReplyObject(reply); 2127} 2128 2129 2130static void cliOutputCommandHelp(struct commandHelp *help, int group) { 2131 printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params); 2132 printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary); 2133 printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since); 2134 if (group) { 2135 printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]); 2136 } 2137} 2138 2139 2140static void cliOutputGenericHelp(void) { 2141 sds version = cliVersion(); 2142 printf( 2143 "redis-cli %s\n" 2144 "To get help about Redis commands type:\n" 2145 " \"help @<group>\" to get a list of commands in <group>\n" 2146 " \"help <command>\" for help on <command>\n" 2147 " \"help <tab>\" to get a list of possible help topics\n" 2148 " \"quit\" to exit\n" 2149 "\n" 2150 "To set redis-cli preferences:\n" 2151 " \":set hints\" enable online hints\n" 2152 " \":set nohints\" disable online hints\n" 2153 "Set your preferences in ~/.redisclirc\n", 2154 version 2155 ); 2156 sdsfree(version); 2157} 2158 2159 2160static void cliOutputHelp(int argc, char **argv) { 2161 int i, j, len; 2162 int group = -1; 2163 helpEntry *entry; 2164 struct commandHelp *help; 2165 2166 if (argc == 0) { 2167 cliOutputGenericHelp(); 2168 return; 2169 } else if (argc > 0 && argv[0][0] == '@') { 2170 len = sizeof(commandGroups)/sizeof(char*); 2171 for (i = 0; i < len; i++) { 2172 if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) { 2173 group = i; 2174 break; 2175 } 2176 } 2177 } 2178 2179 assert(argc > 0); 2180 for (i = 0; i < helpEntriesLen; i++) { 2181 entry = &helpEntries[i]; 2182 if (entry->type != 1) continue; 2183 2184 help = entry->org; 2185 if (group == -1) { 2186 2187 if (argc == entry->argc) { 2188 for (j = 0; j < argc; j++) { 2189 if (strcasecmp(argv[j],entry->argv[j]) != 0) break; 2190 } 2191 if (j == argc) { 2192 cliOutputCommandHelp(help,1); 2193 } 2194 } 2195 } else { 2196 if (group == help->group) { 2197 cliOutputCommandHelp(help,0); 2198 } 2199 } 2200 } 2201 printf("\r\n"); 2202} 2203 2204 2205static void completionCallback(const char *buf, linenoiseCompletions *lc) { 2206 size_t startpos = 0; 2207 int mask; 2208 int i; 2209 size_t matchlen; 2210 sds tmp; 2211 2212 if (strncasecmp(buf,"help ",5) == 0) { 2213 startpos = 5; 2214 while (isspace(buf[startpos])) startpos++; 2215 mask = 1 | 2; 2216 } else { 2217 mask = 1; 2218 } 2219 2220 for (i = 0; i < helpEntriesLen; i++) { 2221 if (!(helpEntries[i].type & mask)) continue; 2222 2223 matchlen = strlen(buf+startpos); 2224 if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) { 2225 tmp = sdsnewlen(buf,startpos); 2226 tmp = sdscat(tmp,helpEntries[i].full); 2227 linenoiseAddCompletion(lc,tmp); 2228 sdsfree(tmp); 2229 } 2230 } 2231} 2232 2233 2234static char *hintsCallback(const char *buf, int *color, int *bold) { 2235 if (!pref.hints) return 0; 2236 2237 int i, argc, buflen = strlen(buf); 2238 sds *argv = sdssplitargs(buf,&argc); 2239 int endspace = buflen && isspace(buf[buflen-1]); 2240 2241 2242 if (argc == 0) { 2243 sdsfreesplitres(argv,argc); 2244 return 0; 2245 } 2246 2247 for (i = 0; i < helpEntriesLen; i++) { 2248 if (!(helpEntries[i].type & 1)) continue; 2249 2250 if (strcasecmp(argv[0],helpEntries[i].full) == 0) 2251 { 2252 *color = 90; 2253 *bold = 0; 2254 sds hint = sdsnew(helpEntries[i].org->params); 2255 2256 2257 2258 int toremove = argc-1; 2259 while(toremove > 0 && sdslen(hint)) { 2260 if (hint[0] == '[') break; 2261 if (hint[0] == ' ') toremove--; 2262 sdsrange(hint,1,-1); 2263 } 2264 2265 2266 if (!endspace) { 2267 sds newhint = sdsnewlen(" ",1); 2268 newhint = sdscatsds(newhint,hint); 2269 sdsfree(hint); 2270 hint = newhint; 2271 } 2272 2273 sdsfreesplitres(argv,argc); 2274 return hint; 2275 } 2276 } 2277 sdsfreesplitres(argv,argc); 2278 return 0; 2279} 2280 2281static void freeHintsCallback(void *ptr) { 2282 sdsfree(ptr); 2283} 2284 2285 2286 2287 2288 2289 2290static int cliAuth(void) { 2291 redisReply *reply; 2292 if (config.auth == 0) return 0; 2293 2294 reply = redisCommand(context,"AUTH %s",config.auth); 2295 if (reply != 0) { 2296 freeReplyObject(reply); 2297 return 0; 2298 } 2299 return -1; 2300} 2301 2302 2303static int cliSelect(void) { 2304 redisReply *reply; 2305 if (config.dbnum == 0) return 0; 2306 2307 reply = redisCommand(context,"SELECT %d",config.dbnum); 2308 if (reply != 0) { 2309 int result = 0; 2310 if (reply->type == 6) result = -1; 2311 freeReplyObject(reply); 2312 return result; 2313 } 2314 return -1; 2315} 2316 2317 2318 2319static int cliConnect(int force) { 2320 if (context == 0 || force) { 2321 if (context != 0) { 2322 redisFree(context); 2323 } 2324 2325 if (config.hostsocket == 0) { 2326 context = redisConnect(config.hostip,config.hostport); 2327 } else { 2328 context = redisConnectUnix(config.hostsocket); 2329 } 2330 2331 if (context->err) { 2332 fprintf(stderr,"Could not connect to Redis at "); 2333 if (config.hostsocket == 0) 2334 fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr); 2335 else 2336 fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr); 2337 redisFree(context); 2338 context = 0; 2339 return -1; 2340 } 2341 2342 2343 2344 2345 2346 anetKeepAlive(0, context->fd, 15); 2347 2348 2349 if (cliAuth() != 0) 2350 return -1; 2351 if (cliSelect() != 0) 2352 return -1; 2353 } 2354 return 0; 2355} 2356 2357static void cliPrintContextError(void) { 2358 if (context == 0) return; 2359 fprintf(stderr,"Error: %s\n",context->errstr); 2360} 2361 2362static sds cliFormatReplyTTY(redisReply *r, char *prefix) { 2363 sds out = sdsempty(); 2364 switch (r->type) { 2365 case 6: 2366 out = sdscatprintf(out,"(error) %s\n", r->str); 2367 break; 2368 case 5: 2369 out = sdscat(out,r->str); 2370 out = sdscat(out,"\n"); 2371 break; 2372 case 3: 2373 out = sdscatprintf(out,"(integer) %lld\n",r->integer); 2374 break; 2375 case 1: 2376 2377 2378 out = sdscatrepr(out,r->str,r->len); 2379 out = sdscat(out,"\n"); 2380 break; 2381 case 4: 2382 out = sdscat(out,"(nil)\n"); 2383 break; 2384 case 2: 2385 if (r->elements == 0) { 2386 out = sdscat(out,"(empty list or set)\n"); 2387 } else { 2388 unsigned int i, idxlen = 0; 2389 char _prefixlen[16]; 2390 char _prefixfmt[16]; 2391 sds _prefix; 2392 sds tmp; 2393 2394 2395 i = r->elements; 2396 do { 2397 idxlen++; 2398 i /= 10; 2399 } while(i); 2400 2401 2402 memset(_prefixlen,' ',idxlen+2); 2403 _prefixlen[idxlen+2] = '\0'; 2404 _prefix = sdscat(sdsnew(prefix),_prefixlen); 2405 2406 2407 snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%ud) ",idxlen); 2408 2409 for (i = 0; i < r->elements; i++) { 2410 2411 2412 out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1); 2413 2414 2415 tmp = cliFormatReplyTTY(r->element[i],_prefix); 2416 out = sdscatlen(out,tmp,sdslen(tmp)); 2417 sdsfree(tmp); 2418 } 2419 sdsfree(_prefix); 2420 } 2421 break; 2422 default: 2423 fprintf(stderr,"Unknown reply type: %d\n", r->type); 2424 exit(1); 2425 } 2426 return out; 2427} 2428 2429int isColorTerm(void) { 2430 char *t = getenv("TERM"); 2431 return t != 0 && strstr(t,"xterm") != 0; 2432} 2433 2434 2435 2436sds sdscatcolor(sds o, char *s, size_t len, char *color) { 2437 if (!isColorTerm()) return sdscatlen(o,s,len); 2438 2439 int bold = strstr(color,"bold") != 0; 2440 int ccode = 37; 2441 if (strstr(color,"red")) ccode = 31; 2442 else if (strstr(color,"green")) ccode = 32; 2443 else if (strstr(color,"yellow")) ccode = 33; 2444 else if (strstr(color,"blue")) ccode = 34; 2445 else if (strstr(color,"magenta")) ccode = 35; 2446 else if (strstr(color,"cyan")) ccode = 36; 2447 else if (strstr(color,"white")) ccode = 37; 2448 2449 o = sdscatfmt(o,"\033[%i;%i;49m",bold,ccode); 2450 o = sdscatlen(o,s,len); 2451 o = sdscat(o,"\033[0m"); 2452 return o; 2453} 2454 2455 2456 2457sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) { 2458 char *color = "white"; 2459 2460 if (strstr(s,"<debug>")) color = "bold"; 2461 if (strstr(s,"<redis>")) color = "green"; 2462 if (strstr(s,"<reply>")) color = "cyan"; 2463 if (strstr(s,"<error>")) color = "red"; 2464 if (strstr(s,"<hint>")) color = "bold"; 2465 if (strstr(s,"<value>") || strstr(s,"<retval>")) color = "magenta"; 2466 if (len > 4 && isdigit(s[3])) { 2467 if (s[1] == '>') color = "yellow"; 2468 else if (s[2] == '#') color = "bold"; 2469 } 2470 return sdscatcolor(o,s,len,color); 2471} 2472 2473static sds cliFormatReplyRaw(redisReply *r) { 2474 sds out = sdsempty(), tmp; 2475 size_t i; 2476 2477 switch (r->type) { 2478 case 4: 2479 2480 break; 2481 case 6: 2482 out = sdscatlen(out,r->str,r->len); 2483 out = sdscatlen(out,"\n",1); 2484 break; 2485 case 5: 2486 case 1: 2487 if (r->type == 5 && config.eval_ldb) { 2488 2489 2490 2491 2492 2493 if (strstr(r->str,"<endsession>") == r->str) { 2494 config.enable_ldb_on_eval = 0; 2495 config.eval_ldb = 0; 2496 config.eval_ldb_end = 1; 2497 config.output = 0; 2498 cliRefreshPrompt(); 2499 } else { 2500 out = sdsCatColorizedLdbReply(out,r->str,r->len); 2501 } 2502 } else { 2503 out = sdscatlen(out,r->str,r->len); 2504 } 2505 break; 2506 case 3: 2507 out = sdscatprintf(out,"%lld",r->integer); 2508 break; 2509 case 2: 2510 for (i = 0; i < r->elements; i++) { 2511 if (i > 0) out = sdscat(out,config.mb_delim); 2512 tmp = cliFormatReplyRaw(r->element[i]); 2513 out = sdscatlen(out,tmp,sdslen(tmp)); 2514 sdsfree(tmp); 2515 } 2516 break; 2517 default: 2518 fprintf(stderr,"Unknown reply type: %d\n", r->type); 2519 exit(1); 2520 } 2521 return out; 2522} 2523 2524static sds cliFormatReplyCSV(redisReply *r) { 2525 unsigned int i; 2526 2527 sds out = sdsempty(); 2528 switch (r->type) { 2529 case 6: 2530 out = sdscat(out,"ERROR,"); 2531 out = sdscatrepr(out,r->str,strlen(r->str)); 2532 break; 2533 case 5: 2534 out = sdscatrepr(out,r->str,r->len); 2535 break; 2536 case 3: 2537 out = sdscatprintf(out,"%lld",r->integer); 2538 break; 2539 case 1: 2540 out = sdscatrepr(out,r->str,r->len); 2541 break; 2542 case 4: 2543 out = sdscat(out,"NIL"); 2544 break; 2545 case 2: 2546 for (i = 0; i < r->elements; i++) { 2547 sds tmp = cliFormatReplyCSV(r->element[i]); 2548 out = sdscatlen(out,tmp,sdslen(tmp)); 2549 if (i != r->elements-1) out = sdscat(out,","); 2550 sdsfree(tmp); 2551 } 2552 break; 2553 default: 2554 fprintf(stderr,"Unknown reply type: %d\n", r->type); 2555 exit(1); 2556 } 2557 return out; 2558} 2559 2560static int cliReadReply(int output_raw_strings) { 2561 void *_reply; 2562 redisReply *reply; 2563 sds out = 0; 2564 int output = 1; 2565 2566 if (redisGetReply(context,&_reply) != 0) { 2567 if (config.shutdown) { 2568 redisFree(context); 2569 context = 0; 2570 return 0; 2571 } 2572 if (config.interactive) { 2573 2574 if (context->err == 1 && 2575 (errno == ECONNRESET || errno == EPIPE)) 2576 return -1; 2577 if (context->err == 3) 2578 return -1; 2579 } 2580 cliPrintContextError(); 2581 exit(1); 2582 return -1; 2583 } 2584 2585 reply = (redisReply*)_reply; 2586 2587 config.last_cmd_type = reply->type; 2588 2589 2590 2591 if (config.cluster_mode && reply->type == 6 && 2592 (!strncmp(reply->str,"MOVED",5) || !strcmp(reply->str,"ASK"))) 2593 { 2594 char *p = reply->str, *s; 2595 int slot; 2596 2597 output = 0; 2598 2599 2600 2601 2602 2603 s = strchr(p,' '); 2604 p = strchr(s+1,' '); 2605 *p = '\0'; 2606 slot = atoi(s+1); 2607 s = strrchr(p+1,':'); 2608 *s = '\0'; 2609 sdsfree(config.hostip); 2610 config.hostip = sdsnew(p+1); 2611 config.hostport = atoi(s+1); 2612 if (config.interactive) 2613 printf("-> Redirected to slot [%d] located at %s:%d\n", 2614 slot, config.hostip, config.hostport); 2615 config.cluster_reissue_command = 1; 2616 cliRefreshPrompt(); 2617 } 2618 2619 if (output) { 2620 if (output_raw_strings) { 2621 out = cliFormatReplyRaw(reply); 2622 } else { 2623 if (config.output == 1) { 2624 out = cliFormatReplyRaw(reply); 2625 out = sdscat(out,"\n"); 2626 } else if (config.output == 0) { 2627 out = cliFormatReplyTTY(reply,""); 2628 } else if (config.output == 2) { 2629 out = cliFormatReplyCSV(reply); 2630 out = sdscat(out,"\n"); 2631 } 2632 } 2633 fwrite(out,sdslen(out),1,stdout); 2634 sdsfree(out); 2635 } 2636 freeReplyObject(reply); 2637 return 0; 2638} 2639 2640static int cliSendCommand(int argc, char **argv, int repeat) { 2641 char *command = argv[0]; 2642 size_t *argvlen; 2643 int j, output_raw; 2644 2645 if (!config.eval_ldb && 2646 (!strcasecmp(command,"help") || !strcasecmp(command,"?"))) { 2647 cliOutputHelp(--argc, ++argv); 2648 return 0; 2649 } 2650 2651 if (context == 0) return -1; 2652 2653 output_raw = 0; 2654 if (!strcasecmp(command,"info") || 2655 (argc >= 2 && !strcasecmp(command,"debug") && 2656 !strcasecmp(argv[1],"htstats")) || 2657 (argc >= 2 && !strcasecmp(command,"memory") && 2658 (!strcasecmp(argv[1],"malloc-stats") || 2659 !strcasecmp(argv[1],"doctor"))) || 2660 (argc == 2 && !strcasecmp(command,"cluster") && 2661 (!strcasecmp(argv[1],"nodes") || 2662 !strcasecmp(argv[1],"info"))) || 2663 (argc == 2 && !strcasecmp(command,"client") && 2664 !strcasecmp(argv[1],"list")) || 2665 (argc == 3 && !strcasecmp(command,"latency") && 2666 !strcasecmp(argv[1],"graph")) || 2667 (argc == 2 && !strcasecmp(command,"latency") && 2668 !strcasecmp(argv[1],"doctor"))) 2669 { 2670 output_raw = 1; 2671 } 2672 2673 if (!strcasecmp(command,"shutdown")) config.shutdown = 1; 2674 if (!strcasecmp(command,"monitor")) config.monitor_mode = 1; 2675 if (!strcasecmp(command,"subscribe") || 2676 !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1; 2677 if (!strcasecmp(command,"sync") || 2678 !strcasecmp(command,"psync")) config.slave_mode = 1; 2679 2680 2681 2682 if (argc == 3 && !strcasecmp(argv[0],"script") && 2683 !strcasecmp(argv[1],"debug")) 2684 { 2685 if (!strcasecmp(argv[2],"yes") || !strcasecmp(argv[2],"sync")) { 2686 config.enable_ldb_on_eval = 1; 2687 } else { 2688 config.enable_ldb_on_eval = 0; 2689 } 2690 } 2691 2692 2693 if (!strcasecmp(command,"eval") && config.enable_ldb_on_eval) { 2694 config.eval_ldb = 1; 2695 config.output = 1; 2696 } 2697 2698 2699 argvlen = zmalloc(argc*sizeof(size_t)); 2700 for (j = 0; j < argc; j++) 2701 argvlen[j] = sdslen(argv[j]); 2702 2703 while(repeat--) { 2704 redisAppendCommandArgv(context,argc,(const char**)argv,argvlen); 2705 while (config.monitor_mode) { 2706 if (cliReadReply(output_raw) != 0) exit(1); 2707 fflush(stdout); 2708 } 2709 2710 if (config.pubsub_mode) { 2711 if (config.output != 1) 2712 printf("Reading messages... (press Ctrl-C to quit)\n"); 2713 while (1) { 2714 if (cliReadReply(output_raw) != 0) exit(1); 2715 } 2716 } 2717 2718 if (config.slave_mode) { 2719 printf("Entering slave output mode... (press Ctrl-C to quit)\n"); 2720 slaveMode(); 2721 config.slave_mode = 0; 2722 zfree(argvlen); 2723 return -1; 2724 } 2725 2726 if (cliReadReply(output_raw) != 0) { 2727 zfree(argvlen); 2728 return -1; 2729 } else { 2730 2731 if (!strcasecmp(command,"select") && argc == 2 && config.last_cmd_type != 6) { 2732 config.dbnum = atoi(argv[1]); 2733 cliRefreshPrompt(); 2734 } else if (!strcasecmp(command,"auth") && argc == 2) { 2735 cliSelect(); 2736 } 2737 } 2738 if (config.interval) usleep(config.interval); 2739 fflush(stdout); 2740 } 2741 2742 zfree(argvlen); 2743 return 0; 2744} 2745 2746 2747static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ...) { 2748 redisReply *reply = 0; 2749 int tries = 0; 2750 va_list ap; 2751 2752 assert(!c->err); 2753 while(reply == 0) { 2754 while (c->err & (1 | 3)) { 2755 printf("\r\x1b[0K"); 2756 printf("Reconnecting... %d\r", ++tries); 2757 fflush(stdout); 2758 2759 redisFree(c); 2760 c = redisConnect(config.hostip,config.hostport); 2761 usleep(1000000); 2762 } 2763 2764 __builtin_va_start((ap)); 2765 reply = redisvCommand(c,fmt,ap); 2766 ; 2767 2768 if (c->err && !(c->err & (1 | 3))) { 2769 fprintf(stderr, "Error: %s\n", c->errstr); 2770 exit(1); 2771 } else if (tries > 0) { 2772 printf("\r\x1b[0K"); 2773 } 2774 } 2775 2776 context = c; 2777 return reply; 2778} 2779 2780 2781 2782 2783 2784static int parseOptions(int argc, char **argv) { 2785 int i; 2786 2787 for (i = 1; i < argc; i++) { 2788 int lastarg = i==argc-1; 2789 2790 if (!strcmp(argv[i],"-h") && !lastarg) { 2791 sdsfree(config.hostip); 2792 config.hostip = sdsnew(argv[++i]); 2793 } else if (!strcmp(argv[i],"-h") && lastarg) { 2794 usage(); 2795 } else if (!strcmp(argv[i],"--help")) { 2796 usage(); 2797 } else if (!strcmp(argv[i],"-x")) { 2798 config.stdinarg = 1; 2799 } else if (!strcmp(argv[i],"-p") && !lastarg) { 2800 config.hostport = atoi(argv[++i]); 2801 } else if (!strcmp(argv[i],"-s") && !lastarg) { 2802 config.hostsocket = argv[++i]; 2803 } else if (!strcmp(argv[i],"-r") && !lastarg) { 2804 config.repeat = strtoll(argv[++i],0,10); 2805 } else if (!strcmp(argv[i],"-i") && !lastarg) { 2806 double seconds = atof(argv[++i]); 2807 config.interval = seconds*1000000; 2808 } else if (!strcmp(argv[i],"-n") && !lastarg) { 2809 config.dbnum = atoi(argv[++i]); 2810 } else if (!strcmp(argv[i],"-a") && !lastarg) { 2811 config.auth = argv[++i]; 2812 } else if (!strcmp(argv[i],"-u") && !lastarg) { 2813 parseRedisUri(argv[++i]); 2814 } else if (!strcmp(argv[i],"--raw")) { 2815 config.output = 1; 2816 } else if (!strcmp(argv[i],"--no-raw")) { 2817 config.output = 0; 2818 } else if (!strcmp(argv[i],"--csv")) { 2819 config.output = 2; 2820 } else if (!strcmp(argv[i],"--latency")) { 2821 config.latency_mode = 1; 2822 } else if (!strcmp(argv[i],"--latency-dist")) { 2823 config.latency_dist_mode = 1; 2824 } else if (!strcmp(argv[i],"--mono")) { 2825 spectrum_palette = spectrum_palette_mono; 2826 spectrum_palette_size = spectrum_palette_mono_size; 2827 } else if (!strcmp(argv[i],"--latency-history")) { 2828 config.latency_mode = 1; 2829 config.latency_history = 1; 2830 } else if (!strcmp(argv[i],"--lru-test") && !lastarg) { 2831 config.lru_test_mode = 1; 2832 config.lru_test_sample_size = strtoll(argv[++i],0,10); 2833 } else if (!strcmp(argv[i],"--slave")) { 2834 config.slave_mode = 1; 2835 } else if (!strcmp(argv[i],"--stat")) { 2836 config.stat_mode = 1; 2837 } else if (!strcmp(argv[i],"--scan")) { 2838 config.scan_mode = 1; 2839 } else if (!strcmp(argv[i],"--pattern") && !lastarg) { 2840 config.pattern = argv[++i]; 2841 } else if (!strcmp(argv[i],"--intrinsic-latency") && !lastarg) { 2842 config.intrinsic_latency_mode = 1; 2843 config.intrinsic_latency_duration = atoi(argv[++i]); 2844 } else if (!strcmp(argv[i],"--rdb") && !lastarg) { 2845 config.getrdb_mode = 1; 2846 config.rdb_filename = argv[++i]; 2847 } else if (!strcmp(argv[i],"--pipe")) { 2848 config.pipe_mode = 1; 2849 } else if (!strcmp(argv[i],"--pipe-timeout") && !lastarg) { 2850 config.pipe_timeout = atoi(argv[++i]); 2851 } else if (!strcmp(argv[i],"--bigkeys")) { 2852 config.bigkeys = 1; 2853 } else if (!strcmp(argv[i],"--hotkeys")) { 2854 config.hotkeys = 1; 2855 } else if (!strcmp(argv[i],"--eval") && !lastarg) { 2856 config.eval = argv[++i]; 2857 } else if (!strcmp(argv[i],"--ldb")) { 2858 config.eval_ldb = 1; 2859 config.output = 1; 2860 } else if (!strcmp(argv[i],"--ldb-sync-mode")) { 2861 config.eval_ldb = 1; 2862 config.eval_ldb_sync = 1; 2863 config.output = 1; 2864 } else if (!strcmp(argv[i],"-c")) { 2865 config.cluster_mode = 1; 2866 } else if (!strcmp(argv[i],"-d") && !lastarg) { 2867 sdsfree(config.mb_delim); 2868 config.mb_delim = sdsnew(argv[++i]); 2869 } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) { 2870 sds version = cliVersion(); 2871 printf("redis-cli %s\n", version); 2872 sdsfree(version); 2873 exit(0); 2874 } else { 2875 if (argv[i][0] == '-') { 2876 fprintf(stderr, 2877 "Unrecognized option or bad number of args for: '%s'\n", 2878 argv[i]); 2879 exit(1); 2880 } else { 2881 2882 break; 2883 } 2884 } 2885 } 2886 2887 2888 if (config.eval_ldb && config.eval == 0) { 2889 fprintf(stderr,"Options --ldb and --ldb-sync-mode require --eval.\n"); 2890 fprintf(stderr,"Try %s --help for more information.\n", argv[0]); 2891 exit(1); 2892 } 2893 return i; 2894} 2895 2896static sds readArgFromStdin(void) { 2897 char buf[1024]; 2898 sds arg = sdsempty(); 2899 2900 while(1) { 2901 int nread = read(fileno(stdin),buf,1024); 2902 2903 if (nread == 0) break; 2904 else if (nread == -1) { 2905 perror("Reading from standard input"); 2906 exit(1); 2907 } 2908 arg = sdscatlen(arg,buf,nread); 2909 } 2910 return arg; 2911} 2912 2913static void usage(void) { 2914 sds version = cliVersion(); 2915 fprintf(stderr, 2916"redis-cli %s\n" 2917"\n" 2918"Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n" 2919" -h <hostname> Server hostname (default: 127.0.0.1).\n" 2920" -p <port> Server port (default: 6379).\n" 2921" -s <socket> Server socket (overrides hostname and port).\n" 2922" -a <password> Password to use when connecting to the server.\n" 2923" -u <uri> Server URI.\n" 2924" -r <repeat> Execute specified command N times.\n" 2925" -i <interval> When -r is used, waits <interval> seconds per command.\n" 2926" It is possible to specify sub-second times like -i 0.1.\n" 2927" -n <db> Database number.\n" 2928" -x Read last argument from STDIN.\n" 2929" -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n).\n" 2930" -c Enable cluster mode (follow -ASK and -MOVED redirections).\n" 2931" --raw Use raw formatting for replies (default when STDOUT is\n" 2932" not a tty).\n" 2933" --no-raw Force formatted output even when STDOUT is not a tty.\n" 2934" --csv Output in CSV format.\n" 2935" --stat Print rolling stats about server: mem, clients, ...\n" 2936" --latency Enter a special mode continuously sampling latency.\n" 2937" If you use this mode in an interactive session it runs\n" 2938" forever displaying real-time stats. Otherwise if --raw or\n" 2939" --csv is specified, or if you redirect the output to a non\n" 2940" TTY, it samples the latency for 1 second (you can use\n" 2941" -i to change the interval), then produces a single output\n" 2942" and exits.\n" 2943" --latency-history Like --latency but tracking latency changes over time.\n" 2944" Default time interval is 15 sec. Change it using -i.\n" 2945" --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" 2946" Default time interval is 1 sec. Change it using -i.\n" 2947" --lru-test <keys> Simulate a cache workload with an 80-20 distribution.\n" 2948" --slave Simulate a slave showing commands received from the master.\n" 2949" --rdb <filename> Transfer an RDB dump from remote server to local file.\n" 2950" --pipe Transfer raw Redis protocol from stdin to server.\n" 2951" --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n" 2952" no reply is received within <n> seconds.\n" 2953" Default timeout: %d. Use 0 to wait forever.\n" 2954" --bigkeys Sample Redis keys looking for big keys.\n" 2955" --hotkeys Sample Redis keys looking for hot keys.\n" 2956" only works when maxmemory-policy is *lfu.\n" 2957" --scan List all keys using the SCAN command.\n" 2958" --pattern <pat> Useful with --scan to specify a SCAN pattern.\n" 2959" --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n" 2960" The test will run for the specified amount of seconds.\n" 2961" --eval <file> Send an EVAL command using the Lua script at <file>.\n" 2962" --ldb Used with --eval enable the Redis Lua debugger.\n" 2963" --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n" 2964" this mode the server is blocked and script changes are\n" 2965" are not rolled back from the server memory.\n" 2966" --help Output this help and exit.\n" 2967" --version Output version and exit.\n" 2968"\n" 2969"Examples:\n" 2970" cat /etc/passwd | redis-cli -x set mypasswd\n" 2971" redis-cli get mypasswd\n" 2972" redis-cli -r 100 lpush mylist x\n" 2973" redis-cli -r 100 -i 1 info | grep used_memory_human:\n" 2974" redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n" 2975" redis-cli --scan --pattern '*:12345*'\n" 2976"\n" 2977" (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n" 2978"\n" 2979"When no command is given, redis-cli starts in interactive mode.\n" 2980"Type \"help\" in interactive mode for information on available commands\n" 2981"and settings.\n" 2982"\n", 2983 version, 30); 2984 sdsfree(version); 2985 exit(1); 2986} 2987 2988 2989static char **convertToSds(int count, char** args) { 2990 int j; 2991 char **sds = zmalloc(sizeof(char*)*count); 2992 2993 for(j = 0; j < count; j++) 2994 sds[j] = sdsnew(args[j]); 2995 2996 return sds; 2997} 2998 2999static int issueCommandRepeat(int argc, char **argv, long repeat) { 3000 while (1) { 3001 config.cluster_reissue_command = 0; 3002 if (cliSendCommand(argc,argv,repeat) != 0) { 3003 cliConnect(1); 3004 3005 3006 3007 if (cliSendCommand(argc,argv,repeat) != 0) { 3008 cliPrintContextError(); 3009 return -1; 3010 } 3011 } 3012 3013 if (config.cluster_mode && config.cluster_reissue_command) { 3014 cliConnect(1); 3015 } else { 3016 break; 3017 } 3018 } 3019 return 0; 3020} 3021 3022static int issueCommand(int argc, char **argv) { 3023 return issueCommandRepeat(argc, argv, config.repeat); 3024} 3025 3026 3027 3028 3029 3030 3031 3032static sds *cliSplitArgs(char *line, int *argc) { 3033 if (config.eval_ldb && (strstr(line,"eval ") == line || 3034 strstr(line,"e ") == line)) 3035 { 3036 sds *argv = sds_malloc(sizeof(sds)*2); 3037 *argc = 2; 3038 int len = strlen(line); 3039 int elen = line[1] == ' ' ? 2 : 5; 3040 argv[0] = sdsnewlen(line,elen-1); 3041 argv[1] = sdsnewlen(line+elen,len-elen); 3042 return argv; 3043 } else { 3044 return sdssplitargs(line,argc); 3045 } 3046} 3047 3048 3049 3050 3051void cliSetPreferences(char **argv, int argc, int interactive) { 3052 if (!strcasecmp(argv[0],":set") && argc >= 2) { 3053 if (!strcasecmp(argv[1],"hints")) pref.hints = 1; 3054 else if (!strcasecmp(argv[1],"nohints")) pref.hints = 0; 3055 else { 3056 printf("%sunknown redis-cli preference '%s'\n", 3057 interactive ? "" : ".redisclirc: ", 3058 argv[1]); 3059 } 3060 } else { 3061 printf("%sunknown redis-cli internal command '%s'\n", 3062 interactive ? "" : ".redisclirc: ", 3063 argv[0]); 3064 } 3065} 3066 3067 3068void cliLoadPreferences(void) { 3069 sds rcfile = getDotfilePath("REDISCLI_RCFILE",".redisclirc"); 3070 if (rcfile == 0) return; 3071 FILE *fp = fopen(rcfile,"r"); 3072 char buf[1024]; 3073 3074 if (fp) { 3075 while(fgets(buf,sizeof(buf),fp) != 0) { 3076 sds *argv; 3077 int argc; 3078 3079 argv = sdssplitargs(buf,&argc); 3080 if (argc > 0) cliSetPreferences(argv,argc,0); 3081 sdsfreesplitres(argv,argc); 3082 } 3083 fclose(fp); 3084 } 3085 sdsfree(rcfile); 3086} 3087 3088static void repl(void) { 3089 sds historyfile = 0; 3090 int history = 0; 3091 char *line; 3092 int argc; 3093 sds *argv; 3094 3095 3096 3097 cliInitHelp(); 3098 cliIntegrateHelp(); 3099 3100 config.interactive = 1; 3101 linenoiseSetMultiLine(1); 3102 linenoiseSetCompletionCallback(completionCallback); 3103 linenoiseSetHintsCallback(hintsCallback); 3104 linenoiseSetFreeHintsCallback(freeHintsCallback); 3105 3106 3107 if (isatty(fileno(stdin))) { 3108 historyfile = getDotfilePath("REDISCLI_HISTFILE",".rediscli_history"); 3109 3110 history = 1; 3111 if (historyfile != 0) { 3112 linenoiseHistoryLoad(historyfile); 3113 } 3114 cliLoadPreferences(); 3115 } 3116 3117 cliRefreshPrompt(); 3118 while((line = linenoise(context ? config.prompt : "not connected> ")) != 0) { 3119 if (line[0] != '\0') { 3120 argv = cliSplitArgs(line,&argc); 3121 if (history) linenoiseHistoryAdd(line); 3122 if (historyfile) linenoiseHistorySave(historyfile); 3123 3124 if (argv == 0) { 3125 printf("Invalid argument(s)\n"); 3126 linenoiseFree(line); 3127 continue; 3128 } else if (argc > 0) { 3129 if (strcasecmp(argv[0],"quit") == 0 || 3130 strcasecmp(argv[0],"exit") == 0) 3131 { 3132 exit(0); 3133 } else if (argv[0][0] == ':') { 3134 cliSetPreferences(argv,argc,1); 3135 continue; 3136 } else if (strcasecmp(argv[0],"restart") == 0) { 3137 if (config.eval) { 3138 config.eval_ldb = 1; 3139 config.output = 1; 3140 return; 3141 } else { 3142 printf("Use 'restart' only in Lua debugging mode."); 3143 } 3144 } else if (argc == 3 && !strcasecmp(argv[0],"connect")) { 3145 sdsfree(config.hostip); 3146 config.hostip = sdsnew(argv[1]); 3147 config.hostport = atoi(argv[2]); 3148 cliRefreshPrompt(); 3149 cliConnect(1); 3150 } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { 3151 linenoiseClearScreen(); 3152 } else { 3153 long long start_time = mstime(), elapsed; 3154 int repeat, skipargs = 0; 3155 char *endptr; 3156 3157 repeat = strtol(argv[0], &endptr, 10); 3158 if (argc > 1 && *endptr == '\0' && repeat) { 3159 skipargs = 1; 3160 } else { 3161 repeat = 1; 3162 } 3163 3164 issueCommandRepeat(argc-skipargs, argv+skipargs, repeat); 3165 3166 3167 3168 if (config.eval_ldb_end) { 3169 config.eval_ldb_end = 0; 3170 cliReadReply(0); 3171 printf("\n(Lua debugging session ended%s)\n\n", 3172 config.eval_ldb_sync ? "" : 3173 " -- dataset changes rolled back"); 3174 } 3175 3176 elapsed = mstime()-start_time; 3177 if (elapsed >= 500 && 3178 config.output == 0) 3179 { 3180 printf("(%.2fs)\n",(double)elapsed/1000); 3181 } 3182 } 3183 } 3184 3185 sdsfreesplitres(argv,argc); 3186 } 3187 3188 linenoiseFree(line); 3189 } 3190 exit(0); 3191} 3192 3193static int noninteractive(int argc, char **argv) { 3194 int retval = 0; 3195 if (config.stdinarg) { 3196 argv = zrealloc(argv, (argc+1)*sizeof(char*)); 3197 argv[argc] = readArgFromStdin(); 3198 retval = issueCommand(argc+1, argv); 3199 } else { 3200 retval = issueCommand(argc, argv); 3201 } 3202 return retval; 3203} 3204 3205 3206 3207 3208 3209static int evalMode(int argc, char **argv) { 3210 sds script = 0; 3211 FILE *fp; 3212 char buf[1024]; 3213 size_t nread; 3214 char **argv2; 3215 int j, got_comma, keys; 3216 int retval = 0; 3217 3218 while(1) { 3219 if (config.eval_ldb) { 3220 printf( 3221 "Lua debugging session started, please use:\n" 3222 "quit -- End the session.\n" 3223 "restart -- Restart the script in debug mode again.\n" 3224 "help -- Show Lua script debugging commands.\n\n" 3225 ); 3226 } 3227 3228 sdsfree(script); 3229 script = sdsempty(); 3230 got_comma = 0; 3231 keys = 0; 3232 3233 3234 fp = fopen(config.eval,"r"); 3235 if (!fp) { 3236 fprintf(stderr, 3237 "Can't open file '%s': %s\n", config.eval, strerror(errno)); 3238 exit(1); 3239 } 3240 while((nread = fread(buf,1,sizeof(buf),fp)) != 0) { 3241 script = sdscatlen(script,buf,nread); 3242 } 3243 fclose(fp); 3244 3245 3246 if (config.eval_ldb) { 3247 redisReply *reply = redisCommand(context, 3248 config.eval_ldb_sync ? 3249 "SCRIPT DEBUG sync": "SCRIPT DEBUG yes"); 3250 if (reply) freeReplyObject(reply); 3251 } 3252 3253 3254 argv2 = zmalloc(sizeof(sds)*(argc+3)); 3255 argv2[0] = sdsnew("EVAL"); 3256 argv2[1] = script; 3257 for (j = 0; j < argc; j++) { 3258 if (!got_comma && argv[j][0] == ',' && argv[j][1] == 0) { 3259 got_comma = 1; 3260 continue; 3261 } 3262 argv2[j+3-got_comma] = sdsnew(argv[j]); 3263 if (!got_comma) keys++; 3264 } 3265 argv2[2] = sdscatprintf(sdsempty(),"%d",keys); 3266 3267 3268 int eval_ldb = config.eval_ldb; 3269 retval = issueCommand(argc+3-got_comma, argv2); 3270 if (eval_ldb) { 3271 if (!config.eval_ldb) { 3272 3273 3274 3275 printf("Eval debugging session can't start:\n"); 3276 cliReadReply(0); 3277 break; 3278 } else { 3279 strncpy(config.prompt,"lua debugger> ",sizeof(config.prompt)); 3280 repl(); 3281 3282 cliConnect(1); 3283 printf("\n"); 3284 } 3285 } else { 3286 break; 3287 } 3288 } 3289 return retval; 3290} 3291 3292 3293 3294 3295 3296static void latencyModePrint(long long min, long long max, double avg, long long count) { 3297 if (config.output == 0) { 3298 printf("min: %lld, max: %lld, avg: %.2f (%lld samples)", 3299 min, max, avg, count); 3300 fflush(stdout); 3301 } else if (config.output == 2) { 3302 printf("%lld,%lld,%.2f,%lld\n", min, max, avg, count); 3303 } else if (config.output == 1) { 3304 printf("%lld %lld %.2f %lld\n", min, max, avg, count); 3305 } 3306} 3307 3308 3309 3310static void latencyMode(void) { 3311 redisReply *reply; 3312 long long start, latency, min = 0, max = 0, tot = 0, count = 0; 3313 long long history_interval = 3314 config.interval ? config.interval/1000 : 3315 15000; 3316 double avg; 3317 long long history_start = mstime(); 3318 3319 3320 3321 if (config.interval == 0) { 3322 config.interval = 1000; 3323 } else { 3324 config.interval /= 1000; 3325 } 3326 3327 if (!context) exit(1); 3328 while(1) { 3329 start = mstime(); 3330 reply = reconnectingRedisCommand(context,"PING"); 3331 if (reply == 0) { 3332 fprintf(stderr,"\nI/O error\n"); 3333 exit(1); 3334 } 3335 latency = mstime()-start; 3336 freeReplyObject(reply); 3337 count++; 3338 if (count == 1) { 3339 min = max = tot = latency; 3340 avg = (double) latency; 3341 } else { 3342 if (latency < min) min = latency; 3343 if (latency > max) max = latency; 3344 tot += latency; 3345 avg = (double) tot/count; 3346 } 3347 3348 if (config.output == 0) { 3349 printf("\x1b[0G\x1b[2K"); 3350 latencyModePrint(min,max,avg,count); 3351 } else { 3352 if (config.latency_history) { 3353 latencyModePrint(min,max,avg,count); 3354 } else if (mstime()-history_start > config.interval) { 3355 latencyModePrint(min,max,avg,count); 3356 exit(0); 3357 } 3358 } 3359 3360 if (config.latency_history && mstime()-history_start > history_interval) 3361 { 3362 printf(" -- %.2f seconds range\n", (float)(mstime()-history_start)/1000); 3363 history_start = mstime(); 3364 min = max = tot = count = 0; 3365 } 3366 usleep(10 * 1000); 3367 } 3368} 3369# 1657 "src/redis-cli.c" 3370struct distsamples { 3371 long long max; 3372 long long count; 3373 int character; 3374}; 3375# 1674 "src/redis-cli.c" 3376void showLatencyDistSamples(struct distsamples *samples, long long tot) { 3377 int j; 3378 3379 3380 3381 3382 3383 3384 printf("\033[38;5;0m"); 3385 for (j = 0; ; j++) { 3386 int coloridx = 3387 ceil((float) samples[j].count / tot * (spectrum_palette_size-1)); 3388 int color = spectrum_palette[coloridx]; 3389 printf("\033[48;5;%dm%c", (int)color, samples[j].character); 3390 samples[j].count = 0; 3391 if (samples[j].max == 0) break; 3392 } 3393 printf("\033[0m\n"); 3394 fflush(stdout); 3395} 3396 3397 3398 3399void showLatencyDistLegend(void) { 3400 int j; 3401 3402 printf("---------------------------------------------\n"); 3403 printf(". - * # .01 .125 .25 .5 milliseconds\n"); 3404 printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); 3405 printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); 3406 printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); 3407 printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n"); 3408 printf("From 0 to 100%%: "); 3409 for (j = 0; j < spectrum_palette_size; j++) { 3410 printf("\033[48;5;%dm ", spectrum_palette[j]); 3411 } 3412 printf("\033[0m\n"); 3413 printf("---------------------------------------------\n"); 3414} 3415 3416static void latencyDistMode(void) { 3417 redisReply *reply; 3418 long long start, latency, count = 0; 3419 long long history_interval = 3420 config.interval ? config.interval/1000 : 3421 1000; 3422 long long history_start = ustime(); 3423 int j, outputs = 0; 3424 3425 struct distsamples samples[] = { 3426 3427 3428 3429 {10,0,'.'}, 3430 {125,0,'-'}, 3431 {250,0,'*'}, 3432 {500,0,'#'}, 3433 {1000,0,'1'}, 3434 {2000,0,'2'}, 3435 {3000,0,'3'}, 3436 {4000,0,'4'}, 3437 {5000,0,'5'}, 3438 {6000,0,'6'}, 3439 {7000,0,'7'}, 3440 {8000,0,'8'}, 3441 {9000,0,'9'}, 3442 {10000,0,'A'}, 3443 {20000,0,'B'}, 3444 {30000,0,'C'}, 3445 {40000,0,'D'}, 3446 {50000,0,'E'}, 3447 {100000,0,'F'}, 3448 {200000,0,'G'}, 3449 {300000,0,'H'}, 3450 {400000,0,'I'}, 3451 {500000,0,'J'}, 3452 {1000000,0,'K'}, 3453 {2000000,0,'L'}, 3454 {4000000,0,'M'}, 3455 {8000000,0,'N'}, 3456 {16000000,0,'O'}, 3457 {30000000,0,'P'}, 3458 {60000000,0,'Q'}, 3459 {0,0,'?'}, 3460 }; 3461 3462 if (!context) exit(1); 3463 while(1) { 3464 start = ustime(); 3465 reply = reconnectingRedisCommand(context,"PING"); 3466 if (reply == 0) { 3467 fprintf(stderr,"\nI/O error\n"); 3468 exit(1); 3469 } 3470 latency = ustime()-start; 3471 freeReplyObject(reply); 3472 count++; 3473 3474 3475 for (j = 0; ; j++) { 3476 if (samples[j].max == 0 || latency <= samples[j].max) { 3477 samples[j].count++; 3478 break; 3479 } 3480 } 3481 3482 3483 if (count && (ustime()-history_start)/1000 > history_interval) { 3484 if ((outputs++ % 20) == 0) 3485 showLatencyDistLegend(); 3486 showLatencyDistSamples(samples,count); 3487 history_start = ustime(); 3488 count = 0; 3489 } 3490 usleep(10 * 1000); 3491 } 3492} 3493 3494 3495 3496 3497 3498 3499 3500unsigned long long sendSync(int fd) { 3501 3502 3503 3504 3505 char buf[4096], *p; 3506 ssize_t nread; 3507 3508 3509 if (write(fd,"SYNC\r\n",6) != 6) { 3510 fprintf(stderr,"Error writing to master\n"); 3511 exit(1); 3512 } 3513 3514 3515 p = buf; 3516 while(1) { 3517 nread = read(fd,p,1); 3518 if (nread <= 0) { 3519 fprintf(stderr,"Error reading bulk length while SYNCing\n"); 3520 exit(1); 3521 } 3522 if (*p == '\n' && p != buf) break; 3523 if (*p != '\n') p++; 3524 } 3525 *p = '\0'; 3526 if (buf[0] == '-') { 3527 printf("SYNC with master failed: %s\n", buf); 3528 exit(1); 3529 } 3530 return strtoull(buf+1,0,10); 3531} 3532 3533static void slaveMode(void) { 3534 int fd = context->fd; 3535 unsigned long long payload = sendSync(fd); 3536 char buf[1024]; 3537 int original_output = config.output; 3538 3539 fprintf(stderr,"SYNC with master, discarding %llu " 3540 "bytes of bulk transfer...\n", payload); 3541 3542 3543 while(payload) { 3544 ssize_t nread; 3545 3546 nread = read(fd,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); 3547 if (nread <= 0) { 3548 fprintf(stderr,"Error reading RDB payload while SYNCing\n"); 3549 exit(1); 3550 } 3551 payload -= nread; 3552 } 3553 fprintf(stderr,"SYNC done. Logging commands from master.\n"); 3554 3555 3556 config.output = 2; 3557 while (cliReadReply(0) == 0); 3558 config.output = original_output; 3559} 3560 3561 3562 3563 3564 3565 3566 3567static void getRDB(void) { 3568 int s = context->fd; 3569 int fd; 3570 unsigned long long payload = sendSync(s); 3571 char buf[4096]; 3572 3573 fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n", 3574 payload, config.rdb_filename); 3575 3576 3577 if (!strcmp(config.rdb_filename,"-")) { 3578 fd = STDOUT_FILENO; 3579 } else { 3580 fd = open(config.rdb_filename, O_CREAT|O_WRONLY, 0644); 3581 if (fd == -1) { 3582 fprintf(stderr, "Error opening '%s': %s\n", config.rdb_filename, 3583 strerror(errno)); 3584 exit(1); 3585 } 3586 } 3587 3588 while(payload) { 3589 ssize_t nread, nwritten; 3590 3591 nread = read(s,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); 3592 if (nread <= 0) { 3593 fprintf(stderr,"I/O Error reading RDB payload from socket\n"); 3594 exit(1); 3595 } 3596 nwritten = write(fd, buf, nread); 3597 if (nwritten != nread) { 3598 fprintf(stderr,"Error writing data to file: %s\n", 3599 strerror(errno)); 3600 exit(1); 3601 } 3602 payload -= nread; 3603 } 3604 close(s); 3605 fsync(fd); 3606 fprintf(stderr,"Transfer finished with success.\n"); 3607 exit(0); 3608} 3609 3610 3611 3612 3613 3614 3615static void pipeMode(void) { 3616 int fd = context->fd; 3617 long long errors = 0, replies = 0, obuf_len = 0, obuf_pos = 0; 3618 char ibuf[1024*16], obuf[1024*16]; 3619 char aneterr[256]; 3620 redisReader *reader = redisReaderCreate(); 3621 redisReply *reply; 3622 int eof = 0; 3623 int done = 0; 3624 char magic[20]; 3625 time_t last_read_time = time(0); 3626 3627 srand(time(0)); 3628 3629 3630 if (anetNonBlock(aneterr,fd) == -1) { 3631 fprintf(stderr, "Can't set the socket in non blocking mode: %s\n", 3632 aneterr); 3633 exit(1); 3634 } 3635 3636 3637 3638 while(!done) { 3639 int mask = 1; 3640 3641 if (!eof || obuf_len != 0) mask |= 2; 3642 mask = aeWait(fd,mask,1000); 3643 3644 3645 if (mask & 1) { 3646 ssize_t nread; 3647 3648 3649 do { 3650 nread = read(fd,ibuf,sizeof(ibuf)); 3651 if (nread == -1 && errno != EAGAIN && errno != EINTR) { 3652 fprintf(stderr, "Error reading from the server: %s\n", 3653 strerror(errno)); 3654 exit(1); 3655 } 3656 if (nread > 0) { 3657 redisReaderFeed(reader,ibuf,nread); 3658 last_read_time = time(0); 3659 } 3660 } while(nread > 0); 3661 3662 3663 do { 3664 if (redisReaderGetReply(reader,(void**)&reply) == -1) { 3665 fprintf(stderr, "Error reading replies from server\n"); 3666 exit(1); 3667 } 3668 if (reply) { 3669 if (reply->type == 6) { 3670 fprintf(stderr,"%s\n", reply->str); 3671 errors++; 3672 } else if (eof && reply->type == 1 && 3673 reply->len == 20) { 3674 3675 3676 3677 if (memcmp(reply->str,magic,20) == 0) { 3678 printf("Last reply received from server.\n"); 3679 done = 1; 3680 replies--; 3681 } 3682 } 3683 replies++; 3684 freeReplyObject(reply); 3685 } 3686 } while(reply); 3687 } 3688 3689 3690 if (mask & 2) { 3691 ssize_t loop_nwritten = 0; 3692 3693 while(1) { 3694 3695 if (obuf_len != 0) { 3696 ssize_t nwritten = write(fd,obuf+obuf_pos,obuf_len); 3697 3698 if (nwritten == -1) { 3699 if (errno != EAGAIN && errno != EINTR) { 3700 fprintf(stderr, "Error writing to the server: %s\n", 3701 strerror(errno)); 3702 exit(1); 3703 } else { 3704 nwritten = 0; 3705 } 3706 } 3707 obuf_len -= nwritten; 3708 obuf_pos += nwritten; 3709 loop_nwritten += nwritten; 3710 if (obuf_len != 0) break; 3711 } 3712 3713 if (obuf_len == 0 && !eof) { 3714 ssize_t nread = read(STDIN_FILENO,obuf,sizeof(obuf)); 3715 3716 if (nread == 0) { 3717 3718 3719 3720 3721 char echo[] = 3722 "\r\n*2\r\n$4\r\nECHO\r\n$20\r\n01234567890123456789\r\n"; 3723 int j; 3724 3725 eof = 1; 3726 3727 3728 3729 for (j = 0; j < 20; j++) 3730 magic[j] = rand() & 0xff; 3731 memcpy(echo+21,magic,20); 3732 memcpy(obuf,echo,sizeof(echo)-1); 3733 obuf_len = sizeof(echo)-1; 3734 obuf_pos = 0; 3735 printf("All data transferred. Waiting for the last reply...\n"); 3736 } else if (nread == -1) { 3737 fprintf(stderr, "Error reading from stdin: %s\n", 3738 strerror(errno)); 3739 exit(1); 3740 } else { 3741 obuf_len = nread; 3742 obuf_pos = 0; 3743 } 3744 } 3745 if ((obuf_len == 0 && eof) || 3746 loop_nwritten > (128*1024)) break; 3747 } 3748 } 3749 3750 3751 3752 3753 if (eof && config.pipe_timeout > 0 && 3754 time(0)-last_read_time > config.pipe_timeout) 3755 { 3756 fprintf(stderr,"No replies for %d seconds: exiting.\n", 3757 config.pipe_timeout); 3758 errors++; 3759 break; 3760 } 3761 } 3762 redisReaderFree(reader); 3763 printf("errors: %lld, replies: %lld\n", errors, replies); 3764 if (errors) 3765 exit(1); 3766 else 3767 exit(0); 3768} 3769# 2079 "src/redis-cli.c" 3770static redisReply *sendScan(unsigned long long *it) { 3771 redisReply *reply = redisCommand(context, "SCAN %llu", *it); 3772 3773 3774 if(reply == 0) { 3775 fprintf(stderr, "\nI/O error\n"); 3776 exit(1); 3777 } else if(reply->type == 6) { 3778 fprintf(stderr, "SCAN error: %s\n", reply->str); 3779 exit(1); 3780 } else if(reply->type != 2) { 3781 fprintf(stderr, "Non ARRAY response from SCAN!\n"); 3782 exit(1); 3783 } else if(reply->elements != 2) { 3784 fprintf(stderr, "Invalid element count from SCAN!\n"); 3785 exit(1); 3786 } 3787 3788 3789 assert(reply->element[0]->type == 1); 3790 assert(reply->element[1]->type == 2); 3791 3792 3793 *it = strtoull(reply->element[0]->str, 0, 10); 3794 3795 return reply; 3796} 3797 3798static int getDbSize(void) { 3799 redisReply *reply; 3800 int size; 3801 3802 reply = redisCommand(context, "DBSIZE"); 3803 3804 if(reply == 0 || reply->type != 3) { 3805 fprintf(stderr, "Couldn't determine DBSIZE!\n"); 3806 exit(1); 3807 } 3808 3809 3810 size = reply->integer; 3811 freeReplyObject(reply); 3812 3813 return size; 3814} 3815 3816static int toIntType(char *key, char *type) { 3817 if(!strcmp(type, "string")) { 3818 return 0; 3819 } else if(!strcmp(type, "list")) { 3820 return 1; 3821 } else if(!strcmp(type, "set")) { 3822 return 2; 3823 } else if(!strcmp(type, "hash")) { 3824 return 3; 3825 } else if(!strcmp(type, "zset")) { 3826 return 4; 3827 } else if(!strcmp(type, "none")) { 3828 return 5; 3829 } else { 3830 fprintf(stderr, "Unknown type '%s' for key '%s'\n", type, key); 3831 exit(1); 3832 } 3833} 3834 3835static void getKeyTypes(redisReply *keys, int *types) { 3836 redisReply *reply; 3837 unsigned int i; 3838 3839 3840 for(i=0;i<keys->elements;i++) { 3841 redisAppendCommand(context, "TYPE %s", keys->element[i]->str); 3842 } 3843 3844 3845 for(i=0;i<keys->elements;i++) { 3846 if(redisGetReply(context, (void**)&reply)!=0) { 3847 fprintf(stderr, "Error getting type for key '%s' (%d: %s)\n", 3848 keys->element[i]->str, context->err, context->errstr); 3849 exit(1); 3850 } else if(reply->type != 5) { 3851 if(reply->type == 6) { 3852 fprintf(stderr, "TYPE returned an error: %s\n", reply->str); 3853 } else { 3854 fprintf(stderr, 3855 "Invalid reply type (%d) for TYPE on key '%s'!\n", 3856 reply->type, keys->element[i]->str); 3857 } 3858 exit(1); 3859 } 3860 3861 types[i] = toIntType(keys->element[i]->str, reply->str); 3862 freeReplyObject(reply); 3863 } 3864} 3865 3866static void getKeySizes(redisReply *keys, int *types, 3867 unsigned long long *sizes) 3868{ 3869 redisReply *reply; 3870 char *sizecmds[] = {"STRLEN","LLEN","SCARD","HLEN","ZCARD"}; 3871 unsigned int i; 3872 3873 3874 for(i=0;i<keys->elements;i++) { 3875 3876 if(types[i]==5) 3877 continue; 3878 3879 redisAppendCommand(context, "%s %s", sizecmds[types[i]], 3880 keys->element[i]->str); 3881 } 3882 3883 3884 for(i=0;i<keys->elements;i++) { 3885 3886 if(types[i] == 5) { 3887 sizes[i] = 0; 3888 continue; 3889 } 3890 3891 3892 if(redisGetReply(context, (void**)&reply)!=0) { 3893 fprintf(stderr, "Error getting size for key '%s' (%d: %s)\n", 3894 keys->element[i]->str, context->err, context->errstr); 3895 exit(1); 3896 } else if(reply->type != 3) { 3897 3898 3899 fprintf(stderr, 3900 "Warning: %s on '%s' failed (may have changed type)\n", 3901 sizecmds[types[i]], keys->element[i]->str); 3902 sizes[i] = 0; 3903 } else { 3904 sizes[i] = reply->integer; 3905 } 3906 3907 freeReplyObject(reply); 3908 } 3909} 3910 3911static void findBigKeys(void) { 3912 unsigned long long biggest[5] = {0}, counts[5] = {0}, totalsize[5] = {0}; 3913 unsigned long long sampled = 0, total_keys, totlen=0, *sizes=0, it=0; 3914 sds maxkeys[5] = {0}; 3915 char *typename[] = {"string","list","set","hash","zset"}; 3916 char *typeunit[] = {"bytes","items","members","fields","members"}; 3917 redisReply *reply, *keys; 3918 unsigned int arrsize=0, i; 3919 int type, *types=0; 3920 double pct; 3921 3922 3923 total_keys = getDbSize(); 3924 3925 3926 printf("\n# Scanning the entire keyspace to find biggest keys as well as\n"); 3927 printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); 3928 printf("# per 100 SCAN commands (not usually needed).\n\n"); 3929 3930 3931 for(i=0;i<5; i++) { 3932 maxkeys[i] = sdsempty(); 3933 if(!maxkeys[i]) { 3934 fprintf(stderr, "Failed to allocate memory for largest key names!\n"); 3935 exit(1); 3936 } 3937 } 3938 3939 3940 do { 3941 3942 pct = 100 * (double)sampled/total_keys; 3943 3944 3945 reply = sendScan(&it); 3946 keys = reply->element[1]; 3947 3948 3949 if(keys->elements > arrsize) { 3950 types = zrealloc(types, sizeof(int)*keys->elements); 3951 sizes = zrealloc(sizes, sizeof(unsigned long long)*keys->elements); 3952 3953 if(!types || !sizes) { 3954 fprintf(stderr, "Failed to allocate storage for keys!\n"); 3955 exit(1); 3956 } 3957 3958 arrsize = keys->elements; 3959 } 3960 3961 3962 getKeyTypes(keys, types); 3963 getKeySizes(keys, types, sizes); 3964 3965 3966 for(i=0;i<keys->elements;i++) { 3967 if((type = types[i]) == 5) 3968 continue; 3969 3970 totalsize[type] += sizes[i]; 3971 counts[type]++; 3972 totlen += keys->element[i]->len; 3973 sampled++; 3974 3975 if(biggest[type]<sizes[i]) { 3976 printf( 3977 "[%05.2f%%] Biggest %-6s found so far '%s' with %llu %s\n", 3978 pct, typename[type], keys->element[i]->str, sizes[i], 3979 typeunit[type]); 3980 3981 3982 maxkeys[type] = sdscpy(maxkeys[type], keys->element[i]->str); 3983 if(!maxkeys[type]) { 3984 fprintf(stderr, "Failed to allocate memory for key!\n"); 3985 exit(1); 3986 } 3987 3988 3989 biggest[type] = sizes[i]; 3990 } 3991 3992 3993 if(sampled % 1000000 == 0) { 3994 printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); 3995 } 3996 } 3997 3998 3999 if(sampled && (sampled %100) == 0 && config.interval) { 4000 usleep(config.interval); 4001 } 4002 4003 freeReplyObject(reply); 4004 } while(it != 0); 4005 4006 if(types) zfree(types); 4007 if(sizes) zfree(sizes); 4008 4009 4010 printf("\n-------- summary -------\n\n"); 4011 4012 printf("Sampled %llu keys in the keyspace!\n", sampled); 4013 printf("Total key length in bytes is %llu (avg len %.2f)\n\n", 4014 totlen, totlen ? (double)totlen/sampled : 0); 4015 4016 4017 for(i=0;i<5;i++) { 4018 if(sdslen(maxkeys[i])>0) { 4019 printf("Biggest %6s found '%s' has %llu %s\n", typename[i], maxkeys[i], 4020 biggest[i], typeunit[i]); 4021 } 4022 } 4023 4024 printf("\n"); 4025 4026 for(i=0;i<5;i++) { 4027 printf("%llu %ss with %llu %s (%05.2f%% of keys, avg size %.2f)\n", 4028 counts[i], typename[i], totalsize[i], typeunit[i], 4029 sampled ? 100 * (double)counts[i]/sampled : 0, 4030 counts[i] ? (double)totalsize[i]/counts[i] : 0); 4031 } 4032 4033 4034 for(i=0;i<5;i++) { 4035 sdsfree(maxkeys[i]); 4036 } 4037 4038 4039 exit(0); 4040} 4041 4042static void getKeyFreqs(redisReply *keys, unsigned long long *freqs) { 4043 redisReply *reply; 4044 unsigned int i; 4045 4046 4047 for(i=0;i<keys->elements;i++) { 4048 redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str); 4049 } 4050 4051 4052 for(i=0;i<keys->elements;i++) { 4053 if(redisGetReply(context, (void**)&reply)!=0) { 4054 fprintf(stderr, "Error getting freq for key '%s' (%d: %s)\n", 4055 keys->element[i]->str, context->err, context->errstr); 4056 exit(1); 4057 } else if(reply->type != 3) { 4058 if(reply->type == 6) { 4059 fprintf(stderr, "Error: %s\n", reply->str); 4060 exit(1); 4061 } else { 4062 fprintf(stderr, "Warning: OBJECT freq on '%s' failed (may have been deleted)\n", keys->element[i]->str); 4063 freqs[i] = 0; 4064 } 4065 } else { 4066 freqs[i] = reply->integer; 4067 } 4068 freeReplyObject(reply); 4069 } 4070} 4071 4072 4073static void findHotKeys(void) { 4074 redisReply *keys, *reply; 4075 unsigned long long counters[16] = {0}; 4076 sds hotkeys[16] = {0}; 4077 unsigned long long sampled = 0, total_keys, *freqs = 0, it = 0; 4078 unsigned int arrsize = 0, i, k; 4079 double pct; 4080 4081 4082 total_keys = getDbSize(); 4083 4084 4085 printf("\n# Scanning the entire keyspace to find hot keys as well as\n"); 4086 printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); 4087 printf("# per 100 SCAN commands (not usually needed).\n\n"); 4088 4089 4090 do { 4091 4092 pct = 100 * (double)sampled/total_keys; 4093 4094 4095 reply = sendScan(&it); 4096 keys = reply->element[1]; 4097 4098 4099 if(keys->elements > arrsize) { 4100 freqs = zrealloc(freqs, sizeof(unsigned long long)*keys->elements); 4101 4102 if(!freqs) { 4103 fprintf(stderr, "Failed to allocate storage for keys!\n"); 4104 exit(1); 4105 } 4106 4107 arrsize = keys->elements; 4108 } 4109 4110 getKeyFreqs(keys, freqs); 4111 4112 4113 for(i=0;i<keys->elements;i++) { 4114 sampled++; 4115 4116 if(sampled % 1000000 == 0) { 4117 printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); 4118 } 4119 4120 4121 k = 0; 4122 while (k < 16 && freqs[i] > counters[k]) k++; 4123 if (k == 0) continue; 4124 k--; 4125 if (k == 0 || counters[k] == 0) { 4126 sdsfree(hotkeys[k]); 4127 } else { 4128 sdsfree(hotkeys[0]); 4129 memmove(counters,counters+1,sizeof(counters[0])*k); 4130 memmove(hotkeys,hotkeys+1,sizeof(hotkeys[0])*k); 4131 } 4132 counters[k] = freqs[i]; 4133 hotkeys[k] = sdsnew(keys->element[i]->str); 4134 printf( 4135 "[%05.2f%%] Hot key '%s' found so far with counter %llu\n", 4136 pct, keys->element[i]->str, freqs[i]); 4137 } 4138 4139 4140 if(sampled && (sampled %100) == 0 && config.interval) { 4141 usleep(config.interval); 4142 } 4143 4144 freeReplyObject(reply); 4145 } while(it != 0); 4146 4147 if (freqs) zfree(freqs); 4148 4149 4150 printf("\n-------- summary -------\n\n"); 4151 4152 printf("Sampled %llu keys in the keyspace!\n", sampled); 4153 4154 for (i=1; i<= 16; i++) { 4155 k = 16 - i; 4156 if(counters[k]>0) { 4157 printf("hot key found with counter: %llu\tkeyname: %s\n", counters[k], hotkeys[k]); 4158 sdsfree(hotkeys[k]); 4159 } 4160 } 4161 4162 exit(0); 4163} 4164# 2481 "src/redis-cli.c" 4165static char *getInfoField(char *info, char *field) { 4166 char *p = strstr(info,field); 4167 char *n1, *n2; 4168 char *result; 4169 4170 if (!p) return 0; 4171 p += strlen(field)+1; 4172 n1 = strchr(p,'\r'); 4173 n2 = strchr(p,','); 4174 if (n2 && n2 < n1) n1 = n2; 4175 result = zmalloc(sizeof(char)*(n1-p)+1); 4176 memcpy(result,p,(n1-p)); 4177 result[n1-p] = '\0'; 4178 return result; 4179} 4180 4181 4182 4183static long getLongInfoField(char *info, char *field) { 4184 char *value = getInfoField(info,field); 4185 long l; 4186 4187 if (!value) return LONG_MIN; 4188 l = strtol(value,0,10); 4189 zfree(value); 4190 return l; 4191} 4192 4193 4194 4195void bytesToHuman(char *s, long long n) { 4196 double d; 4197 4198 if (n < 0) { 4199 *s = '-'; 4200 s++; 4201 n = -n; 4202 } 4203 if (n < 1024) { 4204 4205 sprintf(s,"%lldB",n); 4206 return; 4207 } else if (n < (1024*1024)) { 4208 d = (double)n/(1024); 4209 sprintf(s,"%.2fK",d); 4210 } else if (n < (1024LL*1024*1024)) { 4211 d = (double)n/(1024*1024); 4212 sprintf(s,"%.2fM",d); 4213 } else if (n < (1024LL*1024*1024*1024)) { 4214 d = (double)n/(1024LL*1024*1024); 4215 sprintf(s,"%.2fG",d); 4216 } 4217} 4218 4219static void statMode(void) { 4220 redisReply *reply; 4221 long aux, requests = 0; 4222 int i = 0; 4223 4224 while(1) { 4225 char buf[64]; 4226 int j; 4227 4228 reply = reconnectingRedisCommand(context,"INFO"); 4229 if (reply->type == 6) { 4230 printf("ERROR: %s\n", reply->str); 4231 exit(1); 4232 } 4233 4234 if ((i++ % 20) == 0) { 4235 printf( 4236"------- data ------ --------------------- load -------------------- - child -\n" 4237"keys mem clients blocked requests connections \n"); 4238 } 4239 4240 4241 aux = 0; 4242 for (j = 0; j < 20; j++) { 4243 long k; 4244 4245 sprintf(buf,"db%d:keys",j); 4246 k = getLongInfoField(reply->str,buf); 4247 if (k == LONG_MIN) continue; 4248 aux += k; 4249 } 4250 sprintf(buf,"%ld",aux); 4251 printf("%-11s",buf); 4252 4253 4254 aux = getLongInfoField(reply->str,"used_memory"); 4255 bytesToHuman(buf,aux); 4256 printf("%-8s",buf); 4257 4258 4259 aux = getLongInfoField(reply->str,"connected_clients"); 4260 sprintf(buf,"%ld",aux); 4261 printf(" %-8s",buf); 4262 4263 4264 aux = getLongInfoField(reply->str,"blocked_clients"); 4265 sprintf(buf,"%ld",aux); 4266 printf("%-8s",buf); 4267 4268 4269 aux = getLongInfoField(reply->str,"total_commands_processed"); 4270 sprintf(buf,"%ld (+%ld)",aux,requests == 0 ? 0 : aux-requests); 4271 printf("%-19s",buf); 4272 requests = aux; 4273 4274 4275 aux = getLongInfoField(reply->str,"total_connections_received"); 4276 sprintf(buf,"%ld",aux); 4277 printf(" %-12s",buf); 4278 4279 4280 aux = getLongInfoField(reply->str,"bgsave_in_progress"); 4281 aux |= getLongInfoField(reply->str,"aof_rewrite_in_progress") << 1; 4282 aux |= getLongInfoField(reply->str,"loading") << 2; 4283 switch(aux) { 4284 case 0: break; 4285 case 1: 4286 printf("SAVE"); 4287 break; 4288 case 2: 4289 printf("AOF"); 4290 break; 4291 case 3: 4292 printf("SAVE+AOF"); 4293 break; 4294 case 4: 4295 printf("LOAD"); 4296 break; 4297 } 4298 4299 printf("\n"); 4300 freeReplyObject(reply); 4301 usleep(config.interval); 4302 } 4303} 4304 4305 4306 4307 4308 4309static void scanMode(void) { 4310 redisReply *reply; 4311 unsigned long long cur = 0; 4312 4313 do { 4314 if (config.pattern) 4315 reply = redisCommand(context,"SCAN %llu MATCH %s", 4316 cur,config.pattern); 4317 else 4318 reply = redisCommand(context,"SCAN %llu",cur); 4319 if (reply == 0) { 4320 printf("I/O error\n"); 4321 exit(1); 4322 } else if (reply->type == 6) { 4323 printf("ERROR: %s\n", reply->str); 4324 exit(1); 4325 } else { 4326 unsigned int j; 4327 4328 cur = strtoull(reply->element[0]->str,0,10); 4329 for (j = 0; j < reply->element[1]->elements; j++) 4330 printf("%s\n", reply->element[1]->element[j]->str); 4331 } 4332 freeReplyObject(reply); 4333 } while(cur != 0); 4334 4335 exit(0); 4336} 4337# 2664 "src/redis-cli.c" 4338long long powerLawRand(long long min, long long max, double alpha) { 4339 double pl, r; 4340 4341 max += 1; 4342 r = ((double)rand()) / 32767; 4343 pl = pow( 4344 ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)), 4345 (1.0/(alpha+1))); 4346 return (max-1-(long long)pl)+min; 4347} 4348 4349 4350 4351void LRUTestGenKey(char *buf, size_t buflen) { 4352 snprintf(buf, buflen, "lru:%lld", 4353 powerLawRand(1, config.lru_test_sample_size, 6.2)); 4354} 4355 4356 4357 4358static void LRUTestMode(void) { 4359 redisReply *reply; 4360 char key[128]; 4361 long long start_cycle; 4362 int j; 4363 4364 srand(time(0)^getpid()); 4365 while(1) { 4366 4367 4368 4369 start_cycle = mstime(); 4370 long long hits = 0, misses = 0; 4371 while(mstime() - start_cycle < 1000) { 4372 4373 for (j = 0; j < 250; j++) { 4374 char val[6]; 4375 val[5] = '\0'; 4376 for (int i = 0; i < 5; i++) val[i] = 'A'+rand()%('z'-'A'); 4377 LRUTestGenKey(key,sizeof(key)); 4378 redisAppendCommand(context, "SET %s %s",key,val); 4379 } 4380 for (j = 0; j < 250; j++) 4381 redisGetReply(context, (void**)&reply); 4382 4383 4384 for (j = 0; j < 250; j++) { 4385 LRUTestGenKey(key,sizeof(key)); 4386 redisAppendCommand(context, "GET %s",key); 4387 } 4388 for (j = 0; j < 250; j++) { 4389 if (redisGetReply(context, (void**)&reply) == 0) { 4390 switch(reply->type) { 4391 case 6: 4392 printf("%s\n", reply->str); 4393 break; 4394 case 4: 4395 misses++; 4396 break; 4397 default: 4398 hits++; 4399 break; 4400 } 4401 } 4402 } 4403 4404 if (context->err) { 4405 fprintf(stderr,"I/O error during LRU test\n"); 4406 exit(1); 4407 } 4408 } 4409 4410 printf( 4411 "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n", 4412 hits+misses, 4413 hits, (double)hits/(hits+misses)*100, 4414 misses, (double)misses/(hits+misses)*100); 4415 } 4416 exit(0); 4417} 4418# 2756 "src/redis-cli.c" 4419unsigned long compute_something_fast(void) { 4420 unsigned char s[256], i, j, t; 4421 int count = 1000, k; 4422 unsigned long output = 0; 4423 4424 for (k = 0; k < 256; k++) s[k] = k; 4425 4426 i = 0; 4427 j = 0; 4428 while(count--) { 4429 i++; 4430 j = j + s[i]; 4431 t = s[i]; 4432 s[i] = s[j]; 4433 s[j] = t; 4434 output += s[(s[i]+s[j])&255]; 4435 } 4436 return output; 4437} 4438 4439static void intrinsicLatencyModeStop(int s) { 4440 ((void) s); 4441 force_cancel_loop = 1; 4442} 4443 4444static void intrinsicLatencyMode(void) { 4445 long long test_end, run_time, max_latency = 0, runs = 0; 4446 4447 run_time = config.intrinsic_latency_duration*1000000; 4448 test_end = ustime() + run_time; 4449 signal(SIGINT, intrinsicLatencyModeStop); 4450 4451 while(1) { 4452 long long start, end, latency; 4453 4454 start = ustime(); 4455 compute_something_fast(); 4456 end = ustime(); 4457 latency = end-start; 4458 runs++; 4459 if (latency <= 0) continue; 4460 4461 4462 if (latency > max_latency) { 4463 max_latency = latency; 4464 printf("Max latency so far: %lld microseconds.\n", max_latency); 4465 } 4466 4467 double avg_us = (double)run_time/runs; 4468 double avg_ns = avg_us * 1e3; 4469 if (force_cancel_loop || end > test_end) { 4470 printf("\n%lld total runs " 4471 "(avg latency: " 4472 "%.4f microseconds / %.2f nanoseconds per run).\n", 4473 runs, avg_us, avg_ns); 4474 printf("Worst run took %.0fx longer than the average latency.\n", 4475 max_latency / avg_us); 4476 exit(0); 4477 } 4478 } 4479} 4480 4481 4482 4483 4484 4485int main(int argc, char **argv) { 4486 int firstarg; 4487 4488 config.hostip = sdsnew("127.0.0.1"); 4489 config.hostport = 6379; 4490 config.hostsocket = 0; 4491 config.repeat = 1; 4492 config.interval = 0; 4493 config.dbnum = 0; 4494 config.interactive = 0; 4495 config.shutdown = 0; 4496 config.monitor_mode = 0; 4497 config.pubsub_mode = 0; 4498 config.latency_mode = 0; 4499 config.latency_dist_mode = 0; 4500 config.latency_history = 0; 4501 config.lru_test_mode = 0; 4502 config.lru_test_sample_size = 0; 4503 config.cluster_mode = 0; 4504 config.slave_mode = 0; 4505 config.getrdb_mode = 0; 4506 config.stat_mode = 0; 4507 config.scan_mode = 0; 4508 config.intrinsic_latency_mode = 0; 4509 config.pattern = 0; 4510 config.rdb_filename = 0; 4511 config.pipe_mode = 0; 4512 config.pipe_timeout = 30; 4513 config.bigkeys = 0; 4514 config.hotkeys = 0; 4515 config.stdinarg = 0; 4516 config.auth = 0; 4517 config.eval = 0; 4518 config.eval_ldb = 0; 4519 config.eval_ldb_end = 0; 4520 config.eval_ldb_sync = 0; 4521 config.enable_ldb_on_eval = 0; 4522 config.last_cmd_type = -1; 4523 4524 pref.hints = 1; 4525 4526 spectrum_palette = spectrum_palette_color; 4527 spectrum_palette_size = spectrum_palette_color_size; 4528 4529 if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == 0)) 4530 config.output = 1; 4531 else 4532 config.output = 0; 4533 config.mb_delim = sdsnew("\n"); 4534 4535 firstarg = parseOptions(argc,argv); 4536 argc -= firstarg; 4537 argv += firstarg; 4538 4539 4540 if (config.latency_mode) { 4541 if (cliConnect(0) == -1) exit(1); 4542 latencyMode(); 4543 } 4544 4545 4546 if (config.latency_dist_mode) { 4547 if (cliConnect(0) == -1) exit(1); 4548 latencyDistMode(); 4549 } 4550 4551 4552 if (config.slave_mode) { 4553 if (cliConnect(0) == -1) exit(1); 4554 slaveMode(); 4555 } 4556 4557 4558 if (config.getrdb_mode) { 4559 if (cliConnect(0) == -1) exit(1); 4560 getRDB(); 4561 } 4562 4563 4564 if (config.pipe_mode) { 4565 if (cliConnect(0) == -1) exit(1); 4566 pipeMode(); 4567 } 4568 4569 4570 if (config.bigkeys) { 4571 if (cliConnect(0) == -1) exit(1); 4572 findBigKeys(); 4573 } 4574 4575 4576 if (config.hotkeys) { 4577 if (cliConnect(0) == -1) exit(1); 4578 findHotKeys(); 4579 } 4580 4581 4582 if (config.stat_mode) { 4583 if (cliConnect(0) == -1) exit(1); 4584 if (config.interval == 0) config.interval = 1000000; 4585 statMode(); 4586 } 4587 4588 4589 if (config.scan_mode) { 4590 if (cliConnect(0) == -1) exit(1); 4591 scanMode(); 4592 } 4593 4594 4595 if (config.lru_test_mode) { 4596 if (cliConnect(0) == -1) exit(1); 4597 LRUTestMode(); 4598 } 4599 4600 4601 if (config.intrinsic_latency_mode) intrinsicLatencyMode(); 4602 4603 4604 if (argc == 0 && !config.eval) { 4605 4606 signal(SIGPIPE, SIG_IGN); 4607 4608 4609 4610 cliConnect(0); 4611 repl(); 4612 } 4613 4614 4615 if (cliConnect(0) != 0) exit(1); 4616 if (config.eval) { 4617 return evalMode(argc,argv); 4618 } else { 4619 return noninteractive(argc,convertToSds(argc,argv)); 4620 } 4621} 4622