/* Add the specified sample to the specified time series "event". * This function is usually called via latencyAddSampleIfNeeded(), that * is a macro that only adds the sample if the latency is higher than * server.latency_monitor_threshold. */ void latencyAddSample(char *event, mstime_t latency) { struct latencyTimeSeries *ts = dictFetchValue(server.latency_events,event); time_t now = time(NULL); int prev; /* Create the time series if it does not exist. */ if (ts == NULL) { ts = zmalloc(sizeof(*ts)); ts->idx = 0; ts->max = 0; memset(ts->samples,0,sizeof(ts->samples)); dictAdd(server.latency_events,zstrdup(event),ts); } /* If the previous sample is in the same second, we update our old sample * if this latency is > of the old one, or just return. */ prev = (ts->idx + LATENCY_TS_LEN - 1) % LATENCY_TS_LEN; if (ts->samples[prev].time == now) { if (latency > ts->samples[prev].latency) ts->samples[prev].latency = (int32_t)latency; return; } ts->samples[ts->idx].time = (int32_t)time(NULL); ts->samples[ts->idx].latency = (int32_t)latency; if (latency > ts->max) ts->max = (int32_t)latency; ts->idx++; if (ts->idx == LATENCY_TS_LEN) ts->idx = 0; }
/* Unblock a client that's waiting in a blocking operation such as BLPOP. * You should never call this function directly, but unblockClient() instead. */ void unblockClientWaitingData(client *c) { dictEntry *de; dictIterator *di; list *l; serverAssertWithInfo(c,NULL,dictSize(c->bpop.keys) != 0); di = dictGetIterator(c->bpop.keys); /* The client may wait for multiple keys, so unblock it for every key. */ while((de = dictNext(di)) != NULL) { robj *key = dictGetKey(de); /* Remove this client from the list of clients waiting for this key. */ l = dictFetchValue(c->db->blocking_keys,key); serverAssertWithInfo(c,key,l != NULL); listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(c->db->blocking_keys,key); } dictReleaseIterator(di); /* Cleanup the client structure */ dictEmpty(c->bpop.keys,NULL); if (c->bpop.target) { decrRefCount(c->bpop.target); c->bpop.target = NULL; } if (c->bpop.xread_group) { decrRefCount(c->bpop.xread_group); decrRefCount(c->bpop.xread_consumer); c->bpop.xread_group = NULL; c->bpop.xread_consumer = NULL; } }
/* 分析某个时间Event的延时结果,结果信息存入latencyStats结构体中 */ void analyzeLatencyForEvent(char *event, struct latencyStats *ls) { struct latencyTimeSeries *ts = dictFetchValue(server.latency_events,event); int j; uint64_t sum; //初始化延时统计结果结构体的变量 ls->all_time_high = ts ? ts->max : 0; ls->avg = 0; ls->min = 0; ls->max = 0; ls->mad = 0; ls->samples = 0; ls->period = 0; if (!ts) return; /* First pass, populate everything but the MAD. */ sum = 0; for (j = 0; j < LATENCY_TS_LEN; j++) { if (ts->samples[j].time == 0) continue; ls->samples++; if (ls->samples == 1) { ls->min = ls->max = ts->samples[j].latency; } else { //找出延时最大和最小的延时时间 if (ls->min > ts->samples[j].latency) ls->min = ts->samples[j].latency; if (ls->max < ts->samples[j].latency) ls->max = ts->samples[j].latency; } sum += ts->samples[j].latency; /* Track the oldest event time in ls->period. */ if (ls->period == 0 || ts->samples[j].time < ls->period) //最早的延时记录点的创建时间 ls->period = ts->samples[j].time; } /* So far avg is actually the sum of the latencies, and period is * the oldest event time. We need to make the first an average and * the second a range of seconds. */ if (ls->samples) { ls->avg = sum / ls->samples; ls->period = time(NULL) - ls->period; if (ls->period == 0) ls->period = 1; } /* Second pass, compute MAD. */ //计算平均相对误差,与平均延时相比 sum = 0; for (j = 0; j < LATENCY_TS_LEN; j++) { int64_t delta; if (ts->samples[j].time == 0) continue; delta = (int64_t)ls->avg - ts->samples[j].latency; if (delta < 0) delta = -delta; sum += delta; } if (ls->samples) ls->mad = sum / ls->samples; }
void *cacheFetch(ccache *c, sds key) { cacheEntry *ce = (cacheEntry *)dictFetchValue(c->data,key); if(ce) { listMoveNodeToTail(c->accesslist,ce->ln); return ce->val; } return NULL; }
cacheEntry *cacheFind(ccache *c, sds key) { cacheEntry *ce = dictFetchValue(c->data,key); if(ce == NULL) { ce = cacheAdd(c,sdsdup(key),NULL); cacheSendMessage(c,ce,CACHE_REQUEST_NEW); } return ce; }
struct redisCommand *lookupCommandByCString(char *s) { struct redisCommand *cmd; sds name = sdsnew(s); cmd = dictFetchValue(server.commands, name); sdsfree(name); return cmd; }
const set *dbGet(const sds setName) { const set *result = NULL; lockRead(sets); result = (const set *) dictFetchValue(sets, setName); unlockRead(sets); return result; }
char* findLookupVal(char *key, unsigned char type) { lookup_log(LOG_DEBUG, "table find %s,%d\n", key, type); lookupKey find; find.name = key; find.type = type; char *val = (char *)dictFetchValue(dt, &find); return val; }
/* LATENCY command implementations. * * LATENCY SAMPLES: return time-latency samples for the specified event. * LATENCY LATEST: return the latest latency for all the events classes. * LATENCY DOCTOR: returns an human readable analysis of instance latency. * LATENCY GRAPH: provide an ASCII graph of the latency of the specified event. */ void latencyCommand(client *c) { struct latencyTimeSeries *ts; if (!strcasecmp(c->argv[1]->ptr,"history") && c->argc == 3) { /* LATENCY HISTORY <event> */ ts = dictFetchValue(server.latency_events,c->argv[2]->ptr); if (ts == NULL) { addReplyMultiBulkLen(c,0); } else { latencyCommandReplyWithSamples(c,ts); } } else if (!strcasecmp(c->argv[1]->ptr,"graph") && c->argc == 3) { /* LATENCY GRAPH <event> */ sds graph; dictEntry *de; char *event; de = dictFind(server.latency_events,c->argv[2]->ptr); if (de == NULL) goto nodataerr; ts = dictGetVal(de); event = dictGetKey(de); graph = latencyCommandGenSparkeline(event,ts); addReplyBulkCString(c,graph); sdsfree(graph); } else if (!strcasecmp(c->argv[1]->ptr,"latest") && c->argc == 2) { /* LATENCY LATEST */ latencyCommandReplyWithLatestEvents(c); } else if (!strcasecmp(c->argv[1]->ptr,"doctor") && c->argc == 2) { /* LATENCY DOCTOR */ sds report = createLatencyReport(); addReplyBulkCBuffer(c,report,sdslen(report)); sdsfree(report); } else if (!strcasecmp(c->argv[1]->ptr,"reset") && c->argc >= 2) { /* LATENCY RESET */ if (c->argc == 2) { addReplyLongLong(c,latencyResetEvent(NULL)); } else { int j, resets = 0; for (j = 2; j < c->argc; j++) resets += latencyResetEvent(c->argv[j]->ptr); addReplyLongLong(c,resets); } } else { addReply(c,shared.syntaxerr); } return; nodataerr: /* Common error when the user asks for an event we have no latency * information about. */ addReplyErrorFormat(c, "No samples available for event '%s'", (char*) c->argv[2]->ptr); }
/* PUBSUB command for Pub/Sub introspection. */ void pubsubCommand(redisClient *c) { // 处理PUBSUB CHANNELS [pattern]命令 if (!strcasecmp(c->argv[1]->ptr,"channels") && (c->argc == 2 || c->argc ==3)) { /* PUBSUB CHANNELS [<pattern>] */ // 获取pattern参数,如果没有则为NULL sds pat = (c->argc == 2) ? NULL : c->argv[2]->ptr; dictIterator *di = dictGetIterator(server.pubsub_channels); dictEntry *de; long mblen = 0; void *replylen; replylen = addDeferredMultiBulkLength(c); // 遍历server.pubsub_channels字典 while((de = dictNext(di)) != NULL) { // 取出当前频道channel robj *cobj = dictGetKey(de); sds channel = cobj->ptr; // 如果没有给定pattern参数,则打印出所有频道 // 如果给定pattern参数,则打印出与pattern参数相匹配的频道 if (!pat || stringmatchlen(pat, sdslen(pat), channel, sdslen(channel),0)) { addReplyBulk(c,cobj); mblen++; } } dictReleaseIterator(di); setDeferredMultiBulkLength(c,replylen,mblen); } // 处理PUBSUB NUMSUB [Channel_1 ... Channel_N]命令 else if (!strcasecmp(c->argv[1]->ptr,"numsub") && c->argc >= 2) { /* PUBSUB NUMSUB [Channel_1 ... Channel_N] */ int j; addReplyMultiBulkLen(c,(c->argc-2)*2); for (j = 2; j < c->argc; j++) { list *l = dictFetchValue(server.pubsub_channels,c->argv[j]); addReplyBulk(c,c->argv[j]); addReplyLongLong(c,l ? listLength(l) : 0); } } // 处理PUBSUB NUMPA命令 else if (!strcasecmp(c->argv[1]->ptr,"numpat") && c->argc == 2) { /* PUBSUB NUMPAT */ addReplyLongLong(c,listLength(server.pubsub_patterns)); } else { addReplyErrorFormat(c, "Unknown PUBSUB subcommand or wrong number of arguments for '%s'", (char*)c->argv[1]->ptr); } }
int process_trigglecmd(sds name) { //int i=0; struct triggleCmd *p=(struct triggleCmd *)dictFetchValue(server.bridge_db.triggle_cmds, name); return (p==NULL)?-1:p->event; }
void engine_set_int(Engine *engine, long doc_id, pstring *field, int value) { //FIXME?! RingBuffer *rb = dictFetchValue(engine->ints, field); assert(field); if(rb == NULL) { rb = ring_buffer_new(engine->ints_capacity); dictAdd(engine->ints, field, rb); } ring_buffer_put(rb, doc_id * sizeof(int), &value, sizeof(int)); }
void cacheDelete(ccache* c, sds key) { cacheEntry *ce = (cacheEntry *)dictFetchValue(c->data,key); /* Master reply by setting val to an object. * We do not delete cache entry until the master reply */ if(ce&&ce->val) { cacheSendMessage(c,sdsdup(key),CACHE_REQUEST_OLD); listDelNode(c->accesslist,ce->ln); dictDelete(c->data,key); } }
int * engine_get_int(Engine *engine, long doc_id, pstring *field) { RingBuffer *rb = dictFetchValue(engine->ints, field); long off = doc_id * sizeof(int); if(rb == NULL || (off + sizeof(int) > rb->written) || (off < rb->written - rb->capacity) ) { return NULL; } else { return (int *) &rb->buffer[off % rb->capacity]; } }
/* Handle a response to a given request. if this is a quorum setting, choose the * right response. Then make sure all the requests are satisfied in a fragmented * request scenario and then use the post coalesce logic to cook up a combined * response */ static rstatus_t client_handle_response(struct conn *conn, msgid_t reqid, struct msg *rsp) { ASSERT_LOG(!rsp->peer, "response %lu:%lu has peer set", rsp->id, rsp->parent_id); // now the handler owns the response. ASSERT(conn->type == CONN_CLIENT); // Fetch the original request struct msg *req = dictFetchValue(conn->outstanding_msgs_dict, &reqid); if (!req) { log_notice("looks like we already cleanedup the request for %d", reqid); rsp_put(rsp); return DN_OK; } // we have to submit the response irrespective of the unref status. rstatus_t status = msg_handle_response(req, rsp); if (conn->waiting_to_unref) { // dont care about the status. if (req->awaiting_rsps) return DN_OK; // all responses received dictDelete(conn->outstanding_msgs_dict, &reqid); log_info("Putting req %d", req->id); req_put(req); client_unref_internal_try_put(conn); return DN_OK; } if (status == DN_NOOPS) { // by now the response is dropped if (!req->awaiting_rsps) { // if we have sent the response for this request or the connection // is closed and we are just waiting to drain off the messages. if (req->rsp_sent) { dictDelete(conn->outstanding_msgs_dict, &reqid); log_info("Putting req %d", req->id); req_put(req); } } } else if (status == DN_OK) { g_pre_coalesce(req->selected_rsp); if (req_done(conn, req)) { struct context *ctx = conn_to_ctx(conn); status = event_add_out(ctx->evb, conn); if (status != DN_OK) { conn->err = errno; } } } return status; }
void* cache_get(qqCache* qc,const void* key){ void* lookup; void* die_key; void* dewrappedVal; size_t valsize; lookup = dictFetchValue(qc->dict,key); if(lookup==NULL){ // not hit return NULL; }else{ dewrappedVal=qc->type->dewrapValue(lookup); access(lookup,lookup,NULL,NULL); return dewrappedVal; } }
/* If the key does not exist, this is just like dbAdd(). Otherwise * the value associated to the key is replaced with the new one. * * On update (key already existed) 0 is returned. Otherwise 1. */ int dbReplace(redisDb *db, robj *key, robj *val) { robj *oldval; int retval; if ((oldval = dictFetchValue(db->dict,key->ptr)) == NULL) { sds copy = sdsdup(key->ptr); dictAdd(db->dict, copy, val); retval = 1; } else { dictReplace(db->dict, key->ptr, val); retval = 0; } if (server.ds_enabled) cacheSetKeyMayExist(db,key); return retval; }
void redis_fetch(dict *d, int times) { int i, j; char buf[20]; sds key, val; srand(1992); for (i = 0; i < times; ++i) { j = rand() % times; snprintf(buf, 20, "key%d", j); key = sdsnew(buf); assert(dictFetchValue(d, key)); sdsfree(key); } }
rcommand *DXDB_lookupCommand(sds name) { struct redisCommand *cmd = dictFetchValue(server.commands, name); if (server.alc.WebServerMode > 0) { // called during load in whitelist if (!server.alc.CurrClient) return cmd; // feed from master if (server.alc.CurrClient == server.master) return cmd; // lua already internal if (server.alc.CurrClient == server.lua_client) return cmd; if (!server.alc.CurrClient->InternalRequest) { if (isWhiteListedIp(server.alc.CurrClient)) return cmd; return cmd ? (cmd->proc == luafuncCommand) ? cmd : NULL : NULL; } } return cmd; }
int dbRemove(const sds setName) { int result = DICT_OK; set *s = NULL; lockWrite(sets); s = (set *) dictFetchValue(sets, setName); if (NULL != s) { unregisterSyncObject(s); if (!s->registered) setDestroy(s); result = dictDelete(sets, setName); } unlockWrite(sets); return result; }
/* * PUBSUB 命令, 内省命令 */ void pubsubCommand(redisClient *c) { if (!strcasecmp(c->argv[1]->ptr,"channels") && (c->argc == 2 || c->argc ==3)) //列出当前活跃的频道,每个频道至少有一个订阅者,订阅模式的客户端不计算在内 { /* PUBSUB CHANNELS [<pattern>] */ sds pat = (c->argc == 2) ? NULL : c->argv[2]->ptr; dictIterator *di = dictGetIterator(server.pubsub_channels); dictEntry *de; long mblen = 0; void *replylen; replylen = addDeferredMultiBulkLength(c); while((de = dictNext(di)) != NULL) { robj *cobj = dictGetKey(de); sds channel = cobj->ptr; if (!pat || stringmatchlen(pat, sdslen(pat), channel, sdslen(channel),0)) { addReplyBulk(c,cobj); mblen++; } } dictReleaseIterator(di); setDeferredMultiBulkLength(c,replylen,mblen); } else if (!strcasecmp(c->argv[1]->ptr,"numsub") && c->argc >= 2) { //返回给定频道的订阅者数量,订阅模式的客户端不计算在内 /* PUBSUB NUMSUB [Channel_1 ... Channel_N] */ int j; addReplyMultiBulkLen(c,(c->argc-2)*2); for (j = 2; j < c->argc; j++) { list *l = dictFetchValue(server.pubsub_channels,c->argv[j]); addReplyBulk(c,c->argv[j]); addReplyLongLong(c,l ? listLength(l) : 0); } } else if (!strcasecmp(c->argv[1]->ptr,"numpat") && c->argc == 2) { //返回订阅模式的数量 /* PUBSUB NUMPAT */ addReplyLongLong(c,listLength(server.pubsub_patterns)); } else { addReplyErrorFormat(c, "Unknown PUBSUB subcommand or wrong number of arguments for '%s'", (char*)c->argv[1]->ptr); } }
/* "Touch" a key, so that if this key is being WATCHed by some client the * next EXEC will fail. */ void touchWatchedKey(redisDb *db, robj *key) { list *clients; listIter li; listNode *ln; if (dictSize(db->watched_keys) == 0) return; clients = dictFetchValue(db->watched_keys, key); if (!clients) return; /* Mark all the clients watching this key as REDIS_DIRTY_CAS */ /* Check if we are already watching for this key */ listRewind(clients,&li); while((ln = listNext(&li))) { redisClient *c = listNodeValue(ln); c->flags |= REDIS_DIRTY_CAS; } }
void _masterProcessStatus() { /* Check if status is expired */ unsigned long now = time(NULL); if(next_master_refresh_time < now) { objSds *value = dictFetchValue(master_cache,statusQuery); if(value) { sds oldptr = value->ptr; /* Re-asign the value */ value->ptr = _masterGetStatus(); sdsfree(oldptr); next_master_refresh_time = now + MASTER_STATUS_REFRESH_PERIOD; } else { ulog(CCACHE_WARNING,"master cache %s not found",statusQuery); next_master_refresh_time = now + MASTER_STATUS_REFRESH_PERIOD*1000; } } }
void _masterProcessCacheNew(ccache *c){ cacheEntry *ce; while((ce=cacheGetMessage(c,CACHE_REQUEST_NEW)) != NULL) { master_numjob++; sds key = ce->de->key; objSds *value = dictFetchValue(master_cache,key); if(!value) { REPORT_MASTER_ADD_KEY(key); value = objSdsCreate(); /* Add cache entry to waiting list */ objSdsAddWaitingEntry(value,ce); /* Add entry to master cache */ sds mkey = sdsdup(key); /* master must have its own key for its own cache */ /* Every when accept new ce, the obj ref is increased */ objSdsAddRef(value); dictAdd(master_cache,mkey,value); /* New IO Job */ bioPushGeneralJob(mkey); OBJ_REPORT_REF(value); } else { switch(value->state) { case OBJSDS_WAITING: /* Every when accept new ce, the obj ref is increased */ objSdsAddRef(value); objSdsAddWaitingEntry(value,ce); break; case OBJSDS_OK: ce->val = value->ptr; /* Every when accept new ce, the obj ref is increased */ objSdsAddRef(value); /* Reply slave cache about the available data */ cacheSendMessage(c,ce,CACHE_REPLY_NEW); break; default: /* Error Unknown Object State */ break; } OBJ_REPORT_REF(value); } } }
/* COMMAND <subcommand> <args> */ void commandCommand(client *c) { dictIterator *di; dictEntry *de; if (c->argc == 1) { addReplyMultiBulkLen(c, dictSize(server.commands)); di = dictGetIterator(server.commands); while ((de = dictNext(di)) != NULL) { addReplyCommand(c, dictGetVal(de)); } dictReleaseIterator(di); } else if (!strcasecmp(c->argv[1]->ptr, "info")) { int i; addReplyMultiBulkLen(c, c->argc-2); for (i = 2; i < c->argc; i++) { addReplyCommand(c, dictFetchValue(server.commands, c->argv[i]->ptr)); } } else if (!strcasecmp(c->argv[1]->ptr, "count") && c->argc == 2) { addReplyLongLong(c, dictSize(server.commands)); } else if (!strcasecmp(c->argv[1]->ptr,"getkeys") && c->argc >= 3) { struct redisCommand *cmd = lookupCommand(c->argv[2]->ptr); int *keys, numkeys, j; if (!cmd) { addReplyErrorFormat(c,"Invalid command specified"); return; } else if ((cmd->arity > 0 && cmd->arity != c->argc-2) || ((c->argc-2) < -cmd->arity)) { addReplyError(c,"Invalid number of arguments specified for command"); return; } keys = getKeysFromCommand(cmd,c->argv+2,c->argc-2,&numkeys); addReplyMultiBulkLen(c,numkeys); for (j = 0; j < numkeys; j++) addReplyBulk(c,c->argv[keys[j]+2]); getKeysFreeResult(keys); } else { addReplyError(c, "Unknown subcommand or wrong number of arguments."); return; } }
/* * 监视给定 key * * T = O(N) */ void watchForKey(redisClient *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ // 检查该 key 是否已经被 WATCH // (出现在 WATCH 命令调用时一个 key 被输入多次的情况) // 如果是的话,直接返回 // O(N) listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { wk = listNodeValue(ln); if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } // key 未被监视 // 根据 key ,将客户端加入到 DB 的监视 key 字典中 /* This key is not already watched in this DB. Let's add it */ // O(1) clients = dictFetchValue(c->db->watched_keys,key); if (!clients) { clients = listCreate(); dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } listAddNodeTail(clients,c); // 将 key 添加到客户端的监视列表中 /* Add the new key to the lits of keys watched by this client */ // O(1) wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }
static void slotsmgrt_close_socket(sds host, sds port) { sds name = sdsempty(); name = sdscatlen(name, host, sdslen(host)); name = sdscatlen(name, ":", 1); name = sdscatlen(name, port, sdslen(port)); slotsmgrt_sockfd *pfd = dictFetchValue(server.slotsmgrt_cached_sockfds, name); if (pfd == NULL) { redisLog(REDIS_WARNING, "slotsmgrt: close target %s:%s again", host, port); sdsfree(name); return; } else { redisLog(REDIS_WARNING, "slotsmgrt: close target %s:%s", host, port); } dictDelete(server.slotsmgrt_cached_sockfds, name); close(pfd->fd); zfree(pfd); sdsfree(name); }
void _masterProcessCacheOld(ccache *c){ sds old_key; while((old_key=cacheGetMessage(c,CACHE_REQUEST_OLD)) != NULL) { master_numjob++; objSds *value = dictFetchValue(master_cache,old_key); if(value) { objSdsSubRef(value); OBJ_REPORT_REF(value); /* No ae thread use this entry anymore */ if(value->ref == 1) { printf("mem freed\n"); master_total_mem -= sdslen(value->ptr); /* TODO: send free mem task to background job threads */ dictDelete(master_cache,old_key); } } sdsfree(old_key); } }
redisKeyInfo *lookupRedisKeyInfo( const char *cmd ) { static dict *commands; /* Command table. sds string -> command struct pointer. */ dictType commandTableDictType = { dictSdsCaseHash, /* hash function */ NULL, /* key dup */ NULL, /* val dup */ dictSdsKeyCaseCompare, /* key compare */ dictSdsDestructor, /* key destructor */ NULL /* val destructor */ }; if( commands == NULL ) { commands = dictCreate(&commandTableDictType,NULL); loadCommandTable(commands); } return dictFetchValue(commands, cmd); }
static void database_worker_save(uv_work_t * req) { save_t * saving = (save_t *) req->data; json_t * obj = saving->data; json_t * result; short short_insert = 0; LOCK if (!(result = dictFetchValue(db, saving->channel))) { result = json_array(); short_insert = 1; } json_array_append(result, obj); if (json_array_size(result) > config->web_history) { json_array_remove(result, 0); } if (short_insert) { dictAdd(db, saving->channel, result); } RELEASE }