/* Add an element, discard the old if the key already exists. * Return 0 on insert and 1 on update. * This function will take care of incrementing the reference count of the * retained fields and value objects. */ int hashTypeSet(robj *o, robj *field, robj *value) { int update = 0; if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *zl, *fptr, *vptr; field = getDecodedObject(field); value = getDecodedObject(value); zl = o->ptr; fptr = ziplistIndex(zl, ZIPLIST_HEAD); if (fptr != NULL) { fptr = ziplistFind(fptr, field->ptr, sdslen(field->ptr), 1); if (fptr != NULL) { /* Grab pointer to the value (fptr points to the field) */ vptr = ziplistNext(zl, fptr); logicErrorExpr(vptr != NULL, "Never happend"); update = 1; /* Delete value */ zl = ziplistDelete(zl, &vptr); /* Insert new value */ zl = ziplistInsert(zl, vptr, value->ptr, sdslen(value->ptr)); } } if (!update) { /* Push new field/value pair onto the tail of the ziplist */ zl = ziplistPush(zl, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL); zl = ziplistPush(zl, value->ptr, sdslen(value->ptr), ZIPLIST_TAIL); } o->ptr = zl; decrRefCount(field); decrRefCount(value); /* Check if the ziplist needs to be converted to a hash table */ if (hashTypeLength(o) > server.hash_max_ziplist_entries) hashTypeConvert(o, REDIS_ENCODING_HT); } else if (o->encoding == REDIS_ENCODING_HT) { if (dictReplace(o->ptr, field, value)) { /* Insert */ incrRefCount(field); } else { /* Update */ update = 1; } incrRefCount(value); } else { logicError("Unknown hash encoding"); } return update; }
/* Get the value from a ziplist encoded hash, identified by field. * Returns -1 when the field cannot be found. */ int hashTypeGetFromZiplist(robj *o, robj *field, unsigned char **vstr, unsigned int *vlen, long long *vll) { unsigned char *zl, *fptr = NULL, *vptr = NULL; int ret; logicErrorExpr(o->encoding == REDIS_ENCODING_ZIPLIST, "Never happend"); field = getDecodedObject(field); zl = o->ptr; fptr = ziplistIndex(zl, ZIPLIST_HEAD); if (fptr != NULL) { fptr = ziplistFind(fptr, field->ptr, sdslen(field->ptr), 1); if (fptr != NULL) { /* Grab pointer to the value (fptr points to the field) */ vptr = ziplistNext(zl, fptr); logicErrorExpr(vptr != NULL, "Never happend"); } } decrRefCount(field); if (vptr != NULL) { ret = ziplistGet(vptr, vstr, vlen, vll); logicErrorExpr(ret, "Never happend"); return 0; } return -1; }
/* 模式订阅,即设置客户端订阅某模式。如果订阅成功则返回1,如果客户端已经订阅了该模式则返回0。*/ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; // 先在客户端的c->pubsub_patterns链表中查找,判断客户端是否已经订阅了该模式 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { // 客户端并没有订阅该模式 retval = 1; pubsubPattern *pat; // 将制定模式添加到c->pubsub_patterns链表中 listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; // 将pubsubPattern结构添加到server.pubsub_patterns链表中 listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ // 回复客户端 addReply(c,shared.mbulkhdr[3]); // 回复“psubscribe”字符串 addReply(c,shared.psubscribebulk); // 回复被订阅的模式字符串 addReplyBulk(c,pattern); // 回复客户端订阅的频道和模式总数目 addReplyLongLong(c,clientSubscriptionsCount(c)); return retval; }
/* 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; }
void listTypeInsert(listTypeEntry *entry, robj *value, int where) { robj *subject = entry->li->subject; if (entry->li->encoding == REDIS_ENCODING_ZIPLIST) { value = getDecodedObject(value); if (where == REDIS_TAIL) { unsigned char *next = ziplistNext(subject->ptr,entry->zi); /* When we insert after the current element, but the current element * is the tail of the list, we need to do a push. */ if (next == NULL) { subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),REDIS_TAIL); } else { subject->ptr = ziplistInsert(subject->ptr,next,value->ptr,sdslen(value->ptr)); } } else { subject->ptr = ziplistInsert(subject->ptr,entry->zi,value->ptr,sdslen(value->ptr)); } decrRefCount(value); } else if (entry->li->encoding == REDIS_ENCODING_LINKEDLIST) { if (where == REDIS_TAIL) { listInsertNode(subject->ptr,entry->ln,value,AL_START_TAIL); } else { listInsertNode(subject->ptr,entry->ln,value,AL_START_HEAD); } incrRefCount(value); } else { redisPanic("Unknown list encoding"); } }
/* 发布一则消息,即将消息发送给所有订阅了指定频道channel的所有客户端以及所有订阅了和指定频道匹配的模式的客户端。*/ int pubsubPublishMessage(robj *channel, robj *message) { int receivers = 0; dictEntry *de; listNode *ln; listIter li; /* Send to clients listening for that channel */ // 取出订阅指定频道的客户端链表 de = dictFind(server.pubsub_channels,channel); if (de) { list *list = dictGetVal(de); listNode *ln; listIter li; listRewind(list,&li); // 遍历该客户端链表,并将消息逐一发送给这些客户端 while ((ln = listNext(&li)) != NULL) { redisClient *c = ln->value; // 发送消息 addReply(c,shared.mbulkhdr[3]); // 回复“message”字符串 addReply(c,shared.messagebulk); // 回复消息的来源频道 addReplyBulk(c,channel); // 回复消息内容 addReplyBulk(c,message); // 统计接收客户端的数量 receivers++; } } /* Send to clients listening to matching channels */ // 将消息发送个订阅了和指定频道匹配的模式的客户端 if (listLength(server.pubsub_patterns)) { listRewind(server.pubsub_patterns,&li); channel = getDecodedObject(channel); // 遍历server.pubsub_patterns while ((ln = listNext(&li)) != NULL) { // 取出当前模式 pubsubPattern *pat = ln->value; // 判断当前模式是否和给定频道相匹配 if (stringmatchlen((char*)pat->pattern->ptr, sdslen(pat->pattern->ptr), (char*)channel->ptr, sdslen(channel->ptr),0)) { // 发送消息 addReply(pat->client,shared.mbulkhdr[4]); addReply(pat->client,shared.pmessagebulk); addReplyBulk(pat->client,pat->pattern); addReplyBulk(pat->client,channel); addReplyBulk(pat->client,message); receivers++; } } decrRefCount(channel); } return receivers; }
int dictEncObjKeyCompare(void *privdata, const void *key1, const void *key2) { robj *o1 = (robj*) key1, *o2 = (robj*) key2; int cmp; if (o1->encoding == OBJ_ENCODING_INT && o2->encoding == OBJ_ENCODING_INT) return o1->ptr == o2->ptr; o1 = getDecodedObject(o1); o2 = getDecodedObject(o2); cmp = dictSdsKeyCompare(privdata,o1->ptr,o2->ptr); decrRefCount(o1); decrRefCount(o2); return cmp; }
void strlenCommand(redisClient *c) { robj *o; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,o,REDIS_STRING)) return; o = getDecodedObject(o); addReplyLongLong(c,sdslen(o->ptr)); decrRefCount(o); }
/* Prepare the string object stored at 'key' to be modified destructively * to implement commands like SETBIT or APPEND. * * An object is usually ready to be modified unless one of the two conditions * are true: * * 1) The object 'o' is shared (refcount > 1), we don't want to affect * other users. * 2) The object encoding is not "RAW". * * If the object is found in one of the above conditions (or both) by the * function, an unshared / not-encoded copy of the string object is stored * at 'key' in the specified 'db'. Otherwise the object 'o' itself is * returned. * * USAGE: * * The object 'o' is what the caller already obtained by looking up 'key' * in 'db', the usage pattern looks like this: * * o = lookupKeyWrite(db,key); * if (checkType(c,o,OBJ_STRING)) return; * o = dbUnshareStringValue(db,key,o); * * At this point the caller is ready to modify the object, for example * using an sdscat() call to append some data, or anything else. */ robj *dbUnshareStringValue(redisDb *db, robj *key, robj *o) { serverAssert(o->type == OBJ_STRING); if (o->refcount != 1 || o->encoding != OBJ_ENCODING_RAW) { robj *decoded = getDecodedObject(o); o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr)); decrRefCount(decoded); dbOverwrite(db,key,o); } return o; }
/* 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"); } }
sds catAppendOnlyGenericCommand(sds buf, int argc, robj **argv) { int j; buf = sdscatprintf(buf,"*%d\r\n",argc); for (j = 0; j < argc; j++) { robj *o = getDecodedObject(argv[j]); buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr)); buf = sdscatlen(buf,o->ptr,sdslen(o->ptr)); buf = sdscatlen(buf,"\r\n",2); decrRefCount(o); } return buf; }
void addReply(redisClient *c, robj *obj) { if (listLength(c->reply) == 0 && (c->replstate == REDIS_REPL_NONE || c->replstate == REDIS_REPL_ONLINE) && aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, sendReplyToClient, c) == AE_ERR) return; if (server.vm_enabled && obj->storage != REDIS_VM_MEMORY) { obj = dupStringObject(obj); obj->refcount = 0; /* getDecodedObject() will increment the refcount */ } listAddNodeTail(c->reply,getDecodedObject(obj)); }
/* * 发布一个消息至指定频道 */ int pubsubPublishMessage(robj *channel, robj *message) { int receivers = 0; dictEntry *de; listNode *ln; listIter li; /* Send to clients listening for that channel */ /* 发布给监听指定频道的客户端 */ de = dictFind(server.pubsub_channels,channel); if (de) { list *list = dictGetVal(de); listNode *ln; listIter li; listRewind(list,&li); while ((ln = listNext(&li)) != NULL) { redisClient *c = ln->value; addReply(c,shared.mbulkhdr[3]); addReply(c,shared.messagebulk); addReplyBulk(c,channel); addReplyBulk(c,message); receivers++; } } /* Send to clients listening to matching channels */ /* 发布给监听模式匹配的客户端 */ if (listLength(server.pubsub_patterns)) { listRewind(server.pubsub_patterns,&li); channel = getDecodedObject(channel); while ((ln = listNext(&li)) != NULL) { pubsubPattern *pat = ln->value; if (stringmatchlen((char*)pat->pattern->ptr, sdslen(pat->pattern->ptr), (char*)channel->ptr, sdslen(channel->ptr),0)) { addReply(pat->client,shared.mbulkhdr[4]); addReply(pat->client,shared.pmessagebulk); addReplyBulk(pat->client,pat->pattern); addReplyBulk(pat->client,channel); addReplyBulk(pat->client,message); receivers++; } } decrRefCount(channel); } return receivers; }
/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. * * 设置客户端 c 订阅模式 pattern 。 * * 订阅成功返回 1 ,如果客户端已经订阅了该模式,那么返回 0 。 */ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; // 在链表中查找模式,看客户端是否已经订阅了这个模式 // 这里为什么不像 channel 那样,用字典来进行检测呢? // 虽然 pattern 的数量一般来说并不多 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { // 如果没有的话,执行以下代码 retval = 1; pubsubPattern *pat; // 将 pattern 添加到 c->pubsub_patterns 链表中 listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); // 创建并设置新的 pubsubPattern 结构 pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; // 添加到末尾 listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ // 回复客户端。 // 示例: // redis 127.0.0.1:6379> PSUBSCRIBE xxx* // Reading messages... (press Ctrl-C to quit) // 1) "psubscribe" // 2) "xxx*" // 3) (integer) 1 addReply(c,shared.mbulkhdr[3]); // 回复 "psubscribe" 字符串 addReply(c,shared.psubscribebulk); // 回复被订阅的模式 addReplyBulk(c,pattern); // 回复客户端订阅的频道和模式的总数 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns)); return retval; }
void listTypeInsert(listTypeEntry *entry, robj *value, int where) { if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { value = getDecodedObject(value); sds str = value->ptr; size_t len = sdslen(str); if (where == LIST_TAIL) { quicklistInsertAfter((quicklist *)entry->entry.quicklist, &entry->entry, str, len); } else if (where == LIST_HEAD) { quicklistInsertBefore((quicklist *)entry->entry.quicklist, &entry->entry, str, len); } decrRefCount(value); } else { serverPanic("Unknown list encoding"); } }
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 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"); } }
sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) { int argc = 3; long when; robj *argv[3]; /* Make sure we can use strtol */ seconds = getDecodedObject(seconds); when = time(NULL)+strtol(seconds->ptr,NULL,10); decrRefCount(seconds); argv[0] = createStringObject("EXPIREAT",8); argv[1] = key; argv[2] = createObject(REDIS_STRING, sdscatprintf(sdsempty(),"%ld",when)); buf = catAppendOnlyGenericCommand(buf, argc, argv); decrRefCount(argv[0]); decrRefCount(argv[2]); return buf; }
/* Log information about the "current" client, that is, the client that is * currently being served by Disque. May be NULL if Disque is not serving a * client right now. */ void logCurrentClient(void) { if (server.current_client == NULL) return; client *cc = server.current_client; sds client; int j; serverLog(LL_WARNING, "--- CURRENT CLIENT INFO"); client = catClientInfoString(sdsempty(),cc); serverLog(LL_WARNING,"client: %s", client); sdsfree(client); for (j = 0; j < cc->argc; j++) { robj *decoded; decoded = getDecodedObject(cc->argv[j]); serverLog(LL_WARNING,"argv[%d]: '%s'", j, (char*)decoded->ptr); decrRefCount(decoded); } }
/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. */ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { retval = 1; pubsubPattern *pat; listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ addReply(c,shared.mbulkhdr[3]); addReply(c,shared.psubscribebulk); addReplyBulk(c,pattern); addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns)); return retval; }
//列表类型的插入操作,将value对象插到where void listTypeInsert(listTypeEntry *entry, robj *value, int where) { //对列表对象编码为quicklist类型操作 if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { value = getDecodedObject(value); //解码对象vlaue为字符串类型 sds str = value->ptr; //获得value对象所保存的值 size_t len = sdslen(str); //获得value值的长度 if (where == LIST_TAIL) { //给定的where为列表尾部 //尾插 quicklistInsertAfter((quicklist *)entry->entry.quicklist, &entry->entry, str, len); } else if (where == LIST_HEAD) { //给定的where为列表头部 //头插 quicklistInsertBefore((quicklist *)entry->entry.quicklist, &entry->entry, str, len); } decrRefCount(value); //引用计数减1,释放value对象 } else { serverPanic("Unknown list encoding"); } }
/* Functions managing dictionary of callbacks for pub/sub. */ static unsigned int callbackHash(const void *key) { robj *o = (robj *) key; if (o->encoding == UG_ENCODING_RAW) { return dictGenHashFunction(o->ptr, (int)sdslen((sds)o->ptr)); } else { if (o->encoding == UG_ENCODING_INT) { char buf[32]; int len; len = ll2string(buf, 32, (long)o->ptr); return dictGenHashFunction((unsigned char *)buf, len); } else { unsigned int hash; o = getDecodedObject(o); hash = dictGenHashFunction(o->ptr, (int)sdslen((sds)o->ptr)); decrRefCount(o); return hash; } } }
/* Write an object into a file in the bulk format $<count>\r\n<payload>\r\n */ static int fwriteBulkObject(FILE *fp, robj *obj) { char buf[128]; int decrrc = 0; /* Avoid the incr/decr ref count business if possible to help * copy-on-write (we are often in a child process when this function * is called). * Also makes sure that key objects don't get incrRefCount-ed when VM * is enabled */ if (obj->encoding != REDIS_ENCODING_RAW) { obj = getDecodedObject(obj); decrrc = 1; } snprintf(buf,sizeof(buf),"$%ld\r\n",(long)sdslen(obj->ptr)); fwrite(buf,strlen(buf),1,fp); fwrite(obj->ptr,sdslen(obj->ptr),1,fp); fwrite("\r\n",2,1,fp); if (decrrc) decrRefCount(obj); return 1; }
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); }
/* Get the value from a ziplist encoded hash, identified by field. * Returns -1 when the field cannot be found. */ int hashTypeGetFromZiplist(robj *o, robj *field, unsigned char **vstr, unsigned int *vlen, PORT_LONGLONG *vll) { unsigned char *zl, *fptr = NULL, *vptr = NULL; int ret; redisAssert(o->encoding == REDIS_ENCODING_ZIPLIST); field = getDecodedObject(field); zl = o->ptr; fptr = ziplistIndex(zl, ZIPLIST_HEAD); if (fptr != NULL) { fptr = ziplistFind(fptr, field->ptr, (unsigned int)sdslen(field->ptr), 1); WIN_PORT_FIX /* cast (unsigned int) */ if (fptr != NULL) { /* Grab pointer to the value (fptr points to the field) */ vptr = ziplistNext(zl, fptr); redisAssert(vptr != NULL); } }
// SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF sds DXDB_SQL_feedAppendOnlyFile(rcommand *cmd, robj **argv, int argc) { if (cmd->proc == insertCommand || cmd->proc == updateCommand || cmd->proc == deleteCommand || cmd->proc == replaceCommand || cmd->proc == createCommand || cmd->proc == dropCommand || cmd->proc == alterCommand) { if (cmd->proc == createCommand) { if ((!strcasecmp(argv[1]->ptr, "LRUINDEX")) || (!strcasecmp(argv[1]->ptr, "LUATRIGGER"))) return sdsempty(); int arg = 1, targ = 4, coln = 5; if (!strcasecmp(argv[1]->ptr, "UNIQUE")) { arg = 2; targ = 5; coln = 6; } if (!strcasecmp(argv[arg]->ptr, "INDEX")) { // index on TEXT int tmatch = find_table(argv[targ]->ptr); r_tbl_t *rt = &Tbl[tmatch]; char *token = argv[coln]->ptr; char *end = strchr(token, ')'); STACK_STRDUP(cname, (token + 1), (end - token - 1)) icol_t ic = find_column(tmatch, cname); uchar ctype = rt->col[ic.cmatch].type; if (C_IS_S(ctype)) { int imatch = find_index(tmatch, ic); r_ind_t *ri = &Index[imatch]; return createAlterTableFullText(rt, ri, ic.cmatch, 1); } } } sds buf = sdsempty(); for (int j = 0; j < argc; j++) { robj *o = getDecodedObject(argv[j]); buf = sdscatlen(buf, o->ptr, sdslen(o->ptr)); if (j != (argc - 1)) buf = sdscatlen(buf," ", 1); decrRefCount(o); } buf = sdscatlen(buf, ";\n", 2); return buf; } return sdsempty(); }
//列表类型的从where插入一个value,PUSH命令的底层实现 void listTypePush(robj *subject, robj *value, int where) { //对列表对象编码为quicklist类型操作 if (subject->encoding == OBJ_ENCODING_QUICKLIST) { //根据where保存quicklist的头节点地址或尾节点地址 int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL; //获得value编码为RAW的字符串对象 value = getDecodedObject(value); //保存value的长度 size_t len = sdslen(value->ptr); //PUSH value的值到quicklist的头或尾 quicklistPush(subject->ptr, value->ptr, len, pos); //value的引用计数减1 decrRefCount(value); } else { serverPanic("Unknown list encoding"); //不是quicklist类型的编码则发送错误信息 } }
void lremCommand(redisClient *c) { robj *subject, *obj = c->argv[3]; int toremove = atoi(c->argv[2]->ptr); int removed = 0; listTypeEntry entry; subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero); 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]); addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed)); if (removed) touchWatchedKey(c->db,c->argv[1]); }
void listTypePush(robj *subject, robj *value, int where) { /* Check if we need to convert the ziplist */ listTypeTryConversion(subject,value); if (subject->encoding == REDIS_ENCODING_ZIPLIST && ziplistLen(subject->ptr) >= server.list_max_ziplist_entries) listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST); if (subject->encoding == REDIS_ENCODING_ZIPLIST) { int pos = (where == REDIS_HEAD) ? ZIPLIST_HEAD : ZIPLIST_TAIL; value = getDecodedObject(value); subject->ptr = ziplistPush(subject->ptr,value->ptr,sdslen(value->ptr),pos); decrRefCount(value); } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) { if (where == REDIS_HEAD) { listAddNodeHead(subject->ptr,value); } else { listAddNodeTail(subject->ptr,value); } incrRefCount(value); } else { redisPanic("Unknown list encoding"); } }
void lsetCommand(redisClient *c) { robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr); if (o == NULL || checkType(c,o,REDIS_LIST)) return; int index = atoi(c->argv[2]->ptr); robj *value = (c->argv[3] = tryObjectEncoding(c->argv[3])); 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]); 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]); server.dirty++; } } else { redisPanic("Unknown list encoding"); } }