| # 1 "src/redis-cli.c" | |
| # 1 "<built-in>" | |
| # 1 "<command-line>" | |
| # 1 "src/redis-cli.c" | |
| # 31 "src/redis-cli.c" | |
| # 1 "src/fmacros.h" 1 | |
| # 32 "src/redis-cli.c" 2 | |
| # 1 "src/version.h" 1 | |
| # 33 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 | |
| typedef int size_t; | |
| typedef int __builtin_va_list; | |
| typedef int __gnuc_va_list; | |
| typedef int va_list; | |
| typedef int __int8_t; | |
| typedef int __uint8_t; | |
| typedef int __int16_t; | |
| typedef int __uint16_t; | |
| typedef int __int_least16_t; | |
| typedef int __uint_least16_t; | |
| typedef int __int32_t; | |
| typedef int __uint32_t; | |
| typedef int __int64_t; | |
| typedef int __uint64_t; | |
| typedef int __int_least32_t; | |
| typedef int __uint_least32_t; | |
| typedef int __s8; | |
| typedef int __u8; | |
| typedef int __s16; | |
| typedef int __u16; | |
| typedef int __s32; | |
| typedef int __u32; | |
| typedef int __s64; | |
| typedef int __u64; | |
| typedef int _LOCK_T; | |
| typedef int _LOCK_RECURSIVE_T; | |
| typedef int _off_t; | |
| typedef int __dev_t; | |
| typedef int __uid_t; | |
| typedef int __gid_t; | |
| typedef int _off64_t; | |
| typedef int _fpos_t; | |
| typedef int _ssize_t; | |
| typedef int wint_t; | |
| typedef int _mbstate_t; | |
| typedef int _flock_t; | |
| typedef int _iconv_t; | |
| typedef int __ULong; | |
| typedef int __FILE; | |
| typedef int ptrdiff_t; | |
| typedef int wchar_t; | |
| typedef int __off_t; | |
| typedef int __pid_t; | |
| typedef int __loff_t; | |
| typedef int u_char; | |
| typedef int u_short; | |
| typedef int u_int; | |
| typedef int u_long; | |
| typedef int ushort; | |
| typedef int uint; | |
| typedef int clock_t; | |
| typedef int time_t; | |
| typedef int daddr_t; | |
| typedef int caddr_t; | |
| typedef int ino_t; | |
| typedef int off_t; | |
| typedef int dev_t; | |
| typedef int uid_t; | |
| typedef int gid_t; | |
| typedef int pid_t; | |
| typedef int key_t; | |
| typedef int ssize_t; | |
| typedef int mode_t; | |
| typedef int nlink_t; | |
| typedef int fd_mask; | |
| typedef int _types_fd_set; | |
| typedef int clockid_t; | |
| typedef int timer_t; | |
| typedef int useconds_t; | |
| typedef int suseconds_t; | |
| typedef int FILE; | |
| typedef int fpos_t; | |
| typedef int cookie_read_function_t; | |
| typedef int cookie_write_function_t; | |
| typedef int cookie_seek_function_t; | |
| typedef int cookie_close_function_t; | |
| typedef int cookie_io_functions_t; | |
| typedef int div_t; | |
| typedef int ldiv_t; | |
| typedef int lldiv_t; | |
| typedef int sigset_t; | |
| typedef int __sigset_t; | |
| typedef int _sig_func_ptr; | |
| typedef int sig_atomic_t; | |
| typedef int __tzrule_type; | |
| typedef int __tzinfo_type; | |
| typedef int mbstate_t; | |
| typedef int sem_t; | |
| typedef int pthread_t; | |
| typedef int pthread_attr_t; | |
| typedef int pthread_mutex_t; | |
| typedef int pthread_mutexattr_t; | |
| typedef int pthread_cond_t; | |
| typedef int pthread_condattr_t; | |
| typedef int pthread_key_t; | |
| typedef int pthread_once_t; | |
| typedef int pthread_rwlock_t; | |
| typedef int pthread_rwlockattr_t; | |
| typedef int pthread_spinlock_t; | |
| typedef int pthread_barrier_t; | |
| typedef int pthread_barrierattr_t; | |
| typedef int jmp_buf; | |
| typedef int rlim_t; | |
| typedef int sa_family_t; | |
| typedef int sigjmp_buf; | |
| typedef int stack_t; | |
| typedef int siginfo_t; | |
| typedef int z_stream; | |
| typedef int int8_t; | |
| typedef int uint8_t; | |
| typedef int int16_t; | |
| typedef int uint16_t; | |
| typedef int int32_t; | |
| typedef int uint32_t; | |
| typedef int int64_t; | |
| typedef int uint64_t; | |
| typedef int int_least8_t; | |
| typedef int uint_least8_t; | |
| typedef int int_least16_t; | |
| typedef int uint_least16_t; | |
| typedef int int_least32_t; | |
| typedef int uint_least32_t; | |
| typedef int int_least64_t; | |
| typedef int uint_least64_t; | |
| typedef int int_fast8_t; | |
| typedef int uint_fast8_t; | |
| typedef int int_fast16_t; | |
| typedef int uint_fast16_t; | |
| typedef int int_fast32_t; | |
| typedef int uint_fast32_t; | |
| typedef int int_fast64_t; | |
| typedef int uint_fast64_t; | |
| typedef int intptr_t; | |
| typedef int uintptr_t; | |
| typedef int intmax_t; | |
| typedef int uintmax_t; | |
| typedef _Bool bool; | |
| typedef void* MirEGLNativeWindowType; | |
| typedef void* MirEGLNativeDisplayType; | |
| typedef struct MirConnection MirConnection; | |
| typedef struct MirSurface MirSurface; | |
| typedef struct MirSurfaceSpec MirSurfaceSpec; | |
| typedef struct MirScreencast MirScreencast; | |
| typedef struct MirPromptSession MirPromptSession; | |
| typedef struct MirBufferStream MirBufferStream; | |
| typedef struct MirPersistentId MirPersistentId; | |
| typedef struct MirBlob MirBlob; | |
| typedef struct MirDisplayConfig MirDisplayConfig; | |
| typedef struct xcb_connection_t xcb_connection_t; | |
| typedef uint32_t xcb_window_t; | |
| typedef uint32_t xcb_visualid_t; | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 | |
| # 35 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 | |
| # 36 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 | |
| # 37 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 2 | |
| # 38 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2 | |
| # 39 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 | |
| # 40 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 2 | |
| # 41 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2 | |
| # 42 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2 | |
| # 43 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 | |
| # 44 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 2 | |
| # 45 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2 | |
| # 46 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 2 | |
| # 47 "src/redis-cli.c" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2 | |
| # 48 "src/redis-cli.c" 2 | |
| # 1 "deps/hiredis/hiredis.h" 1 | |
| # 36 "deps/hiredis/hiredis.h" | |
| # 1 "deps/hiredis/read.h" 1 | |
| # 35 "deps/hiredis/read.h" | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 | |
| # 36 "deps/hiredis/read.h" 2 | |
| # 63 "deps/hiredis/read.h" | |
| typedef struct redisReadTask { | |
| int type; | |
| int elements; | |
| int idx; | |
| void *obj; | |
| struct redisReadTask *parent; | |
| void *privdata; | |
| } redisReadTask; | |
| typedef struct redisReplyObjectFunctions { | |
| void *(*createString)(const redisReadTask*, char*, size_t); | |
| void *(*createArray)(const redisReadTask*, int); | |
| void *(*createInteger)(const redisReadTask*, long long); | |
| void *(*createNil)(const redisReadTask*); | |
| void (*freeObject)(void*); | |
| } redisReplyObjectFunctions; | |
| typedef struct redisReader { | |
| int err; | |
| char errstr[128]; | |
| char *buf; | |
| size_t pos; | |
| size_t len; | |
| size_t maxbuf; | |
| redisReadTask rstack[9]; | |
| int ridx; | |
| void *reply; | |
| redisReplyObjectFunctions *fn; | |
| void *privdata; | |
| } redisReader; | |
| redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); | |
| void redisReaderFree(redisReader *r); | |
| int redisReaderFeed(redisReader *r, const char *buf, size_t len); | |
| int redisReaderGetReply(redisReader *r, void **reply); | |
| # 37 "deps/hiredis/hiredis.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 | |
| # 38 "deps/hiredis/hiredis.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 | |
| # 39 "deps/hiredis/hiredis.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 | |
| # 40 "deps/hiredis/hiredis.h" 2 | |
| # 1 "deps/hiredis/sds.h" 1 | |
| # 38 "deps/hiredis/sds.h" | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 | |
| # 39 "deps/hiredis/sds.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 | |
| # 40 "deps/hiredis/sds.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2 | |
| # 41 "deps/hiredis/sds.h" 2 | |
| typedef char *sds; | |
| struct sdshdr5 { | |
| unsigned char flags; | |
| char buf[]; | |
| }; | |
| struct sdshdr8 { | |
| uint8_t len; | |
| uint8_t alloc; | |
| unsigned char flags; | |
| char buf[]; | |
| }; | |
| struct sdshdr16 { | |
| uint16_t len; | |
| uint16_t alloc; | |
| unsigned char flags; | |
| char buf[]; | |
| }; | |
| struct sdshdr32 { | |
| uint32_t len; | |
| uint32_t alloc; | |
| unsigned char flags; | |
| char buf[]; | |
| }; | |
| struct sdshdr64 { | |
| uint64_t len; | |
| uint64_t alloc; | |
| unsigned char flags; | |
| char buf[]; | |
| }; | |
| # 86 "deps/hiredis/sds.h" | |
| static inline size_t sdslen(const sds s) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: | |
| return ((flags)>>3); | |
| case 1: | |
| return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len; | |
| case 2: | |
| return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len; | |
| case 3: | |
| return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len; | |
| case 4: | |
| return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len; | |
| } | |
| return 0; | |
| } | |
| static inline size_t sdsavail(const sds s) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: { | |
| return 0; | |
| } | |
| case 1: { | |
| struct sdshdr8 *sh = (struct sdshdr8 *)((s)-(sizeof(struct sdshdr8)));; | |
| return sh->alloc - sh->len; | |
| } | |
| case 2: { | |
| struct sdshdr16 *sh = (struct sdshdr16 *)((s)-(sizeof(struct sdshdr16)));; | |
| return sh->alloc - sh->len; | |
| } | |
| case 3: { | |
| struct sdshdr32 *sh = (struct sdshdr32 *)((s)-(sizeof(struct sdshdr32)));; | |
| return sh->alloc - sh->len; | |
| } | |
| case 4: { | |
| struct sdshdr64 *sh = (struct sdshdr64 *)((s)-(sizeof(struct sdshdr64)));; | |
| return sh->alloc - sh->len; | |
| } | |
| } | |
| return 0; | |
| } | |
| static inline void sdssetlen(sds s, size_t newlen) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: | |
| { | |
| unsigned char *fp = ((unsigned char*)s)-1; | |
| *fp = 0 | (newlen << 3); | |
| } | |
| break; | |
| case 1: | |
| ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len = newlen; | |
| break; | |
| case 2: | |
| ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len = newlen; | |
| break; | |
| case 3: | |
| ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len = newlen; | |
| break; | |
| case 4: | |
| ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len = newlen; | |
| break; | |
| } | |
| } | |
| static inline void sdsinclen(sds s, size_t inc) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: | |
| { | |
| unsigned char *fp = ((unsigned char*)s)-1; | |
| unsigned char newlen = ((flags)>>3)+inc; | |
| *fp = 0 | (newlen << 3); | |
| } | |
| break; | |
| case 1: | |
| ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len += inc; | |
| break; | |
| case 2: | |
| ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len += inc; | |
| break; | |
| case 3: | |
| ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len += inc; | |
| break; | |
| case 4: | |
| ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len += inc; | |
| break; | |
| } | |
| } | |
| static inline size_t sdsalloc(const sds s) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: | |
| return ((flags)>>3); | |
| case 1: | |
| return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc; | |
| case 2: | |
| return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc; | |
| case 3: | |
| return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc; | |
| case 4: | |
| return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc; | |
| } | |
| return 0; | |
| } | |
| static inline void sdssetalloc(sds s, size_t newlen) { | |
| unsigned char flags = s[-1]; | |
| switch(flags&7) { | |
| case 0: | |
| break; | |
| case 1: | |
| ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc = newlen; | |
| break; | |
| case 2: | |
| ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc = newlen; | |
| break; | |
| case 3: | |
| ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc = newlen; | |
| break; | |
| case 4: | |
| ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc = newlen; | |
| break; | |
| } | |
| } | |
| sds sdsnewlen(const void *init, size_t initlen); | |
| sds sdsnew(const char *init); | |
| sds sdsempty(void); | |
| sds sdsdup(const sds s); | |
| void sdsfree(sds s); | |
| sds sdsgrowzero(sds s, size_t len); | |
| sds sdscatlen(sds s, const void *t, size_t len); | |
| sds sdscat(sds s, const char *t); | |
| sds sdscatsds(sds s, const sds t); | |
| sds sdscpylen(sds s, const char *t, size_t len); | |
| sds sdscpy(sds s, const char *t); | |
| sds sdscatvprintf(sds s, const char *fmt, va_list ap); | |
| sds sdscatprintf(sds s, const char *fmt, ...) | |
| ; | |
| sds sdscatfmt(sds s, char const *fmt, ...); | |
| sds sdstrim(sds s, const char *cset); | |
| void sdsrange(sds s, int start, int end); | |
| void sdsupdatelen(sds s); | |
| void sdsclear(sds s); | |
| int sdscmp(const sds s1, const sds s2); | |
| sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); | |
| void sdsfreesplitres(sds *tokens, int count); | |
| void sdstolower(sds s); | |
| void sdstoupper(sds s); | |
| sds sdsfromlonglong(long long value); | |
| sds sdscatrepr(sds s, const char *p, size_t len); | |
| sds *sdssplitargs(const char *line, int *argc); | |
| sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); | |
| sds sdsjoin(char **argv, int argc, char *sep); | |
| sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); | |
| sds sdsMakeRoomFor(sds s, size_t addlen); | |
| void sdsIncrLen(sds s, int incr); | |
| sds sdsRemoveFreeSpace(sds s); | |
| size_t sdsAllocSize(sds s); | |
| void *sdsAllocPtr(sds s); | |
| void *sds_malloc(size_t size); | |
| void *sds_realloc(void *ptr, size_t size); | |
| void sds_free(void *ptr); | |
| # 41 "deps/hiredis/hiredis.h" 2 | |
| # 112 "deps/hiredis/hiredis.h" | |
| typedef struct redisReply { | |
| int type; | |
| long long integer; | |
| size_t len; | |
| char *str; | |
| size_t elements; | |
| struct redisReply **element; | |
| } redisReply; | |
| redisReader *redisReaderCreate(void); | |
| void freeReplyObject(void *reply); | |
| int redisvFormatCommand(char **target, const char *format, va_list ap); | |
| int redisFormatCommand(char **target, const char *format, ...); | |
| int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); | |
| int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); | |
| void redisFreeCommand(char *cmd); | |
| void redisFreeSdsCommand(sds cmd); | |
| enum redisConnectionType { | |
| REDIS_CONN_TCP, | |
| REDIS_CONN_UNIX | |
| }; | |
| typedef struct redisContext { | |
| int err; | |
| char errstr[128]; | |
| int fd; | |
| int flags; | |
| char *obuf; | |
| redisReader *reader; | |
| enum redisConnectionType connection_type; | |
| struct timeval *timeout; | |
| struct { | |
| char *host; | |
| char *source_addr; | |
| int port; | |
| } tcp; | |
| struct { | |
| char *path; | |
| } unix_sock; | |
| } redisContext; | |
| redisContext *redisConnect(const char *ip, int port); | |
| redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); | |
| redisContext *redisConnectNonBlock(const char *ip, int port); | |
| redisContext *redisConnectBindNonBlock(const char *ip, int port, | |
| const char *source_addr); | |
| redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, | |
| const char *source_addr); | |
| redisContext *redisConnectUnix(const char *path); | |
| redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); | |
| redisContext *redisConnectUnixNonBlock(const char *path); | |
| redisContext *redisConnectFd(int fd); | |
| # 184 "deps/hiredis/hiredis.h" | |
| int redisReconnect(redisContext *c); | |
| int redisSetTimeout(redisContext *c, const struct timeval tv); | |
| int redisEnableKeepAlive(redisContext *c); | |
| void redisFree(redisContext *c); | |
| int redisFreeKeepFd(redisContext *c); | |
| int redisBufferRead(redisContext *c); | |
| int redisBufferWrite(redisContext *c, int *done); | |
| int redisGetReply(redisContext *c, void **reply); | |
| int redisGetReplyFromReader(redisContext *c, void **reply); | |
| int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); | |
| int redisvAppendCommand(redisContext *c, const char *format, va_list ap); | |
| int redisAppendCommand(redisContext *c, const char *format, ...); | |
| int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); | |
| void *redisvCommand(redisContext *c, const char *format, va_list ap); | |
| void *redisCommand(redisContext *c, const char *format, ...); | |
| void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); | |
| # 50 "src/redis-cli.c" 2 | |
| # 1 "src/sds.h" 1 | |
| # 51 "src/redis-cli.c" 2 | |
| # 1 "src/zmalloc.h" 1 | |
| # 75 "src/zmalloc.h" | |
| void *zmalloc(size_t size); | |
| void *zcalloc(size_t size); | |
| void *zrealloc(void *ptr, size_t size); | |
| void zfree(void *ptr); | |
| char *zstrdup(const char *s); | |
| size_t zmalloc_used_memory(void); | |
| void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); | |
| float zmalloc_get_fragmentation_ratio(size_t rss); | |
| size_t zmalloc_get_rss(void); | |
| size_t zmalloc_get_private_dirty(long pid); | |
| size_t zmalloc_get_smap_bytes_by_field(char *field, long pid); | |
| size_t zmalloc_get_memory_size(void); | |
| void zlibc_free(void *ptr); | |
| size_t zmalloc_size(void *ptr); | |
| # 52 "src/redis-cli.c" 2 | |
| # 1 "deps/linenoise/linenoise.h" 1 | |
| # 46 "deps/linenoise/linenoise.h" | |
| typedef struct linenoiseCompletions { | |
| size_t len; | |
| char **cvec; | |
| } linenoiseCompletions; | |
| typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); | |
| typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold); | |
| typedef void(linenoiseFreeHintsCallback)(void *); | |
| void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); | |
| void linenoiseSetHintsCallback(linenoiseHintsCallback *); | |
| void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *); | |
| void linenoiseAddCompletion(linenoiseCompletions *, const char *); | |
| char *linenoise(const char *prompt); | |
| void linenoiseFree(void *ptr); | |
| int linenoiseHistoryAdd(const char *line); | |
| int linenoiseHistorySetMaxLen(int len); | |
| int linenoiseHistorySave(const char *filename); | |
| int linenoiseHistoryLoad(const char *filename); | |
| void linenoiseClearScreen(void); | |
| void linenoiseSetMultiLine(int ml); | |
| void linenoisePrintKeyCodes(void); | |
| # 53 "src/redis-cli.c" 2 | |
| # 1 "src/help.h" 1 | |
| static char *commandGroups[] = { | |
| "generic", | |
| "string", | |
| "list", | |
| "set", | |
| "sorted_set", | |
| "hash", | |
| "pubsub", | |
| "transactions", | |
| "connection", | |
| "server", | |
| "scripting", | |
| "hyperloglog", | |
| "cluster", | |
| "geo" | |
| }; | |
| struct commandHelp { | |
| char *name; | |
| char *params; | |
| char *summary; | |
| int group; | |
| char *since; | |
| } commandHelp[] = { | |
| { "APPEND", | |
| "key value", | |
| "Append a value to a key", | |
| 1, | |
| "2.0.0" }, | |
| { "AUTH", | |
| "password", | |
| "Authenticate to the server", | |
| 8, | |
| "1.0.0" }, | |
| { "BGREWRITEAOF", | |
| "-", | |
| "Asynchronously rewrite the append-only file", | |
| 9, | |
| "1.0.0" }, | |
| { "BGSAVE", | |
| "-", | |
| "Asynchronously save the dataset to disk", | |
| 9, | |
| "1.0.0" }, | |
| { "BITCOUNT", | |
| "key [start end]", | |
| "Count set bits in a string", | |
| 1, | |
| "2.6.0" }, | |
| { "BITFIELD", | |
| "key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]", | |
| "Perform arbitrary bitfield integer operations on strings", | |
| 1, | |
| "3.2.0" }, | |
| { "BITOP", | |
| "operation destkey key [key ...]", | |
| "Perform bitwise operations between strings", | |
| 1, | |
| "2.6.0" }, | |
| { "BITPOS", | |
| "key bit [start] [end]", | |
| "Find first bit set or clear in a string", | |
| 1, | |
| "2.8.7" }, | |
| { "BLPOP", | |
| "key [key ...] timeout", | |
| "Remove and get the first element in a list, or block until one is available", | |
| 2, | |
| "2.0.0" }, | |
| { "BRPOP", | |
| "key [key ...] timeout", | |
| "Remove and get the last element in a list, or block until one is available", | |
| 2, | |
| "2.0.0" }, | |
| { "BRPOPLPUSH", | |
| "source destination timeout", | |
| "Pop a value from a list, push it to another list and return it; or block until one is available", | |
| 2, | |
| "2.2.0" }, | |
| { "CLIENT GETNAME", | |
| "-", | |
| "Get the current connection name", | |
| 9, | |
| "2.6.9" }, | |
| { "CLIENT KILL", | |
| "[ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]", | |
| "Kill the connection of a client", | |
| 9, | |
| "2.4.0" }, | |
| { "CLIENT LIST", | |
| "-", | |
| "Get the list of client connections", | |
| 9, | |
| "2.4.0" }, | |
| { "CLIENT PAUSE", | |
| "timeout", | |
| "Stop processing commands from clients for some time", | |
| 9, | |
| "2.9.50" }, | |
| { "CLIENT REPLY", | |
| "ON|OFF|SKIP", | |
| "Instruct the server whether to reply to commands", | |
| 9, | |
| "3.2" }, | |
| { "CLIENT SETNAME", | |
| "connection-name", | |
| "Set the current connection name", | |
| 9, | |
| "2.6.9" }, | |
| { "CLUSTER ADDSLOTS", | |
| "slot [slot ...]", | |
| "Assign new hash slots to receiving node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER COUNT-FAILURE-REPORTS", | |
| "node-id", | |
| "Return the number of failure reports active for a given node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER COUNTKEYSINSLOT", | |
| "slot", | |
| "Return the number of local keys in the specified hash slot", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER DELSLOTS", | |
| "slot [slot ...]", | |
| "Set hash slots as unbound in receiving node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER FAILOVER", | |
| "[FORCE|TAKEOVER]", | |
| "Forces a slave to perform a manual failover of its master.", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER FORGET", | |
| "node-id", | |
| "Remove a node from the nodes table", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER GETKEYSINSLOT", | |
| "slot count", | |
| "Return local key names in the specified hash slot", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER INFO", | |
| "-", | |
| "Provides info about Redis Cluster node state", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER KEYSLOT", | |
| "key", | |
| "Returns the hash slot of the specified key", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER MEET", | |
| "ip port", | |
| "Force a node cluster to handshake with another node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER NODES", | |
| "-", | |
| "Get Cluster config for the node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER REPLICATE", | |
| "node-id", | |
| "Reconfigure a node as a slave of the specified master node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER RESET", | |
| "[HARD|SOFT]", | |
| "Reset a Redis Cluster node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER SAVECONFIG", | |
| "-", | |
| "Forces the node to save cluster state on disk", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER SET-CONFIG-EPOCH", | |
| "config-epoch", | |
| "Set the configuration epoch in a new node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER SETSLOT", | |
| "slot IMPORTING|MIGRATING|STABLE|NODE [node-id]", | |
| "Bind a hash slot to a specific node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER SLAVES", | |
| "node-id", | |
| "List slave nodes of the specified master node", | |
| 12, | |
| "3.0.0" }, | |
| { "CLUSTER SLOTS", | |
| "-", | |
| "Get array of Cluster slot to node mappings", | |
| 12, | |
| "3.0.0" }, | |
| { "COMMAND", | |
| "-", | |
| "Get array of Redis command details", | |
| 9, | |
| "2.8.13" }, | |
| { "COMMAND COUNT", | |
| "-", | |
| "Get total number of Redis commands", | |
| 9, | |
| "2.8.13" }, | |
| { "COMMAND GETKEYS", | |
| "-", | |
| "Extract keys given a full Redis command", | |
| 9, | |
| "2.8.13" }, | |
| { "COMMAND INFO", | |
| "command-name [command-name ...]", | |
| "Get array of specific Redis command details", | |
| 9, | |
| "2.8.13" }, | |
| { "CONFIG GET", | |
| "parameter", | |
| "Get the value of a configuration parameter", | |
| 9, | |
| "2.0.0" }, | |
| { "CONFIG RESETSTAT", | |
| "-", | |
| "Reset the stats returned by INFO", | |
| 9, | |
| "2.0.0" }, | |
| { "CONFIG REWRITE", | |
| "-", | |
| "Rewrite the configuration file with the in memory configuration", | |
| 9, | |
| "2.8.0" }, | |
| { "CONFIG SET", | |
| "parameter value", | |
| "Set a configuration parameter to the given value", | |
| 9, | |
| "2.0.0" }, | |
| { "DBSIZE", | |
| "-", | |
| "Return the number of keys in the selected database", | |
| 9, | |
| "1.0.0" }, | |
| { "DEBUG OBJECT", | |
| "key", | |
| "Get debugging information about a key", | |
| 9, | |
| "1.0.0" }, | |
| { "DEBUG SEGFAULT", | |
| "-", | |
| "Make the server crash", | |
| 9, | |
| "1.0.0" }, | |
| { "DECR", | |
| "key", | |
| "Decrement the integer value of a key by one", | |
| 1, | |
| "1.0.0" }, | |
| { "DECRBY", | |
| "key decrement", | |
| "Decrement the integer value of a key by the given number", | |
| 1, | |
| "1.0.0" }, | |
| { "DEL", | |
| "key [key ...]", | |
| "Delete a key", | |
| 0, | |
| "1.0.0" }, | |
| { "DISCARD", | |
| "-", | |
| "Discard all commands issued after MULTI", | |
| 7, | |
| "2.0.0" }, | |
| { "DUMP", | |
| "key", | |
| "Return a serialized version of the value stored at the specified key.", | |
| 0, | |
| "2.6.0" }, | |
| { "ECHO", | |
| "message", | |
| "Echo the given string", | |
| 8, | |
| "1.0.0" }, | |
| { "EVAL", | |
| "script numkeys key [key ...] arg [arg ...]", | |
| "Execute a Lua script server side", | |
| 10, | |
| "2.6.0" }, | |
| { "EVALSHA", | |
| "sha1 numkeys key [key ...] arg [arg ...]", | |
| "Execute a Lua script server side", | |
| 10, | |
| "2.6.0" }, | |
| { "EXEC", | |
| "-", | |
| "Execute all commands issued after MULTI", | |
| 7, | |
| "1.2.0" }, | |
| { "EXISTS", | |
| "key [key ...]", | |
| "Determine if a key exists", | |
| 0, | |
| "1.0.0" }, | |
| { "EXPIRE", | |
| "key seconds", | |
| "Set a key's time to live in seconds", | |
| 0, | |
| "1.0.0" }, | |
| { "EXPIREAT", | |
| "key timestamp", | |
| "Set the expiration for a key as a UNIX timestamp", | |
| 0, | |
| "1.2.0" }, | |
| { "FLUSHALL", | |
| "-", | |
| "Remove all keys from all databases", | |
| 9, | |
| "1.0.0" }, | |
| { "FLUSHDB", | |
| "-", | |
| "Remove all keys from the current database", | |
| 9, | |
| "1.0.0" }, | |
| { "GEOADD", | |
| "key longitude latitude member [longitude latitude member ...]", | |
| "Add one or more geospatial items in the geospatial index represented using a sorted set", | |
| 13, | |
| "3.2.0" }, | |
| { "GEODIST", | |
| "key member1 member2 [unit]", | |
| "Returns the distance between two members of a geospatial index", | |
| 13, | |
| "3.2.0" }, | |
| { "GEOHASH", | |
| "key member [member ...]", | |
| "Returns members of a geospatial index as standard geohash strings", | |
| 13, | |
| "3.2.0" }, | |
| { "GEOPOS", | |
| "key member [member ...]", | |
| "Returns longitude and latitude of members of a geospatial index", | |
| 13, | |
| "3.2.0" }, | |
| { "GEORADIUS", | |
| "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", | |
| "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", | |
| 13, | |
| "3.2.0" }, | |
| { "GEORADIUSBYMEMBER", | |
| "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]", | |
| "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", | |
| 13, | |
| "3.2.0" }, | |
| { "GET", | |
| "key", | |
| "Get the value of a key", | |
| 1, | |
| "1.0.0" }, | |
| { "GETBIT", | |
| "key offset", | |
| "Returns the bit value at offset in the string value stored at key", | |
| 1, | |
| "2.2.0" }, | |
| { "GETRANGE", | |
| "key start end", | |
| "Get a substring of the string stored at a key", | |
| 1, | |
| "2.4.0" }, | |
| { "GETSET", | |
| "key value", | |
| "Set the string value of a key and return its old value", | |
| 1, | |
| "1.0.0" }, | |
| { "HDEL", | |
| "key field [field ...]", | |
| "Delete one or more hash fields", | |
| 5, | |
| "2.0.0" }, | |
| { "HEXISTS", | |
| "key field", | |
| "Determine if a hash field exists", | |
| 5, | |
| "2.0.0" }, | |
| { "HGET", | |
| "key field", | |
| "Get the value of a hash field", | |
| 5, | |
| "2.0.0" }, | |
| { "HGETALL", | |
| "key", | |
| "Get all the fields and values in a hash", | |
| 5, | |
| "2.0.0" }, | |
| { "HINCRBY", | |
| "key field increment", | |
| "Increment the integer value of a hash field by the given number", | |
| 5, | |
| "2.0.0" }, | |
| { "HINCRBYFLOAT", | |
| "key field increment", | |
| "Increment the float value of a hash field by the given amount", | |
| 5, | |
| "2.6.0" }, | |
| { "HKEYS", | |
| "key", | |
| "Get all the fields in a hash", | |
| 5, | |
| "2.0.0" }, | |
| { "HLEN", | |
| "key", | |
| "Get the number of fields in a hash", | |
| 5, | |
| "2.0.0" }, | |
| { "HMGET", | |
| "key field [field ...]", | |
| "Get the values of all the given hash fields", | |
| 5, | |
| "2.0.0" }, | |
| { "HMSET", | |
| "key field value [field value ...]", | |
| "Set multiple hash fields to multiple values", | |
| 5, | |
| "2.0.0" }, | |
| { "HSCAN", | |
| "key cursor [MATCH pattern] [COUNT count]", | |
| "Incrementally iterate hash fields and associated values", | |
| 5, | |
| "2.8.0" }, | |
| { "HSET", | |
| "key field value", | |
| "Set the string value of a hash field", | |
| 5, | |
| "2.0.0" }, | |
| { "HSETNX", | |
| "key field value", | |
| "Set the value of a hash field, only if the field does not exist", | |
| 5, | |
| "2.0.0" }, | |
| { "HSTRLEN", | |
| "key field", | |
| "Get the length of the value of a hash field", | |
| 5, | |
| "3.2.0" }, | |
| { "HVALS", | |
| "key", | |
| "Get all the values in a hash", | |
| 5, | |
| "2.0.0" }, | |
| { "INCR", | |
| "key", | |
| "Increment the integer value of a key by one", | |
| 1, | |
| "1.0.0" }, | |
| { "INCRBY", | |
| "key increment", | |
| "Increment the integer value of a key by the given amount", | |
| 1, | |
| "1.0.0" }, | |
| { "INCRBYFLOAT", | |
| "key increment", | |
| "Increment the float value of a key by the given amount", | |
| 1, | |
| "2.6.0" }, | |
| { "INFO", | |
| "[section]", | |
| "Get information and statistics about the server", | |
| 9, | |
| "1.0.0" }, | |
| { "KEYS", | |
| "pattern", | |
| "Find all keys matching the given pattern", | |
| 0, | |
| "1.0.0" }, | |
| { "LASTSAVE", | |
| "-", | |
| "Get the UNIX time stamp of the last successful save to disk", | |
| 9, | |
| "1.0.0" }, | |
| { "LINDEX", | |
| "key index", | |
| "Get an element from a list by its index", | |
| 2, | |
| "1.0.0" }, | |
| { "LINSERT", | |
| "key BEFORE|AFTER pivot value", | |
| "Insert an element before or after another element in a list", | |
| 2, | |
| "2.2.0" }, | |
| { "LLEN", | |
| "key", | |
| "Get the length of a list", | |
| 2, | |
| "1.0.0" }, | |
| { "LPOP", | |
| "key", | |
| "Remove and get the first element in a list", | |
| 2, | |
| "1.0.0" }, | |
| { "LPUSH", | |
| "key value [value ...]", | |
| "Prepend one or multiple values to a list", | |
| 2, | |
| "1.0.0" }, | |
| { "LPUSHX", | |
| "key value", | |
| "Prepend a value to a list, only if the list exists", | |
| 2, | |
| "2.2.0" }, | |
| { "LRANGE", | |
| "key start stop", | |
| "Get a range of elements from a list", | |
| 2, | |
| "1.0.0" }, | |
| { "LREM", | |
| "key count value", | |
| "Remove elements from a list", | |
| 2, | |
| "1.0.0" }, | |
| { "LSET", | |
| "key index value", | |
| "Set the value of an element in a list by its index", | |
| 2, | |
| "1.0.0" }, | |
| { "LTRIM", | |
| "key start stop", | |
| "Trim a list to the specified range", | |
| 2, | |
| "1.0.0" }, | |
| { "MGET", | |
| "key [key ...]", | |
| "Get the values of all the given keys", | |
| 1, | |
| "1.0.0" }, | |
| { "MIGRATE", | |
| "host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]", | |
| "Atomically transfer a key from a Redis instance to another one.", | |
| 0, | |
| "2.6.0" }, | |
| { "MONITOR", | |
| "-", | |
| "Listen for all requests received by the server in real time", | |
| 9, | |
| "1.0.0" }, | |
| { "MOVE", | |
| "key db", | |
| "Move a key to another database", | |
| 0, | |
| "1.0.0" }, | |
| { "MSET", | |
| "key value [key value ...]", | |
| "Set multiple keys to multiple values", | |
| 1, | |
| "1.0.1" }, | |
| { "MSETNX", | |
| "key value [key value ...]", | |
| "Set multiple keys to multiple values, only if none of the keys exist", | |
| 1, | |
| "1.0.1" }, | |
| { "MULTI", | |
| "-", | |
| "Mark the start of a transaction block", | |
| 7, | |
| "1.2.0" }, | |
| { "OBJECT", | |
| "subcommand [arguments [arguments ...]]", | |
| "Inspect the internals of Redis objects", | |
| 0, | |
| "2.2.3" }, | |
| { "PERSIST", | |
| "key", | |
| "Remove the expiration from a key", | |
| 0, | |
| "2.2.0" }, | |
| { "PEXPIRE", | |
| "key milliseconds", | |
| "Set a key's time to live in milliseconds", | |
| 0, | |
| "2.6.0" }, | |
| { "PEXPIREAT", | |
| "key milliseconds-timestamp", | |
| "Set the expiration for a key as a UNIX timestamp specified in milliseconds", | |
| 0, | |
| "2.6.0" }, | |
| { "PFADD", | |
| "key element [element ...]", | |
| "Adds the specified elements to the specified HyperLogLog.", | |
| 11, | |
| "2.8.9" }, | |
| { "PFCOUNT", | |
| "key [key ...]", | |
| "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", | |
| 11, | |
| "2.8.9" }, | |
| { "PFMERGE", | |
| "destkey sourcekey [sourcekey ...]", | |
| "Merge N different HyperLogLogs into a single one.", | |
| 11, | |
| "2.8.9" }, | |
| { "PING", | |
| "[message]", | |
| "Ping the server", | |
| 8, | |
| "1.0.0" }, | |
| { "PSETEX", | |
| "key milliseconds value", | |
| "Set the value and expiration in milliseconds of a key", | |
| 1, | |
| "2.6.0" }, | |
| { "PSUBSCRIBE", | |
| "pattern [pattern ...]", | |
| "Listen for messages published to channels matching the given patterns", | |
| 6, | |
| "2.0.0" }, | |
| { "PTTL", | |
| "key", | |
| "Get the time to live for a key in milliseconds", | |
| 0, | |
| "2.6.0" }, | |
| { "PUBLISH", | |
| "channel message", | |
| "Post a message to a channel", | |
| 6, | |
| "2.0.0" }, | |
| { "PUBSUB", | |
| "subcommand [argument [argument ...]]", | |
| "Inspect the state of the Pub/Sub subsystem", | |
| 6, | |
| "2.8.0" }, | |
| { "PUNSUBSCRIBE", | |
| "[pattern [pattern ...]]", | |
| "Stop listening for messages posted to channels matching the given patterns", | |
| 6, | |
| "2.0.0" }, | |
| { "QUIT", | |
| "-", | |
| "Close the connection", | |
| 8, | |
| "1.0.0" }, | |
| { "RANDOMKEY", | |
| "-", | |
| "Return a random key from the keyspace", | |
| 0, | |
| "1.0.0" }, | |
| { "READONLY", | |
| "-", | |
| "Enables read queries for a connection to a cluster slave node", | |
| 12, | |
| "3.0.0" }, | |
| { "READWRITE", | |
| "-", | |
| "Disables read queries for a connection to a cluster slave node", | |
| 12, | |
| "3.0.0" }, | |
| { "RENAME", | |
| "key newkey", | |
| "Rename a key", | |
| 0, | |
| "1.0.0" }, | |
| { "RENAMENX", | |
| "key newkey", | |
| "Rename a key, only if the new key does not exist", | |
| 0, | |
| "1.0.0" }, | |
| { "RESTORE", | |
| "key ttl serialized-value [REPLACE]", | |
| "Create a key using the provided serialized value, previously obtained using DUMP.", | |
| 0, | |
| "2.6.0" }, | |
| { "ROLE", | |
| "-", | |
| "Return the role of the instance in the context of replication", | |
| 9, | |
| "2.8.12" }, | |
| { "RPOP", | |
| "key", | |
| "Remove and get the last element in a list", | |
| 2, | |
| "1.0.0" }, | |
| { "RPOPLPUSH", | |
| "source destination", | |
| "Remove the last element in a list, prepend it to another list and return it", | |
| 2, | |
| "1.2.0" }, | |
| { "RPUSH", | |
| "key value [value ...]", | |
| "Append one or multiple values to a list", | |
| 2, | |
| "1.0.0" }, | |
| { "RPUSHX", | |
| "key value", | |
| "Append a value to a list, only if the list exists", | |
| 2, | |
| "2.2.0" }, | |
| { "SADD", | |
| "key member [member ...]", | |
| "Add one or more members to a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SAVE", | |
| "-", | |
| "Synchronously save the dataset to disk", | |
| 9, | |
| "1.0.0" }, | |
| { "SCAN", | |
| "cursor [MATCH pattern] [COUNT count]", | |
| "Incrementally iterate the keys space", | |
| 0, | |
| "2.8.0" }, | |
| { "SCARD", | |
| "key", | |
| "Get the number of members in a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SCRIPT DEBUG", | |
| "YES|SYNC|NO", | |
| "Set the debug mode for executed scripts.", | |
| 10, | |
| "3.2.0" }, | |
| { "SCRIPT EXISTS", | |
| "script [script ...]", | |
| "Check existence of scripts in the script cache.", | |
| 10, | |
| "2.6.0" }, | |
| { "SCRIPT FLUSH", | |
| "-", | |
| "Remove all the scripts from the script cache.", | |
| 10, | |
| "2.6.0" }, | |
| { "SCRIPT KILL", | |
| "-", | |
| "Kill the script currently in execution.", | |
| 10, | |
| "2.6.0" }, | |
| { "SCRIPT LOAD", | |
| "script", | |
| "Load the specified Lua script into the script cache.", | |
| 10, | |
| "2.6.0" }, | |
| { "SDIFF", | |
| "key [key ...]", | |
| "Subtract multiple sets", | |
| 3, | |
| "1.0.0" }, | |
| { "SDIFFSTORE", | |
| "destination key [key ...]", | |
| "Subtract multiple sets and store the resulting set in a key", | |
| 3, | |
| "1.0.0" }, | |
| { "SELECT", | |
| "index", | |
| "Change the selected database for the current connection", | |
| 8, | |
| "1.0.0" }, | |
| { "SET", | |
| "key value [EX seconds] [PX milliseconds] [NX|XX]", | |
| "Set the string value of a key", | |
| 1, | |
| "1.0.0" }, | |
| { "SETBIT", | |
| "key offset value", | |
| "Sets or clears the bit at offset in the string value stored at key", | |
| 1, | |
| "2.2.0" }, | |
| { "SETEX", | |
| "key seconds value", | |
| "Set the value and expiration of a key", | |
| 1, | |
| "2.0.0" }, | |
| { "SETNX", | |
| "key value", | |
| "Set the value of a key, only if the key does not exist", | |
| 1, | |
| "1.0.0" }, | |
| { "SETRANGE", | |
| "key offset value", | |
| "Overwrite part of a string at key starting at the specified offset", | |
| 1, | |
| "2.2.0" }, | |
| { "SHUTDOWN", | |
| "[NOSAVE|SAVE]", | |
| "Synchronously save the dataset to disk and then shut down the server", | |
| 9, | |
| "1.0.0" }, | |
| { "SINTER", | |
| "key [key ...]", | |
| "Intersect multiple sets", | |
| 3, | |
| "1.0.0" }, | |
| { "SINTERSTORE", | |
| "destination key [key ...]", | |
| "Intersect multiple sets and store the resulting set in a key", | |
| 3, | |
| "1.0.0" }, | |
| { "SISMEMBER", | |
| "key member", | |
| "Determine if a given value is a member of a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SLAVEOF", | |
| "host port", | |
| "Make the server a slave of another instance, or promote it as master", | |
| 9, | |
| "1.0.0" }, | |
| { "SLOWLOG", | |
| "subcommand [argument]", | |
| "Manages the Redis slow queries log", | |
| 9, | |
| "2.2.12" }, | |
| { "SMEMBERS", | |
| "key", | |
| "Get all the members in a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SMOVE", | |
| "source destination member", | |
| "Move a member from one set to another", | |
| 3, | |
| "1.0.0" }, | |
| { "SORT", | |
| "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", | |
| "Sort the elements in a list, set or sorted set", | |
| 0, | |
| "1.0.0" }, | |
| { "SPOP", | |
| "key [count]", | |
| "Remove and return one or multiple random members from a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SRANDMEMBER", | |
| "key [count]", | |
| "Get one or multiple random members from a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SREM", | |
| "key member [member ...]", | |
| "Remove one or more members from a set", | |
| 3, | |
| "1.0.0" }, | |
| { "SSCAN", | |
| "key cursor [MATCH pattern] [COUNT count]", | |
| "Incrementally iterate Set elements", | |
| 3, | |
| "2.8.0" }, | |
| { "STRLEN", | |
| "key", | |
| "Get the length of the value stored in a key", | |
| 1, | |
| "2.2.0" }, | |
| { "SUBSCRIBE", | |
| "channel [channel ...]", | |
| "Listen for messages published to the given channels", | |
| 6, | |
| "2.0.0" }, | |
| { "SUNION", | |
| "key [key ...]", | |
| "Add multiple sets", | |
| 3, | |
| "1.0.0" }, | |
| { "SUNIONSTORE", | |
| "destination key [key ...]", | |
| "Add multiple sets and store the resulting set in a key", | |
| 3, | |
| "1.0.0" }, | |
| { "SYNC", | |
| "-", | |
| "Internal command used for replication", | |
| 9, | |
| "1.0.0" }, | |
| { "TIME", | |
| "-", | |
| "Return the current server time", | |
| 9, | |
| "2.6.0" }, | |
| { "TTL", | |
| "key", | |
| "Get the time to live for a key", | |
| 0, | |
| "1.0.0" }, | |
| { "TYPE", | |
| "key", | |
| "Determine the type stored at key", | |
| 0, | |
| "1.0.0" }, | |
| { "UNSUBSCRIBE", | |
| "[channel [channel ...]]", | |
| "Stop listening for messages posted to the given channels", | |
| 6, | |
| "2.0.0" }, | |
| { "UNWATCH", | |
| "-", | |
| "Forget about all watched keys", | |
| 7, | |
| "2.2.0" }, | |
| { "WAIT", | |
| "numslaves timeout", | |
| "Wait for the synchronous replication of all the write commands sent in the context of the current connection", | |
| 0, | |
| "3.0.0" }, | |
| { "WATCH", | |
| "key [key ...]", | |
| "Watch the given keys to determine execution of the MULTI/EXEC block", | |
| 7, | |
| "2.2.0" }, | |
| { "ZADD", | |
| "key [NX|XX] [CH] [INCR] score member [score member ...]", | |
| "Add one or more members to a sorted set, or update its score if it already exists", | |
| 4, | |
| "1.2.0" }, | |
| { "ZCARD", | |
| "key", | |
| "Get the number of members in a sorted set", | |
| 4, | |
| "1.2.0" }, | |
| { "ZCOUNT", | |
| "key min max", | |
| "Count the members in a sorted set with scores within the given values", | |
| 4, | |
| "2.0.0" }, | |
| { "ZINCRBY", | |
| "key increment member", | |
| "Increment the score of a member in a sorted set", | |
| 4, | |
| "1.2.0" }, | |
| { "ZINTERSTORE", | |
| "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", | |
| "Intersect multiple sorted sets and store the resulting sorted set in a new key", | |
| 4, | |
| "2.0.0" }, | |
| { "ZLEXCOUNT", | |
| "key min max", | |
| "Count the number of members in a sorted set between a given lexicographical range", | |
| 4, | |
| "2.8.9" }, | |
| { "ZRANGE", | |
| "key start stop [WITHSCORES]", | |
| "Return a range of members in a sorted set, by index", | |
| 4, | |
| "1.2.0" }, | |
| { "ZRANGEBYLEX", | |
| "key min max [LIMIT offset count]", | |
| "Return a range of members in a sorted set, by lexicographical range", | |
| 4, | |
| "2.8.9" }, | |
| { "ZRANGEBYSCORE", | |
| "key min max [WITHSCORES] [LIMIT offset count]", | |
| "Return a range of members in a sorted set, by score", | |
| 4, | |
| "1.0.5" }, | |
| { "ZRANK", | |
| "key member", | |
| "Determine the index of a member in a sorted set", | |
| 4, | |
| "2.0.0" }, | |
| { "ZREM", | |
| "key member [member ...]", | |
| "Remove one or more members from a sorted set", | |
| 4, | |
| "1.2.0" }, | |
| { "ZREMRANGEBYLEX", | |
| "key min max", | |
| "Remove all members in a sorted set between the given lexicographical range", | |
| 4, | |
| "2.8.9" }, | |
| { "ZREMRANGEBYRANK", | |
| "key start stop", | |
| "Remove all members in a sorted set within the given indexes", | |
| 4, | |
| "2.0.0" }, | |
| { "ZREMRANGEBYSCORE", | |
| "key min max", | |
| "Remove all members in a sorted set within the given scores", | |
| 4, | |
| "1.2.0" }, | |
| { "ZREVRANGE", | |
| "key start stop [WITHSCORES]", | |
| "Return a range of members in a sorted set, by index, with scores ordered from high to low", | |
| 4, | |
| "1.2.0" }, | |
| { "ZREVRANGEBYLEX", | |
| "key max min [LIMIT offset count]", | |
| "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", | |
| 4, | |
| "2.8.9" }, | |
| { "ZREVRANGEBYSCORE", | |
| "key max min [WITHSCORES] [LIMIT offset count]", | |
| "Return a range of members in a sorted set, by score, with scores ordered from high to low", | |
| 4, | |
| "2.2.0" }, | |
| { "ZREVRANK", | |
| "key member", | |
| "Determine the index of a member in a sorted set, with scores ordered from high to low", | |
| 4, | |
| "2.0.0" }, | |
| { "ZSCAN", | |
| "key cursor [MATCH pattern] [COUNT count]", | |
| "Incrementally iterate sorted sets elements and associated scores", | |
| 4, | |
| "2.8.0" }, | |
| { "ZSCORE", | |
| "key member", | |
| "Get the score associated with the given member in a sorted set", | |
| 4, | |
| "1.2.0" }, | |
| { "ZUNIONSTORE", | |
| "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", | |
| "Add multiple sorted sets and store the resulting sorted set in a new key", | |
| 4, | |
| "2.0.0" } | |
| }; | |
| # 54 "src/redis-cli.c" 2 | |
| # 1 "src/anet.h" 1 | |
| # 34 "src/anet.h" | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2 | |
| # 35 "src/anet.h" 2 | |
| # 52 "src/anet.h" | |
| int anetTcpConnect(char *err, char *addr, int port); | |
| int anetTcpNonBlockConnect(char *err, char *addr, int port); | |
| int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr); | |
| int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr); | |
| int anetUnixConnect(char *err, char *path); | |
| int anetUnixNonBlockConnect(char *err, char *path); | |
| int anetRead(int fd, char *buf, int count); | |
| int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len); | |
| int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len); | |
| int anetTcpServer(char *err, int port, char *bindaddr, int backlog); | |
| int anetTcp6Server(char *err, int port, char *bindaddr, int backlog); | |
| int anetUnixServer(char *err, char *path, mode_t perm, int backlog); | |
| int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port); | |
| int anetUnixAccept(char *err, int serversock); | |
| int anetWrite(int fd, char *buf, int count); | |
| int anetNonBlock(char *err, int fd); | |
| int anetBlock(char *err, int fd); | |
| int anetEnableTcpNoDelay(char *err, int fd); | |
| int anetDisableTcpNoDelay(char *err, int fd); | |
| int anetTcpKeepAlive(char *err, int fd); | |
| int anetSendTimeout(char *err, int fd, long long ms); | |
| int anetPeerToString(int fd, char *ip, size_t ip_len, int *port); | |
| int anetKeepAlive(char *err, int fd, int interval); | |
| int anetSockName(int fd, char *ip, size_t ip_len, int *port); | |
| int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); | |
| int anetFormatPeer(int fd, char *fmt, size_t fmt_len); | |
| int anetFormatSock(int fd, char *fmt, size_t fmt_len); | |
| # 55 "src/redis-cli.c" 2 | |
| # 1 "src/ae.h" 1 | |
| # 36 "src/ae.h" | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 | |
| # 37 "src/ae.h" 2 | |
| # 57 "src/ae.h" | |
| struct aeEventLoop; | |
| typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); | |
| typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); | |
| typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); | |
| typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); | |
| typedef struct aeFileEvent { | |
| int mask; | |
| aeFileProc *rfileProc; | |
| aeFileProc *wfileProc; | |
| void *clientData; | |
| } aeFileEvent; | |
| typedef struct aeTimeEvent { | |
| long long id; | |
| long when_sec; | |
| long when_ms; | |
| aeTimeProc *timeProc; | |
| aeEventFinalizerProc *finalizerProc; | |
| void *clientData; | |
| struct aeTimeEvent *next; | |
| } aeTimeEvent; | |
| typedef struct aeFiredEvent { | |
| int fd; | |
| int mask; | |
| } aeFiredEvent; | |
| typedef struct aeEventLoop { | |
| int maxfd; | |
| int setsize; | |
| long long timeEventNextId; | |
| time_t lastTime; | |
| aeFileEvent *events; | |
| aeFiredEvent *fired; | |
| aeTimeEvent *timeEventHead; | |
| int stop; | |
| void *apidata; | |
| aeBeforeSleepProc *beforesleep; | |
| aeBeforeSleepProc *aftersleep; | |
| } aeEventLoop; | |
| aeEventLoop *aeCreateEventLoop(int setsize); | |
| void aeDeleteEventLoop(aeEventLoop *eventLoop); | |
| void aeStop(aeEventLoop *eventLoop); | |
| int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, | |
| aeFileProc *proc, void *clientData); | |
| void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); | |
| int aeGetFileEvents(aeEventLoop *eventLoop, int fd); | |
| long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, | |
| aeTimeProc *proc, void *clientData, | |
| aeEventFinalizerProc *finalizerProc); | |
| int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); | |
| int aeProcessEvents(aeEventLoop *eventLoop, int flags); | |
| int aeWait(int fd, int mask, long long milliseconds); | |
| void aeMain(aeEventLoop *eventLoop); | |
| char *aeGetApiName(void); | |
| void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); | |
| void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep); | |
| int aeGetSetSize(aeEventLoop *eventLoop); | |
| int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); | |
| # 56 "src/redis-cli.c" 2 | |
| # 70 "src/redis-cli.c" | |
| int spectrum_palette_color_size = 19; | |
| int spectrum_palette_color[] = {0,233,234,235,237,239,241,243,245,247,144,143,142,184,226,214,208,202,196}; | |
| int spectrum_palette_mono_size = 13; | |
| int spectrum_palette_mono[] = {0,233,234,235,237,239,241,243,245,247,249,251,253}; | |
| int *spectrum_palette; | |
| int spectrum_palette_size; | |
| static redisContext *context; | |
| static struct config { | |
| char *hostip; | |
| int hostport; | |
| char *hostsocket; | |
| long repeat; | |
| long interval; | |
| int dbnum; | |
| int interactive; | |
| int shutdown; | |
| int monitor_mode; | |
| int pubsub_mode; | |
| int latency_mode; | |
| int latency_dist_mode; | |
| int latency_history; | |
| int lru_test_mode; | |
| long long lru_test_sample_size; | |
| int cluster_mode; | |
| int cluster_reissue_command; | |
| int slave_mode; | |
| int pipe_mode; | |
| int pipe_timeout; | |
| int getrdb_mode; | |
| int stat_mode; | |
| int scan_mode; | |
| int intrinsic_latency_mode; | |
| int intrinsic_latency_duration; | |
| char *pattern; | |
| char *rdb_filename; | |
| int bigkeys; | |
| int hotkeys; | |
| int stdinarg; | |
| char *auth; | |
| int output; | |
| sds mb_delim; | |
| char prompt[128]; | |
| char *eval; | |
| int eval_ldb; | |
| int eval_ldb_sync; | |
| int eval_ldb_end; | |
| int enable_ldb_on_eval; | |
| int last_cmd_type; | |
| } config; | |
| static struct pref { | |
| int hints; | |
| } pref; | |
| static volatile sig_atomic_t force_cancel_loop = 0; | |
| static void usage(void); | |
| static void slaveMode(void); | |
| char *redisGitSHA1(void); | |
| char *redisGitDirty(void); | |
| static int cliConnect(int force); | |
| static long long ustime(void) { | |
| struct timeval tv; | |
| long long ust; | |
| gettimeofday(&tv, 0); | |
| ust = ((long long)tv.tv_sec)*1000000; | |
| ust += tv.tv_usec; | |
| return ust; | |
| } | |
| static long long mstime(void) { | |
| return ustime()/1000; | |
| } | |
| static void cliRefreshPrompt(void) { | |
| int len; | |
| if (config.eval_ldb) return; | |
| if (config.hostsocket != 0) | |
| len = snprintf(config.prompt,sizeof(config.prompt),"redis %s", | |
| config.hostsocket); | |
| else | |
| len = anetFormatAddr(config.prompt, sizeof(config.prompt), | |
| config.hostip, config.hostport); | |
| if (config.dbnum != 0) | |
| len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]", | |
| config.dbnum); | |
| snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); | |
| } | |
| # 179 "src/redis-cli.c" | |
| static sds getDotfilePath(char *envoverride, char *dotfilename) { | |
| char *path = 0; | |
| sds dotPath = 0; | |
| path = getenv(envoverride); | |
| if (path != 0 && *path != '\0') { | |
| if (!strcmp("/dev/null", path)) { | |
| return 0; | |
| } | |
| dotPath = sdsnew(path); | |
| } else { | |
| char *home = getenv("HOME"); | |
| if (home != 0 && *home != '\0') { | |
| dotPath = sdscatprintf(sdsempty(), "%s/%s", home, dotfilename); | |
| } | |
| } | |
| return dotPath; | |
| } | |
| static sds percentDecode(const char *pe, size_t len) { | |
| const char *end = pe + len; | |
| sds ret = sdsempty(); | |
| const char *curr = pe; | |
| while (curr < end) { | |
| if (*curr == '%') { | |
| if ((end - curr) < 2) { | |
| fprintf(stderr, "Incomplete URI encoding\n"); | |
| exit(1); | |
| } | |
| char h = tolower(*(++curr)); | |
| char l = tolower(*(++curr)); | |
| if (!(isdigit(h) || (h >= 'a' && h <= 'f')) || !(isdigit(l) || (l >= 'a' && l <= 'f'))) { | |
| fprintf(stderr, "Illegal character in URI encoding\n"); | |
| exit(1); | |
| } | |
| char c = (((isdigit(h) ? h - '0' : h - 'a' + 10) << 4) + (isdigit(l) ? l - '0' : l - 'a' + 10)); | |
| ret = sdscatlen(ret, &c, 1); | |
| curr++; | |
| } else { | |
| ret = sdscatlen(ret, curr++, 1); | |
| } | |
| } | |
| return ret; | |
| } | |
| # 244 "src/redis-cli.c" | |
| static void parseRedisUri(const char *uri) { | |
| const char *scheme = "redis://"; | |
| const char *curr = uri; | |
| const char *end = uri + strlen(uri); | |
| const char *userinfo, *username, *port, *host, *path; | |
| if (strncasecmp(scheme, curr, strlen(scheme))) { | |
| fprintf(stderr,"Invalid URI scheme\n"); | |
| exit(1); | |
| } | |
| curr += strlen(scheme); | |
| if (curr == end) return; | |
| if ((userinfo = strchr(curr,'@'))) { | |
| if ((username = strchr(curr, ':')) && username < userinfo) { | |
| curr = username + 1; | |
| } | |
| config.auth = percentDecode(curr, userinfo - curr); | |
| curr = userinfo + 1; | |
| } | |
| if (curr == end) return; | |
| path = strchr(curr, '/'); | |
| if (*curr != '/') { | |
| host = path ? path - 1 : end; | |
| if ((port = strchr(curr, ':'))) { | |
| config.hostport = atoi(port + 1); | |
| host = port - 1; | |
| } | |
| config.hostip = sdsnewlen(curr, host - curr + 1); | |
| } | |
| curr = path ? path + 1 : end; | |
| if (curr == end) return; | |
| config.dbnum = atoi(curr); | |
| } | |
| # 295 "src/redis-cli.c" | |
| typedef struct { | |
| int type; | |
| int argc; | |
| sds *argv; | |
| sds full; | |
| struct commandHelp *org; | |
| } helpEntry; | |
| static helpEntry *helpEntries; | |
| static int helpEntriesLen; | |
| static sds cliVersion(void) { | |
| sds version; | |
| version = sdscatprintf(sdsempty(), "%s", "4.0.8"); | |
| if (strtoll(redisGitSHA1(),0,16)) { | |
| version = sdscatprintf(version, " (git:%s", redisGitSHA1()); | |
| if (strtoll(redisGitDirty(),0,10)) | |
| version = sdscatprintf(version, "-dirty"); | |
| version = sdscat(version, ")"); | |
| } | |
| return version; | |
| } | |
| static void cliInitHelp(void) { | |
| int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp); | |
| int groupslen = sizeof(commandGroups)/sizeof(char*); | |
| int i, len, pos = 0; | |
| helpEntry tmp; | |
| helpEntriesLen = len = commandslen+groupslen; | |
| helpEntries = zmalloc(sizeof(helpEntry)*len); | |
| for (i = 0; i < groupslen; i++) { | |
| tmp.argc = 1; | |
| tmp.argv = zmalloc(sizeof(sds)); | |
| tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]); | |
| tmp.full = tmp.argv[0]; | |
| tmp.type = 2; | |
| tmp.org = 0; | |
| helpEntries[pos++] = tmp; | |
| } | |
| for (i = 0; i < commandslen; i++) { | |
| tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc); | |
| tmp.full = sdsnew(commandHelp[i].name); | |
| tmp.type = 1; | |
| tmp.org = &commandHelp[i]; | |
| helpEntries[pos++] = tmp; | |
| } | |
| } | |
| static void cliIntegrateHelp(void) { | |
| if (cliConnect(0) == -1) return; | |
| redisReply *reply = redisCommand(context, "COMMAND"); | |
| if(reply == 0 || reply->type != 2) return; | |
| for (size_t j = 0; j < reply->elements; j++) { | |
| redisReply *entry = reply->element[j]; | |
| if (entry->type != 2 || entry->elements < 4 || | |
| entry->element[0]->type != 1 || | |
| entry->element[1]->type != 3 || | |
| entry->element[3]->type != 3) return; | |
| char *cmdname = entry->element[0]->str; | |
| int i; | |
| for (i = 0; i < helpEntriesLen; i++) { | |
| helpEntry *he = helpEntries+i; | |
| if (!strcasecmp(he->argv[0],cmdname)) | |
| break; | |
| } | |
| if (i != helpEntriesLen) continue; | |
| helpEntriesLen++; | |
| helpEntries = zrealloc(helpEntries,sizeof(helpEntry)*helpEntriesLen); | |
| helpEntry *new = helpEntries+(helpEntriesLen-1); | |
| new->argc = 1; | |
| new->argv = zmalloc(sizeof(sds)); | |
| new->argv[0] = sdsnew(cmdname); | |
| new->full = new->argv[0]; | |
| new->type = 1; | |
| sdstoupper(new->argv[0]); | |
| struct commandHelp *ch = zmalloc(sizeof(*ch)); | |
| ch->name = new->argv[0]; | |
| ch->params = sdsempty(); | |
| int args = llabs(entry->element[1]->integer); | |
| if (entry->element[3]->integer == 1) { | |
| ch->params = sdscat(ch->params,"key "); | |
| args--; | |
| } | |
| while(args--) ch->params = sdscat(ch->params,"arg "); | |
| if (entry->element[1]->integer < 0) | |
| ch->params = sdscat(ch->params,"...options..."); | |
| ch->summary = "Help not available"; | |
| ch->group = 0; | |
| ch->since = "not known"; | |
| new->org = ch; | |
| } | |
| freeReplyObject(reply); | |
| } | |
| static void cliOutputCommandHelp(struct commandHelp *help, int group) { | |
| printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params); | |
| printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary); | |
| printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since); | |
| if (group) { | |
| printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]); | |
| } | |
| } | |
| static void cliOutputGenericHelp(void) { | |
| sds version = cliVersion(); | |
| printf( | |
| "redis-cli %s\n" | |
| "To get help about Redis commands type:\n" | |
| " \"help @<group>\" to get a list of commands in <group>\n" | |
| " \"help <command>\" for help on <command>\n" | |
| " \"help <tab>\" to get a list of possible help topics\n" | |
| " \"quit\" to exit\n" | |
| "\n" | |
| "To set redis-cli preferences:\n" | |
| " \":set hints\" enable online hints\n" | |
| " \":set nohints\" disable online hints\n" | |
| "Set your preferences in ~/.redisclirc\n", | |
| version | |
| ); | |
| sdsfree(version); | |
| } | |
| static void cliOutputHelp(int argc, char **argv) { | |
| int i, j, len; | |
| int group = -1; | |
| helpEntry *entry; | |
| struct commandHelp *help; | |
| if (argc == 0) { | |
| cliOutputGenericHelp(); | |
| return; | |
| } else if (argc > 0 && argv[0][0] == '@') { | |
| len = sizeof(commandGroups)/sizeof(char*); | |
| for (i = 0; i < len; i++) { | |
| if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) { | |
| group = i; | |
| break; | |
| } | |
| } | |
| } | |
| assert(argc > 0); | |
| for (i = 0; i < helpEntriesLen; i++) { | |
| entry = &helpEntries[i]; | |
| if (entry->type != 1) continue; | |
| help = entry->org; | |
| if (group == -1) { | |
| if (argc == entry->argc) { | |
| for (j = 0; j < argc; j++) { | |
| if (strcasecmp(argv[j],entry->argv[j]) != 0) break; | |
| } | |
| if (j == argc) { | |
| cliOutputCommandHelp(help,1); | |
| } | |
| } | |
| } else { | |
| if (group == help->group) { | |
| cliOutputCommandHelp(help,0); | |
| } | |
| } | |
| } | |
| printf("\r\n"); | |
| } | |
| static void completionCallback(const char *buf, linenoiseCompletions *lc) { | |
| size_t startpos = 0; | |
| int mask; | |
| int i; | |
| size_t matchlen; | |
| sds tmp; | |
| if (strncasecmp(buf,"help ",5) == 0) { | |
| startpos = 5; | |
| while (isspace(buf[startpos])) startpos++; | |
| mask = 1 | 2; | |
| } else { | |
| mask = 1; | |
| } | |
| for (i = 0; i < helpEntriesLen; i++) { | |
| if (!(helpEntries[i].type & mask)) continue; | |
| matchlen = strlen(buf+startpos); | |
| if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) { | |
| tmp = sdsnewlen(buf,startpos); | |
| tmp = sdscat(tmp,helpEntries[i].full); | |
| linenoiseAddCompletion(lc,tmp); | |
| sdsfree(tmp); | |
| } | |
| } | |
| } | |
| static char *hintsCallback(const char *buf, int *color, int *bold) { | |
| if (!pref.hints) return 0; | |
| int i, argc, buflen = strlen(buf); | |
| sds *argv = sdssplitargs(buf,&argc); | |
| int endspace = buflen && isspace(buf[buflen-1]); | |
| if (argc == 0) { | |
| sdsfreesplitres(argv,argc); | |
| return 0; | |
| } | |
| for (i = 0; i < helpEntriesLen; i++) { | |
| if (!(helpEntries[i].type & 1)) continue; | |
| if (strcasecmp(argv[0],helpEntries[i].full) == 0) | |
| { | |
| *color = 90; | |
| *bold = 0; | |
| sds hint = sdsnew(helpEntries[i].org->params); | |
| int toremove = argc-1; | |
| while(toremove > 0 && sdslen(hint)) { | |
| if (hint[0] == '[') break; | |
| if (hint[0] == ' ') toremove--; | |
| sdsrange(hint,1,-1); | |
| } | |
| if (!endspace) { | |
| sds newhint = sdsnewlen(" ",1); | |
| newhint = sdscatsds(newhint,hint); | |
| sdsfree(hint); | |
| hint = newhint; | |
| } | |
| sdsfreesplitres(argv,argc); | |
| return hint; | |
| } | |
| } | |
| sdsfreesplitres(argv,argc); | |
| return 0; | |
| } | |
| static void freeHintsCallback(void *ptr) { | |
| sdsfree(ptr); | |
| } | |
| static int cliAuth(void) { | |
| redisReply *reply; | |
| if (config.auth == 0) return 0; | |
| reply = redisCommand(context,"AUTH %s",config.auth); | |
| if (reply != 0) { | |
| freeReplyObject(reply); | |
| return 0; | |
| } | |
| return -1; | |
| } | |
| static int cliSelect(void) { | |
| redisReply *reply; | |
| if (config.dbnum == 0) return 0; | |
| reply = redisCommand(context,"SELECT %d",config.dbnum); | |
| if (reply != 0) { | |
| int result = 0; | |
| if (reply->type == 6) result = -1; | |
| freeReplyObject(reply); | |
| return result; | |
| } | |
| return -1; | |
| } | |
| static int cliConnect(int force) { | |
| if (context == 0 || force) { | |
| if (context != 0) { | |
| redisFree(context); | |
| } | |
| if (config.hostsocket == 0) { | |
| context = redisConnect(config.hostip,config.hostport); | |
| } else { | |
| context = redisConnectUnix(config.hostsocket); | |
| } | |
| if (context->err) { | |
| fprintf(stderr,"Could not connect to Redis at "); | |
| if (config.hostsocket == 0) | |
| fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr); | |
| else | |
| fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr); | |
| redisFree(context); | |
| context = 0; | |
| return -1; | |
| } | |
| anetKeepAlive(0, context->fd, 15); | |
| if (cliAuth() != 0) | |
| return -1; | |
| if (cliSelect() != 0) | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| static void cliPrintContextError(void) { | |
| if (context == 0) return; | |
| fprintf(stderr,"Error: %s\n",context->errstr); | |
| } | |
| static sds cliFormatReplyTTY(redisReply *r, char *prefix) { | |
| sds out = sdsempty(); | |
| switch (r->type) { | |
| case 6: | |
| out = sdscatprintf(out,"(error) %s\n", r->str); | |
| break; | |
| case 5: | |
| out = sdscat(out,r->str); | |
| out = sdscat(out,"\n"); | |
| break; | |
| case 3: | |
| out = sdscatprintf(out,"(integer) %lld\n",r->integer); | |
| break; | |
| case 1: | |
| out = sdscatrepr(out,r->str,r->len); | |
| out = sdscat(out,"\n"); | |
| break; | |
| case 4: | |
| out = sdscat(out,"(nil)\n"); | |
| break; | |
| case 2: | |
| if (r->elements == 0) { | |
| out = sdscat(out,"(empty list or set)\n"); | |
| } else { | |
| unsigned int i, idxlen = 0; | |
| char _prefixlen[16]; | |
| char _prefixfmt[16]; | |
| sds _prefix; | |
| sds tmp; | |
| i = r->elements; | |
| do { | |
| idxlen++; | |
| i /= 10; | |
| } while(i); | |
| memset(_prefixlen,' ',idxlen+2); | |
| _prefixlen[idxlen+2] = '\0'; | |
| _prefix = sdscat(sdsnew(prefix),_prefixlen); | |
| snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%ud) ",idxlen); | |
| for (i = 0; i < r->elements; i++) { | |
| out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1); | |
| tmp = cliFormatReplyTTY(r->element[i],_prefix); | |
| out = sdscatlen(out,tmp,sdslen(tmp)); | |
| sdsfree(tmp); | |
| } | |
| sdsfree(_prefix); | |
| } | |
| break; | |
| default: | |
| fprintf(stderr,"Unknown reply type: %d\n", r->type); | |
| exit(1); | |
| } | |
| return out; | |
| } | |
| int isColorTerm(void) { | |
| char *t = getenv("TERM"); | |
| return t != 0 && strstr(t,"xterm") != 0; | |
| } | |
| sds sdscatcolor(sds o, char *s, size_t len, char *color) { | |
| if (!isColorTerm()) return sdscatlen(o,s,len); | |
| int bold = strstr(color,"bold") != 0; | |
| int ccode = 37; | |
| if (strstr(color,"red")) ccode = 31; | |
| else if (strstr(color,"green")) ccode = 32; | |
| else if (strstr(color,"yellow")) ccode = 33; | |
| else if (strstr(color,"blue")) ccode = 34; | |
| else if (strstr(color,"magenta")) ccode = 35; | |
| else if (strstr(color,"cyan")) ccode = 36; | |
| else if (strstr(color,"white")) ccode = 37; | |
| o = sdscatfmt(o,"\033[%i;%i;49m",bold,ccode); | |
| o = sdscatlen(o,s,len); | |
| o = sdscat(o,"\033[0m"); | |
| return o; | |
| } | |
| sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) { | |
| char *color = "white"; | |
| if (strstr(s,"<debug>")) color = "bold"; | |
| if (strstr(s,"<redis>")) color = "green"; | |
| if (strstr(s,"<reply>")) color = "cyan"; | |
| if (strstr(s,"<error>")) color = "red"; | |
| if (strstr(s,"<hint>")) color = "bold"; | |
| if (strstr(s,"<value>") || strstr(s,"<retval>")) color = "magenta"; | |
| if (len > 4 && isdigit(s[3])) { | |
| if (s[1] == '>') color = "yellow"; | |
| else if (s[2] == '#') color = "bold"; | |
| } | |
| return sdscatcolor(o,s,len,color); | |
| } | |
| static sds cliFormatReplyRaw(redisReply *r) { | |
| sds out = sdsempty(), tmp; | |
| size_t i; | |
| switch (r->type) { | |
| case 4: | |
| break; | |
| case 6: | |
| out = sdscatlen(out,r->str,r->len); | |
| out = sdscatlen(out,"\n",1); | |
| break; | |
| case 5: | |
| case 1: | |
| if (r->type == 5 && config.eval_ldb) { | |
| if (strstr(r->str,"<endsession>") == r->str) { | |
| config.enable_ldb_on_eval = 0; | |
| config.eval_ldb = 0; | |
| config.eval_ldb_end = 1; | |
| config.output = 0; | |
| cliRefreshPrompt(); | |
| } else { | |
| out = sdsCatColorizedLdbReply(out,r->str,r->len); | |
| } | |
| } else { | |
| out = sdscatlen(out,r->str,r->len); | |
| } | |
| break; | |
| case 3: | |
| out = sdscatprintf(out,"%lld",r->integer); | |
| break; | |
| case 2: | |
| for (i = 0; i < r->elements; i++) { | |
| if (i > 0) out = sdscat(out,config.mb_delim); | |
| tmp = cliFormatReplyRaw(r->element[i]); | |
| out = sdscatlen(out,tmp,sdslen(tmp)); | |
| sdsfree(tmp); | |
| } | |
| break; | |
| default: | |
| fprintf(stderr,"Unknown reply type: %d\n", r->type); | |
| exit(1); | |
| } | |
| return out; | |
| } | |
| static sds cliFormatReplyCSV(redisReply *r) { | |
| unsigned int i; | |
| sds out = sdsempty(); | |
| switch (r->type) { | |
| case 6: | |
| out = sdscat(out,"ERROR,"); | |
| out = sdscatrepr(out,r->str,strlen(r->str)); | |
| break; | |
| case 5: | |
| out = sdscatrepr(out,r->str,r->len); | |
| break; | |
| case 3: | |
| out = sdscatprintf(out,"%lld",r->integer); | |
| break; | |
| case 1: | |
| out = sdscatrepr(out,r->str,r->len); | |
| break; | |
| case 4: | |
| out = sdscat(out,"NIL"); | |
| break; | |
| case 2: | |
| for (i = 0; i < r->elements; i++) { | |
| sds tmp = cliFormatReplyCSV(r->element[i]); | |
| out = sdscatlen(out,tmp,sdslen(tmp)); | |
| if (i != r->elements-1) out = sdscat(out,","); | |
| sdsfree(tmp); | |
| } | |
| break; | |
| default: | |
| fprintf(stderr,"Unknown reply type: %d\n", r->type); | |
| exit(1); | |
| } | |
| return out; | |
| } | |
| static int cliReadReply(int output_raw_strings) { | |
| void *_reply; | |
| redisReply *reply; | |
| sds out = 0; | |
| int output = 1; | |
| if (redisGetReply(context,&_reply) != 0) { | |
| if (config.shutdown) { | |
| redisFree(context); | |
| context = 0; | |
| return 0; | |
| } | |
| if (config.interactive) { | |
| if (context->err == 1 && | |
| (errno == ECONNRESET || errno == EPIPE)) | |
| return -1; | |
| if (context->err == 3) | |
| return -1; | |
| } | |
| cliPrintContextError(); | |
| exit(1); | |
| return -1; | |
| } | |
| reply = (redisReply*)_reply; | |
| config.last_cmd_type = reply->type; | |
| if (config.cluster_mode && reply->type == 6 && | |
| (!strncmp(reply->str,"MOVED",5) || !strcmp(reply->str,"ASK"))) | |
| { | |
| char *p = reply->str, *s; | |
| int slot; | |
| output = 0; | |
| s = strchr(p,' '); | |
| p = strchr(s+1,' '); | |
| *p = '\0'; | |
| slot = atoi(s+1); | |
| s = strrchr(p+1,':'); | |
| *s = '\0'; | |
| sdsfree(config.hostip); | |
| config.hostip = sdsnew(p+1); | |
| config.hostport = atoi(s+1); | |
| if (config.interactive) | |
| printf("-> Redirected to slot [%d] located at %s:%d\n", | |
| slot, config.hostip, config.hostport); | |
| config.cluster_reissue_command = 1; | |
| cliRefreshPrompt(); | |
| } | |
| if (output) { | |
| if (output_raw_strings) { | |
| out = cliFormatReplyRaw(reply); | |
| } else { | |
| if (config.output == 1) { | |
| out = cliFormatReplyRaw(reply); | |
| out = sdscat(out,"\n"); | |
| } else if (config.output == 0) { | |
| out = cliFormatReplyTTY(reply,""); | |
| } else if (config.output == 2) { | |
| out = cliFormatReplyCSV(reply); | |
| out = sdscat(out,"\n"); | |
| } | |
| } | |
| fwrite(out,sdslen(out),1,stdout); | |
| sdsfree(out); | |
| } | |
| freeReplyObject(reply); | |
| return 0; | |
| } | |
| static int cliSendCommand(int argc, char **argv, int repeat) { | |
| char *command = argv[0]; | |
| size_t *argvlen; | |
| int j, output_raw; | |
| if (!config.eval_ldb && | |
| (!strcasecmp(command,"help") || !strcasecmp(command,"?"))) { | |
| cliOutputHelp(--argc, ++argv); | |
| return 0; | |
| } | |
| if (context == 0) return -1; | |
| output_raw = 0; | |
| if (!strcasecmp(command,"info") || | |
| (argc >= 2 && !strcasecmp(command,"debug") && | |
| !strcasecmp(argv[1],"htstats")) || | |
| (argc >= 2 && !strcasecmp(command,"memory") && | |
| (!strcasecmp(argv[1],"malloc-stats") || | |
| !strcasecmp(argv[1],"doctor"))) || | |
| (argc == 2 && !strcasecmp(command,"cluster") && | |
| (!strcasecmp(argv[1],"nodes") || | |
| !strcasecmp(argv[1],"info"))) || | |
| (argc == 2 && !strcasecmp(command,"client") && | |
| !strcasecmp(argv[1],"list")) || | |
| (argc == 3 && !strcasecmp(command,"latency") && | |
| !strcasecmp(argv[1],"graph")) || | |
| (argc == 2 && !strcasecmp(command,"latency") && | |
| !strcasecmp(argv[1],"doctor"))) | |
| { | |
| output_raw = 1; | |
| } | |
| if (!strcasecmp(command,"shutdown")) config.shutdown = 1; | |
| if (!strcasecmp(command,"monitor")) config.monitor_mode = 1; | |
| if (!strcasecmp(command,"subscribe") || | |
| !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1; | |
| if (!strcasecmp(command,"sync") || | |
| !strcasecmp(command,"psync")) config.slave_mode = 1; | |
| if (argc == 3 && !strcasecmp(argv[0],"script") && | |
| !strcasecmp(argv[1],"debug")) | |
| { | |
| if (!strcasecmp(argv[2],"yes") || !strcasecmp(argv[2],"sync")) { | |
| config.enable_ldb_on_eval = 1; | |
| } else { | |
| config.enable_ldb_on_eval = 0; | |
| } | |
| } | |
| if (!strcasecmp(command,"eval") && config.enable_ldb_on_eval) { | |
| config.eval_ldb = 1; | |
| config.output = 1; | |
| } | |
| argvlen = zmalloc(argc*sizeof(size_t)); | |
| for (j = 0; j < argc; j++) | |
| argvlen[j] = sdslen(argv[j]); | |
| while(repeat--) { | |
| redisAppendCommandArgv(context,argc,(const char**)argv,argvlen); | |
| while (config.monitor_mode) { | |
| if (cliReadReply(output_raw) != 0) exit(1); | |
| fflush(stdout); | |
| } | |
| if (config.pubsub_mode) { | |
| if (config.output != 1) | |
| printf("Reading messages... (press Ctrl-C to quit)\n"); | |
| while (1) { | |
| if (cliReadReply(output_raw) != 0) exit(1); | |
| } | |
| } | |
| if (config.slave_mode) { | |
| printf("Entering slave output mode... (press Ctrl-C to quit)\n"); | |
| slaveMode(); | |
| config.slave_mode = 0; | |
| zfree(argvlen); | |
| return -1; | |
| } | |
| if (cliReadReply(output_raw) != 0) { | |
| zfree(argvlen); | |
| return -1; | |
| } else { | |
| if (!strcasecmp(command,"select") && argc == 2 && config.last_cmd_type != 6) { | |
| config.dbnum = atoi(argv[1]); | |
| cliRefreshPrompt(); | |
| } else if (!strcasecmp(command,"auth") && argc == 2) { | |
| cliSelect(); | |
| } | |
| } | |
| if (config.interval) usleep(config.interval); | |
| fflush(stdout); | |
| } | |
| zfree(argvlen); | |
| return 0; | |
| } | |
| static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ...) { | |
| redisReply *reply = 0; | |
| int tries = 0; | |
| va_list ap; | |
| assert(!c->err); | |
| while(reply == 0) { | |
| while (c->err & (1 | 3)) { | |
| printf("\r\x1b[0K"); | |
| printf("Reconnecting... %d\r", ++tries); | |
| fflush(stdout); | |
| redisFree(c); | |
| c = redisConnect(config.hostip,config.hostport); | |
| usleep(1000000); | |
| } | |
| __builtin_va_start((ap)); | |
| reply = redisvCommand(c,fmt,ap); | |
| ; | |
| if (c->err && !(c->err & (1 | 3))) { | |
| fprintf(stderr, "Error: %s\n", c->errstr); | |
| exit(1); | |
| } else if (tries > 0) { | |
| printf("\r\x1b[0K"); | |
| } | |
| } | |
| context = c; | |
| return reply; | |
| } | |
| static int parseOptions(int argc, char **argv) { | |
| int i; | |
| for (i = 1; i < argc; i++) { | |
| int lastarg = i==argc-1; | |
| if (!strcmp(argv[i],"-h") && !lastarg) { | |
| sdsfree(config.hostip); | |
| config.hostip = sdsnew(argv[++i]); | |
| } else if (!strcmp(argv[i],"-h") && lastarg) { | |
| usage(); | |
| } else if (!strcmp(argv[i],"--help")) { | |
| usage(); | |
| } else if (!strcmp(argv[i],"-x")) { | |
| config.stdinarg = 1; | |
| } else if (!strcmp(argv[i],"-p") && !lastarg) { | |
| config.hostport = atoi(argv[++i]); | |
| } else if (!strcmp(argv[i],"-s") && !lastarg) { | |
| config.hostsocket = argv[++i]; | |
| } else if (!strcmp(argv[i],"-r") && !lastarg) { | |
| config.repeat = strtoll(argv[++i],0,10); | |
| } else if (!strcmp(argv[i],"-i") && !lastarg) { | |
| double seconds = atof(argv[++i]); | |
| config.interval = seconds*1000000; | |
| } else if (!strcmp(argv[i],"-n") && !lastarg) { | |
| config.dbnum = atoi(argv[++i]); | |
| } else if (!strcmp(argv[i],"-a") && !lastarg) { | |
| config.auth = argv[++i]; | |
| } else if (!strcmp(argv[i],"-u") && !lastarg) { | |
| parseRedisUri(argv[++i]); | |
| } else if (!strcmp(argv[i],"--raw")) { | |
| config.output = 1; | |
| } else if (!strcmp(argv[i],"--no-raw")) { | |
| config.output = 0; | |
| } else if (!strcmp(argv[i],"--csv")) { | |
| config.output = 2; | |
| } else if (!strcmp(argv[i],"--latency")) { | |
| config.latency_mode = 1; | |
| } else if (!strcmp(argv[i],"--latency-dist")) { | |
| config.latency_dist_mode = 1; | |
| } else if (!strcmp(argv[i],"--mono")) { | |
| spectrum_palette = spectrum_palette_mono; | |
| spectrum_palette_size = spectrum_palette_mono_size; | |
| } else if (!strcmp(argv[i],"--latency-history")) { | |
| config.latency_mode = 1; | |
| config.latency_history = 1; | |
| } else if (!strcmp(argv[i],"--lru-test") && !lastarg) { | |
| config.lru_test_mode = 1; | |
| config.lru_test_sample_size = strtoll(argv[++i],0,10); | |
| } else if (!strcmp(argv[i],"--slave")) { | |
| config.slave_mode = 1; | |
| } else if (!strcmp(argv[i],"--stat")) { | |
| config.stat_mode = 1; | |
| } else if (!strcmp(argv[i],"--scan")) { | |
| config.scan_mode = 1; | |
| } else if (!strcmp(argv[i],"--pattern") && !lastarg) { | |
| config.pattern = argv[++i]; | |
| } else if (!strcmp(argv[i],"--intrinsic-latency") && !lastarg) { | |
| config.intrinsic_latency_mode = 1; | |
| config.intrinsic_latency_duration = atoi(argv[++i]); | |
| } else if (!strcmp(argv[i],"--rdb") && !lastarg) { | |
| config.getrdb_mode = 1; | |
| config.rdb_filename = argv[++i]; | |
| } else if (!strcmp(argv[i],"--pipe")) { | |
| config.pipe_mode = 1; | |
| } else if (!strcmp(argv[i],"--pipe-timeout") && !lastarg) { | |
| config.pipe_timeout = atoi(argv[++i]); | |
| } else if (!strcmp(argv[i],"--bigkeys")) { | |
| config.bigkeys = 1; | |
| } else if (!strcmp(argv[i],"--hotkeys")) { | |
| config.hotkeys = 1; | |
| } else if (!strcmp(argv[i],"--eval") && !lastarg) { | |
| config.eval = argv[++i]; | |
| } else if (!strcmp(argv[i],"--ldb")) { | |
| config.eval_ldb = 1; | |
| config.output = 1; | |
| } else if (!strcmp(argv[i],"--ldb-sync-mode")) { | |
| config.eval_ldb = 1; | |
| config.eval_ldb_sync = 1; | |
| config.output = 1; | |
| } else if (!strcmp(argv[i],"-c")) { | |
| config.cluster_mode = 1; | |
| } else if (!strcmp(argv[i],"-d") && !lastarg) { | |
| sdsfree(config.mb_delim); | |
| config.mb_delim = sdsnew(argv[++i]); | |
| } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) { | |
| sds version = cliVersion(); | |
| printf("redis-cli %s\n", version); | |
| sdsfree(version); | |
| exit(0); | |
| } else { | |
| if (argv[i][0] == '-') { | |
| fprintf(stderr, | |
| "Unrecognized option or bad number of args for: '%s'\n", | |
| argv[i]); | |
| exit(1); | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| if (config.eval_ldb && config.eval == 0) { | |
| fprintf(stderr,"Options --ldb and --ldb-sync-mode require --eval.\n"); | |
| fprintf(stderr,"Try %s --help for more information.\n", argv[0]); | |
| exit(1); | |
| } | |
| return i; | |
| } | |
| static sds readArgFromStdin(void) { | |
| char buf[1024]; | |
| sds arg = sdsempty(); | |
| while(1) { | |
| int nread = read(fileno(stdin),buf,1024); | |
| if (nread == 0) break; | |
| else if (nread == -1) { | |
| perror("Reading from standard input"); | |
| exit(1); | |
| } | |
| arg = sdscatlen(arg,buf,nread); | |
| } | |
| return arg; | |
| } | |
| static void usage(void) { | |
| sds version = cliVersion(); | |
| fprintf(stderr, | |
| "redis-cli %s\n" | |
| "\n" | |
| "Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n" | |
| " -h <hostname> Server hostname (default: 127.0.0.1).\n" | |
| " -p <port> Server port (default: 6379).\n" | |
| " -s <socket> Server socket (overrides hostname and port).\n" | |
| " -a <password> Password to use when connecting to the server.\n" | |
| " -u <uri> Server URI.\n" | |
| " -r <repeat> Execute specified command N times.\n" | |
| " -i <interval> When -r is used, waits <interval> seconds per command.\n" | |
| " It is possible to specify sub-second times like -i 0.1.\n" | |
| " -n <db> Database number.\n" | |
| " -x Read last argument from STDIN.\n" | |
| " -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n).\n" | |
| " -c Enable cluster mode (follow -ASK and -MOVED redirections).\n" | |
| " --raw Use raw formatting for replies (default when STDOUT is\n" | |
| " not a tty).\n" | |
| " --no-raw Force formatted output even when STDOUT is not a tty.\n" | |
| " --csv Output in CSV format.\n" | |
| " --stat Print rolling stats about server: mem, clients, ...\n" | |
| " --latency Enter a special mode continuously sampling latency.\n" | |
| " If you use this mode in an interactive session it runs\n" | |
| " forever displaying real-time stats. Otherwise if --raw or\n" | |
| " --csv is specified, or if you redirect the output to a non\n" | |
| " TTY, it samples the latency for 1 second (you can use\n" | |
| " -i to change the interval), then produces a single output\n" | |
| " and exits.\n" | |
| " --latency-history Like --latency but tracking latency changes over time.\n" | |
| " Default time interval is 15 sec. Change it using -i.\n" | |
| " --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" | |
| " Default time interval is 1 sec. Change it using -i.\n" | |
| " --lru-test <keys> Simulate a cache workload with an 80-20 distribution.\n" | |
| " --slave Simulate a slave showing commands received from the master.\n" | |
| " --rdb <filename> Transfer an RDB dump from remote server to local file.\n" | |
| " --pipe Transfer raw Redis protocol from stdin to server.\n" | |
| " --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n" | |
| " no reply is received within <n> seconds.\n" | |
| " Default timeout: %d. Use 0 to wait forever.\n" | |
| " --bigkeys Sample Redis keys looking for big keys.\n" | |
| " --hotkeys Sample Redis keys looking for hot keys.\n" | |
| " only works when maxmemory-policy is *lfu.\n" | |
| " --scan List all keys using the SCAN command.\n" | |
| " --pattern <pat> Useful with --scan to specify a SCAN pattern.\n" | |
| " --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n" | |
| " The test will run for the specified amount of seconds.\n" | |
| " --eval <file> Send an EVAL command using the Lua script at <file>.\n" | |
| " --ldb Used with --eval enable the Redis Lua debugger.\n" | |
| " --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n" | |
| " this mode the server is blocked and script changes are\n" | |
| " are not rolled back from the server memory.\n" | |
| " --help Output this help and exit.\n" | |
| " --version Output version and exit.\n" | |
| "\n" | |
| "Examples:\n" | |
| " cat /etc/passwd | redis-cli -x set mypasswd\n" | |
| " redis-cli get mypasswd\n" | |
| " redis-cli -r 100 lpush mylist x\n" | |
| " redis-cli -r 100 -i 1 info | grep used_memory_human:\n" | |
| " redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n" | |
| " redis-cli --scan --pattern '*:12345*'\n" | |
| "\n" | |
| " (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n" | |
| "\n" | |
| "When no command is given, redis-cli starts in interactive mode.\n" | |
| "Type \"help\" in interactive mode for information on available commands\n" | |
| "and settings.\n" | |
| "\n", | |
| version, 30); | |
| sdsfree(version); | |
| exit(1); | |
| } | |
| static char **convertToSds(int count, char** args) { | |
| int j; | |
| char **sds = zmalloc(sizeof(char*)*count); | |
| for(j = 0; j < count; j++) | |
| sds[j] = sdsnew(args[j]); | |
| return sds; | |
| } | |
| static int issueCommandRepeat(int argc, char **argv, long repeat) { | |
| while (1) { | |
| config.cluster_reissue_command = 0; | |
| if (cliSendCommand(argc,argv,repeat) != 0) { | |
| cliConnect(1); | |
| if (cliSendCommand(argc,argv,repeat) != 0) { | |
| cliPrintContextError(); | |
| return -1; | |
| } | |
| } | |
| if (config.cluster_mode && config.cluster_reissue_command) { | |
| cliConnect(1); | |
| } else { | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| static int issueCommand(int argc, char **argv) { | |
| return issueCommandRepeat(argc, argv, config.repeat); | |
| } | |
| static sds *cliSplitArgs(char *line, int *argc) { | |
| if (config.eval_ldb && (strstr(line,"eval ") == line || | |
| strstr(line,"e ") == line)) | |
| { | |
| sds *argv = sds_malloc(sizeof(sds)*2); | |
| *argc = 2; | |
| int len = strlen(line); | |
| int elen = line[1] == ' ' ? 2 : 5; | |
| argv[0] = sdsnewlen(line,elen-1); | |
| argv[1] = sdsnewlen(line+elen,len-elen); | |
| return argv; | |
| } else { | |
| return sdssplitargs(line,argc); | |
| } | |
| } | |
| void cliSetPreferences(char **argv, int argc, int interactive) { | |
| if (!strcasecmp(argv[0],":set") && argc >= 2) { | |
| if (!strcasecmp(argv[1],"hints")) pref.hints = 1; | |
| else if (!strcasecmp(argv[1],"nohints")) pref.hints = 0; | |
| else { | |
| printf("%sunknown redis-cli preference '%s'\n", | |
| interactive ? "" : ".redisclirc: ", | |
| argv[1]); | |
| } | |
| } else { | |
| printf("%sunknown redis-cli internal command '%s'\n", | |
| interactive ? "" : ".redisclirc: ", | |
| argv[0]); | |
| } | |
| } | |
| void cliLoadPreferences(void) { | |
| sds rcfile = getDotfilePath("REDISCLI_RCFILE",".redisclirc"); | |
| if (rcfile == 0) return; | |
| FILE *fp = fopen(rcfile,"r"); | |
| char buf[1024]; | |
| if (fp) { | |
| while(fgets(buf,sizeof(buf),fp) != 0) { | |
| sds *argv; | |
| int argc; | |
| argv = sdssplitargs(buf,&argc); | |
| if (argc > 0) cliSetPreferences(argv,argc,0); | |
| sdsfreesplitres(argv,argc); | |
| } | |
| fclose(fp); | |
| } | |
| sdsfree(rcfile); | |
| } | |
| static void repl(void) { | |
| sds historyfile = 0; | |
| int history = 0; | |
| char *line; | |
| int argc; | |
| sds *argv; | |
| cliInitHelp(); | |
| cliIntegrateHelp(); | |
| config.interactive = 1; | |
| linenoiseSetMultiLine(1); | |
| linenoiseSetCompletionCallback(completionCallback); | |
| linenoiseSetHintsCallback(hintsCallback); | |
| linenoiseSetFreeHintsCallback(freeHintsCallback); | |
| if (isatty(fileno(stdin))) { | |
| historyfile = getDotfilePath("REDISCLI_HISTFILE",".rediscli_history"); | |
| history = 1; | |
| if (historyfile != 0) { | |
| linenoiseHistoryLoad(historyfile); | |
| } | |
| cliLoadPreferences(); | |
| } | |
| cliRefreshPrompt(); | |
| while((line = linenoise(context ? config.prompt : "not connected> ")) != 0) { | |
| if (line[0] != '\0') { | |
| argv = cliSplitArgs(line,&argc); | |
| if (history) linenoiseHistoryAdd(line); | |
| if (historyfile) linenoiseHistorySave(historyfile); | |
| if (argv == 0) { | |
| printf("Invalid argument(s)\n"); | |
| linenoiseFree(line); | |
| continue; | |
| } else if (argc > 0) { | |
| if (strcasecmp(argv[0],"quit") == 0 || | |
| strcasecmp(argv[0],"exit") == 0) | |
| { | |
| exit(0); | |
| } else if (argv[0][0] == ':') { | |
| cliSetPreferences(argv,argc,1); | |
| continue; | |
| } else if (strcasecmp(argv[0],"restart") == 0) { | |
| if (config.eval) { | |
| config.eval_ldb = 1; | |
| config.output = 1; | |
| return; | |
| } else { | |
| printf("Use 'restart' only in Lua debugging mode."); | |
| } | |
| } else if (argc == 3 && !strcasecmp(argv[0],"connect")) { | |
| sdsfree(config.hostip); | |
| config.hostip = sdsnew(argv[1]); | |
| config.hostport = atoi(argv[2]); | |
| cliRefreshPrompt(); | |
| cliConnect(1); | |
| } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { | |
| linenoiseClearScreen(); | |
| } else { | |
| long long start_time = mstime(), elapsed; | |
| int repeat, skipargs = 0; | |
| char *endptr; | |
| repeat = strtol(argv[0], &endptr, 10); | |
| if (argc > 1 && *endptr == '\0' && repeat) { | |
| skipargs = 1; | |
| } else { | |
| repeat = 1; | |
| } | |
| issueCommandRepeat(argc-skipargs, argv+skipargs, repeat); | |
| if (config.eval_ldb_end) { | |
| config.eval_ldb_end = 0; | |
| cliReadReply(0); | |
| printf("\n(Lua debugging session ended%s)\n\n", | |
| config.eval_ldb_sync ? "" : | |
| " -- dataset changes rolled back"); | |
| } | |
| elapsed = mstime()-start_time; | |
| if (elapsed >= 500 && | |
| config.output == 0) | |
| { | |
| printf("(%.2fs)\n",(double)elapsed/1000); | |
| } | |
| } | |
| } | |
| sdsfreesplitres(argv,argc); | |
| } | |
| linenoiseFree(line); | |
| } | |
| exit(0); | |
| } | |
| static int noninteractive(int argc, char **argv) { | |
| int retval = 0; | |
| if (config.stdinarg) { | |
| argv = zrealloc(argv, (argc+1)*sizeof(char*)); | |
| argv[argc] = readArgFromStdin(); | |
| retval = issueCommand(argc+1, argv); | |
| } else { | |
| retval = issueCommand(argc, argv); | |
| } | |
| return retval; | |
| } | |
| static int evalMode(int argc, char **argv) { | |
| sds script = 0; | |
| FILE *fp; | |
| char buf[1024]; | |
| size_t nread; | |
| char **argv2; | |
| int j, got_comma, keys; | |
| int retval = 0; | |
| while(1) { | |
| if (config.eval_ldb) { | |
| printf( | |
| "Lua debugging session started, please use:\n" | |
| "quit -- End the session.\n" | |
| "restart -- Restart the script in debug mode again.\n" | |
| "help -- Show Lua script debugging commands.\n\n" | |
| ); | |
| } | |
| sdsfree(script); | |
| script = sdsempty(); | |
| got_comma = 0; | |
| keys = 0; | |
| fp = fopen(config.eval,"r"); | |
| if (!fp) { | |
| fprintf(stderr, | |
| "Can't open file '%s': %s\n", config.eval, strerror(errno)); | |
| exit(1); | |
| } | |
| while((nread = fread(buf,1,sizeof(buf),fp)) != 0) { | |
| script = sdscatlen(script,buf,nread); | |
| } | |
| fclose(fp); | |
| if (config.eval_ldb) { | |
| redisReply *reply = redisCommand(context, | |
| config.eval_ldb_sync ? | |
| "SCRIPT DEBUG sync": "SCRIPT DEBUG yes"); | |
| if (reply) freeReplyObject(reply); | |
| } | |
| argv2 = zmalloc(sizeof(sds)*(argc+3)); | |
| argv2[0] = sdsnew("EVAL"); | |
| argv2[1] = script; | |
| for (j = 0; j < argc; j++) { | |
| if (!got_comma && argv[j][0] == ',' && argv[j][1] == 0) { | |
| got_comma = 1; | |
| continue; | |
| } | |
| argv2[j+3-got_comma] = sdsnew(argv[j]); | |
| if (!got_comma) keys++; | |
| } | |
| argv2[2] = sdscatprintf(sdsempty(),"%d",keys); | |
| int eval_ldb = config.eval_ldb; | |
| retval = issueCommand(argc+3-got_comma, argv2); | |
| if (eval_ldb) { | |
| if (!config.eval_ldb) { | |
| printf("Eval debugging session can't start:\n"); | |
| cliReadReply(0); | |
| break; | |
| } else { | |
| strncpy(config.prompt,"lua debugger> ",sizeof(config.prompt)); | |
| repl(); | |
| cliConnect(1); | |
| printf("\n"); | |
| } | |
| } else { | |
| break; | |
| } | |
| } | |
| return retval; | |
| } | |
| static void latencyModePrint(long long min, long long max, double avg, long long count) { | |
| if (config.output == 0) { | |
| printf("min: %lld, max: %lld, avg: %.2f (%lld samples)", | |
| min, max, avg, count); | |
| fflush(stdout); | |
| } else if (config.output == 2) { | |
| printf("%lld,%lld,%.2f,%lld\n", min, max, avg, count); | |
| } else if (config.output == 1) { | |
| printf("%lld %lld %.2f %lld\n", min, max, avg, count); | |
| } | |
| } | |
| static void latencyMode(void) { | |
| redisReply *reply; | |
| long long start, latency, min = 0, max = 0, tot = 0, count = 0; | |
| long long history_interval = | |
| config.interval ? config.interval/1000 : | |
| 15000; | |
| double avg; | |
| long long history_start = mstime(); | |
| if (config.interval == 0) { | |
| config.interval = 1000; | |
| } else { | |
| config.interval /= 1000; | |
| } | |
| if (!context) exit(1); | |
| while(1) { | |
| start = mstime(); | |
| reply = reconnectingRedisCommand(context,"PING"); | |
| if (reply == 0) { | |
| fprintf(stderr,"\nI/O error\n"); | |
| exit(1); | |
| } | |
| latency = mstime()-start; | |
| freeReplyObject(reply); | |
| count++; | |
| if (count == 1) { | |
| min = max = tot = latency; | |
| avg = (double) latency; | |
| } else { | |
| if (latency < min) min = latency; | |
| if (latency > max) max = latency; | |
| tot += latency; | |
| avg = (double) tot/count; | |
| } | |
| if (config.output == 0) { | |
| printf("\x1b[0G\x1b[2K"); | |
| latencyModePrint(min,max,avg,count); | |
| } else { | |
| if (config.latency_history) { | |
| latencyModePrint(min,max,avg,count); | |
| } else if (mstime()-history_start > config.interval) { | |
| latencyModePrint(min,max,avg,count); | |
| exit(0); | |
| } | |
| } | |
| if (config.latency_history && mstime()-history_start > history_interval) | |
| { | |
| printf(" -- %.2f seconds range\n", (float)(mstime()-history_start)/1000); | |
| history_start = mstime(); | |
| min = max = tot = count = 0; | |
| } | |
| usleep(10 * 1000); | |
| } | |
| } | |
| # 1657 "src/redis-cli.c" | |
| struct distsamples { | |
| long long max; | |
| long long count; | |
| int character; | |
| }; | |
| # 1674 "src/redis-cli.c" | |
| void showLatencyDistSamples(struct distsamples *samples, long long tot) { | |
| int j; | |
| printf("\033[38;5;0m"); | |
| for (j = 0; ; j++) { | |
| int coloridx = | |
| ceil((float) samples[j].count / tot * (spectrum_palette_size-1)); | |
| int color = spectrum_palette[coloridx]; | |
| printf("\033[48;5;%dm%c", (int)color, samples[j].character); | |
| samples[j].count = 0; | |
| if (samples[j].max == 0) break; | |
| } | |
| printf("\033[0m\n"); | |
| fflush(stdout); | |
| } | |
| void showLatencyDistLegend(void) { | |
| int j; | |
| printf("---------------------------------------------\n"); | |
| printf(". - * # .01 .125 .25 .5 milliseconds\n"); | |
| printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); | |
| printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); | |
| printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); | |
| printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n"); | |
| printf("From 0 to 100%%: "); | |
| for (j = 0; j < spectrum_palette_size; j++) { | |
| printf("\033[48;5;%dm ", spectrum_palette[j]); | |
| } | |
| printf("\033[0m\n"); | |
| printf("---------------------------------------------\n"); | |
| } | |
| static void latencyDistMode(void) { | |
| redisReply *reply; | |
| long long start, latency, count = 0; | |
| long long history_interval = | |
| config.interval ? config.interval/1000 : | |
| 1000; | |
| long long history_start = ustime(); | |
| int j, outputs = 0; | |
| struct distsamples samples[] = { | |
| {10,0,'.'}, | |
| {125,0,'-'}, | |
| {250,0,'*'}, | |
| {500,0,'#'}, | |
| {1000,0,'1'}, | |
| {2000,0,'2'}, | |
| {3000,0,'3'}, | |
| {4000,0,'4'}, | |
| {5000,0,'5'}, | |
| {6000,0,'6'}, | |
| {7000,0,'7'}, | |
| {8000,0,'8'}, | |
| {9000,0,'9'}, | |
| {10000,0,'A'}, | |
| {20000,0,'B'}, | |
| {30000,0,'C'}, | |
| {40000,0,'D'}, | |
| {50000,0,'E'}, | |
| {100000,0,'F'}, | |
| {200000,0,'G'}, | |
| {300000,0,'H'}, | |
| {400000,0,'I'}, | |
| {500000,0,'J'}, | |
| {1000000,0,'K'}, | |
| {2000000,0,'L'}, | |
| {4000000,0,'M'}, | |
| {8000000,0,'N'}, | |
| {16000000,0,'O'}, | |
| {30000000,0,'P'}, | |
| {60000000,0,'Q'}, | |
| {0,0,'?'}, | |
| }; | |
| if (!context) exit(1); | |
| while(1) { | |
| start = ustime(); | |
| reply = reconnectingRedisCommand(context,"PING"); | |
| if (reply == 0) { | |
| fprintf(stderr,"\nI/O error\n"); | |
| exit(1); | |
| } | |
| latency = ustime()-start; | |
| freeReplyObject(reply); | |
| count++; | |
| for (j = 0; ; j++) { | |
| if (samples[j].max == 0 || latency <= samples[j].max) { | |
| samples[j].count++; | |
| break; | |
| } | |
| } | |
| if (count && (ustime()-history_start)/1000 > history_interval) { | |
| if ((outputs++ % 20) == 0) | |
| showLatencyDistLegend(); | |
| showLatencyDistSamples(samples,count); | |
| history_start = ustime(); | |
| count = 0; | |
| } | |
| usleep(10 * 1000); | |
| } | |
| } | |
| unsigned long long sendSync(int fd) { | |
| char buf[4096], *p; | |
| ssize_t nread; | |
| if (write(fd,"SYNC\r\n",6) != 6) { | |
| fprintf(stderr,"Error writing to master\n"); | |
| exit(1); | |
| } | |
| p = buf; | |
| while(1) { | |
| nread = read(fd,p,1); | |
| if (nread <= 0) { | |
| fprintf(stderr,"Error reading bulk length while SYNCing\n"); | |
| exit(1); | |
| } | |
| if (*p == '\n' && p != buf) break; | |
| if (*p != '\n') p++; | |
| } | |
| *p = '\0'; | |
| if (buf[0] == '-') { | |
| printf("SYNC with master failed: %s\n", buf); | |
| exit(1); | |
| } | |
| return strtoull(buf+1,0,10); | |
| } | |
| static void slaveMode(void) { | |
| int fd = context->fd; | |
| unsigned long long payload = sendSync(fd); | |
| char buf[1024]; | |
| int original_output = config.output; | |
| fprintf(stderr,"SYNC with master, discarding %llu " | |
| "bytes of bulk transfer...\n", payload); | |
| while(payload) { | |
| ssize_t nread; | |
| nread = read(fd,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); | |
| if (nread <= 0) { | |
| fprintf(stderr,"Error reading RDB payload while SYNCing\n"); | |
| exit(1); | |
| } | |
| payload -= nread; | |
| } | |
| fprintf(stderr,"SYNC done. Logging commands from master.\n"); | |
| config.output = 2; | |
| while (cliReadReply(0) == 0); | |
| config.output = original_output; | |
| } | |
| static void getRDB(void) { | |
| int s = context->fd; | |
| int fd; | |
| unsigned long long payload = sendSync(s); | |
| char buf[4096]; | |
| fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n", | |
| payload, config.rdb_filename); | |
| if (!strcmp(config.rdb_filename,"-")) { | |
| fd = STDOUT_FILENO; | |
| } else { | |
| fd = open(config.rdb_filename, O_CREAT|O_WRONLY, 0644); | |
| if (fd == -1) { | |
| fprintf(stderr, "Error opening '%s': %s\n", config.rdb_filename, | |
| strerror(errno)); | |
| exit(1); | |
| } | |
| } | |
| while(payload) { | |
| ssize_t nread, nwritten; | |
| nread = read(s,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload); | |
| if (nread <= 0) { | |
| fprintf(stderr,"I/O Error reading RDB payload from socket\n"); | |
| exit(1); | |
| } | |
| nwritten = write(fd, buf, nread); | |
| if (nwritten != nread) { | |
| fprintf(stderr,"Error writing data to file: %s\n", | |
| strerror(errno)); | |
| exit(1); | |
| } | |
| payload -= nread; | |
| } | |
| close(s); | |
| fsync(fd); | |
| fprintf(stderr,"Transfer finished with success.\n"); | |
| exit(0); | |
| } | |
| static void pipeMode(void) { | |
| int fd = context->fd; | |
| long long errors = 0, replies = 0, obuf_len = 0, obuf_pos = 0; | |
| char ibuf[1024*16], obuf[1024*16]; | |
| char aneterr[256]; | |
| redisReader *reader = redisReaderCreate(); | |
| redisReply *reply; | |
| int eof = 0; | |
| int done = 0; | |
| char magic[20]; | |
| time_t last_read_time = time(0); | |
| srand(time(0)); | |
| if (anetNonBlock(aneterr,fd) == -1) { | |
| fprintf(stderr, "Can't set the socket in non blocking mode: %s\n", | |
| aneterr); | |
| exit(1); | |
| } | |
| while(!done) { | |
| int mask = 1; | |
| if (!eof || obuf_len != 0) mask |= 2; | |
| mask = aeWait(fd,mask,1000); | |
| if (mask & 1) { | |
| ssize_t nread; | |
| do { | |
| nread = read(fd,ibuf,sizeof(ibuf)); | |
| if (nread == -1 && errno != EAGAIN && errno != EINTR) { | |
| fprintf(stderr, "Error reading from the server: %s\n", | |
| strerror(errno)); | |
| exit(1); | |
| } | |
| if (nread > 0) { | |
| redisReaderFeed(reader,ibuf,nread); | |
| last_read_time = time(0); | |
| } | |
| } while(nread > 0); | |
| do { | |
| if (redisReaderGetReply(reader,(void**)&reply) == -1) { | |
| fprintf(stderr, "Error reading replies from server\n"); | |
| exit(1); | |
| } | |
| if (reply) { | |
| if (reply->type == 6) { | |
| fprintf(stderr,"%s\n", reply->str); | |
| errors++; | |
| } else if (eof && reply->type == 1 && | |
| reply->len == 20) { | |
| if (memcmp(reply->str,magic,20) == 0) { | |
| printf("Last reply received from server.\n"); | |
| done = 1; | |
| replies--; | |
| } | |
| } | |
| replies++; | |
| freeReplyObject(reply); | |
| } | |
| } while(reply); | |
| } | |
| if (mask & 2) { | |
| ssize_t loop_nwritten = 0; | |
| while(1) { | |
| if (obuf_len != 0) { | |
| ssize_t nwritten = write(fd,obuf+obuf_pos,obuf_len); | |
| if (nwritten == -1) { | |
| if (errno != EAGAIN && errno != EINTR) { | |
| fprintf(stderr, "Error writing to the server: %s\n", | |
| strerror(errno)); | |
| exit(1); | |
| } else { | |
| nwritten = 0; | |
| } | |
| } | |
| obuf_len -= nwritten; | |
| obuf_pos += nwritten; | |
| loop_nwritten += nwritten; | |
| if (obuf_len != 0) break; | |
| } | |
| if (obuf_len == 0 && !eof) { | |
| ssize_t nread = read(STDIN_FILENO,obuf,sizeof(obuf)); | |
| if (nread == 0) { | |
| char echo[] = | |
| "\r\n*2\r\n$4\r\nECHO\r\n$20\r\n01234567890123456789\r\n"; | |
| int j; | |
| eof = 1; | |
| for (j = 0; j < 20; j++) | |
| magic[j] = rand() & 0xff; | |
| memcpy(echo+21,magic,20); | |
| memcpy(obuf,echo,sizeof(echo)-1); | |
| obuf_len = sizeof(echo)-1; | |
| obuf_pos = 0; | |
| printf("All data transferred. Waiting for the last reply...\n"); | |
| } else if (nread == -1) { | |
| fprintf(stderr, "Error reading from stdin: %s\n", | |
| strerror(errno)); | |
| exit(1); | |
| } else { | |
| obuf_len = nread; | |
| obuf_pos = 0; | |
| } | |
| } | |
| if ((obuf_len == 0 && eof) || | |
| loop_nwritten > (128*1024)) break; | |
| } | |
| } | |
| if (eof && config.pipe_timeout > 0 && | |
| time(0)-last_read_time > config.pipe_timeout) | |
| { | |
| fprintf(stderr,"No replies for %d seconds: exiting.\n", | |
| config.pipe_timeout); | |
| errors++; | |
| break; | |
| } | |
| } | |
| redisReaderFree(reader); | |
| printf("errors: %lld, replies: %lld\n", errors, replies); | |
| if (errors) | |
| exit(1); | |
| else | |
| exit(0); | |
| } | |
| # 2079 "src/redis-cli.c" | |
| static redisReply *sendScan(unsigned long long *it) { | |
| redisReply *reply = redisCommand(context, "SCAN %llu", *it); | |
| if(reply == 0) { | |
| fprintf(stderr, "\nI/O error\n"); | |
| exit(1); | |
| } else if(reply->type == 6) { | |
| fprintf(stderr, "SCAN error: %s\n", reply->str); | |
| exit(1); | |
| } else if(reply->type != 2) { | |
| fprintf(stderr, "Non ARRAY response from SCAN!\n"); | |
| exit(1); | |
| } else if(reply->elements != 2) { | |
| fprintf(stderr, "Invalid element count from SCAN!\n"); | |
| exit(1); | |
| } | |
| assert(reply->element[0]->type == 1); | |
| assert(reply->element[1]->type == 2); | |
| *it = strtoull(reply->element[0]->str, 0, 10); | |
| return reply; | |
| } | |
| static int getDbSize(void) { | |
| redisReply *reply; | |
| int size; | |
| reply = redisCommand(context, "DBSIZE"); | |
| if(reply == 0 || reply->type != 3) { | |
| fprintf(stderr, "Couldn't determine DBSIZE!\n"); | |
| exit(1); | |
| } | |
| size = reply->integer; | |
| freeReplyObject(reply); | |
| return size; | |
| } | |
| static int toIntType(char *key, char *type) { | |
| if(!strcmp(type, "string")) { | |
| return 0; | |
| } else if(!strcmp(type, "list")) { | |
| return 1; | |
| } else if(!strcmp(type, "set")) { | |
| return 2; | |
| } else if(!strcmp(type, "hash")) { | |
| return 3; | |
| } else if(!strcmp(type, "zset")) { | |
| return 4; | |
| } else if(!strcmp(type, "none")) { | |
| return 5; | |
| } else { | |
| fprintf(stderr, "Unknown type '%s' for key '%s'\n", type, key); | |
| exit(1); | |
| } | |
| } | |
| static void getKeyTypes(redisReply *keys, int *types) { | |
| redisReply *reply; | |
| unsigned int i; | |
| for(i=0;i<keys->elements;i++) { | |
| redisAppendCommand(context, "TYPE %s", keys->element[i]->str); | |
| } | |
| for(i=0;i<keys->elements;i++) { | |
| if(redisGetReply(context, (void**)&reply)!=0) { | |
| fprintf(stderr, "Error getting type for key '%s' (%d: %s)\n", | |
| keys->element[i]->str, context->err, context->errstr); | |
| exit(1); | |
| } else if(reply->type != 5) { | |
| if(reply->type == 6) { | |
| fprintf(stderr, "TYPE returned an error: %s\n", reply->str); | |
| } else { | |
| fprintf(stderr, | |
| "Invalid reply type (%d) for TYPE on key '%s'!\n", | |
| reply->type, keys->element[i]->str); | |
| } | |
| exit(1); | |
| } | |
| types[i] = toIntType(keys->element[i]->str, reply->str); | |
| freeReplyObject(reply); | |
| } | |
| } | |
| static void getKeySizes(redisReply *keys, int *types, | |
| unsigned long long *sizes) | |
| { | |
| redisReply *reply; | |
| char *sizecmds[] = {"STRLEN","LLEN","SCARD","HLEN","ZCARD"}; | |
| unsigned int i; | |
| for(i=0;i<keys->elements;i++) { | |
| if(types[i]==5) | |
| continue; | |
| redisAppendCommand(context, "%s %s", sizecmds[types[i]], | |
| keys->element[i]->str); | |
| } | |
| for(i=0;i<keys->elements;i++) { | |
| if(types[i] == 5) { | |
| sizes[i] = 0; | |
| continue; | |
| } | |
| if(redisGetReply(context, (void**)&reply)!=0) { | |
| fprintf(stderr, "Error getting size for key '%s' (%d: %s)\n", | |
| keys->element[i]->str, context->err, context->errstr); | |
| exit(1); | |
| } else if(reply->type != 3) { | |
| fprintf(stderr, | |
| "Warning: %s on '%s' failed (may have changed type)\n", | |
| sizecmds[types[i]], keys->element[i]->str); | |
| sizes[i] = 0; | |
| } else { | |
| sizes[i] = reply->integer; | |
| } | |
| freeReplyObject(reply); | |
| } | |
| } | |
| static void findBigKeys(void) { | |
| unsigned long long biggest[5] = {0}, counts[5] = {0}, totalsize[5] = {0}; | |
| unsigned long long sampled = 0, total_keys, totlen=0, *sizes=0, it=0; | |
| sds maxkeys[5] = {0}; | |
| char *typename[] = {"string","list","set","hash","zset"}; | |
| char *typeunit[] = {"bytes","items","members","fields","members"}; | |
| redisReply *reply, *keys; | |
| unsigned int arrsize=0, i; | |
| int type, *types=0; | |
| double pct; | |
| total_keys = getDbSize(); | |
| printf("\n# Scanning the entire keyspace to find biggest keys as well as\n"); | |
| printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); | |
| printf("# per 100 SCAN commands (not usually needed).\n\n"); | |
| for(i=0;i<5; i++) { | |
| maxkeys[i] = sdsempty(); | |
| if(!maxkeys[i]) { | |
| fprintf(stderr, "Failed to allocate memory for largest key names!\n"); | |
| exit(1); | |
| } | |
| } | |
| do { | |
| pct = 100 * (double)sampled/total_keys; | |
| reply = sendScan(&it); | |
| keys = reply->element[1]; | |
| if(keys->elements > arrsize) { | |
| types = zrealloc(types, sizeof(int)*keys->elements); | |
| sizes = zrealloc(sizes, sizeof(unsigned long long)*keys->elements); | |
| if(!types || !sizes) { | |
| fprintf(stderr, "Failed to allocate storage for keys!\n"); | |
| exit(1); | |
| } | |
| arrsize = keys->elements; | |
| } | |
| getKeyTypes(keys, types); | |
| getKeySizes(keys, types, sizes); | |
| for(i=0;i<keys->elements;i++) { | |
| if((type = types[i]) == 5) | |
| continue; | |
| totalsize[type] += sizes[i]; | |
| counts[type]++; | |
| totlen += keys->element[i]->len; | |
| sampled++; | |
| if(biggest[type]<sizes[i]) { | |
| printf( | |
| "[%05.2f%%] Biggest %-6s found so far '%s' with %llu %s\n", | |
| pct, typename[type], keys->element[i]->str, sizes[i], | |
| typeunit[type]); | |
| maxkeys[type] = sdscpy(maxkeys[type], keys->element[i]->str); | |
| if(!maxkeys[type]) { | |
| fprintf(stderr, "Failed to allocate memory for key!\n"); | |
| exit(1); | |
| } | |
| biggest[type] = sizes[i]; | |
| } | |
| if(sampled % 1000000 == 0) { | |
| printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); | |
| } | |
| } | |
| if(sampled && (sampled %100) == 0 && config.interval) { | |
| usleep(config.interval); | |
| } | |
| freeReplyObject(reply); | |
| } while(it != 0); | |
| if(types) zfree(types); | |
| if(sizes) zfree(sizes); | |
| printf("\n-------- summary -------\n\n"); | |
| printf("Sampled %llu keys in the keyspace!\n", sampled); | |
| printf("Total key length in bytes is %llu (avg len %.2f)\n\n", | |
| totlen, totlen ? (double)totlen/sampled : 0); | |
| for(i=0;i<5;i++) { | |
| if(sdslen(maxkeys[i])>0) { | |
| printf("Biggest %6s found '%s' has %llu %s\n", typename[i], maxkeys[i], | |
| biggest[i], typeunit[i]); | |
| } | |
| } | |
| printf("\n"); | |
| for(i=0;i<5;i++) { | |
| printf("%llu %ss with %llu %s (%05.2f%% of keys, avg size %.2f)\n", | |
| counts[i], typename[i], totalsize[i], typeunit[i], | |
| sampled ? 100 * (double)counts[i]/sampled : 0, | |
| counts[i] ? (double)totalsize[i]/counts[i] : 0); | |
| } | |
| for(i=0;i<5;i++) { | |
| sdsfree(maxkeys[i]); | |
| } | |
| exit(0); | |
| } | |
| static void getKeyFreqs(redisReply *keys, unsigned long long *freqs) { | |
| redisReply *reply; | |
| unsigned int i; | |
| for(i=0;i<keys->elements;i++) { | |
| redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str); | |
| } | |
| for(i=0;i<keys->elements;i++) { | |
| if(redisGetReply(context, (void**)&reply)!=0) { | |
| fprintf(stderr, "Error getting freq for key '%s' (%d: %s)\n", | |
| keys->element[i]->str, context->err, context->errstr); | |
| exit(1); | |
| } else if(reply->type != 3) { | |
| if(reply->type == 6) { | |
| fprintf(stderr, "Error: %s\n", reply->str); | |
| exit(1); | |
| } else { | |
| fprintf(stderr, "Warning: OBJECT freq on '%s' failed (may have been deleted)\n", keys->element[i]->str); | |
| freqs[i] = 0; | |
| } | |
| } else { | |
| freqs[i] = reply->integer; | |
| } | |
| freeReplyObject(reply); | |
| } | |
| } | |
| static void findHotKeys(void) { | |
| redisReply *keys, *reply; | |
| unsigned long long counters[16] = {0}; | |
| sds hotkeys[16] = {0}; | |
| unsigned long long sampled = 0, total_keys, *freqs = 0, it = 0; | |
| unsigned int arrsize = 0, i, k; | |
| double pct; | |
| total_keys = getDbSize(); | |
| printf("\n# Scanning the entire keyspace to find hot keys as well as\n"); | |
| printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n"); | |
| printf("# per 100 SCAN commands (not usually needed).\n\n"); | |
| do { | |
| pct = 100 * (double)sampled/total_keys; | |
| reply = sendScan(&it); | |
| keys = reply->element[1]; | |
| if(keys->elements > arrsize) { | |
| freqs = zrealloc(freqs, sizeof(unsigned long long)*keys->elements); | |
| if(!freqs) { | |
| fprintf(stderr, "Failed to allocate storage for keys!\n"); | |
| exit(1); | |
| } | |
| arrsize = keys->elements; | |
| } | |
| getKeyFreqs(keys, freqs); | |
| for(i=0;i<keys->elements;i++) { | |
| sampled++; | |
| if(sampled % 1000000 == 0) { | |
| printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled); | |
| } | |
| k = 0; | |
| while (k < 16 && freqs[i] > counters[k]) k++; | |
| if (k == 0) continue; | |
| k--; | |
| if (k == 0 || counters[k] == 0) { | |
| sdsfree(hotkeys[k]); | |
| } else { | |
| sdsfree(hotkeys[0]); | |
| memmove(counters,counters+1,sizeof(counters[0])*k); | |
| memmove(hotkeys,hotkeys+1,sizeof(hotkeys[0])*k); | |
| } | |
| counters[k] = freqs[i]; | |
| hotkeys[k] = sdsnew(keys->element[i]->str); | |
| printf( | |
| "[%05.2f%%] Hot key '%s' found so far with counter %llu\n", | |
| pct, keys->element[i]->str, freqs[i]); | |
| } | |
| if(sampled && (sampled %100) == 0 && config.interval) { | |
| usleep(config.interval); | |
| } | |
| freeReplyObject(reply); | |
| } while(it != 0); | |
| if (freqs) zfree(freqs); | |
| printf("\n-------- summary -------\n\n"); | |
| printf("Sampled %llu keys in the keyspace!\n", sampled); | |
| for (i=1; i<= 16; i++) { | |
| k = 16 - i; | |
| if(counters[k]>0) { | |
| printf("hot key found with counter: %llu\tkeyname: %s\n", counters[k], hotkeys[k]); | |
| sdsfree(hotkeys[k]); | |
| } | |
| } | |
| exit(0); | |
| } | |
| # 2481 "src/redis-cli.c" | |
| static char *getInfoField(char *info, char *field) { | |
| char *p = strstr(info,field); | |
| char *n1, *n2; | |
| char *result; | |
| if (!p) return 0; | |
| p += strlen(field)+1; | |
| n1 = strchr(p,'\r'); | |
| n2 = strchr(p,','); | |
| if (n2 && n2 < n1) n1 = n2; | |
| result = zmalloc(sizeof(char)*(n1-p)+1); | |
| memcpy(result,p,(n1-p)); | |
| result[n1-p] = '\0'; | |
| return result; | |
| } | |
| static long getLongInfoField(char *info, char *field) { | |
| char *value = getInfoField(info,field); | |
| long l; | |
| if (!value) return LONG_MIN; | |
| l = strtol(value,0,10); | |
| zfree(value); | |
| return l; | |
| } | |
| void bytesToHuman(char *s, long long n) { | |
| double d; | |
| if (n < 0) { | |
| *s = '-'; | |
| s++; | |
| n = -n; | |
| } | |
| if (n < 1024) { | |
| sprintf(s,"%lldB",n); | |
| return; | |
| } else if (n < (1024*1024)) { | |
| d = (double)n/(1024); | |
| sprintf(s,"%.2fK",d); | |
| } else if (n < (1024LL*1024*1024)) { | |
| d = (double)n/(1024*1024); | |
| sprintf(s,"%.2fM",d); | |
| } else if (n < (1024LL*1024*1024*1024)) { | |
| d = (double)n/(1024LL*1024*1024); | |
| sprintf(s,"%.2fG",d); | |
| } | |
| } | |
| static void statMode(void) { | |
| redisReply *reply; | |
| long aux, requests = 0; | |
| int i = 0; | |
| while(1) { | |
| char buf[64]; | |
| int j; | |
| reply = reconnectingRedisCommand(context,"INFO"); | |
| if (reply->type == 6) { | |
| printf("ERROR: %s\n", reply->str); | |
| exit(1); | |
| } | |
| if ((i++ % 20) == 0) { | |
| printf( | |
| "------- data ------ --------------------- load -------------------- - child -\n" | |
| "keys mem clients blocked requests connections \n"); | |
| } | |
| aux = 0; | |
| for (j = 0; j < 20; j++) { | |
| long k; | |
| sprintf(buf,"db%d:keys",j); | |
| k = getLongInfoField(reply->str,buf); | |
| if (k == LONG_MIN) continue; | |
| aux += k; | |
| } | |
| sprintf(buf,"%ld",aux); | |
| printf("%-11s",buf); | |
| aux = getLongInfoField(reply->str,"used_memory"); | |
| bytesToHuman(buf,aux); | |
| printf("%-8s",buf); | |
| aux = getLongInfoField(reply->str,"connected_clients"); | |
| sprintf(buf,"%ld",aux); | |
| printf(" %-8s",buf); | |
| aux = getLongInfoField(reply->str,"blocked_clients"); | |
| sprintf(buf,"%ld",aux); | |
| printf("%-8s",buf); | |
| aux = getLongInfoField(reply->str,"total_commands_processed"); | |
| sprintf(buf,"%ld (+%ld)",aux,requests == 0 ? 0 : aux-requests); | |
| printf("%-19s",buf); | |
| requests = aux; | |
| aux = getLongInfoField(reply->str,"total_connections_received"); | |
| sprintf(buf,"%ld",aux); | |
| printf(" %-12s",buf); | |
| aux = getLongInfoField(reply->str,"bgsave_in_progress"); | |
| aux |= getLongInfoField(reply->str,"aof_rewrite_in_progress") << 1; | |
| aux |= getLongInfoField(reply->str,"loading") << 2; | |
| switch(aux) { | |
| case 0: break; | |
| case 1: | |
| printf("SAVE"); | |
| break; | |
| case 2: | |
| printf("AOF"); | |
| break; | |
| case 3: | |
| printf("SAVE+AOF"); | |
| break; | |
| case 4: | |
| printf("LOAD"); | |
| break; | |
| } | |
| printf("\n"); | |
| freeReplyObject(reply); | |
| usleep(config.interval); | |
| } | |
| } | |
| static void scanMode(void) { | |
| redisReply *reply; | |
| unsigned long long cur = 0; | |
| do { | |
| if (config.pattern) | |
| reply = redisCommand(context,"SCAN %llu MATCH %s", | |
| cur,config.pattern); | |
| else | |
| reply = redisCommand(context,"SCAN %llu",cur); | |
| if (reply == 0) { | |
| printf("I/O error\n"); | |
| exit(1); | |
| } else if (reply->type == 6) { | |
| printf("ERROR: %s\n", reply->str); | |
| exit(1); | |
| } else { | |
| unsigned int j; | |
| cur = strtoull(reply->element[0]->str,0,10); | |
| for (j = 0; j < reply->element[1]->elements; j++) | |
| printf("%s\n", reply->element[1]->element[j]->str); | |
| } | |
| freeReplyObject(reply); | |
| } while(cur != 0); | |
| exit(0); | |
| } | |
| # 2664 "src/redis-cli.c" | |
| long long powerLawRand(long long min, long long max, double alpha) { | |
| double pl, r; | |
| max += 1; | |
| r = ((double)rand()) / 32767; | |
| pl = pow( | |
| ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)), | |
| (1.0/(alpha+1))); | |
| return (max-1-(long long)pl)+min; | |
| } | |
| void LRUTestGenKey(char *buf, size_t buflen) { | |
| snprintf(buf, buflen, "lru:%lld", | |
| powerLawRand(1, config.lru_test_sample_size, 6.2)); | |
| } | |
| static void LRUTestMode(void) { | |
| redisReply *reply; | |
| char key[128]; | |
| long long start_cycle; | |
| int j; | |
| srand(time(0)^getpid()); | |
| while(1) { | |
| start_cycle = mstime(); | |
| long long hits = 0, misses = 0; | |
| while(mstime() - start_cycle < 1000) { | |
| for (j = 0; j < 250; j++) { | |
| char val[6]; | |
| val[5] = '\0'; | |
| for (int i = 0; i < 5; i++) val[i] = 'A'+rand()%('z'-'A'); | |
| LRUTestGenKey(key,sizeof(key)); | |
| redisAppendCommand(context, "SET %s %s",key,val); | |
| } | |
| for (j = 0; j < 250; j++) | |
| redisGetReply(context, (void**)&reply); | |
| for (j = 0; j < 250; j++) { | |
| LRUTestGenKey(key,sizeof(key)); | |
| redisAppendCommand(context, "GET %s",key); | |
| } | |
| for (j = 0; j < 250; j++) { | |
| if (redisGetReply(context, (void**)&reply) == 0) { | |
| switch(reply->type) { | |
| case 6: | |
| printf("%s\n", reply->str); | |
| break; | |
| case 4: | |
| misses++; | |
| break; | |
| default: | |
| hits++; | |
| break; | |
| } | |
| } | |
| } | |
| if (context->err) { | |
| fprintf(stderr,"I/O error during LRU test\n"); | |
| exit(1); | |
| } | |
| } | |
| printf( | |
| "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n", | |
| hits+misses, | |
| hits, (double)hits/(hits+misses)*100, | |
| misses, (double)misses/(hits+misses)*100); | |
| } | |
| exit(0); | |
| } | |
| # 2756 "src/redis-cli.c" | |
| unsigned long compute_something_fast(void) { | |
| unsigned char s[256], i, j, t; | |
| int count = 1000, k; | |
| unsigned long output = 0; | |
| for (k = 0; k < 256; k++) s[k] = k; | |
| i = 0; | |
| j = 0; | |
| while(count--) { | |
| i++; | |
| j = j + s[i]; | |
| t = s[i]; | |
| s[i] = s[j]; | |
| s[j] = t; | |
| output += s[(s[i]+s[j])&255]; | |
| } | |
| return output; | |
| } | |
| static void intrinsicLatencyModeStop(int s) { | |
| ((void) s); | |
| force_cancel_loop = 1; | |
| } | |
| static void intrinsicLatencyMode(void) { | |
| long long test_end, run_time, max_latency = 0, runs = 0; | |
| run_time = config.intrinsic_latency_duration*1000000; | |
| test_end = ustime() + run_time; | |
| signal(SIGINT, intrinsicLatencyModeStop); | |
| while(1) { | |
| long long start, end, latency; | |
| start = ustime(); | |
| compute_something_fast(); | |
| end = ustime(); | |
| latency = end-start; | |
| runs++; | |
| if (latency <= 0) continue; | |
| if (latency > max_latency) { | |
| max_latency = latency; | |
| printf("Max latency so far: %lld microseconds.\n", max_latency); | |
| } | |
| double avg_us = (double)run_time/runs; | |
| double avg_ns = avg_us * 1e3; | |
| if (force_cancel_loop || end > test_end) { | |
| printf("\n%lld total runs " | |
| "(avg latency: " | |
| "%.4f microseconds / %.2f nanoseconds per run).\n", | |
| runs, avg_us, avg_ns); | |
| printf("Worst run took %.0fx longer than the average latency.\n", | |
| max_latency / avg_us); | |
| exit(0); | |
| } | |
| } | |
| } | |
| int main(int argc, char **argv) { | |
| int firstarg; | |
| config.hostip = sdsnew("127.0.0.1"); | |
| config.hostport = 6379; | |
| config.hostsocket = 0; | |
| config.repeat = 1; | |
| config.interval = 0; | |
| config.dbnum = 0; | |
| config.interactive = 0; | |
| config.shutdown = 0; | |
| config.monitor_mode = 0; | |
| config.pubsub_mode = 0; | |
| config.latency_mode = 0; | |
| config.latency_dist_mode = 0; | |
| config.latency_history = 0; | |
| config.lru_test_mode = 0; | |
| config.lru_test_sample_size = 0; | |
| config.cluster_mode = 0; | |
| config.slave_mode = 0; | |
| config.getrdb_mode = 0; | |
| config.stat_mode = 0; | |
| config.scan_mode = 0; | |
| config.intrinsic_latency_mode = 0; | |
| config.pattern = 0; | |
| config.rdb_filename = 0; | |
| config.pipe_mode = 0; | |
| config.pipe_timeout = 30; | |
| config.bigkeys = 0; | |
| config.hotkeys = 0; | |
| config.stdinarg = 0; | |
| config.auth = 0; | |
| config.eval = 0; | |
| config.eval_ldb = 0; | |
| config.eval_ldb_end = 0; | |
| config.eval_ldb_sync = 0; | |
| config.enable_ldb_on_eval = 0; | |
| config.last_cmd_type = -1; | |
| pref.hints = 1; | |
| spectrum_palette = spectrum_palette_color; | |
| spectrum_palette_size = spectrum_palette_color_size; | |
| if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == 0)) | |
| config.output = 1; | |
| else | |
| config.output = 0; | |
| config.mb_delim = sdsnew("\n"); | |
| firstarg = parseOptions(argc,argv); | |
| argc -= firstarg; | |
| argv += firstarg; | |
| if (config.latency_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| latencyMode(); | |
| } | |
| if (config.latency_dist_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| latencyDistMode(); | |
| } | |
| if (config.slave_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| slaveMode(); | |
| } | |
| if (config.getrdb_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| getRDB(); | |
| } | |
| if (config.pipe_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| pipeMode(); | |
| } | |
| if (config.bigkeys) { | |
| if (cliConnect(0) == -1) exit(1); | |
| findBigKeys(); | |
| } | |
| if (config.hotkeys) { | |
| if (cliConnect(0) == -1) exit(1); | |
| findHotKeys(); | |
| } | |
| if (config.stat_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| if (config.interval == 0) config.interval = 1000000; | |
| statMode(); | |
| } | |
| if (config.scan_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| scanMode(); | |
| } | |
| if (config.lru_test_mode) { | |
| if (cliConnect(0) == -1) exit(1); | |
| LRUTestMode(); | |
| } | |
| if (config.intrinsic_latency_mode) intrinsicLatencyMode(); | |
| if (argc == 0 && !config.eval) { | |
| signal(SIGPIPE, SIG_IGN); | |
| cliConnect(0); | |
| repl(); | |
| } | |
| if (cliConnect(0) != 0) exit(1); | |
| if (config.eval) { | |
| return evalMode(argc,argv); | |
| } else { | |
| return noninteractive(argc,convertToSds(argc,argv)); | |
| } | |
| } |