/* This callback is used by scanGenericCommand in order to collect elements * returned by the dictionary iterator into a list. */ void scanCallback(void *privdata, const dictEntry *de) { void **pd = (void**) privdata; list *keys = pd[0]; robj *o = pd[1]; robj *key, *val = NULL; if (o == NULL) { sds sdskey = dictGetKey(de); key = createStringObject(sdskey, sdslen(sdskey)); } else if (o->type == OBJ_SET) { sds keysds = dictGetKey(de); key = createStringObject(keysds,sdslen(keysds)); } else if (o->type == OBJ_HASH) { sds sdskey = dictGetKey(de); sds sdsval = dictGetVal(de); key = createStringObject(sdskey,sdslen(sdskey)); val = createStringObject(sdsval,sdslen(sdsval)); } else if (o->type == OBJ_ZSET) { sds sdskey = dictGetKey(de); key = createStringObject(sdskey,sdslen(sdskey)); val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0); } else { serverPanic("Type not handled in SCAN callback."); } listAddNodeTail(keys, key); if (val) listAddNodeTail(keys, val); }
int z_incr_key(void *cptr, char *arg) { redisClient *c = (redisClient *)cptr; robj *argv[2], *cmd, *key; int i, increment_max = 1000; printf("z_incr_key: %s\n", arg); z_set(c, "incr", "1"); cmd = createStringObject("INCR", 4); key = createStringObject("incr", 4); argv[0] = cmd; argv[1] = key; c->argv = argv; c->argc = 2; if(arg) { increment_max = atoi(arg); } for(i = 0; i < increment_max; i++) { incrDecrCommand(c, 1); } freeStringObject(cmd); freeStringObject(key); c->argv = NULL; c->argc = 0; return 0; }
int z_sadd(void *cptr, char * name, char * val) { redisClient *c = (redisClient *)cptr; robj *argv[10], *sadd, *rkey, *rval; sadd = createStringObject("SADD", 4); rkey = createStringObject(name, strlen(name)); rval = createStringObject(val, strlen(val)); argv[0] = sadd; argv[1] = rkey; argv[2] = rval; c->argv = argv; c->argc = 3; saddCommand(c); c->argv = NULL; c->argc = 0; freeStringObject(sadd); freeStringObject(rkey); // FAILS! tryObjectEncoding() in t_set.c .. freeStringObject(rval); return 0; }
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) { robj *aux; if (!handleClientsWaitingListPush(c,dstkey,value)) { /* Create the list if the key does not exist */ if (!dstobj) { dstobj = createZiplistObject(); dbAdd(c->db,dstkey,dstobj); } else { signalModifiedKey(c->db,dstkey); } listTypePush(dstobj,value,REDIS_HEAD); /* If we are pushing as a result of LPUSH against a key * watched by BLPOPLPUSH, we need to rewrite the command vector. * But if this is called directly by RPOPLPUSH (either directly * or via a BRPOPLPUSH where the popped list exists) * we should replicate the BRPOPLPUSH command itself. */ if (c != origclient) { aux = createStringObject("LPUSH",5); rewriteClientCommandVector(origclient,3,aux,dstkey,value); decrRefCount(aux); } else { /* Make sure to always use RPOPLPUSH in the replication / AOF, * even if the original command was BRPOPLPUSH. */ aux = createStringObject("RPOPLPUSH",9); rewriteClientCommandVector(origclient,3,aux,c->argv[1],c->argv[2]); decrRefCount(aux); } server.dirty++; } /* Always send the pushed value to the client. */ addReplyBulk(c,value); }
int z_keys_star(void *cptr, char *arg) { redisClient *c = (redisClient *)cptr; robj *argv[2], *keys, *star; printf("z_keys_star: %s\n", arg); keys = createStringObject("KEYS", 4); star = createStringObject("*", 1); argv[0] = keys; argv[1] = star; c->argv = argv; c->argc = 2; keysCommand(c); freeStringObject(keys); freeStringObject(star); c->argv = NULL; c->argc = 0; return 0; }
void spopCommand(client *c) { robj *set, *ele, *aux; sds sdsele; int64_t llele; int encoding; if (c->argc == 3) { spopWithCountCommand(c); return; } else if (c->argc > 3) { addReply(c,shared.syntaxerr); return; } /* Make sure a key with the name inputted exists, and that it's type is * indeed a set */ if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL || checkType(c,set,OBJ_SET)) return; /* Get a random element from the set */ encoding = setTypeRandomElement(set,&sdsele,&llele); /* Remove the element from the set */ if (encoding == OBJ_ENCODING_INTSET) { ele = createStringObjectFromLongLong(llele); set->ptr = intsetRemove(set->ptr,llele,NULL); } else { ele = createStringObject(sdsele,sdslen(sdsele)); setTypeRemove(set,ele->ptr); } notifyKeyspaceEvent(NOTIFY_SET,"spop",c->argv[1],c->db->id); /* Replicate/AOF this command as an SREM operation */ aux = createStringObject("SREM",4); rewriteClientCommandVector(c,3,aux,c->argv[1],ele); decrRefCount(aux); /* Add the element to the reply */ addReplyBulk(c,ele); decrRefCount(ele); /* Delete the set if it's empty */ if (setTypeSize(set) == 0) { dbDelete(c->db,c->argv[1]); notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } /* Set has been modified */ signalModifiedKey(c->db,c->argv[1]); server.dirty++; }
int z_set(void *cptr, char * key, char * val) { redisClient *c = (redisClient *) cptr; robj *rkey, *rval; rkey = createStringObject(key, strlen(key)); rval = createStringObject(val, strlen(val)); setGenericCommand(c, 0, rkey, rval, NULL, 0, NULL, NULL); freeStringObject(rkey); freeStringObject(rval); return 0; }
void keysCommand(redisClient *c) { dictIterator *di; dictEntry *de; sds pattern = c->argv[1]->ptr; int plen = sdslen(pattern); unsigned long numkeys = 0; robj *lenobj = createObject(REDIS_STRING,NULL); di = dictGetIterator(c->db->dict); addReply(c,lenobj); decrRefCount(lenobj); while((de = dictNext(di)) != NULL) { sds key = dictGetEntryKey(de); robj *keyobj; if ((pattern[0] == '*' && pattern[1] == '\0') || stringmatchlen(pattern,plen,key,sdslen(key),0)) { keyobj = createStringObject(key,sdslen(key)); if (expireIfNeeded(c->db,keyobj) == 0) { addReplyBulk(c,keyobj); numkeys++; } decrRefCount(keyobj); } } dictReleaseIterator(di); lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",numkeys); }
/* Create the sds representation of an PEXPIREAT command, using * 'seconds' as time to live and 'cmd' to understand what command * we are translating into a PEXPIREAT. * * This command is used in order to translate EXPIRE and PEXPIRE commands * into PEXPIREAT command so that we retain precision in the append only * file, and the time is always absolute and not relative. */ sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, robj *seconds) { long long when; robj *argv[3]; /* Make sure we can use strtol */ seconds = getDecodedObject(seconds); when = strtoll(seconds->ptr,NULL,10); /* Convert argument into milliseconds for EXPIRE, SETEX, EXPIREAT */ if (cmd->proc == expireCommand || cmd->proc == setexCommand || cmd->proc == expireatCommand) { when *= 1000; } /* Convert into absolute time for EXPIRE, PEXPIRE, SETEX, PSETEX */ if (cmd->proc == expireCommand || cmd->proc == pexpireCommand || cmd->proc == setexCommand || cmd->proc == psetexCommand) { when += mstime(); } decrRefCount(seconds); argv[0] = createStringObject("PEXPIREAT",9); argv[1] = key; argv[2] = createStringObjectFromLongLong(when); buf = catAppendOnlyGenericCommand(buf, 3, argv); decrRefCount(argv[0]); decrRefCount(argv[2]); return buf; }
// LINDEX key index // LINDEX命令的实现 void lindexCommand(client *c) { //以读操作取出key对象的value值 robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk); //如果key没找到或value对象不是列表类型则直接返回 if (o == NULL || checkType(c,o,OBJ_LIST)) return; long index; robj *value = NULL; //将index参数转换为long类型的整数,保存在index中 if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return; //只对编码为quicklist类型的value对象操作 if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklistEntry entry; //将下标为index的entry节点保存到entry中 if (quicklistIndex(o->ptr, index, &entry)) { if (entry.value) { //如果vlaue是字符串类型 //创建一个字符串类型的对象,保存value值 value = createStringObject((char*)entry.value,entry.sz); } else { //将整型的value值转换为字符串类型并创建字符串类型的对象 value = createStringObjectFromLongLong(entry.longval); } addReplyBulk(c,value); //发送value对象 decrRefCount(value); //释放value对象 } else { addReply(c,shared.nullbulk); //如果下标为index没找到,则发送空信息 } } else { serverPanic("Unknown list encoding"); //发送未知的列表编码类型 } }
void delkeysCommand(redisClient *c) { dictIterator *di; dictEntry *de; sds pattern = c->argv[1]->ptr; int plen = sdslen(pattern), allkeys; unsigned long deleted = 0; di = dictGetIterator(c->db->dict); allkeys = (pattern[0] == '*' && pattern[1] == '\0'); while((de = dictNext(di)) != NULL) { sds key = dictGetEntryKey(de); robj *keyobj; if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) { keyobj = createStringObject(key,sdslen(key)); if (dbDelete(c->db,keyobj)) { touchWatchedKey(c->db,keyobj); server.dirty++; deleted++; } decrRefCount(keyobj); } } dictReleaseIterator(di); addReplyLongLong(c,deleted); }
/* Note: this function is defined into object.c since here it is where it * belongs but it is actually designed to be used just for INCRBYFLOAT */ robj *createStringObjectFromLongDouble(long double value) { char buf[256]; int len; /* We use 17 digits precision since with 128 bit floats that precision * after rounding is able to represent most small decimal numbers in a way * that is "non surprising" for the user (that is, most small decimal * numbers will be represented in a way that when converted back into * a string are exactly the same as what the user typed.) */ #ifdef _WIN32 /* on Windows the magic number is 15 */ len = snprintf(buf,sizeof(buf),"%.15Lf", value); #else len = snprintf(buf,sizeof(buf),"%.17Lf", value); #endif /* Now remove trailing zeroes after the '.' */ if (strchr(buf,'.') != NULL) { char *p = buf+len-1; while(*p == '0') { p--; len--; } if (*p == '.') len--; } return createStringObject(buf,len); }
void lindexCommand(redisClient *c) { robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk); if (o == NULL || checkType(c,o,REDIS_LIST)) return; int index = atoi(c->argv[2]->ptr); robj *value = NULL; if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *p; unsigned char *vstr; unsigned int vlen; long long vlong; p = ziplistIndex(o->ptr,index); if (ziplistGet(p,&vstr,&vlen,&vlong)) { if (vstr) { value = createStringObject((char*)vstr,vlen); } else { value = createStringObjectFromLongLong(vlong); } addReplyBulk(c,value); decrRefCount(value); } else { addReply(c,shared.nullbulk); } } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { listNode *ln = listIndex(o->ptr,index); if (ln != NULL) { value = listNodeValue(ln); addReplyBulk(c,value); } else { addReply(c,shared.nullbulk); } } else { redisPanic("Unknown list encoding"); } }
/* Send a MULTI command to all the slaves and AOF file. Check the execCommand * implementation for more information. */ void execCommandPropagateMulti(client *c) { robj *multistring = createStringObject("MULTI",5); propagate(server.multiCommand,c->db->id,&multistring,1, PROPAGATE_AOF|PROPAGATE_REPL); decrRefCount(multistring); }
void lindexCommand(client *c) { robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk); if (o == NULL || checkType(c,o,OBJ_LIST)) return; long index; robj *value = NULL; if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return; if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklistEntry entry; if (quicklistIndex(o->ptr, index, &entry)) { if (entry.value) { value = createStringObject((char*)entry.value,entry.sz); } else { value = createStringObjectFromLongLong(entry.longval); } addReplyBulk(c,value); decrRefCount(value); } else { addReply(c,shared.nullbulk); } } else { serverPanic("Unknown list encoding"); } }
void scriptCommand(rliteClient *c) { if (c->argc == 2 && !strcasecmp(c->argv[1],"flush")) { scriptingReset(); c->reply = createStatusObject(RLITE_STR_OK); } else if (c->argc >= 2 && !strcasecmp(c->argv[1],"exists")) { int j; c->reply = createArrayObject(c->argc - 2); for (j = 2; j < c->argc; j++) { c->reply->element[j - 2] = createLongLongObject(getScript(c, c->argv[j], NULL, NULL) == RL_OK ? 1 : 0); } } else if (c->argc == 3 && !strcasecmp(c->argv[1],"load")) { char sha[41]; sha1hex(sha,c->argv[2],c->argvlen[2]); setScript(c, c->argv[2], c->argvlen[2]); c->reply = createStringObject(sha,40); } else if (c->argc == 2 && !strcasecmp(c->argv[1],"kill")) { if (lua_caller == NULL) { c->reply = createCStringObject("NOTBUSY No scripts in execution right now.\r\n"); } else if (lua_write_dirty) { c->reply = createCStringObject("UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.\r\n"); } else { lua_kill = 1; c->reply = createStatusObject(RLITE_STR_OK); } } else { c->reply = createErrorObject("ERR Unknown SCRIPT subcommand or wrong # of args."); } }
void evalName(redisClient *c, char *name) { sds hash; robj *sha; /* if len(name) == 40, then this *could* be a script hash. * Try to look it up as a hash first. */ if (sdslen(name) == 40 && dictFind(server.lua_scripts, name)) { hash = name; } else { hash = dictFetchValue(g.names, name); /* If we didn't find it, or if we did find it but for some * reason the len(hash) != 40, ... */ if (!hash || sdslen(hash) != 40) { addReply(c, g.err.nosha); return; } } /* the redisClient object uses robj * for fields, * so here we convert the sds hash into an robj of * an sds */ sha = createStringObject(hash, sdslen(hash)); rewriteClientCommandArgument(c, 1, sha); decrRefCount(sha); /* No leaking memory from our created robj */ /* Now run the script as normal, just like we never existed. *poof* */ evalGenericCommand(c, 1); }
void spopCommand(redisClient *c) { robj *set, *ele, *aux; int64_t llele; int encoding; if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL || checkType(c,set,REDIS_SET)) return; encoding = setTypeRandomElement(set,&ele,&llele); if (encoding == REDIS_ENCODING_INTSET) { ele = createStringObjectFromLongLong(llele); set->ptr = intsetRemove(set->ptr,llele,NULL); } else { incrRefCount(ele); setTypeRemove(set,ele); } notifyKeyspaceEvent(REDIS_NOTIFY_SET,"spop",c->argv[1],c->db->id); /* Replicate/AOF this command as an SREM operation */ aux = createStringObject("SREM",4); rewriteClientCommandVector(c,3,aux,c->argv[1],ele); decrRefCount(ele); decrRefCount(aux); addReplyBulk(c,ele); if (setTypeSize(set) == 0) { dbDelete(c->db,c->argv[1]); notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } signalModifiedKey(c->db,c->argv[1]); server.dirty++; }
/* Higher level function of hashTypeGet*() that always returns a Redis * object (either new or with refcount incremented), so that the caller * can retain a reference or call decrRefCount after the usage. * * The lower level function can prevent copy on write so it is * the preferred way of doing read operations. */ robj *hashTypeGetObject(robj *o, robj *field) { robj *value = NULL; if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *vstr = NULL; unsigned int vlen = UINT_MAX; long long vll = LLONG_MAX; if (hashTypeGetFromZiplist(o, field, &vstr, &vlen, &vll) == 0) { if (vstr) { value = createStringObject((char*)vstr, vlen); } else { value = createStringObjectFromLongLong(vll); } } } else if (o->encoding == REDIS_ENCODING_HT) { robj *aux; if (hashTypeGetFromHashTable(o, field, &aux) == 0) { incrRefCount(aux); value = aux; } } else { logicError("Unknown hash encoding"); } return value; }
static void slotsremove(redisClient *c, robj **keys, int n, int rewrite) { for (int i = 0; i < n; i ++) { dbDelete(c->db, keys[i]); signalModifiedKey(c->db, keys[i]); server.dirty ++; } if (!rewrite) { return; } for (int i = 0; i < n; i ++) { incrRefCount(keys[i]); } for (int i = 0; i < c->argc; i ++) { decrRefCount(c->argv[i]); } zfree(c->argv); c->argc = n + 1; c->argv = zmalloc(sizeof(robj *) * c->argc); c->argv[0] = createStringObject("DEL", 3); for (int i = 0; i < n; i ++) { c->argv[i + 1] = keys[i]; } c->cmd = lookupCommandOrOriginal(c->argv[0]->ptr); redisAssertWithInfo(c, NULL, c->cmd != NULL); }
/* * * slotsmgrttagslot host port timeout slot * */ void slotsmgrttagslotCommand(redisClient *c) { sds host = c->argv[1]->ptr; sds port = c->argv[2]->ptr; int timeout, slot; if (parse_timeout(c, c->argv[3], &timeout) != 0) { return; } if (parse_slot(c, c->argv[4], &slot) != 0) { return; } dict *d = c->db->hash_slots[slot]; int succ = 0; do { const dictEntry *de = dictGetRandomKey(d); if (de == NULL) { break; } sds skey = dictGetKey(de); robj *key = createStringObject(skey, sdslen(skey)); succ = slotsmgrttag_command(c, host, port, timeout, key); decrRefCount(key); if (succ < 0) { return; } } while (0); addReplyMultiBulkLen(c, 2); addReplyLongLong(c, succ); addReplyLongLong(c, dictSize(d)); }
static void slotsScanSdsKeyTagCallback(void *privdata, const dictEntry *de) { void **args = (void **)privdata; list *l = (list *)args[0]; void *tag1 = args[1]; int taglen1 = *(int *)args[2]; void *vcrc = args[3]; if (vcrc != dictGetVal(de)) { return; } sds skey = dictGetKey(de); int taglen2; void *tag2 = slots_tag(skey, &taglen2); if (tag2 == NULL) { return; } if (taglen2 != taglen1) { return; } if (strncmp(tag1, tag2, taglen1) != 0) { return; } robj *key = createStringObject(skey, sdslen(skey)); listAddNodeTail(l, key); }
static bool jRowReply(jrow_reply_t *r, int lvl) { int cnt = 0; for (int i = 0; i <= lvl; i++) { /* sort columns back to queried-order */ for (int j = 0; j < r->jind_ncols[i]; j++) { int n = r->reordered ? r->csort_order[cnt].n : cnt; Jrcols[n] = Rcols[i][j]; Jrc_lens[n] = Rc_lens[i][j]; cnt++; } } if (!Order_by && r->cstar) return 1; /* NOOP just count */ int slot = 0; for (int i = 0; i < cnt; i++) { char *s = *Jrcols[i]; int rlen = Jrc_lens[i]; memcpy(r->reply + slot, s, rlen); slot += rlen; memcpy(r->reply + slot, OUTPUT_DELIM, 1); slot++; } robj *resp = createStringObject(r->reply, slot -1); if (Order_by) { addJoinOutputRowToList(r, resp); } else { addReplyBulk(r->c, resp); decrRefCount(resp); } return 1; }
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) { if (!handleClientsWaitingListPush(origclient,dstkey,value)) { /* Create the list if the key does not exist */ if (!dstobj) { dstobj = createZiplistObject(); dbAdd(c->db,dstkey,dstobj); } else { signalModifiedKey(c->db,dstkey); } listTypePush(dstobj,value,REDIS_HEAD); /* Additionally propagate this PUSH operation together with * the operation performed by the command. */ { robj **argv = zmalloc(sizeof(robj*)*3); argv[0] = createStringObject("LPUSH",5); argv[1] = dstkey; argv[2] = value; incrRefCount(argv[1]); incrRefCount(argv[2]); alsoPropagate(server.lpushCommand,c->db->id,argv,3, REDIS_PROPAGATE_AOF|REDIS_PROPAGATE_REPL); } } /* Always send the pushed value to the client. */ addReplyBulk(c,value); }
int rdbSaveNRL(FILE *fp, robj *o) { listNode *ln; d_l_t *nrlind = o->ptr; list *nrltoks = nrlind->l1; int imatch = nrlind->num; if (rdbSaveLen(fp, imatch) == -1) return -1; robj *iname = Index[server.dbid][imatch].obj; if (rdbSaveStringObject(fp, iname) == -1) return -1; int tmatch = Index[server.dbid][imatch].table; if (rdbSaveLen(fp, tmatch) == -1) return -1; if (rdbSaveLen(fp, listLength(nrltoks)) == -1) return -1; listIter *li = listGetIterator(nrltoks, AL_START_HEAD); while((ln = listNext(li)) != NULL) { sds s = ln->value; robj *r = createStringObject(s, sdslen(s)); if (rdbSaveStringObject(fp, r) == -1) return -1; decrRefCount(r); } listReleaseIterator(li); list *nrlcols = nrlind->l2; if (rdbSaveLen(fp, listLength(nrlcols)) == -1) return -1; li = listGetIterator(nrlcols, AL_START_HEAD); while((ln = listNext(li)) != NULL) { uint32 i = (uint32)(long)ln->value; if (rdbSaveLen(fp, i) == -1) return -1; } listReleaseIterator(li); return 0; }
void keysCommand(redisClient *c) { dictIterator *di; dictEntry *de; sds pattern = c->argv[1]->ptr; int plen = sdslen(pattern), allkeys; unsigned long numkeys = 0; void *replylen = addDeferredMultiBulkLength(c); di = dictGetSafeIterator(c->db->dict); allkeys = (pattern[0] == '*' && pattern[1] == '\0'); while((de = dictNext(di)) != NULL) { sds key = dictGetKey(de); robj *keyobj; if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) { keyobj = createStringObject(key,sdslen(key)); if (expireIfNeeded(c->db,keyobj) == 0) { addReplyBulk(c,keyobj); numkeys++; } decrRefCount(keyobj); } } dictReleaseIterator(di); setDeferredMultiBulkLength(c,replylen,numkeys); }
/* * 根据传入的 long double 值,为它创建一个字符串对象 * * 对象将 long double 转换为字符串来保存 */ robj *createStringObjectFromLongDouble(long double value) { char buf[256]; int len; /* We use 17 digits precision since with 128 bit floats that precision * after rounding is able to represent most small decimal numbers in a way * that is "non surprising" for the user (that is, most small decimal * numbers will be represented in a way that when converted back into * a string are exactly the same as what the user typed.) */ // 使用 17 位小数精度,这种精度可以在大部分机器上被 rounding 而不改变 len = snprintf(buf,sizeof(buf),"%.17Lf", value); /* Now remove trailing zeroes after the '.' */ // 移除尾部的 0 // 比如 3.1400000 将变成 3.14 // 而 3.00000 将变成 3 if (strchr(buf,'.') != NULL) { char *p = buf+len-1; while(*p == '0') { p--; len--; } // 如果不需要小数点,那么移除它 if (*p == '.') len--; } // 创建对象 return createStringObject(buf,len); }
void call_expire_delete_event(void *pdb,void *pkeyobj) { redisDb *db=(redisDb *)pdb; robj *myobj=(robj *)pkeyobj; robj *keyobj = createStringObject(myobj->ptr,sdslen(myobj->ptr)); struct dictIterator *iter=dictGetIterator(server.bridge_db.triggle_scipts[db->id]); dictEntry *trigs; do{ trigs=dictNext(iter); if(trigs!=NULL) { struct bridge_db_triggle_t * tmptrg=dictGetVal(trigs); //add func str check for the function only the key satisfy the funcname:XXXX can call the event if(tmptrg->event==DELETE_EXPIRE&&strncmp(keyobj->ptr,dictGetKey(trigs),sdslen(dictGetKey(trigs)))==0){ //找到指定的类型事件 redisLog(REDIS_NOTICE,"triggle_event:%d,%s",DELETE_EXPIRE,(char *)dictGetKey(trigs)); triggle_expire_event(db,dictGetKey(trigs),keyobj); } } }while(trigs!=NULL); dictReleaseIterator(iter); decrRefCount(keyobj); }
/* Create a string object from a long double. If humanfriendly is non-zero * it does not use exponential format and trims trailing zeroes at the end, * however this results in loss of precision. Otherwise exp format is used * and the output of snprintf() is not modified. * * The 'humanfriendly' option is used for INCRBYFLOAT and HINCRBYFLOAT. */ robj *createStringObjectFromLongDouble(long double value, int humanfriendly) { char buf[256]; int len; if (isinf(value)) { /* Libc in odd systems (Hi Solaris!) will format infinite in a * different way, so better to handle it in an explicit way. */ if (value > 0) { memcpy(buf,"inf",3); len = 3; } else { memcpy(buf,"-inf",4); len = 4; } } else if (humanfriendly) { /* We use 17 digits precision since with 128 bit floats that precision * after rounding is able to represent most small decimal numbers in a * way that is "non surprising" for the user (that is, most small * decimal numbers will be represented in a way that when converted * back into a string are exactly the same as what the user typed.) */ len = snprintf(buf,sizeof(buf),"%.17Lf", value); /* Now remove trailing zeroes after the '.' */ if (strchr(buf,'.') != NULL) { char *p = buf+len-1; while(*p == '0') { p--; len--; } if (*p == '.') len--; } } else { len = snprintf(buf,sizeof(buf),"%.17Lg", value); } return createStringObject(buf,len); }
static void runCmdInFakeClient(sds s) { //RL4 "runCmdInFakeClient: %s", s); int argc; sds *argv = sdssplitlen(s, sdslen(s), " ", 1, &argc); // FREEME 017 if (!argv) return; if (argc < 1) goto run_cmd_end; redisCommand *cmd = lookupCommand(argv[0]); if (!cmd) goto run_cmd_end; if ((cmd->arity > 0 && cmd->arity > argc) || (argc < -cmd->arity)) goto run_cmd_end; int arity; robj **rargv; if (cmd->arity > 0 || cmd->proc == insertCommand || cmd->proc == sqlSelectCommand || cmd->proc == tscanCommand) { arity = abs(cmd->arity); rargv = zmalloc(sizeof(robj *) * arity); /* ZFREE ME 018 */ for (int j = 0; j < arity - 1; j++) { rargv[j] = createStringObject(argv[j], sdslen(argv[j])); // FREE 019 } sds lastarg = sdsempty(); for (int j = arity - 1; j < argc; j++) { if (j != (arity - 1)) lastarg = sdscatlen(lastarg, " ", 1); lastarg = sdscatlen(lastarg, argv[j], sdslen(argv[j])); } rargv[arity - 1] = createObject(REDIS_STRING, lastarg); // FREE 019 } else { arity = argc; rargv = zmalloc(sizeof(robj *) * arity); /* ZFREE ME 018 */ for (int j = 0; j < arity; j++) { rargv[j] = createStringObject(argv[j], sdslen(argv[j])); // FREE 019 } } redisClient *c = CurrClient; redisClient *fc = rsql_createFakeClient(); /* DESTROY ME 020 */ fc->argv = rargv; fc->argc = arity; fakeClientPipe(c, fc, NULL, 0, &NriFlag, nonRelIndRespHandler, emptyNonRelIndRespHandler); rsql_freeFakeClient(fc); /* DESTROYED 020 */ for (int j = 0; j < arity; j++) decrRefCount(rargv[j]); /* FREED 019 */ zfree(rargv); /* ZFREED 018 */ run_cmd_end: for (int j = 0; j < argc; j++) sdsfree(argv[j]); /* FREED 017 */ zfree(argv); /* FREED 017 */ }