| # 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)); |
| } |
| } |