static sds cliFormatReplyCSV(redisReply *r) { unsigned int i; sds out = sdsempty(); switch (r->type) { case REDIS_REPLY_ERROR: out = sdscat(out,"ERROR,"); out = sdscatrepr(out,r->str,strlen(r->str)); break; case REDIS_REPLY_STATUS: out = sdscatrepr(out,r->str,r->len); break; case REDIS_REPLY_INTEGER: out = sdscatprintf(out,"%lld",r->integer); break; case REDIS_REPLY_STRING: out = sdscatrepr(out,r->str,r->len); break; case REDIS_REPLY_NIL: out = sdscat(out,"NIL\n"); break; case REDIS_REPLY_ARRAY: 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; }
void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc) { listNode *ln; listIter li; int j; sds cmdrepr = sdsnew("+"); robj *cmdobj; struct timeval tv; gettimeofday(&tv,NULL); cmdrepr = sdscatprintf(cmdrepr,"%ld.%06ld ",(long)tv.tv_sec,(long)tv.tv_usec); if (dictid != 0) cmdrepr = sdscatprintf(cmdrepr,"(db %d) ", dictid); for (j = 0; j < argc; j++) { if (argv[j]->encoding == REDIS_ENCODING_INT) { cmdrepr = sdscatprintf(cmdrepr, "\"%ld\"", (long)argv[j]->ptr); } else { cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr, sdslen(argv[j]->ptr)); } if (j != argc-1) cmdrepr = sdscatlen(cmdrepr," ",1); } cmdrepr = sdscatlen(cmdrepr,"\r\n",2); cmdobj = createObject(REDIS_STRING,cmdrepr); listRewind(monitors,&li); while((ln = listNext(&li))) { redisClient *monitor = ln->value; addReply(monitor,cmdobj); } decrRefCount(cmdobj); }
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { client *c = (client*) privdata; int nread, readlen; size_t qblen; UNUSED(el); UNUSED(mask); readlen = PROTO_IOBUF_LEN; /* If this is a multi bulk request, and we are processing a bulk reply * that is large enough, try to maximize the probability that the query * buffer contains exactly the SDS string representing the object, even * at the risk of requiring more read(2) calls. This way the function * processMultiBulkBuffer() can avoid copying buffers to create the * Redis Object representing the argument. */ if (c->reqtype == PROTO_REQ_MULTIBULK && c->multibulklen && c->bulklen != -1 && c->bulklen >= PROTO_MBULK_BIG_ARG) { int remaining = (unsigned)(c->bulklen+2)-sdslen(c->querybuf); if (remaining < readlen) readlen = remaining; } qblen = sdslen(c->querybuf); if (c->querybuf_peak < qblen) c->querybuf_peak = qblen; c->querybuf = sdsMakeRoomFor(c->querybuf, readlen); nread = read(fd, c->querybuf+qblen, readlen); if (nread == -1) { if (errno == EAGAIN) { return; } else { Log(LL_VERBOSE, "Reading from client: %s",strerror(errno)); freeClient(c); return; } } else if (nread == 0) { Log(LL_VERBOSE, "Client closed connection"); freeClient(c); return; } sdsIncrLen(c->querybuf,nread); c->lastinteraction = server.unixtime; server.stat_net_input_bytes += nread; if (sdslen(c->querybuf) > server.client_max_querybuf_len) { sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty(); bytes = sdscatrepr(bytes,c->querybuf,64); Log(LL_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes); sdsfree(ci); sdsfree(bytes); freeClient(c); return; } processInputBuffer(c); }
static int processItem(redisReader *r) { redisReadTask *cur = &(r->rstack[r->ridx]); char *p; sds byte; /* check if we need to read type */ if (cur->type < 0) { if ((p = readBytes(r,1)) != NULL) { switch (p[0]) { case '-': cur->type = REDIS_REPLY_ERROR; break; case '+': cur->type = REDIS_REPLY_STATUS; break; case ':': cur->type = REDIS_REPLY_INTEGER; break; case '$': cur->type = REDIS_REPLY_STRING; break; case '*': cur->type = REDIS_REPLY_ARRAY; break; default: byte = sdscatrepr(sdsempty(),p,1); redisSetReplyReaderError(r,sdscatprintf(sdsempty(), "Protocol error, got %s as reply type byte", byte)); sdsfree(byte); return -1; } } else { /* could not consume 1 byte */ return -1; } } /* process typed item */ switch(cur->type) { case REDIS_REPLY_ERROR: case REDIS_REPLY_STATUS: case REDIS_REPLY_INTEGER: return processLineItem(r); case REDIS_REPLY_STRING: return processBulkItem(r); case REDIS_REPLY_ARRAY: return processMultiBulkItem(r); default: assert(NULL); return -1; } }
void serverLogObjectDebugInfo(robj *o) { serverLog(LL_WARNING,"Object type: %d", o->type); serverLog(LL_WARNING,"Object encoding: %d", o->encoding); serverLog(LL_WARNING,"Object refcount: %d", o->refcount); if (o->type == OBJ_STRING && sdsEncodedObject(o)) { serverLog(LL_WARNING,"Object raw string len: %zu", sdslen(o->ptr)); if (sdslen(o->ptr) < 4096) { sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr)); serverLog(LL_WARNING,"Object raw string content: %s", repr); sdsfree(repr); } } }
void replicationFeedMonitors(redisClient *c, list *monitors, int dictid, robj **argv, int argc) { listNode *ln; listIter li; int j, port; sds cmdrepr = sdsnew("+"); robj *cmdobj; char ip[32]; struct timeval tv; gettimeofday(&tv,NULL); cmdrepr = sdscatprintf(cmdrepr,"%ld.%06ld ",(long)tv.tv_sec,(long)tv.tv_usec); if (c->flags & REDIS_LUA_CLIENT) { cmdrepr = sdscatprintf(cmdrepr,"[%d lua] ",dictid); } else if (c->flags & REDIS_UNIX_SOCKET) { cmdrepr = sdscatprintf(cmdrepr,"[%d unix:%s] ",dictid,server.unixsocket); } else { anetPeerToString(c->fd,ip,&port); cmdrepr = sdscatprintf(cmdrepr,"[%d %s:%d] ",dictid,ip,port); } for (j = 0; j < argc; j++) { if (argv[j]->encoding == REDIS_ENCODING_INT) { cmdrepr = sdscatprintf(cmdrepr, "\"%ld\"", (long)argv[j]->ptr); } else { cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr, sdslen(argv[j]->ptr)); } if (j != argc-1) cmdrepr = sdscatlen(cmdrepr," ",1); } cmdrepr = sdscatlen(cmdrepr,"\r\n",2); cmdobj = createObject(REDIS_STRING,cmdrepr); listRewind(monitors,&li); while((ln = listNext(&li))) { redisClient *monitor = ln->value; addReply(monitor,cmdobj); } decrRefCount(cmdobj); }
void prezLogObjectDebugInfo(robj *o) { prezLog(PREZ_WARNING,"Object type: %d", o->type); prezLog(PREZ_WARNING,"Object encoding: %d", o->encoding); prezLog(PREZ_WARNING,"Object refcount: %d", o->refcount); if (o->type == PREZ_STRING && sdsEncodedObject(o)) { prezLog(PREZ_WARNING,"Object raw string len: %zu", sdslen(o->ptr)); if (sdslen(o->ptr) < 4096) { sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr)); prezLog(PREZ_WARNING,"Object raw string content: %s", repr); sdsfree(repr); } } /*else if (o->type == PREZ_LIST) { prezLog(PREZ_WARNING,"List length: %d", (int) listTypeLength(o)); } else if (o->type == PREZ_SET) { prezLog(PREZ_WARNING,"Set size: %d", (int) setTypeSize(o)); } else if (o->type == PREZ_HASH) { prezLog(PREZ_WARNING,"Hash size: %d", (int) hashTypeLength(o)); } else if (o->type == PREZ_ZSET) { prezLog(PREZ_WARNING,"Sorted set size: %d", (int) zsetLength(o)); if (o->encoding == PREZ_ENCODING_SKIPLIST) prezLog(PREZ_WARNING,"Skiplist level: %d", (int) ((zset*)o->ptr)->zsl->level); } */ }
static sds cliFormatReplyTTY(redisReply *r, char *prefix) { sds out = sdsempty(); switch (r->type) { case REDIS_REPLY_ERROR: out = sdscatprintf(out,"(error) %s\n", r->str); break; case REDIS_REPLY_STATUS: out = sdscat(out,r->str); out = sdscat(out,"\n"); break; case REDIS_REPLY_INTEGER: out = sdscatprintf(out,"(integer) %lld\n",r->integer); break; case REDIS_REPLY_STRING: /* If you are producing output for the standard output we want * a more interesting output with quoted characters and so forth */ out = sdscatrepr(out,r->str,r->len); out = sdscat(out,"\n"); break; case REDIS_REPLY_NIL: out = sdscat(out,"(nil)\n"); break; case REDIS_REPLY_ARRAY: 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; /* Calculate chars needed to represent the largest index */ i = r->elements; do { idxlen++; i /= 10; } while(i); /* Prefix for nested multi bulks should grow with idxlen+2 spaces */ memset(_prefixlen,' ',idxlen+2); _prefixlen[idxlen+2] = '\0'; _prefix = sdscat(sdsnew(prefix),_prefixlen); /* Setup prefix format for every entry */ snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%dd) ",idxlen); for (i = 0; i < r->elements; i++) { /* Don't use the prefix for the first element, as the parent * caller already prepended the index number. */ out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1); /* Format the multi bulk entry */ 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 main(void) { { sdshdr *sh; sds x = sdsnew("foo"), y; test_cond("Create a string and obtain the length", sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) sdsfree(x); x = sdsnewlen("foo",2); test_cond("Create a string with specified length", sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) x = sdscat(x,"bar"); test_cond("Strings concatenation", sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); x = sdscpy(x,"a"); test_cond("sdscpy() against an originally longer string", sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); test_cond("sdscpy() against an originally shorter string", sdslen(x) == 33 && memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) sdsfree(x); x = sdscatprintf(sdsempty(),"%d",123); test_cond("sdscatprintf() seems working in the base case", sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) sdsfree(x); x = sdsnew("xxciaoyyy"); sdstrim(x,"xy"); test_cond("sdstrim() correctly trims characters", sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) y = sdsdup(x); sdsrange(y,1,1); test_cond("sdsrange(...,1,1)", sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,-1); test_cond("sdsrange(...,1,-1)", sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,-2,-1); test_cond("sdsrange(...,-2,-1)", sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,2,1); test_cond("sdsrange(...,2,1)", sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,100); test_cond("sdsrange(...,1,100)", sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,100,100); test_cond("sdsrange(...,100,100)", sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); sdsfree(x); x = sdsnew("foo"); y = sdsnew("foa"); test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) sdsfree(y); sdsfree(x); x = sdsnew("bar"); y = sdsnew("bar"); test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) sdsfree(y); sdsfree(x); x = sdsnew("aar"); y = sdsnew("bar"); test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) sdsfree(y); sdsfree(x); x = sdsnewlen("\a\n\0foo\r",7); y = sdscatrepr(sdsempty(),x,sdslen(x)); test_cond("sdscatrepr(...data...)", memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) sdsfree(y); { size_t oldfree; sdsfree(x); x = sdsnew("0"); sh = sds_start(x); test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); x = sdsMakeRoomFor(x,1); sh = sds_start(x); test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); oldfree = sh->free; x[1] = '1'; sdsIncrLen(x,1); test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); test_cond("sdsIncrLen() -- len", sh->len == 2); test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); sdsfree(x); } x = sdsnew("0FoO1bar\n"); sdstolower(x); test_cond("sdstolower(...)", memcmp(x,"0foo1bar\n\0",10) == 0) sdsfree(x); x = sdsnew("0FoO1bar\n"); sdstoupper(x); test_cond("sdstoupper(...)", memcmp(x,"0FOO1BAR\n\0",10) == 0) sdsfree(x); } test_report() return 0; }
int main (int argc, char **argv) { struct timeval tv; // 初始化相关环境变量与库 #ifdef INIT_SETPROCTITLE_REPLACEMENT spt_init(argc, argv); #endif // 设置当前的`locale`命令里的内容 setlocale(LC_COLLATE, ""); // 自动分配线程安全 zmalloc_enable_thread_safeness(); // 设置自动分配函数句柄(out of memory) zmalloc_set_oom_handler(redisOutOfMemoryHandler); // 时间异或pid生成随机数种子 srand(time(NULL) ^ getpid()); gettimeofday(&tv, NULL); // 设置字典hash值种子 dictSetHashFunctionSeed(tv.tv_sec ^ tv.tv_usec ^ getpid()); // 定点模式检测 server.sentinel_mode = checkForSentinelMode(argc, argv); // 初始化服务配置 initServerConfig(); // 定点模式处理 if (server.sentinel_mode) { printf("deal with sentinel mode\n"); } if (argc >= 2) { int j = 1; // init empty string sds options = sdsempty(); char *configfile = NULL; if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) version(); if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) usage(); if (strcmp(argv[1], "--test-memory") == 0) { if (argc == 3) { // 内存测试还未完全写完 memtest(atoi(argv[2]), 50); exit(0); } else { fprintf(stderr, "Please specify the amount of memory to test in megabytes.\n"); fprintf(stderr, "Example: ./redis-server --test-memory 4096\n\n"); exit(1); } } /* * 第一个参数为'--'开头, j始终为1 * 第一个参数不为'--'开头, j始终为2 * */ // j为1,第1个参数不是'--'开头的是配置文件 if (argv[j][0] != '-' || argv[j][1] != '-') { configfile = argv[j++]; } // 配置文件参数后还有内容 while (j != argc) { // 所有参数有包括'--'开头的参数 if (argv[j][0] == '-' && argv[j][1] == '-') { if (sdslen(options)) options = sdscat(options, "\n"); options = sdscat(options, " "); } else { // append new string, 转义特殊字符, return new pointer options = sdscatrepr(options, argv[j], strlen(argv[j])); options = sdscat(options, " "); } j++; } if (server.sentinel_mode && configfile && *configfile == '-') { printf("need redis log\n"); exit(1); } if (configfile) { server.configfile = getAbsolutePath(configfile); } resetServerSaveParams(); loadServerConfig(configfile, options); sdsfree(options); } else { printf("warning: no config file specified\n"); } // 后台模式 if (server.daemonize) { daemonize(); } // init server initServer(); printf("redis done\n"); return 0; }