void pushGenericCommand(redisClient *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); if (pushed) { char *event = (where == REDIS_HEAD) ? "lpush" : "rpush"; signalModifiedKey(c->db,c->argv[1]); notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id); } server.dirty += pushed; }
// XX 对应的getset实现吗? void setCommand(redisClient *c) { int j; robj *expire = NULL; int unit = UNIT_SECONDS; int flags = REDIS_SET_NO_FLAGS; for (j = 3; j < c->argc; j++) { char *a = c->argv[j]->ptr; robj *next = (j == c->argc-1) ? NULL : c->argv[j+1]; if ((a[0] == 'n' || a[0] == 'N') && (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') { flags |= REDIS_SET_NX; } else if ((a[0] == 'x' || a[0] == 'X') && (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') { flags |= REDIS_SET_XX; } else if ((a[0] == 'e' || a[0] == 'E') && (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) { unit = UNIT_SECONDS; expire = next; j++; } else if ((a[0] == 'p' || a[0] == 'P') && (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) { unit = UNIT_MILLISECONDS; expire = next; j++; } else { addReply(c,shared.syntaxerr); return; } } c->argv[2] = tryObjectEncoding(c->argv[2]); setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL); }
void pushGenericCommand(redisClient *c, int where) { robj *lobj = lookupKeyWrite(c->db,c->argv[1]); c->argv[2] = tryObjectEncoding(c->argv[2]); if (lobj == NULL) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) { addReply(c,shared.cone); return; } lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } else { if (lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) { touchWatchedKey(c->db,c->argv[1]); addReply(c,shared.cone); return; } } listTypePush(lobj,c->argv[2],where); addReplyLongLong(c,listTypeLength(lobj)); touchWatchedKey(c->db,c->argv[1]); server.dirty++; }
void pushGenericCommand(redisClient *c, int where) { int j, addlen = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); int may_have_waiting_clients = (lobj == NULL); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (may_have_waiting_clients) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) { addlen++; continue; } else { may_have_waiting_clients = 0; } } if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c,addlen + (lobj ? listTypeLength(lobj) : 0)); if (pushed) signalModifiedKey(c->db,c->argv[1]); server.dirty += pushed; }
void zremCommand(redisClient *c) { robj *zsetobj; zset *zs; dictEntry *de; double curscore; int deleted; if ((zsetobj = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,zsetobj,REDIS_ZSET)) return; zs = zsetobj->ptr; c->argv[2] = tryObjectEncoding(c->argv[2]); de = dictFind(zs->dict,c->argv[2]); if (de == NULL) { addReply(c,shared.czero); return; } /* Delete from the skiplist */ curscore = *(double*)dictGetEntryVal(de); deleted = zslDelete(zs->zsl,curscore,c->argv[2]); redisAssert(deleted != 0); /* Delete from the hash table */ dictDelete(zs->dict,c->argv[2]); if (htNeedsResize(zs->dict)) dictResize(zs->dict); if (dictSize(zs->dict) == 0) dbDelete(c->db,c->argv[1]); touchWatchedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.cone); }
void zrankGenericCommand(redisClient *c, int reverse) { robj *o; zset *zs; zskiplist *zsl; dictEntry *de; unsigned long rank; double *score; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL || checkType(c,o,REDIS_ZSET)) return; zs = o->ptr; zsl = zs->zsl; c->argv[2] = tryObjectEncoding(c->argv[2]); de = dictFind(zs->dict,c->argv[2]); if (!de) { addReply(c,shared.nullbulk); return; } score = dictGetEntryVal(de); rank = zslGetRank(zsl, *score, c->argv[2]); if (rank) { if (reverse) { addReplyLongLong(c, zsl->length - rank); } else { addReplyLongLong(c, rank-1); } } else { addReply(c,shared.nullbulk); } }
void getsetCommand(redisClient *c) { if (getGenericCommand(c) == REDIS_ERR) return; c->argv[2] = tryObjectEncoding(c->argv[2]); setKey(c->db,c->argv[1],c->argv[2]); notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",c->argv[1],c->db->id); server.dirty++; }
void msetGenericCommand(redisClient *c, int nx) { int j, busykeys = 0; if ((c->argc % 2) == 0) { addReplyError(c,"wrong number of arguments for MSET"); return; } /* Handle the NX flag. The MSETNX semantic is to return zero and don't * set nothing at all if at least one already key exists. */ if (nx) { for (j = 1; j < c->argc; j += 2) { if (lookupKeyWrite(c->db,c->argv[j]) != NULL) { busykeys++; } } } if (busykeys) { addReply(c, shared.czero); return; } for (j = 1; j < c->argc; j += 2) { c->argv[j+1] = tryObjectEncoding(c->argv[j+1]); dbReplace(c->db,c->argv[j],c->argv[j+1]); incrRefCount(c->argv[j+1]); removeExpire(c->db,c->argv[j]); touchWatchedKey(c->db,c->argv[j]); } server.dirty += (c->argc-1)/2; addReply(c, nx ? shared.cone : shared.ok); }
void msetGenericCommand(redisClient *c, int nx) { int j, busykeys = 0; if ((c->argc % 2) == 0) { addReplyError(c,"wrong number of arguments for MSET"); return; } /* Handle the NX flag. The MSETNX semantic is to return zero and don't * set nothing at all if at least one already key exists. */ if (nx) { for (j = 1; j < c->argc; j += 2) { if (lookupKeyWrite(c->db,c->argv[j]) != NULL) { busykeys++; } } if (busykeys) { addReply(c, shared.czero); return; } } for (j = 1; j < c->argc; j += 2) { c->argv[j+1] = tryObjectEncoding(c->argv[j+1]); setKey(c->db,c->argv[j],c->argv[j+1]); notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",c->argv[j],c->db->id); } server.dirty += (c->argc-1)/2; addReply(c, nx ? shared.cone : shared.ok); }
void pushGenericCommand(redisClient *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); int may_have_waiting_clients = (lobj == NULL); if (lobj && lobj->type != REDIS_LIST) {//检查类型是否是list类型 addReply(c,shared.wrongtypeerr); return; } if (may_have_waiting_clients) signalListAsReady(c,c->argv[1]); for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (!lobj) {//该键不存在 创建压缩列表 lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj);//该键添加到db中 } listTypePush(lobj,c->argv[j],where);//把value添加列表中 pushed++; } addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); if (pushed) { char *event = (where == REDIS_HEAD) ? "lpush" : "rpush"; signalModifiedKey(c->db,c->argv[1]); notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,c->argv[1],c->db->id);//使用键空间通知 } //改变最后一次保存的节点 server.dirty += pushed; }
void getsetCommand(redisClient *c) { uint16_t version = sdsversion(c->argv[1]->ptr); if (getGenericCommand(c) == REDIS_ERR) return; c->argv[2] = tryObjectEncoding(c->argv[2]); if (c->returncode == REDIS_OK_NOT_EXIST) { sdsversion_change(c->argv[1]->ptr, 0); } else { if(c->version_care && version != 0 && version != c->version) { c->returncode = REDIS_ERR_VERSION_ERROR; return; } else { sdsversion_change(c->argv[1]->ptr, c->version); } } if(c->version_care) { sdsversion_add(c->argv[1]->ptr, 1); } dbSuperReplace(c->db,c->argv[1],c->argv[2]); incrRefCount(c->argv[2]); c->db->dirty++; if (c->expiretime > 0) { setExpire(c->db,c->argv[1],c->expiretime); } else if(c->expiretime == 0) { removeXExpire(c->db, c->argv[1]); } c->returncode = REDIS_OK; }
void saddCommand(redisClient *c) { robj *set; int j, added = 0; set = lookupKeyWrite(c->db,c->argv[1]); if (set == NULL) { set = setTypeCreate(c->argv[2]); dbAdd(c->db,c->argv[1],set); } else { if (set->type != REDIS_SET) { addReply(c,shared.wrongtypeerr); return; } } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (setTypeAdd(set,c->argv[j])) added++; } if (added) { signalModifiedKey(c->db,c->argv[1]); notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[1],c->db->id); } server.dirty += added; addReplyLongLong(c,added); }
void linsertCommand(redisClient *c) { c->argv[4] = tryObjectEncoding(c->argv[4]); if (strcasecmp(c->argv[2]->ptr,"after") == 0) { pushxGenericCommand(c,c->argv[3],c->argv[4],REDIS_TAIL); } else if (strcasecmp(c->argv[2]->ptr,"before") == 0) { pushxGenericCommand(c,c->argv[3],c->argv[4],REDIS_HEAD); } else { addReply(c,shared.syntaxerr); } }
void debugCommand(client *c) { if (!strcasecmp(c->argv[1]->ptr,"segfault")) { *((char*)-1) = 'x'; } else if (!strcasecmp(c->argv[1]->ptr,"oom")) { void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */ zfree(ptr); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"assert")) { if (c->argc >= 3) c->argv[2] = tryObjectEncoding(c->argv[2]); serverAssertWithInfo(c,c->argv[0],1 == 2); } else if (!strcasecmp(c->argv[1]->ptr,"flushall")) { flushServerData(); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) { flushServerData(); if (loadAppendOnlyFile(server.aof_filename) != C_OK) { addReply(c,shared.err); return; } serverLog(LL_WARNING,"Append Only File loaded by DEBUG LOADAOF"); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) { double dtime = strtod(c->argv[2]->ptr,NULL); long long utime = dtime*1000000; struct timespec tv; tv.tv_sec = utime / 1000000; tv.tv_nsec = (utime % 1000000) * 1000; nanosleep(&tv, NULL); addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) { sds errstr = sdsnewlen("-",1); errstr = sdscatsds(errstr,c->argv[2]->ptr); errstr = sdsmapchars(errstr,"\n\r"," ",2); /* no newlines in errors. */ errstr = sdscatlen(errstr,"\r\n",2); addReplySds(c,errstr); } else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) { sds sizes = sdsempty(); sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32); sizes = sdscatprintf(sizes,"job:%d ", (int)sizeof(job)); sizes = sdscatprintf(sizes,"queue:%d ", (int)sizeof(queue)); sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj)); sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry)); sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5)); sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8)); sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16)); sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32)); sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64)); addReplyBulkSds(c,sizes); } else { addReplyErrorFormat(c, "Unknown DEBUG subcommand or wrong number of arguments for '%s'", (char*)c->argv[1]->ptr); } }
void pushnGenericCommand(redisClient *c, int where) { /* return_value must be null,otherwise it have memory leak */ c->returncode = REDIS_ERR; robj *lobj = lookupKeyWriteWithVersion(c->db, c->argv[1], &c->version); robj* key = c->argv[1]; if(lobj != NULL) { if(checkType(c, lobj, REDIS_LIST)) { c->returncode = REDIS_ERR_WRONG_TYPE_ERROR; return; } uint16_t version = sdsversion(key->ptr); if(c->version_care && version != 0 && version != c->version) { c->returncode = REDIS_ERR_VERSION_ERROR; return; } else { sdsversion_change(key->ptr, c->version); } } else { sdsversion_change(key->ptr, 0); } if(c->version_care) { sdsversion_add(key->ptr, 1); } c->return_value = (void*)zmalloc(sizeof(push_return_value)); if(c->return_value == NULL) { c->returncode = REDIS_ERR_MEMORY_ALLOCATE_ERROR; return; } int i = 2; for(; i < c->argc; i++) { if(lobj == NULL) { c->argv[i] = tryObjectEncoding(c->argv[i]); lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } unsigned long list_len = listTypeLength(lobj); if (list_len >= (unsigned long)(c->server->list_max_size)) { break; } listTypePush(c,lobj,c->argv[i],where); c->server->dirty++; } if (i != 2) { dbUpdateKey(c->db, key); EXPIRE_OR_NOT }
void sismemberCommand(redisClient *c) { robj *set; if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,set,REDIS_SET)) return; c->argv[2] = tryObjectEncoding(c->argv[2]); if (setTypeIsMember(set,c->argv[2])) addReply(c,shared.cone); else addReply(c,shared.czero); }
void smoveCommand(redisClient *c) { robj *srcset, *dstset, *ele; srcset = lookupKeyWrite(c->db,c->argv[1]); dstset = lookupKeyWrite(c->db,c->argv[2]); ele = c->argv[3] = tryObjectEncoding(c->argv[3]); /* If the source key does not exist return 0 */ if (srcset == NULL) { addReply(c,shared.czero); return; } /* If the source key has the wrong type, or the destination key * is set and has the wrong type, return with an error. */ if (checkType(c,srcset,REDIS_SET) || (dstset && checkType(c,dstset,REDIS_SET))) return; /* If srcset and dstset are equal, SMOVE is a no-op */ if (srcset == dstset) { addReply(c,shared.cone); return; } /* If the element cannot be removed from the src set, return 0. */ if (!setTypeRemove(srcset,ele)) { addReply(c,shared.czero); return; } notifyKeyspaceEvent(REDIS_NOTIFY_SET,"srem",c->argv[1],c->db->id); /* Remove the src set from the database when empty */ if (setTypeSize(srcset) == 0) { dbDelete(c->db,c->argv[1]); notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[2]); server.dirty++; /* Create the destination set when it doesn't exist */ if (!dstset) { dstset = setTypeCreate(ele); dbAdd(c->db,c->argv[2],dstset); } /* An extra key has changed when ele was successfully added to dstset */ if (setTypeAdd(dstset,ele)) { server.dirty++; notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[2],c->db->id); } addReply(c,shared.cone); }
void hashTypeConvertZiplist(robj *o, int enc) { logicErrorExpr(o->encoding == REDIS_ENCODING_ZIPLIST, "Invalid type"); if (enc == REDIS_ENCODING_ZIPLIST) { /* Nothing to do... */ } else if (enc == REDIS_ENCODING_HT) { hashTypeIterator *hi; dict *dict; int ret; hi = hashTypeInitIterator(o); dict = dictCreate(&hashDictType, NULL); while (hashTypeNext(hi) != REDIS_ERR) { robj *field, *value; field = hashTypeCurrentObject(hi, REDIS_HASH_KEY); field = tryObjectEncoding(field); value = hashTypeCurrentObject(hi, REDIS_HASH_VALUE); value = tryObjectEncoding(value); ret = dictAdd(dict, field, value); if (ret != DICT_OK) { // redisLogHexDump(REDIS_WARNING,"ziplist with dup elements dump", // o->ptr,ziplistBlobLen(o->ptr)); logicErrorExpr(ret == DICT_OK, "Never happend"); } } hashTypeReleaseIterator(hi); zfree(o->ptr); o->encoding = REDIS_ENCODING_HT; o->ptr = dict; } else { logicError("Unknown hash encoding"); } }
// LINSERT key BEFORE|AFTER pivot(基准值) value // LINSERT命令的实现 void linsertCommand(client *c) { //对基准值进行优化编码 c->argv[4] = tryObjectEncoding(c->argv[4]); //比较where字符串,忽略大小写 if (strcasecmp(c->argv[2]->ptr,"after") == 0) { //如果是after,则是在基准值的后插入 pushxGenericCommand(c,c->argv[3],c->argv[4],LIST_TAIL); } else if (strcasecmp(c->argv[2]->ptr,"before") == 0) { //如果是before,则是在基准值的前插入 pushxGenericCommand(c,c->argv[3],c->argv[4],LIST_HEAD); } else { addReply(c,shared.syntaxerr); //否则发送语法错误信息 } }
void sremCommand(redisClient *c) { robj *set; if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,set,REDIS_SET)) return; c->argv[2] = tryObjectEncoding(c->argv[2]); if (setTypeRemove(set,c->argv[2])) { if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]); touchWatchedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.cone); } else { addReply(c,shared.czero); } }
void lremCommand(redisClient *c) { robj *subject, *obj; obj = c->argv[3] = tryObjectEncoding(c->argv[3]); long toremove; long removed = 0; listTypeEntry entry; int slotnum = keyHashSlot(c->argv[1]->ptr, sdslen(c->argv[1]->ptr)); if ((getLongFromObjectOrReply(c, c->argv[2], &toremove, NULL) != REDIS_OK)) return; subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero,slotnum); if (subject == NULL || checkType(c,subject,REDIS_LIST)) return; /* Make sure obj is raw when we're dealing with a ziplist */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) obj = getDecodedObject(obj); listTypeIterator *li; if (toremove < 0) { toremove = -toremove; li = listTypeInitIterator(subject,-1,REDIS_HEAD); } else { li = listTypeInitIterator(subject,0,REDIS_TAIL); } while (listTypeNext(li,&entry)) { if (listTypeEqual(&entry,obj)) { listTypeDelete(&entry); server.dirty++; removed++; if (toremove && removed == toremove) break; } } listTypeReleaseIterator(li); /* Clean up raw encoded object */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) decrRefCount(obj); if (listTypeLength(subject) == 0) dbDelete(c->db,c->argv[1],slotnum); addReplyLongLong(c,removed); if (removed) signalModifiedKey(c->db,c->argv[1],slotnum); }
void pushGenericCommand(redisClient *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); int may_have_waiting_clients = (lobj == NULL); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (may_have_waiting_clients) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) { waiting++; continue; } else { may_have_waiting_clients = 0; } } if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); if (pushed) signalModifiedKey(c->db,c->argv[1]); server.dirty += pushed; /* Alter the replication of the command accordingly to the number of * list elements delivered to clients waiting into a blocking operation. * We do that only if there were waiting clients, and only if still some * element was pushed into the list (othewise dirty is 0 and nothign will * be propagated). */ if (waiting && pushed) { /* CMD KEY a b C D E */ for (j = 0; j < waiting; j++) decrRefCount(c->argv[j+2]); memmove(c->argv+2,c->argv+2+waiting,sizeof(robj*)*pushed); c->argc -= waiting; } }
void getsetCommand(redisClient *c) { if (getGenericCommand(c) == REDIS_ERR) return; #ifdef AUTH_FEATURE /* Check mod permissions */ if (authCheckModOrReply(c) == REDIS_ERR) return; /* Check path permissions */ if (authCheckPathOrReply(c, c->argv[2]) == REDIS_ERR) return; #endif c->argv[2] = tryObjectEncoding(c->argv[2]); dbReplace(c->db,c->argv[1],c->argv[2]); incrRefCount(c->argv[2]); touchWatchedKey(c->db,c->argv[1]); server.dirty++; removeExpire(c->db,c->argv[1]); }
void zscoreCommand(redisClient *c) { robj *o; zset *zs; dictEntry *de; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL || checkType(c,o,REDIS_ZSET)) return; zs = o->ptr; c->argv[2] = tryObjectEncoding(c->argv[2]); de = dictFind(zs->dict,c->argv[2]); if (!de) { addReply(c,shared.nullbulk); } else { double *score = dictGetEntryVal(de); addReplyDouble(c,*score); } }
void lsetCommand(redisClient *c) { int slotnum = keyHashSlot(c->argv[1]->ptr, sdslen(c->argv[1]->ptr)); robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr,slotnum); if (o == NULL || checkType(c,o,REDIS_LIST)) return; long index; robj *value = (c->argv[3] = tryObjectEncoding(c->argv[3])); if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != REDIS_OK)) return; listTypeTryConversion(o,value); if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *p, *zl = o->ptr; p = ziplistIndex(zl,index); if (p == NULL) { addReply(c,shared.outofrangeerr); } else { o->ptr = ziplistDelete(o->ptr,&p); value = getDecodedObject(value); o->ptr = ziplistInsert(o->ptr,p,value->ptr,sdslen(value->ptr)); decrRefCount(value); addReply(c,shared.ok); signalModifiedKey(c->db,c->argv[1],slotnum); notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"lset",c->argv[1],c->db->id); server.dirty++; } } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) { listNode *ln = listIndex(o->ptr,index); if (ln == NULL) { addReply(c,shared.outofrangeerr); } else { decrRefCount((robj*)listNodeValue(ln)); listNodeValue(ln) = value; incrRefCount(value); addReply(c,shared.ok); signalModifiedKey(c->db,c->argv[1],slotnum); notifyKeyspaceEvent(REDIS_NOTIFY_LIST,"lset",c->argv[1],c->db->id); server.dirty++; } } else { redisPanic("Unknown list encoding"); } }
//PUSH命令的底层实现,where保存push的位置 void pushGenericCommand(client *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); //以写操作读取key对象的value //如果value对象不是列表类型则发送错误信息,返回 if (lobj && lobj->type != OBJ_LIST) { addReply(c,shared.wrongtypeerr); return; } //从第一个value开始遍历 for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); //将value对象优化编码 //如果没有找到key对象 if (!lobj) { //创建一个quicklist类型的对象 lobj = createQuicklistObject(); //设置ziplist最大的长度和压缩程度,配置文件指定 quicklistSetOptions(lobj->ptr, server.list_max_ziplist_size, server.list_compress_depth); //将新的key对象和优化编码过的value对象进行组成键值对 dbAdd(c->db,c->argv[1],lobj); } //在where推入一个value对象 listTypePush(lobj,c->argv[j],where); pushed++; //更新计数器 } //发送当前列表中元素的个数 addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); //如果推入元素成功 if (pushed) { char *event = (where == LIST_HEAD) ? "lpush" : "rpush"; //当数据库的键被改动,则会调用该函数发送信号 signalModifiedKey(c->db,c->argv[1]); //发送"lpush"或"rpush"事件通知 notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id); } server.dirty += pushed; //更新脏键 }
void appendCommand(redisClient *c) { int retval; size_t totlen; robj *o; o = lookupKeyWrite(c->db,c->argv[1]); c->argv[2] = tryObjectEncoding(c->argv[2]); if (o == NULL) { /* Create the key */ retval = dbAdd(c->db,c->argv[1],c->argv[2]); incrRefCount(c->argv[2]); totlen = stringObjectLen(c->argv[2]); } else { if (o->type != REDIS_STRING) { addReply(c,shared.wrongtypeerr); return; } /* If the object is specially encoded or shared we have to make * a copy */ if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) { robj *decoded = getDecodedObject(o); o = createStringObject(decoded->ptr, sdslen(decoded->ptr)); decrRefCount(decoded); dbReplace(c->db,c->argv[1],o); } /* APPEND! */ if (c->argv[2]->encoding == REDIS_ENCODING_RAW) { o->ptr = sdscatlen(o->ptr, c->argv[2]->ptr, sdslen(c->argv[2]->ptr)); } else { o->ptr = sdscatprintf(o->ptr, "%ld", (unsigned long) c->argv[2]->ptr); } totlen = sdslen(o->ptr); } touchWatchedKey(c->db,c->argv[1]); server.dirty++; addReplyLongLong(c,totlen); }
/* zset access is mostly a copy/paste from zscoreCommand() */ double zsetScore(robj *zobj, robj *member, double *score) { if (!zobj || !member) return false; if (zobj->encoding == REDIS_ENCODING_ZIPLIST) { if (zzlFind(zobj->ptr, member, score) == NULL) return false; } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) { zset *zs = zobj->ptr; dictEntry *de; member = tryObjectEncoding(member); de = dictFind(zs->dict, member); if (de != NULL) { *score = *(double *)dictGetVal(de); } else return false; } else { return false; } return true; }
void pushGenericCommand(redisClient *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); if (pushed) { signalModifiedKey(c->db,c->argv[1]); } }
void saddCommand(redisClient *c) { robj *set; set = lookupKeyWrite(c->db,c->argv[1]); c->argv[2] = tryObjectEncoding(c->argv[2]); if (set == NULL) { set = setTypeCreate(c->argv[2]); dbAdd(c->db,c->argv[1],set); } else { if (set->type != REDIS_SET) { addReply(c,shared.wrongtypeerr); return; } } if (setTypeAdd(set,c->argv[2])) { touchWatchedKey(c->db,c->argv[1]); server.dirty++; addReply(c,shared.cone); } else { addReply(c,shared.czero); } }