void decrRefCount(robj *o) { if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0"); if (o->refcount == 1) { switch(o->type) { case OBJ_STRING: freeStringObject(o); break; default: serverPanic("Unknown object type"); break; } zfree(o); } else { o->refcount--; } }
/* Convert the set to specified encoding. The resulting dict (when converting * to a hash table) is presized to hold the number of elements in the original * set. */ void setTypeConvert(robj *setobj, int enc) { setTypeIterator *si; serverAssertWithInfo(NULL,setobj,setobj->type == OBJ_SET && setobj->encoding == OBJ_ENCODING_INTSET); if (enc == OBJ_ENCODING_HT) { int64_t intele; dict *d = dictCreate(&setDictType,NULL); sds element; /* Presize the dict to avoid rehashing */ dictExpand(d,intsetLen(setobj->ptr)); /* To add the elements we extract integers and create redis objects */ si = setTypeInitIterator(setobj); while (setTypeNext(si,&element,&intele) != -1) { element = sdsfromlonglong(intele); serverAssert(dictAdd(d,element,NULL) == DICT_OK); } setTypeReleaseIterator(si); setobj->encoding = OBJ_ENCODING_HT; zfree(setobj->ptr); setobj->ptr = d; } else { serverPanic("Unsupported set conversion"); } }
// LSET key index value // LSET命令实现 void lsetCommand(client *c) { //以写操作取出key对象的value值 robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr); // 如果key没找到或value对象不是列表类型则直接返回 if (o == NULL || checkType(c,o,OBJ_LIST)) return; long index; robj *value = c->argv[3]; //将index参数转换为long类型的整数,保存在index中 if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return; //只对编码为quicklist类型的value对象操作 if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklist *ql = o->ptr; //将下标为index的entry替换成value对象的值 int replaced = quicklistReplaceAtIndex(ql, index, value->ptr, sdslen(value->ptr)); if (!replaced) { //如果替换失败,则发送下标越界错误信息 addReply(c,shared.outofrangeerr); } else { //替换成功,则发送ok addReply(c,shared.ok); //当数据库的键被改动,则会调用该函数发送信号 signalModifiedKey(c->db,c->argv[1]); //发送"lset"时间通知 notifyKeyspaceEvent(NOTIFY_LIST,"lset",c->argv[1],c->db->id); //更新脏键 server.dirty++; } } else { serverPanic("Unknown list encoding"); } }
// 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"); //发送未知的列表编码类型 } }
//从对象中将字符串值转换为long double并存储在target中 int getLongDoubleFromObject(robj *o, long double *target) { long double value; char *eptr; if (o == NULL) { //对象不存在 value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); //如果是字符串编码的两种类型 if (sdsEncodedObject(o)) { errno = 0; value = strtold(o->ptr, &eptr); //将字符串转换为long double类型 if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || errno == ERANGE || isnan(value)) //转换失败返回-1 return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { //整数编码 value = (long)o->ptr; //保存整数值 } else { serverPanic("Unknown string encoding"); } } *target = value; //将值存到传入参数中,返回0成功 return C_OK; }
void decrRefCount(robj *o) { if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0"); if (o->refcount == 1) { switch(o->type) { case OBJ_STRING: freeStringObject(o); break; case OBJ_LIST: freeListObject(o); break; case OBJ_SET: freeSetObject(o); break; case OBJ_ZSET: freeZsetObject(o); break; case OBJ_HASH: freeHashObject(o); break; default: serverPanic("Unknown object type"); break; } dfree(o); } else { o->refcount--; } }
//初始化列表类型的迭代器为一个指定的下标 listTypeIterator *listTypeInitIterator(robj *subject, long index, unsigned char direction) { listTypeIterator *li = zmalloc(sizeof(listTypeIterator)); //分配空间 //设置迭代器的各个成员的初始值 li->subject = subject; li->encoding = subject->encoding; li->direction = direction; li->iter = NULL; //quicklist迭代器为空 /* LIST_HEAD means start at TAIL and move *towards* head. * LIST_TAIL means start at HEAD and move *towards tail. */ //获得迭代方向 int iter_direction = direction == LIST_HEAD ? AL_START_TAIL : AL_START_HEAD; //对列表对象编码为quicklist类型操作 if (li->encoding == OBJ_ENCODING_QUICKLIST) { //将迭代器和下标为index的quicklistNode结合,迭代器指向该节点 li->iter = quicklistGetIteratorAtIdx(li->subject->ptr, iter_direction, index); } else { serverPanic("Unknown list encoding"); } return li; }
unsigned long listTypeLength(robj *subject) { if (subject->encoding == OBJ_ENCODING_QUICKLIST) { return quicklistCount(subject->ptr); } else { serverPanic("Unknown list encoding"); } }
void lsetCommand(client *c) { robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr); if (o == NULL || checkType(c,o,OBJ_LIST)) return; long index; robj *value = c->argv[3]; if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK)) return; if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklist *ql = o->ptr; int replaced = quicklistReplaceAtIndex(ql, index, value->ptr, sdslen(value->ptr)); if (!replaced) { addReply(c,shared.outofrangeerr); } else { addReply(c,shared.ok); signalModifiedKey(c->db,c->argv[1]); notifyKeyspaceEvent(NOTIFY_LIST,"lset",c->argv[1],c->db->id); server.dirty++; } } else { serverPanic("Unknown list encoding"); } }
/* 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) { key = dictGetKey(de); incrRefCount(key); } else if (o->type == OBJ_HASH) { key = dictGetKey(de); incrRefCount(key); val = dictGetVal(de); incrRefCount(val); } else if (o->type == OBJ_ZSET) { key = dictGetKey(de); incrRefCount(key); val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0); } else { serverPanic("Type not handled in SCAN callback."); } listAddNodeTail(keys, key); if (val) listAddNodeTail(keys, val); }
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"); } }
/* Delete the element pointed to. */ void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry) { if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { quicklistDelEntry(iter->iter, &entry->entry); } else { serverPanic("Unknown list encoding"); } }
void freeListObject(robj *o) { if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklistRelease(o->ptr); } else { serverPanic("Unknown list encoding type"); } }
int getDoubleFromObject(robj *o, double *target) { double value; char *eptr; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { errno = 0; value = strtod(o->ptr, &eptr); if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || (errno == ERANGE && (value == HUGE_VAL || value == -HUGE_VAL || value == 0)) || errno == EINVAL || isnan(value)) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } *target = value; return C_OK; }
/* Add the specified value into a set. * * If the value was already member of the set, nothing is done and 0 is * returned, otherwise the new element is added and 1 is returned. */ int setTypeAdd(robj *subject, sds value) { long long llval; if (subject->encoding == OBJ_ENCODING_HT) { dict *ht = subject->ptr; dictEntry *de = dictAddRaw(ht,value); if (de) { dictSetKey(ht,de,sdsdup(value)); dictSetVal(ht,de,NULL); return 1; } } else if (subject->encoding == OBJ_ENCODING_INTSET) { if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) { uint8_t success = 0; subject->ptr = intsetAdd(subject->ptr,llval,&success); if (success) { /* Convert to regular set when the intset contains * too many entries. */ if (intsetLen(subject->ptr) > server.set_max_intset_entries) setTypeConvert(subject,OBJ_ENCODING_HT); return 1; } } else { /* Failed to get integer from object, convert to regular set. */ setTypeConvert(subject,OBJ_ENCODING_HT); /* The set *was* an intset and this value is not integer * encodable, so dictAdd should always work. */ serverAssert(dictAdd(subject->ptr,sdsdup(value),NULL) == DICT_OK); return 1; } } else { serverPanic("Unknown set encoding"); } return 0; }
/* Populates the Redis Command Table starting from the hard coded list * we have on top of redis.c file. */ void populateCommandTable(void) { int j; int numcommands = sizeof(redisCommandTable)/sizeof(struct redisCommand); for (j = 0; j < numcommands; j++) { struct redisCommand *c = redisCommandTable+j; char *f = c->sflags; int retval1; while(*f != '\0') { switch(*f) { case 'w': c->flags |= CMD_WRITE; break; case 'r': c->flags |= CMD_READONLY; break; case 'm': c->flags |= CMD_DENYOOM; break; case 'a': c->flags |= CMD_ADMIN; break; case 'p': c->flags |= CMD_PUBSUB; break; case 's': c->flags |= CMD_NOSCRIPT; break; case 'R': c->flags |= CMD_RANDOM; break; case 'S': c->flags |= CMD_SORT_FOR_SCRIPT; break; case 'l': c->flags |= CMD_LOADING; break; case 't': c->flags |= CMD_STALE; break; case 'M': c->flags |= CMD_SKIP_MONITOR; break; case 'k': c->flags |= CMD_ASKING; break; case 'F': c->flags |= CMD_FAST; break; default: serverPanic("Unsupported command flag"); break; } f++; } retval1 = dictAdd(server.commands, sdsnew(c->name), c); ASSERT(retval1 == DICT_OK); } }
// LTRIM key start stop // LTRIM命令实现 void ltrimCommand(client *c) { robj *o; long start, end, llen, ltrim, rtrim; //将字符串类型起始地址start和结束地址end转换为long类型保存在start和end中 //如果任意失败,则直接返回 if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) || (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return; // 以读操作取出key大小的value值,如果value对象不是列表类型,直接返回 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == NULL || checkType(c,o,OBJ_LIST)) return; //获取列表元素数量 llen = listTypeLength(o); /* convert negative indexes */ // 将负数范围转换成合法范围 if (start < 0) start = llen+start; if (end < 0) end = llen+end; if (start < 0) start = 0; /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ //不合理的范围,移除所有的元素 if (start > end || start >= llen) { /* Out of range start or start > end result in empty list */ ltrim = llen; rtrim = 0; } else { if (end >= llen) end = llen-1; //end值不能超过元素个数 ltrim = start; //左边界 rtrim = llen-end-1; //右边界 } /* Remove list elements to perform the trim */ //只对编码为quicklist类型的value对象操作 if (o->encoding == OBJ_ENCODING_QUICKLIST) { quicklistDelRange(o->ptr,0,ltrim); //删除左边界以左的所有元素 quicklistDelRange(o->ptr,-rtrim,rtrim); //删除左边界以右的所有元素 } else { serverPanic("Unknown list encoding"); } //发送"ltrim"事件通知 notifyKeyspaceEvent(NOTIFY_LIST,"ltrim",c->argv[1],c->db->id); //如果将所有元素全部删除完了 if (listTypeLength(o) == 0) { //从数据库中删除该key dbDelete(c->db,c->argv[1]); //发送"del"时间通知 notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } //当数据库的键被改动,则会调用该函数发送信号 signalModifiedKey(c->db,c->argv[1]); //更新脏键 server.dirty++; //发送ok信息给client addReply(c,shared.ok); }
//返回对象的长度,entry节点个数 unsigned long listTypeLength(robj *subject) { //对列表对象编码为quicklist类型操作 if (subject->encoding == OBJ_ENCODING_QUICKLIST) { return quicklistCount(subject->ptr); //返回对象的entry节点个数 } else { serverPanic("Unknown list encoding"); } }
/* Compare the given object with the entry at the current position. */ int listTypeEqual(listTypeEntry *entry, robj *o) { if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { serverAssertWithInfo(NULL,o,sdsEncodedObject(o)); return quicklistCompare(entry->entry.zi,o->ptr,sdslen(o->ptr)); } else { serverPanic("Unknown list encoding"); } }
unsigned long setTypeSize(robj *subject) { if (subject->encoding == OBJ_ENCODING_HT) { return dictSize((dict*)subject->ptr); } else if (subject->encoding == OBJ_ENCODING_INTSET) { return intsetLen((intset*)subject->ptr); } else { serverPanic("Unknown set encoding"); } }
void freeListObject(robj *o) { switch (o->encoding) { case OBJ_ENCODING_QUICKLIST: quicklistRelease(o->ptr); break; default: serverPanic("Unknown list encoding type"); } }
//删除迭代器指向的entry void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry) { //对列表对象编码为quicklist类型操作 if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { //删除entry节点,更新迭代器 quicklistDelEntry(iter->iter, &entry->entry); } else { serverPanic("Unknown list encoding"); } }
//引用计数减1 void decrRefCount(robj *o) { if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0"); //当引用对象等于1时,在操作引用计数减1,直接释放对象的ptr和对象空间 if (o->refcount == 1) { switch(o->type) { case OBJ_STRING: freeStringObject(o); break; case OBJ_LIST: freeListObject(o); break; case OBJ_SET: freeSetObject(o); break; case OBJ_ZSET: freeZsetObject(o); break; case OBJ_HASH: freeHashObject(o); break; default: serverPanic("Unknown object type"); break; } zfree(o); } else { o->refcount--; //否则减1 } }
/* This function gets called when a blocked client timed out in order to * send it a reply of some kind. */ void replyToBlockedClientTimedOut(client *c) { if (c->btype == BLOCKED_LIST) { addReply(c,shared.nullmultibulk); } else if (c->btype == BLOCKED_WAIT) { addReplyLongLong(c,replicationCountAcksByOffset(c->bpop.reploffset)); } else { serverPanic("Unknown btype in replyToBlockedClientTimedOut()."); } }
/* The function pushes an element to the specified list object 'subject', * at head or tail position as specified by 'where'. * * There is no need for the caller to increment the refcount of 'value' as * the function takes care of it if needed. */ void listTypePush(robj *subject, robj *value, int where) { if (subject->encoding == OBJ_ENCODING_QUICKLIST) { int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL; value = getDecodedObject(value); size_t len = sdslen(value->ptr); quicklistPush(subject->ptr, value->ptr, len, pos); decrRefCount(value); } else { serverPanic("Unknown list encoding"); } }
void *bioProcessBackgroundJobs(void *arg) { struct bio_job *job; unsigned long type = (unsigned long) arg; sigset_t sigset; /* Make the thread killable at any time, so that bioKillThreads() * can work reliably. */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&bio_mutex[type]); /* Block SIGALRM so we are sure that only the main thread will * receive the watchdog signal. */ sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) serverLog(LL_WARNING, "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno)); while(1) { listNode *ln; /* The loop always starts with the lock hold. */ if (listLength(bio_jobs[type]) == 0) { pthread_cond_wait(&bio_newjob_cond[type],&bio_mutex[type]); continue; } /* Pop the job from the queue. */ ln = listFirst(bio_jobs[type]); job = ln->value; /* It is now possible to unlock the background system as we know have * a stand alone job structure to process.*/ pthread_mutex_unlock(&bio_mutex[type]); /* Process the job accordingly to its type. */ if (type == BIO_CLOSE_FILE) { close((long)job->arg1); } else if (type == BIO_AOF_FSYNC) { aof_fsync((long)job->arg1); } else { serverPanic("Wrong job type in bioProcessBackgroundJobs()."); } zfree(job); /* Unblock threads blocked on bioWaitStepOfType() if any. */ pthread_cond_broadcast(&bio_step_cond[type]); /* Lock again before reiterating the loop, if there are no longer * jobs to process we'll block again in pthread_cond_wait(). */ pthread_mutex_lock(&bio_mutex[type]); listDelNode(bio_jobs[type],ln); bio_pending[type]--; } }
/* Stores pointer to current the entry in the provided entry structure * and advances the position of the iterator. Returns 1 when the current * entry is in fact an entry, 0 otherwise. */ int listTypeNext(listTypeIterator *li, listTypeEntry *entry) { /* Protect from converting when iterating */ serverAssert(li->subject->encoding == li->encoding); entry->li = li; if (li->encoding == OBJ_ENCODING_QUICKLIST) { return quicklistNext(li->iter, &entry->entry); } else { serverPanic("Unknown list encoding"); } return 0; }
void freeSetObject(robj *o) { switch (o->encoding) { case OBJ_ENCODING_HT: dictRelease((dict*) o->ptr); break; case OBJ_ENCODING_INTSET: zfree(o->ptr); break; default: serverPanic("Unknown set encoding type"); } }
//比较列表类型的entry结构与对象的entry节点的值是否等,相等返回1 int listTypeEqual(listTypeEntry *entry, robj *o) { //对列表对象编码为quicklist类型操作 if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { //确保objptr的编码类型是简单动态字符串类型的RAW或EMBSTR serverAssertWithInfo(NULL,o,sdsEncodedObject(o)); //比较listTypeEntry结构中的entry值和给定的对象的值 return quicklistCompare(entry->entry.zi,o->ptr,sdslen(o->ptr)); } else { serverPanic("Unknown list encoding"); } }
void freeHashObject(robj *o) { switch (o->encoding) { case OBJ_ENCODING_HT: dictRelease((dict*) o->ptr); break; case OBJ_ENCODING_ZIPLIST: zfree(o->ptr); break; default: serverPanic("Unknown hash encoding type"); break; } }