diff --git a/src/cluster.c b/src/cluster.c index fb25405f..1a3a348b 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -4836,7 +4836,7 @@ void dumpCommand(client *c) { /* Check if the key is here. */ if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) { - addReply(c,shared.nullbulk); + addReplyNull(c); return; } diff --git a/src/db.c b/src/db.c index 49306311..74965f66 100644 --- a/src/db.c +++ b/src/db.c @@ -525,7 +525,7 @@ void randomkeyCommand(client *c) { robj *key; if ((key = dbRandomKey(c->db)) == NULL) { - addReply(c,shared.nullbulk); + addReplyNull(c); return; } diff --git a/src/multi.c b/src/multi.c index 84a7bb86..b84b75f7 100644 --- a/src/multi.c +++ b/src/multi.c @@ -134,7 +134,7 @@ void execCommand(client *c) { * in the second an EXECABORT error is returned. */ if (c->flags & (CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC)) { addReply(c, c->flags & CLIENT_DIRTY_EXEC ? shared.execaborterr : - shared.nullmultibulk); + shared.null[c->resp]); discardTransaction(c); goto handle_monitor; } diff --git a/src/networking.c b/src/networking.c index bb51619f..72f44f07 100644 --- a/src/networking.c +++ b/src/networking.c @@ -661,7 +661,7 @@ void addReplyBulkSds(client *c, sds s) { /* Add a C null term string as bulk reply */ void addReplyBulkCString(client *c, const char *s) { if (s == NULL) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { addReplyBulkCBuffer(c,s,strlen(s)); } @@ -1973,7 +1973,7 @@ NULL if (c->name) addReplyBulk(c,c->name); else - addReply(c,shared.nullbulk); + addReplyNull(c); } else if (!strcasecmp(c->argv[1]->ptr,"pause") && c->argc == 3) { long long duration; diff --git a/src/object.c b/src/object.c index 041af8b0..ec0bd02e 100644 --- a/src/object.c +++ b/src/object.c @@ -1248,15 +1248,15 @@ NULL }; addReplyHelp(c, help); } else if (!strcasecmp(c->argv[1]->ptr,"refcount") && c->argc == 3) { - if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk)) + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp])) == NULL) return; addReplyLongLong(c,o->refcount); } else if (!strcasecmp(c->argv[1]->ptr,"encoding") && c->argc == 3) { - if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk)) + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp])) == NULL) return; addReplyBulkCString(c,strEncoding(o->encoding)); } else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) { - if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk)) + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp])) == NULL) return; if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { addReplyError(c,"An LFU maxmemory policy is selected, idle time not tracked. Please note that when switching between policies at runtime LRU and LFU data will take some time to adjust."); @@ -1264,7 +1264,7 @@ NULL } addReplyLongLong(c,estimateObjectIdleTime(o)/1000); } else if (!strcasecmp(c->argv[1]->ptr,"freq") && c->argc == 3) { - if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk)) + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.null[c->resp])) == NULL) return; if (!(server.maxmemory_policy & MAXMEMORY_FLAG_LFU)) { addReplyError(c,"An LFU maxmemory policy is not selected, access frequency not tracked. Please note that when switching between policies at runtime LRU and LFU data will take some time to adjust."); @@ -1316,7 +1316,7 @@ NULL } } if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) { - addReply(c, shared.nullbulk); + addReplyNull(c); return; } size_t usage = objectComputeSize(dictGetVal(de),samples); diff --git a/src/pubsub.c b/src/pubsub.c index c407cadf..335c52d9 100644 --- a/src/pubsub.c +++ b/src/pubsub.c @@ -189,7 +189,7 @@ int pubsubUnsubscribeAllChannels(client *c, int notify) { if (notify && count == 0) { addReply(c,shared.mbulkhdr[3]); addReply(c,shared.unsubscribebulk); - addReply(c,shared.nullbulk); + addReplyNull(c); addReplyLongLong(c,dictSize(c->pubsub_channels)+ listLength(c->pubsub_patterns)); } @@ -214,7 +214,7 @@ int pubsubUnsubscribeAllPatterns(client *c, int notify) { /* We were subscribed to nothing? Still reply to the client. */ addReply(c,shared.mbulkhdr[3]); addReply(c,shared.punsubscribebulk); - addReply(c,shared.nullbulk); + addReplyNull(c); addReplyLongLong(c,dictSize(c->pubsub_channels)+ listLength(c->pubsub_patterns)); } diff --git a/src/scripting.c b/src/scripting.c index 9b8d5fd3..f6df3840 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -300,7 +300,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1)); break; case LUA_TBOOLEAN: - addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.nullbulk); + addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.null[c->resp]); break; case LUA_TNUMBER: addReplyLongLong(c,(long long)lua_tonumber(lua,-1)); @@ -352,7 +352,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { } break; default: - addReply(c,shared.nullbulk); + addReplyNull(c); } lua_pop(lua,1); } diff --git a/src/server.c b/src/server.c index 5b6a9c4a..a736a1e5 100644 --- a/src/server.c +++ b/src/server.c @@ -1468,6 +1468,12 @@ void createSharedObjects(void) { shared.colon = createObject(OBJ_STRING,sdsnew(":")); shared.plus = createObject(OBJ_STRING,sdsnew("+")); + /* The shared NULL depends on the protocol version. */ + shared.null[0] = NULL; + shared.null[1] = NULL; + shared.null[2] = createObject(OBJ_STRING,sdsnew("*-1\r\n")); + shared.null[3] = createObject(OBJ_STRING,sdsnew("_\r\n")); + for (j = 0; j < PROTO_SHARED_SELECT_CMDS; j++) { char dictid_str[64]; int dictid_len; diff --git a/src/server.h b/src/server.h index a483e1a6..2958c635 100644 --- a/src/server.h +++ b/src/server.h @@ -782,7 +782,7 @@ struct moduleLoadQueueEntry { struct sharedObjectsStruct { robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space, - *colon, *queued, + *colon, *queued, *null[4], *emptyarray, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr, *outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr, *masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr, diff --git a/src/sort.c b/src/sort.c index 322f0272..8608cd8b 100644 --- a/src/sort.c +++ b/src/sort.c @@ -519,7 +519,7 @@ void sortCommand(client *c) { if (sop->type == SORT_OP_GET) { if (!val) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { addReplyBulk(c,val); decrRefCount(val); diff --git a/src/t_hash.c b/src/t_hash.c index fe0e71fb..a50da579 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -641,7 +641,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) { int ret; if (o == NULL) { - addReply(c, shared.nullbulk); + addReplyNull(c); return; } @@ -652,7 +652,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) { ret = hashTypeGetFromZiplist(o, field, &vstr, &vlen, &vll); if (ret < 0) { - addReply(c, shared.nullbulk); + addReplyNull(c); } else { if (vstr) { addReplyBulkCBuffer(c, vstr, vlen); @@ -664,7 +664,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) { } else if (o->encoding == OBJ_ENCODING_HT) { sds value = hashTypeGetFromHashTable(o, field); if (value == NULL) - addReply(c, shared.nullbulk); + addReplyNull(c); else addReplyBulkCBuffer(c, value, sdslen(value)); } else { @@ -675,7 +675,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) { void hgetCommand(client *c) { robj *o; - if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL || + if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL || checkType(c,o,OBJ_HASH)) return; addHashFieldToReply(c, o, c->argv[2]->ptr); @@ -768,7 +768,7 @@ void genericHgetallCommand(client *c, int flags) { hashTypeIterator *hi; int length, count = 0; - if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL + if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL || checkType(c,o,OBJ_HASH)) return; /* We return a map if the user requested keys and values, like in the diff --git a/src/t_list.c b/src/t_list.c index 60c8e9ab..d6daad69 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -312,7 +312,7 @@ void llenCommand(client *c) { } void lindexCommand(client *c) { - robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk); + robj *o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp]); if (o == NULL || checkType(c,o,OBJ_LIST)) return; long index; robj *value = NULL; @@ -331,7 +331,7 @@ void lindexCommand(client *c) { addReplyBulk(c,value); decrRefCount(value); } else { - addReply(c,shared.nullbulk); + addReplyNull(c); } } else { serverPanic("Unknown list encoding"); @@ -365,12 +365,12 @@ void lsetCommand(client *c) { } void popGenericCommand(client *c, int where) { - robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk); + robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.null[c->resp]); if (o == NULL || checkType(c,o,OBJ_LIST)) return; robj *value = listTypePop(o,where); if (value == NULL) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { char *event = (where == LIST_HEAD) ? "lpop" : "rpop"; @@ -402,7 +402,7 @@ void lrangeCommand(client *c) { if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) || (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return; - if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL + if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL || checkType(c,o,OBJ_LIST)) return; llen = listTypeLength(o); @@ -414,7 +414,7 @@ void lrangeCommand(client *c) { /* 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) { - addReply(c,shared.emptymultibulk); + addReplyNull(c); return; } if (end >= llen) end = llen-1; @@ -564,13 +564,13 @@ void rpoplpushHandlePush(client *c, robj *dstkey, robj *dstobj, robj *value) { void rpoplpushCommand(client *c) { robj *sobj, *value; - if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL || - checkType(c,sobj,OBJ_LIST)) return; + if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.null[c->resp])) + == NULL || checkType(c,sobj,OBJ_LIST)) return; if (listTypeLength(sobj) == 0) { /* This may only happen after loading very old RDB files. Recent * versions of Redis delete keys of empty lists. */ - addReply(c,shared.nullbulk); + addReplyNull(c); } else { robj *dobj = lookupKeyWrite(c->db,c->argv[2]); robj *touchedkey = c->argv[1]; @@ -731,7 +731,7 @@ void blockingPopGenericCommand(client *c, int where) { /* If we are inside a MULTI/EXEC and the list is empty the only thing * we can do is treating it as a timeout (even with timeout 0). */ if (c->flags & CLIENT_MULTI) { - addReply(c,shared.nullmultibulk); + addReplyNull(c); return; } @@ -759,7 +759,7 @@ void brpoplpushCommand(client *c) { if (c->flags & CLIENT_MULTI) { /* Blocking against an empty list in a multi state * returns immediately. */ - addReply(c, shared.nullbulk); + addReplyNull(c); } else { /* The list is empty and the client blocks. */ blockForKeys(c,BLOCKED_LIST,c->argv + 1,1,timeout,c->argv[2],NULL); diff --git a/src/t_set.c b/src/t_set.c index e78957d9..61013dbc 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -415,13 +415,13 @@ void spopWithCountCommand(client *c) { /* Make sure a key with the name inputted exists, and that it's type is * indeed a set. Otherwise, return nil */ - if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) + if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL || checkType(c,set,OBJ_SET)) return; /* If count is zero, serve an empty multibulk ASAP to avoid special * cases later. */ if (count == 0) { - addReply(c,shared.emptymultibulk); + addReplyNull(c); return; } @@ -566,8 +566,8 @@ void spopCommand(client *c) { /* 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; + if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.null[c->resp])) + == NULL || checkType(c,set,OBJ_SET)) return; /* Get a random element from the set */ encoding = setTypeRandomElement(set,&sdsele,&llele); @@ -632,13 +632,13 @@ void srandmemberWithCountCommand(client *c) { uniq = 0; } - if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) + if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL || checkType(c,set,OBJ_SET)) return; size = setTypeSize(set); /* If count is zero, serve it ASAP to avoid special cases later. */ if (count == 0) { - addReply(c,shared.emptymultibulk); + addReplyNull(c); return; } @@ -760,8 +760,8 @@ void srandmemberCommand(client *c) { return; } - if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL || - checkType(c,set,OBJ_SET)) return; + if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) + == NULL || checkType(c,set,OBJ_SET)) return; encoding = setTypeRandomElement(set,&ele,&llele); if (encoding == OBJ_ENCODING_INTSET) { @@ -813,7 +813,7 @@ void sinterGenericCommand(client *c, robj **setkeys, } addReply(c,shared.czero); } else { - addReply(c,shared.emptymultibulk); + addReplyNull(c); } return; } diff --git a/src/t_string.c b/src/t_string.c index 2dfb327f..5800c5c0 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -80,7 +80,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) || (flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL)) { - addReply(c, abort_reply ? abort_reply : shared.nullbulk); + addReply(c, abort_reply ? abort_reply : shared.null[c->resp]); return; } setKey(c->db,key,val); @@ -157,7 +157,7 @@ void psetexCommand(client *c) { int getGenericCommand(client *c) { robj *o; - if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL) + if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL) return C_OK; if (o->type != OBJ_STRING) { @@ -289,10 +289,10 @@ void mgetCommand(client *c) { for (j = 1; j < c->argc; j++) { robj *o = lookupKeyRead(c->db,c->argv[j]); if (o == NULL) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { if (o->type != OBJ_STRING) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { addReplyBulk(c,o); } diff --git a/src/t_zset.c b/src/t_zset.c index f1b14018..1c943cae 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -1638,7 +1638,7 @@ reply_to_client: if (processed) addReplyDouble(c,score); else - addReply(c,shared.nullbulk); + addReplyNull(c); } else { /* ZADD. */ addReplyLongLong(c,ch ? added+updated : added); } @@ -2427,7 +2427,7 @@ void zrangeGenericCommand(client *c, int reverse) { return; } - if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL + if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL || checkType(c,zobj,OBJ_ZSET)) return; /* Sanitize indexes. */ @@ -2439,7 +2439,7 @@ void zrangeGenericCommand(client *c, int reverse) { /* 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) { - addReply(c,shared.emptymultibulk); + addReplyNull(c); return; } if (end >= llen) end = llen-1; @@ -2571,7 +2571,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) { } /* Ok, lookup the key and get the range */ - if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL || + if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL || checkType(c,zobj,OBJ_ZSET)) return; if (zobj->encoding == OBJ_ENCODING_ZIPLIST) { @@ -2591,7 +2591,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) { /* No "first" element in the specified interval. */ if (eptr == NULL) { - addReply(c, shared.emptymultibulk); + addReplyNull(c); return; } @@ -2658,7 +2658,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) { /* No "first" element in the specified interval. */ if (ln == NULL) { - addReply(c, shared.emptymultibulk); + addReplyNull(c); return; } @@ -2913,7 +2913,7 @@ void genericZrangebylexCommand(client *c, int reverse) { } /* Ok, lookup the key and get the range */ - if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL || + if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL || checkType(c,zobj,OBJ_ZSET)) { zslFreeLexRange(&range); @@ -2936,7 +2936,7 @@ void genericZrangebylexCommand(client *c, int reverse) { /* No "first" element in the specified interval. */ if (eptr == NULL) { - addReply(c, shared.emptymultibulk); + addReplyNull(c); zslFreeLexRange(&range); return; } @@ -3000,7 +3000,7 @@ void genericZrangebylexCommand(client *c, int reverse) { /* No "first" element in the specified interval. */ if (ln == NULL) { - addReply(c, shared.emptymultibulk); + addReplyNull(c); zslFreeLexRange(&range); return; } @@ -3069,11 +3069,11 @@ void zscoreCommand(client *c) { robj *zobj; double score; - if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL || + if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL || checkType(c,zobj,OBJ_ZSET)) return; if (zsetScore(zobj,c->argv[2]->ptr,&score) == C_ERR) { - addReply(c,shared.nullbulk); + addReplyNull(c); } else { addReplyDouble(c,score); } @@ -3085,7 +3085,7 @@ void zrankGenericCommand(client *c, int reverse) { robj *zobj; long rank; - if ((zobj = lookupKeyReadOrReply(c,key,shared.nullbulk)) == NULL || + if ((zobj = lookupKeyReadOrReply(c,key,shared.null[c->resp])) == NULL || checkType(c,zobj,OBJ_ZSET)) return; serverAssertWithInfo(c,ele,sdsEncodedObject(ele)); @@ -3093,7 +3093,7 @@ void zrankGenericCommand(client *c, int reverse) { if (rank >= 0) { addReplyLongLong(c,rank); } else { - addReply(c,shared.nullbulk); + addReplyNull(c); } } @@ -3151,7 +3151,7 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey /* No candidate for zpopping, return empty. */ if (!zobj) { - addReply(c,shared.emptymultibulk); + addReplyNull(c); return; } @@ -3277,7 +3277,7 @@ void blockingGenericZpopCommand(client *c, int where) { /* If we are inside a MULTI/EXEC and the zset is empty the only thing * we can do is treating it as a timeout (even with timeout 0). */ if (c->flags & CLIENT_MULTI) { - addReply(c,shared.nullmultibulk); + addReplyNull(c); return; }