summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2012-06-05 21:50:10 +0200
committerantirez <antirez@gmail.com>2013-07-22 10:31:38 +0200
commit894eba07c8484c0f34b09d54a84e69314c37c427 (patch)
tree245c97d2e0b4b10297fa8d461c64b041ab887e68
parentb9cc90a1192a3ac2edbdac63540f889843f37284 (diff)
downloadredis-894eba07c8484c0f34b09d54a84e69314c37c427.tar.gz
Introduction of a new string encoding: EMBSTR
Previously two string encodings were used for string objects: 1) REDIS_ENCODING_RAW: a string object with obj->ptr pointing to an sds stirng. 2) REDIS_ENCODING_INT: a string object where the obj->ptr void pointer is casted to a long. This commit introduces a experimental new encoding called REDIS_ENCODING_EMBSTR that implements an object represented by an sds string that is not modifiable but allocated in the same memory chunk as the robj structure itself. The chunk looks like the following: +--------------+-----------+------------+--------+----+ | robj data... | robj->ptr | sds header | string | \0 | +--------------+-----+-----+------------+--------+----+ | ^ +-----------------------+ The robj->ptr points to the contiguous sds string data, so the object can be manipulated with the same functions used to manipulate plan string objects, however we need just on malloc and one free in order to allocate or release this kind of objects. Moreover it has better cache locality. This new allocation strategy should benefit both the memory usage and the performances. A performance gain between 60 and 70% was observed during micro-benchmarks, however there is more work to do to evaluate the performance impact and the memory usage behavior.
-rw-r--r--src/aof.c2
-rw-r--r--src/bitops.c10
-rw-r--r--src/cluster.c2
-rw-r--r--src/config.c6
-rw-r--r--src/debug.c6
-rw-r--r--src/networking.c30
-rw-r--r--src/object.c115
-rw-r--r--src/rdb.c13
-rw-r--r--src/redis.c2
-rw-r--r--src/redis.h4
-rw-r--r--src/slowlog.c2
-rw-r--r--src/sort.c2
-rw-r--r--src/t_hash.c2
-rw-r--r--src/t_list.c4
-rw-r--r--src/t_set.c9
-rw-r--r--src/t_string.c4
-rw-r--r--src/t_zset.c15
17 files changed, 157 insertions, 71 deletions
diff --git a/src/aof.c b/src/aof.c
index 89f17abab..2a29f72fb 100644
--- a/src/aof.c
+++ b/src/aof.c
@@ -591,7 +591,7 @@ int rioWriteBulkObject(rio *r, robj *obj) {
* in a child process when this function is called). */
if (obj->encoding == REDIS_ENCODING_INT) {
return rioWriteBulkLongLong(r,(long)obj->ptr);
- } else if (obj->encoding == REDIS_ENCODING_RAW) {
+ } else if (sdsEncodedObject(obj)) {
return rioWriteBulkString(r,obj->ptr,sdslen(obj->ptr));
} else {
redisPanic("Unknown string encoding");
diff --git a/src/bitops.c b/src/bitops.c
index c96a9e3c7..599d4dd8e 100644
--- a/src/bitops.c
+++ b/src/bitops.c
@@ -133,7 +133,7 @@ void setbitCommand(redisClient *c) {
/* Create a copy when the object is shared or encoded. */
if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
robj *decoded = getDecodedObject(o);
- o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
+ o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded);
dbOverwrite(c->db,c->argv[1],o);
}
@@ -174,12 +174,12 @@ void getbitCommand(redisClient *c) {
byte = bitoffset >> 3;
bit = 7 - (bitoffset & 0x7);
- if (o->encoding != REDIS_ENCODING_RAW) {
- if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
- bitval = llbuf[byte] & (1 << bit);
- } else {
+ if (sdsEncodedObject(o)) {
if (byte < sdslen(o->ptr))
bitval = ((uint8_t*)o->ptr)[byte] & (1 << bit);
+ } else {
+ if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
+ bitval = llbuf[byte] & (1 << bit);
}
addReply(c, bitval ? shared.cone : shared.czero);
diff --git a/src/cluster.c b/src/cluster.c
index 76ab67112..017989df3 100644
--- a/src/cluster.c
+++ b/src/cluster.c
@@ -2691,7 +2691,7 @@ try_again:
rioWriteBulkString(&cmd,"RESTORE-ASKING",14));
else
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"RESTORE",7));
- redisAssertWithInfo(c,NULL,c->argv[3]->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(c,NULL,sdsEncodedObject(c->argv[3]));
redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,c->argv[3]->ptr,sdslen(c->argv[3]->ptr)));
redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,ttl));
diff --git a/src/config.c b/src/config.c
index 78b458dcc..3a14a6e94 100644
--- a/src/config.c
+++ b/src/config.c
@@ -550,8 +550,8 @@ void loadServerConfig(char *filename, char *options) {
void configSetCommand(redisClient *c) {
robj *o;
long long ll;
- redisAssertWithInfo(c,c->argv[2],c->argv[2]->encoding == REDIS_ENCODING_RAW);
- redisAssertWithInfo(c,c->argv[2],c->argv[3]->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(c,c->argv[2],sdsEncodedObject(c->argv[2]));
+ redisAssertWithInfo(c,c->argv[3],sdsEncodedObject(c->argv[3]));
o = c->argv[3];
if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
@@ -918,7 +918,7 @@ void configGetCommand(redisClient *c) {
char *pattern = o->ptr;
char buf[128];
int matches = 0;
- redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(c,o,sdsEncodedObject(o));
/* String values */
config_get_string_field("dbfilename",server.rdb_filename);
diff --git a/src/debug.c b/src/debug.c
index 0a947e564..a0352b5dd 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -373,9 +373,7 @@ void _redisAssertPrintClientInfo(redisClient *c) {
char buf[128];
char *arg;
- if (c->argv[j]->type == REDIS_STRING &&
- c->argv[j]->encoding == REDIS_ENCODING_RAW)
- {
+ if (c->argv[j]->type == REDIS_STRING && sdsEncodedObject(c->argv[j])) {
arg = (char*) c->argv[j]->ptr;
} else {
snprintf(buf,sizeof(buf),"Object type: %d, encoding: %d",
@@ -391,7 +389,7 @@ void redisLogObjectDebugInfo(robj *o) {
redisLog(REDIS_WARNING,"Object type: %d", o->type);
redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
- if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_RAW) {
+ if (o->type == REDIS_STRING && sdsEncodedObject(o)) {
redisLog(REDIS_WARNING,"Object raw string len: %zu", sdslen(o->ptr));
if (sdslen(o->ptr) < 4096) {
sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr));
diff --git a/src/networking.c b/src/networking.c
index e2cbf9ad8..4066d69a8 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -184,12 +184,15 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
if (listLength(c->reply) == 0) {
incrRefCount(o);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size_sds(o->ptr);
+ c->reply_bytes += (o->encoding == REDIS_ENCODING_RAW) ?
+ zmalloc_size_sds(o->ptr) :
+ sdslen(o->ptr);
} else {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
if (tail->ptr != NULL &&
+ tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -199,7 +202,9 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
} else {
incrRefCount(o);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size_sds(o->ptr);
+ c->reply_bytes += (o->encoding == REDIS_ENCODING_RAW) ?
+ zmalloc_size_sds(o->ptr) :
+ sdslen(o->ptr);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
@@ -222,7 +227,7 @@ void _addReplySdsToList(redisClient *c, sds s) {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
- if (tail->ptr != NULL &&
+ if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -247,12 +252,14 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size_sds(o->ptr);
+ c->reply_bytes += (o->encoding == REDIS_ENCODING_RAW) ?
+ zmalloc_size_sds(o->ptr) :
+ sdslen(o->ptr);
} else {
tail = listNodeValue(listLast(c->reply));
/* Append to this object when possible. */
- if (tail->ptr != NULL &&
+ if (tail->ptr != NULL && tail->encoding == REDIS_ENCODING_RAW &&
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
{
c->reply_bytes -= zmalloc_size_sds(tail->ptr);
@@ -263,7 +270,9 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size_sds(o->ptr);
+ c->reply_bytes += (o->encoding == REDIS_ENCODING_RAW) ?
+ zmalloc_size_sds(o->ptr) :
+ sdslen(o->ptr);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
@@ -284,7 +293,7 @@ void addReply(redisClient *c, robj *obj) {
* If the encoding is RAW and there is room in the static buffer
* we'll be able to send the object to the client without
* messing with its page. */
- if (obj->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(obj)) {
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
_addReplyObjectToList(c,obj);
} else if (obj->encoding == REDIS_ENCODING_INT) {
@@ -396,6 +405,7 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
len = listNodeValue(ln);
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
+ len->encoding = REDIS_ENCODING_RAW; /* in case it was an EMBSTR. */
c->reply_bytes += zmalloc_size_sds(len->ptr);
if (ln->next != NULL) {
next = listNodeValue(ln->next);
@@ -468,7 +478,7 @@ void addReplyMultiBulkLen(redisClient *c, long length) {
void addReplyBulkLen(redisClient *c, robj *obj) {
size_t len;
- if (obj->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(obj)) {
len = sdslen(obj->ptr);
} else {
long n = (long)obj->ptr;
@@ -765,7 +775,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
} else {
o = listNodeValue(listFirst(c->reply));
objlen = sdslen(o->ptr);
- objmem = zmalloc_size_sds(o->ptr);
+ objmem = (o->encoding == REDIS_ENCODING_RAW) ?
+ zmalloc_size_sds(o->ptr) :
+ sdslen(o->ptr);
if (objlen == 0) {
listDelNode(c->reply,listFirst(c->reply));
diff --git a/src/object.c b/src/object.c
index 472d4a34b..9efb590f8 100644
--- a/src/object.c
+++ b/src/object.c
@@ -44,10 +44,47 @@ robj *createObject(int type, void *ptr) {
return o;
}
-robj *createStringObject(char *ptr, size_t len) {
+/* Create a string object with encoding REDIS_ENCODING_RAW, that is a plain
+ * string object where o->ptr points to a proper sds string. */
+robj *createRawStringObject(char *ptr, size_t len) {
return createObject(REDIS_STRING,sdsnewlen(ptr,len));
}
+/* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is
+ * an object where the sds string is actually an unmodifiable string
+ * allocated in the same chunk as the object itself. */
+robj *createEmbeddedStringObject(char *ptr, size_t len) {
+ robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
+ struct sdshdr *sh = (void*)(o+1);
+
+ o->type = REDIS_STRING;
+ o->encoding = REDIS_ENCODING_EMBSTR;
+ o->ptr = sh+1;
+ o->refcount = 1;
+ o->lru = server.lruclock;
+
+ sh->len = len;
+ sh->free = 0;
+ if (ptr) {
+ memcpy(sh->buf,ptr,len);
+ sh->buf[len] = '\0';
+ } else {
+ memset(sh->buf,0,len+1);
+ }
+ return o;
+}
+
+/* Create a string object with EMBSTR encoding if it is smaller than
+ * REIDS_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
+ * used. */
+#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 32
+robj *createStringObject(char *ptr, size_t len) {
+ if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
+ return createEmbeddedStringObject(ptr,len);
+ else
+ return createRawStringObject(ptr,len);
+}
+
robj *createStringObjectFromLongLong(long long value) {
robj *o;
if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
@@ -89,9 +126,33 @@ robj *createStringObjectFromLongDouble(long double value) {
return createStringObject(buf,len);
}
+/* Duplicate a string object, with the guarantee that the returned object
+ * has the same encoding as the original one.
+ *
+ * This function also guarantees that duplicating a small integere object
+ * (or a string object that contains a representation of a small integer)
+ * will always result in a fresh object that is unshared (refcount == 1).
+ *
+ * The resulting object always has refcount set to 1. */
robj *dupStringObject(robj *o) {
- redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
- return createStringObject(o->ptr,sdslen(o->ptr));
+ robj *d;
+
+ redisAssert(o->type == REDIS_STRING);
+
+ switch(o->encoding) {
+ case REDIS_ENCODING_RAW:
+ return createRawStringObject(o->ptr,sdslen(o->ptr));
+ case REDIS_ENCODING_EMBSTR:
+ return createEmbeddedStringObject(o->ptr,sdslen(o->ptr));
+ case REDIS_ENCODING_INT:
+ d = createObject(REDIS_STRING, NULL);
+ d->encoding = REDIS_ENCODING_INT;
+ d->ptr = o->ptr;
+ return d;
+ default:
+ redisPanic("Wrong encoding.");
+ break;
+ }
}
robj *createListObject(void) {
@@ -279,7 +340,7 @@ robj *tryObjectEncoding(robj *o) {
long value;
sds s = o->ptr;
- if (o->encoding != REDIS_ENCODING_RAW)
+ if (o->encoding == REDIS_ENCODING_INT)
return o; /* Already encoded */
/* It's not safe to encode shared objects: shared objects can be shared
@@ -291,7 +352,17 @@ robj *tryObjectEncoding(robj *o) {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
/* Check if we can represent this string as a long integer */
- if (!string2l(s,sdslen(s),&value)) return o;
+ if (!string2l(s,sdslen(s),&value)) {
+ /* Integer encoding not possible. Check if we can use EMBSTR. */
+ if (sdslen(s) <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) {
+ robj *emb = createEmbeddedStringObject(s,sdslen(s));
+ decrRefCount(o);
+ return emb;
+ } else {
+ /* Otherwise return the original object. */
+ return o;
+ }
+ }
/* Ok, this object can be encoded...
*
@@ -305,8 +376,8 @@ robj *tryObjectEncoding(robj *o) {
incrRefCount(shared.integers[value]);
return shared.integers[value];
} else {
+ if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr);
o->encoding = REDIS_ENCODING_INT;
- sdsfree(o->ptr);
o->ptr = (void*) value;
return o;
}
@@ -317,7 +388,7 @@ robj *tryObjectEncoding(robj *o) {
robj *getDecodedObject(robj *o) {
robj *dec;
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
incrRefCount(o);
return o;
}
@@ -350,21 +421,21 @@ int compareStringObjectsWithFlags(robj *a, robj *b, int flags) {
int bothsds = 1;
if (a == b) return 0;
- if (a->encoding != REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(a)) {
+ astr = a->ptr;
+ alen = sdslen(astr);
+ } else {
alen = ll2string(bufa,sizeof(bufa),(long) a->ptr);
astr = bufa;
bothsds = 0;
- } else {
- astr = a->ptr;
- alen = sdslen(astr);
}
- if (b->encoding != REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(b)) {
+ bstr = b->ptr;
+ blen = sdslen(bstr);
+ } else {
blen = ll2string(bufb,sizeof(bufb),(long) b->ptr);
bstr = bufb;
bothsds = 0;
- } else {
- bstr = b->ptr;
- blen = sdslen(bstr);
}
if (flags & REDIS_COMPARE_COLL) {
return strcoll(astr,bstr);
@@ -393,7 +464,10 @@ int collateStringObjects(robj *a, robj *b) {
* this function is faster then checking for (compareStringObject(a,b) == 0)
* because it can perform some more optimization. */
int equalStringObjects(robj *a, robj *b) {
- if (a->encoding != REDIS_ENCODING_RAW && b->encoding != REDIS_ENCODING_RAW){
+ if (a->encoding == REDIS_ENCODING_INT &&
+ b->encoding == REDIS_ENCODING_INT){
+ /* If both strings are integer encoded just check if the stored
+ * long is the same. */
return a->ptr == b->ptr;
} else {
return compareStringObjects(a,b) == 0;
@@ -402,7 +476,7 @@ int equalStringObjects(robj *a, robj *b) {
size_t stringObjectLen(robj *o) {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
return sdslen(o->ptr);
} else {
char buf[32];
@@ -419,7 +493,7 @@ int getDoubleFromObject(robj *o, double *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
errno = 0;
value = strtod(o->ptr, &eptr);
if (isspace(((char*)o->ptr)[0]) ||
@@ -461,7 +535,7 @@ int getLongDoubleFromObject(robj *o, long double *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
errno = 0;
value = strtold(o->ptr, &eptr);
if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
@@ -499,7 +573,7 @@ int getLongLongFromObject(robj *o, long long *target) {
value = 0;
} else {
redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
errno = 0;
value = strtoll(o->ptr, &eptr, 10);
if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' ||
@@ -554,6 +628,7 @@ char *strEncoding(int encoding) {
case REDIS_ENCODING_ZIPLIST: return "ziplist";
case REDIS_ENCODING_INTSET: return "intset";
case REDIS_ENCODING_SKIPLIST: return "skiplist";
+ case REDIS_ENCODING_EMBSTR: return "embstr";
default: return "unknown";
}
}
diff --git a/src/rdb.c b/src/rdb.c
index c53c157c5..1c2b0ed0d 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -325,7 +325,7 @@ int rdbSaveStringObject(rio *rdb, robj *obj) {
if (obj->encoding == REDIS_ENCODING_INT) {
return rdbSaveLongLongAsStringObject(rdb,(long)obj->ptr);
} else {
- redisAssertWithInfo(NULL,obj,obj->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(NULL,obj,sdsEncodedObject(obj));
return rdbSaveRawString(rdb,obj->ptr,sdslen(obj->ptr));
}
}
@@ -795,7 +795,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* If we are using a ziplist and the value is too big, convert
* the object to a real list. */
if (o->encoding == REDIS_ENCODING_ZIPLIST &&
- ele->encoding == REDIS_ENCODING_RAW &&
+ sdsEncodedObject(ele) &&
sdslen(ele->ptr) > server.list_max_ziplist_value)
listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
@@ -869,9 +869,8 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
if (rdbLoadDoubleValue(rdb,&score) == -1) return NULL;
/* Don't care about integer-encoded strings. */
- if (ele->encoding == REDIS_ENCODING_RAW &&
- sdslen(ele->ptr) > maxelelen)
- maxelelen = sdslen(ele->ptr);
+ if (sdsEncodedObject(ele) && sdslen(ele->ptr) > maxelelen)
+ maxelelen = sdslen(ele->ptr);
znode = zslInsert(zs->zsl,score,ele);
dictAdd(zs->dict,ele,&znode->score);
@@ -903,10 +902,10 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* Load raw strings */
field = rdbLoadStringObject(rdb);
if (field == NULL) return NULL;
- redisAssert(field->encoding == REDIS_ENCODING_RAW);
+ redisAssert(sdsEncodedObject(field));
value = rdbLoadStringObject(rdb);
if (value == NULL) return NULL;
- redisAssert(field->encoding == REDIS_ENCODING_RAW);
+ redisAssert(sdsEncodedObject(value));
/* Add pair to ziplist */
o->ptr = ziplistPush(o->ptr, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL);
diff --git a/src/redis.c b/src/redis.c
index 99955488e..8a833d509 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -465,7 +465,7 @@ int dictEncObjKeyCompare(void *privdata, const void *key1,
unsigned int dictEncObjHash(const void *key) {
robj *o = (robj*) key;
- if (o->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(o)) {
return dictGenHashFunction(o->ptr, sdslen((sds)o->ptr));
} else {
if (o->encoding == REDIS_ENCODING_INT) {
diff --git a/src/redis.h b/src/redis.h
index e78dc528d..57e39ad2b 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -174,6 +174,7 @@
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
+#define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
/* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of
@@ -1138,6 +1139,8 @@ void freeZsetObject(robj *o);
void freeHashObject(robj *o);
robj *createObject(int type, void *ptr);
robj *createStringObject(char *ptr, size_t len);
+robj *createRawStringObject(char *ptr, size_t len);
+robj *createEmbeddedStringObject(char *ptr, size_t len);
robj *dupStringObject(robj *o);
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
robj *tryObjectEncoding(robj *o);
@@ -1164,6 +1167,7 @@ int compareStringObjects(robj *a, robj *b);
int collateStringObjects(robj *a, robj *b);
int equalStringObjects(robj *a, robj *b);
unsigned long estimateObjectIdleTime(robj *o);
+#define sdsEncodedObject(objptr) (objptr->encoding == REDIS_ENCODING_RAW || objptr->encoding == REDIS_ENCODING_EMBSTR)
/* Synchronous I/O with timeout */
ssize_t syncWrite(int fd, char *ptr, ssize_t size, long long timeout);
diff --git a/src/slowlog.c b/src/slowlog.c
index fdc18e579..ff6ccf472 100644
--- a/src/slowlog.c
+++ b/src/slowlog.c
@@ -63,7 +63,7 @@ slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
} else {
/* Trim too long strings as well... */
if (argv[j]->type == REDIS_STRING &&
- argv[j]->encoding == REDIS_ENCODING_RAW &&
+ sdsEncodedObject(argv[j]) &&
sdslen(argv[j]->ptr) > SLOWLOG_ENTRY_MAX_STRING)
{
sds s = sdsnewlen(argv[j]->ptr, SLOWLOG_ENTRY_MAX_STRING);
diff --git a/src/sort.c b/src/sort.c
index a4b062645..ebdf5469c 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -411,7 +411,7 @@ void sortCommand(redisClient *c) {
if (alpha) {
if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
} else {
- if (byval->encoding == REDIS_ENCODING_RAW) {
+ if (sdsEncodedObject(byval)) {
char *eptr;
vector[j].u.score = strtod(byval->ptr,&eptr);
diff --git a/src/t_hash.c b/src/t_hash.c
index 9484e531b..3b87b92ca 100644
--- a/src/t_hash.c
+++ b/src/t_hash.c
@@ -43,7 +43,7 @@ void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
if (o->encoding != REDIS_ENCODING_ZIPLIST) return;
for (i = start; i <= end; i++) {
- if (argv[i]->encoding == REDIS_ENCODING_RAW &&
+ if (sdsEncodedObject(argv[i]) &&
sdslen(argv[i]->ptr) > server.hash_max_ziplist_value)
{
hashTypeConvert(o, REDIS_ENCODING_HT);
diff --git a/src/t_list.c b/src/t_list.c
index 0413dc69b..a8ce9b976 100644
--- a/src/t_list.c
+++ b/src/t_list.c
@@ -40,7 +40,7 @@ void signalListAsReady(redisClient *c, robj *key);
* objects are never too long. */
void listTypeTryConversion(robj *subject, robj *value) {
if (subject->encoding != REDIS_ENCODING_ZIPLIST) return;
- if (value->encoding == REDIS_ENCODING_RAW &&
+ if (sdsEncodedObject(value) &&
sdslen(value->ptr) > server.list_max_ziplist_value)
listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST);
}
@@ -234,7 +234,7 @@ void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
int listTypeEqual(listTypeEntry *entry, robj *o) {
listTypeIterator *li = entry->li;
if (li->encoding == REDIS_ENCODING_ZIPLIST) {
- redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(NULL,o,sdsEncodedObject(o));
return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
} else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
return equalStringObjects(o,listNodeValue(entry->ln));
diff --git a/src/t_set.c b/src/t_set.c
index a522cd88a..ab65e23f3 100644
--- a/src/t_set.c
+++ b/src/t_set.c
@@ -495,11 +495,8 @@ void srandmemberWithCountCommand(redisClient *c) {
if (encoding == REDIS_ENCODING_INTSET) {
retval = dictAdd(d,createStringObjectFromLongLong(llele),NULL);
- } else if (ele->encoding == REDIS_ENCODING_RAW) {
+ } else {
retval = dictAdd(d,dupStringObject(ele),NULL);
- } else if (ele->encoding == REDIS_ENCODING_INT) {
- retval = dictAdd(d,
- createStringObjectFromLongLong((long)ele->ptr),NULL);
}
redisAssert(retval == DICT_OK);
}
@@ -527,10 +524,8 @@ void srandmemberWithCountCommand(redisClient *c) {
encoding = setTypeRandomElement(set,&ele,&llele);
if (encoding == REDIS_ENCODING_INTSET) {
ele = createStringObjectFromLongLong(llele);
- } else if (ele->encoding == REDIS_ENCODING_RAW) {
+ } else {
ele = dupStringObject(ele);
- } else if (ele->encoding == REDIS_ENCODING_INT) {
- ele = createStringObjectFromLongLong((long)ele->ptr);
}
/* Try to add the object to the dictionary. If it already exists
* free it, otherwise increment the number of objects we have
diff --git a/src/t_string.c b/src/t_string.c
index cbd069d3c..3645ae7c5 100644
--- a/src/t_string.c
+++ b/src/t_string.c
@@ -217,7 +217,7 @@ void setrangeCommand(redisClient *c) {
/* Create a copy when the object is shared or encoded. */
if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
robj *decoded = getDecodedObject(o);
- o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
+ o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded);
dbOverwrite(c->db,c->argv[1],o);
}
@@ -436,7 +436,7 @@ void appendCommand(redisClient *c) {
/* If the object is shared or encoded, 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));
+ o = createRawStringObject(decoded->ptr, sdslen(decoded->ptr));
decrRefCount(decoded);
dbOverwrite(c->db,c->argv[1],o);
}
diff --git a/src/t_zset.c b/src/t_zset.c
index 8ef9c5376..291a7eacf 100644
--- a/src/t_zset.c
+++ b/src/t_zset.c
@@ -646,7 +646,7 @@ unsigned char *zzlInsertAt(unsigned char *zl, unsigned char *eptr, robj *ele, do
int scorelen;
size_t offset;
- redisAssertWithInfo(NULL,ele,ele->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(NULL,ele,sdsEncodedObject(ele));
scorelen = d2string(scorebuf,sizeof(scorebuf),score);
if (eptr == NULL) {
zl = ziplistPush(zl,ele->ptr,sdslen(ele->ptr),ZIPLIST_TAIL);
@@ -1363,7 +1363,7 @@ int zuiLongLongFromValue(zsetopval *val) {
if (val->ele->encoding == REDIS_ENCODING_INT) {
val->ell = (long)val->ele->ptr;
val->flags |= OPVAL_VALID_LL;
- } else if (val->ele->encoding == REDIS_ENCODING_RAW) {
+ } else if (sdsEncodedObject(val->ele)) {
if (string2ll(val->ele->ptr,sdslen(val->ele->ptr),&val->ell))
val->flags |= OPVAL_VALID_LL;
} else {
@@ -1398,7 +1398,7 @@ int zuiBufferFromValue(zsetopval *val) {
if (val->ele->encoding == REDIS_ENCODING_INT) {
val->elen = ll2string((char*)val->_buf,sizeof(val->_buf),(long)val->ele->ptr);
val->estr = val->_buf;
- } else if (val->ele->encoding == REDIS_ENCODING_RAW) {
+ } else if (sdsEncodedObject(val->ele)) {
val->elen = sdslen(val->ele->ptr);
val->estr = val->ele->ptr;
} else {
@@ -1624,9 +1624,10 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dictAdd(dstzset->dict,tmp,&znode->score);
incrRefCount(tmp); /* added to dictionary */
- if (tmp->encoding == REDIS_ENCODING_RAW)
+ if (sdsEncodedObject(tmp)) {
if (sdslen(tmp->ptr) > maxelelen)
maxelelen = sdslen(tmp->ptr);
+ }
}
}
}
@@ -1666,9 +1667,10 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dictAdd(dstzset->dict,tmp,&znode->score);
incrRefCount(zval.ele); /* added to dictionary */
- if (tmp->encoding == REDIS_ENCODING_RAW)
+ if (sdsEncodedObject(tmp)) {
if (sdslen(tmp->ptr) > maxelelen)
maxelelen = sdslen(tmp->ptr);
+ }
}
}
} else {
@@ -2146,7 +2148,8 @@ void zrankGenericCommand(redisClient *c, int reverse) {
checkType(c,zobj,REDIS_ZSET)) return;
llen = zsetLength(zobj);
- redisAssertWithInfo(c,ele,ele->encoding == REDIS_ENCODING_RAW);
+ redisAssertWithInfo(c,ele,sdsEncodedObject(ele));
+
if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *zl = zobj->ptr;
unsigned char *eptr, *sptr;