Commit ebd85e9a authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

Encode small hashes with a ziplist

parent 9ea54fee
...@@ -607,17 +607,38 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) { ...@@ -607,17 +607,38 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
return 1; return 1;
} }
static int rioWriteHashIteratorCursor(rio *r, hashTypeIterator *hi, int what) {
if (hi->encoding == REDIS_ENCODING_ZIPLIST) {
unsigned char *vstr = NULL;
unsigned int vlen = UINT_MAX;
long long vll = LLONG_MAX;
hashTypeCurrentFromZiplist(hi, what, &vstr, &vlen, &vll);
if (vstr) {
return rioWriteBulkString(r, (char*)vstr, vlen);
} else {
return rioWriteBulkLongLong(r, vll);
}
} else if (hi->encoding == REDIS_ENCODING_HT) {
robj *value;
hashTypeCurrentFromHashTable(hi, what, &value);
return rioWriteBulkObject(r, value);
}
redisPanic("Unknown hash encoding");
return 0;
}
/* Emit the commands needed to rebuild a hash object. /* Emit the commands needed to rebuild a hash object.
* The function returns 0 on error, 1 on success. */ * The function returns 0 on error, 1 on success. */
int rewriteHashObject(rio *r, robj *key, robj *o) { int rewriteHashObject(rio *r, robj *key, robj *o) {
hashTypeIterator *hi;
long long count = 0, items = hashTypeLength(o); long long count = 0, items = hashTypeLength(o);
if (o->encoding == REDIS_ENCODING_ZIPMAP) { hi = hashTypeInitIterator(o);
unsigned char *p = zipmapRewind(o->ptr); while (hashTypeNext(hi) != REDIS_ERR) {
unsigned char *field, *val;
unsigned int flen, vlen;
while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
if (count == 0) { if (count == 0) {
int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ? int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ?
REDIS_AOF_REWRITE_ITEMS_PER_CMD : items; REDIS_AOF_REWRITE_ITEMS_PER_CMD : items;
...@@ -626,34 +647,15 @@ int rewriteHashObject(rio *r, robj *key, robj *o) { ...@@ -626,34 +647,15 @@ int rewriteHashObject(rio *r, robj *key, robj *o) {
if (rioWriteBulkString(r,"HMSET",5) == 0) return 0; if (rioWriteBulkString(r,"HMSET",5) == 0) return 0;
if (rioWriteBulkObject(r,key) == 0) return 0; if (rioWriteBulkObject(r,key) == 0) return 0;
} }
if (rioWriteBulkString(r,(char*)field,flen) == 0) return 0;
if (rioWriteBulkString(r,(char*)val,vlen) == 0) return 0; if (rioWriteHashIteratorCursor(r, hi, REDIS_HASH_KEY) == 0) return 0;
if (rioWriteHashIteratorCursor(r, hi, REDIS_HASH_VALUE) == 0) return 0;
if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0; if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0;
items--; items--;
} }
} else {
dictIterator *di = dictGetIterator(o->ptr);
dictEntry *de;
while((de = dictNext(di)) != NULL) { hashTypeReleaseIterator(hi);
robj *field = dictGetKey(de);
robj *val = dictGetVal(de);
if (count == 0) {
int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ?
REDIS_AOF_REWRITE_ITEMS_PER_CMD : items;
if (rioWriteBulkCount(r,'*',2+cmd_items*2) == 0) return 0;
if (rioWriteBulkString(r,"HMSET",5) == 0) return 0;
if (rioWriteBulkObject(r,key) == 0) return 0;
}
if (rioWriteBulkObject(r,field) == 0) return 0;
if (rioWriteBulkObject(r,val) == 0) return 0;
if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0;
items--;
}
dictReleaseIterator(di);
}
return 1; return 1;
} }
......
...@@ -259,9 +259,15 @@ void loadServerConfigFromString(char *config) { ...@@ -259,9 +259,15 @@ void loadServerConfigFromString(char *config) {
zfree(server.rdb_filename); zfree(server.rdb_filename);
server.rdb_filename = zstrdup(argv[1]); server.rdb_filename = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) { } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) {
server.hash_max_zipmap_entries = memtoll(argv[1], NULL); redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]);
server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) { } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) {
server.hash_max_zipmap_value = memtoll(argv[1], NULL); redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]);
server.hash_max_ziplist_value = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) {
server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) {
server.hash_max_ziplist_value = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){ } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
server.list_max_ziplist_entries = memtoll(argv[1], NULL); server.list_max_ziplist_entries = memtoll(argv[1], NULL);
} else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) { } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
...@@ -491,12 +497,12 @@ void configSetCommand(redisClient *c) { ...@@ -491,12 +497,12 @@ void configSetCommand(redisClient *c) {
addReplyErrorFormat(c,"Changing directory: %s", strerror(errno)); addReplyErrorFormat(c,"Changing directory: %s", strerror(errno));
return; return;
} }
} else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-entries")) { } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.hash_max_zipmap_entries = ll; server.hash_max_ziplist_entries = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-value")) { } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-value")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.hash_max_zipmap_value = ll; server.hash_max_ziplist_value = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) { } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.list_max_ziplist_entries = ll; server.list_max_ziplist_entries = ll;
...@@ -668,14 +674,14 @@ void configGetCommand(redisClient *c) { ...@@ -668,14 +674,14 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no"); addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no");
matches++; matches++;
} }
if (stringmatch(pattern,"hash-max-zipmap-entries",0)) { if (stringmatch(pattern,"hash-max-ziplist-entries",0)) {
addReplyBulkCString(c,"hash-max-zipmap-entries"); addReplyBulkCString(c,"hash-max-ziplist-entries");
addReplyBulkLongLong(c,server.hash_max_zipmap_entries); addReplyBulkLongLong(c,server.hash_max_ziplist_entries);
matches++; matches++;
} }
if (stringmatch(pattern,"hash-max-zipmap-value",0)) { if (stringmatch(pattern,"hash-max-ziplist-value",0)) {
addReplyBulkCString(c,"hash-max-zipmap-value"); addReplyBulkCString(c,"hash-max-ziplist-value");
addReplyBulkLongLong(c,server.hash_max_zipmap_value); addReplyBulkLongLong(c,server.hash_max_ziplist_value);
matches++; matches++;
} }
if (stringmatch(pattern,"list-max-ziplist-entries",0)) { if (stringmatch(pattern,"list-max-ziplist-entries",0)) {
......
...@@ -95,12 +95,9 @@ robj *createIntsetObject(void) { ...@@ -95,12 +95,9 @@ robj *createIntsetObject(void) {
} }
robj *createHashObject(void) { robj *createHashObject(void) {
/* All the Hashes start as zipmaps. Will be automatically converted unsigned char *zl = ziplistNew();
* into hash tables if there are enough elements or big elements robj *o = createObject(REDIS_HASH, zl);
* inside. */ o->encoding = REDIS_ENCODING_ZIPLIST;
unsigned char *zm = zipmapNew();
robj *o = createObject(REDIS_HASH,zm);
o->encoding = REDIS_ENCODING_ZIPMAP;
return o; return o;
} }
...@@ -176,7 +173,7 @@ void freeHashObject(robj *o) { ...@@ -176,7 +173,7 @@ void freeHashObject(robj *o) {
case REDIS_ENCODING_HT: case REDIS_ENCODING_HT:
dictRelease((dict*) o->ptr); dictRelease((dict*) o->ptr);
break; break;
case REDIS_ENCODING_ZIPMAP: case REDIS_ENCODING_ZIPLIST:
zfree(o->ptr); zfree(o->ptr);
break; break;
default: default:
...@@ -492,7 +489,6 @@ char *strEncoding(int encoding) { ...@@ -492,7 +489,6 @@ char *strEncoding(int encoding) {
case REDIS_ENCODING_RAW: return "raw"; case REDIS_ENCODING_RAW: return "raw";
case REDIS_ENCODING_INT: return "int"; case REDIS_ENCODING_INT: return "int";
case REDIS_ENCODING_HT: return "hashtable"; case REDIS_ENCODING_HT: return "hashtable";
case REDIS_ENCODING_ZIPMAP: return "zipmap";
case REDIS_ENCODING_LINKEDLIST: return "linkedlist"; case REDIS_ENCODING_LINKEDLIST: return "linkedlist";
case REDIS_ENCODING_ZIPLIST: return "ziplist"; case REDIS_ENCODING_ZIPLIST: return "ziplist";
case REDIS_ENCODING_INTSET: return "intset"; case REDIS_ENCODING_INTSET: return "intset";
......
#include "redis.h" #include "redis.h"
#include "lzf.h" /* LZF compression library */ #include "lzf.h" /* LZF compression library */
#include "zipmap.h"
#include <math.h> #include <math.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -424,8 +425,8 @@ int rdbSaveObjectType(rio *rdb, robj *o) { ...@@ -424,8 +425,8 @@ int rdbSaveObjectType(rio *rdb, robj *o) {
else else
redisPanic("Unknown sorted set encoding"); redisPanic("Unknown sorted set encoding");
case REDIS_HASH: case REDIS_HASH:
if (o->encoding == REDIS_ENCODING_ZIPMAP) if (o->encoding == REDIS_ENCODING_ZIPLIST)
return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH_ZIPMAP); return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH_ZIPLIST);
else if (o->encoding == REDIS_ENCODING_HT) else if (o->encoding == REDIS_ENCODING_HT)
return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH); return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH);
else else
...@@ -530,12 +531,13 @@ int rdbSaveObject(rio *rdb, robj *o) { ...@@ -530,12 +531,13 @@ int rdbSaveObject(rio *rdb, robj *o) {
} }
} else if (o->type == REDIS_HASH) { } else if (o->type == REDIS_HASH) {
/* Save a hash value */ /* Save a hash value */
if (o->encoding == REDIS_ENCODING_ZIPMAP) { if (o->encoding == REDIS_ENCODING_ZIPLIST) {
size_t l = zipmapBlobLen((unsigned char*)o->ptr); size_t l = ziplistBlobLen((unsigned char*)o->ptr);
if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1; if ((n = rdbSaveRawString(rdb,o->ptr,l)) == -1) return -1;
nwritten += n; nwritten += n;
} else {
} else if (o->encoding == REDIS_ENCODING_HT) {
dictIterator *di = dictGetIterator(o->ptr); dictIterator *di = dictGetIterator(o->ptr);
dictEntry *de; dictEntry *de;
...@@ -552,7 +554,11 @@ int rdbSaveObject(rio *rdb, robj *o) { ...@@ -552,7 +554,11 @@ int rdbSaveObject(rio *rdb, robj *o) {
nwritten += n; nwritten += n;
} }
dictReleaseIterator(di); dictReleaseIterator(di);
} else {
redisPanic("Unknown hash encoding");
} }
} else { } else {
redisPanic("Unknown object type"); redisPanic("Unknown object type");
} }
...@@ -824,55 +830,69 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -824,55 +830,69 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
maxelelen <= server.zset_max_ziplist_value) maxelelen <= server.zset_max_ziplist_value)
zsetConvert(o,REDIS_ENCODING_ZIPLIST); zsetConvert(o,REDIS_ENCODING_ZIPLIST);
} else if (rdbtype == REDIS_RDB_TYPE_HASH) { } else if (rdbtype == REDIS_RDB_TYPE_HASH) {
size_t hashlen; size_t len;
int ret;
len = rdbLoadLen(rdb, NULL);
if (len == REDIS_RDB_LENERR) return NULL;
if ((hashlen = rdbLoadLen(rdb,NULL)) == REDIS_RDB_LENERR) return NULL;
o = createHashObject(); o = createHashObject();
/* Too many entries? Use an hash table. */
if (hashlen > server.hash_max_zipmap_entries)
convertToRealHash(o);
/* Load every key/value, then set it into the zipmap or hash
* table, as needed. */
while(hashlen--) {
robj *key, *val;
if ((key = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; /* Too many entries? Use an hash table. */
if ((val = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; if (len > server.hash_max_ziplist_entries)
/* If we are using a zipmap and there are too big values hashTypeConvert(o, REDIS_ENCODING_HT);
* the object is converted to real hash table encoding. */
if (o->encoding != REDIS_ENCODING_HT && /* Load every field and value into the ziplist */
((key->encoding == REDIS_ENCODING_RAW && while (o->encoding == REDIS_ENCODING_ZIPLIST && len-- > 0) {
sdslen(key->ptr) > server.hash_max_zipmap_value) || robj *field, *value;
(val->encoding == REDIS_ENCODING_RAW &&
sdslen(val->ptr) > server.hash_max_zipmap_value))) /* Load raw strings */
field = rdbLoadStringObject(rdb);
if (field == NULL) return NULL;
redisAssert(field->encoding == REDIS_ENCODING_RAW);
value = rdbLoadStringObject(rdb);
if (value == NULL) return NULL;
redisAssert(field->encoding == REDIS_ENCODING_RAW);
/* Convert to hash table if size threshold is exceeded */
if (sdslen(field->ptr) > server.hash_max_ziplist_value ||
sdslen(value->ptr) > server.hash_max_ziplist_value)
{ {
convertToRealHash(o); hashTypeConvert(o, REDIS_ENCODING_HT);
break;
} }
if (o->encoding == REDIS_ENCODING_ZIPMAP) { /* Add pair to ziplist */
unsigned char *zm = o->ptr; o->ptr = ziplistPush(o->ptr, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL);
robj *deckey, *decval; o->ptr = ziplistPush(o->ptr, value->ptr, sdslen(value->ptr), ZIPLIST_TAIL);
/* We need raw string objects to add them to the zipmap */
deckey = getDecodedObject(key);
decval = getDecodedObject(val);
zm = zipmapSet(zm,deckey->ptr,sdslen(deckey->ptr),
decval->ptr,sdslen(decval->ptr),NULL);
o->ptr = zm;
decrRefCount(deckey);
decrRefCount(decval);
decrRefCount(key);
decrRefCount(val);
} else {
key = tryObjectEncoding(key);
val = tryObjectEncoding(val);
dictAdd((dict*)o->ptr,key,val);
} }
/* Load remaining fields and values into the hash table */
while (o->encoding == REDIS_ENCODING_HT && len-- > 0) {
robj *field, *value;
/* Load encoded strings */
field = rdbLoadEncodedStringObject(rdb);
if (field == NULL) return NULL;
value = rdbLoadEncodedStringObject(rdb);
if (value == NULL) return NULL;
field = tryObjectEncoding(field);
value = tryObjectEncoding(value);
/* Add pair to hash table */
ret = dictAdd((dict*)o->ptr, field, value);
redisAssert(ret == REDIS_OK);
} }
/* All pairs should be read by now */
redisAssert(len == 0);
} else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP || } else if (rdbtype == REDIS_RDB_TYPE_HASH_ZIPMAP ||
rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST || rdbtype == REDIS_RDB_TYPE_LIST_ZIPLIST ||
rdbtype == REDIS_RDB_TYPE_SET_INTSET || rdbtype == REDIS_RDB_TYPE_SET_INTSET ||
rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST) rdbtype == REDIS_RDB_TYPE_ZSET_ZIPLIST ||
rdbtype == REDIS_RDB_TYPE_HASH_ZIPLIST)
{ {
robj *aux = rdbLoadStringObject(rdb); robj *aux = rdbLoadStringObject(rdb);
...@@ -890,10 +910,29 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -890,10 +910,29 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
* converted. */ * converted. */
switch(rdbtype) { switch(rdbtype) {
case REDIS_RDB_TYPE_HASH_ZIPMAP: case REDIS_RDB_TYPE_HASH_ZIPMAP:
/* Convert to ziplist encoded hash. This must be deprecated
* when loading dumps created by Redis 2.4 gets deprecated. */
{
unsigned char *zl = ziplistNew();
unsigned char *zi = zipmapRewind(o->ptr);
while (zi != NULL) {
unsigned char *fstr, *vstr;
unsigned int flen, vlen;
zi = zipmapNext(zi, &fstr, &flen, &vstr, &vlen);
zl = ziplistPush(zl, fstr, flen, ZIPLIST_TAIL);
zl = ziplistPush(zl, vstr, vlen, ZIPLIST_TAIL);
}
zfree(o->ptr);
o->ptr = zl;
o->type = REDIS_HASH; o->type = REDIS_HASH;
o->encoding = REDIS_ENCODING_ZIPMAP; o->encoding = REDIS_ENCODING_ZIPLIST;
if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
convertToRealHash(o); if (hashTypeLength(o) > server.hash_max_ziplist_entries)
hashTypeConvert(o, REDIS_ENCODING_HT);
}
break; break;
case REDIS_RDB_TYPE_LIST_ZIPLIST: case REDIS_RDB_TYPE_LIST_ZIPLIST:
o->type = REDIS_LIST; o->type = REDIS_LIST;
...@@ -913,6 +952,12 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { ...@@ -913,6 +952,12 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
if (zsetLength(o) > server.zset_max_ziplist_entries) if (zsetLength(o) > server.zset_max_ziplist_entries)
zsetConvert(o,REDIS_ENCODING_SKIPLIST); zsetConvert(o,REDIS_ENCODING_SKIPLIST);
break; break;
case REDIS_RDB_TYPE_HASH_ZIPLIST:
o->type = REDIS_HASH;
o->encoding = REDIS_ENCODING_ZIPLIST;
if (hashTypeLength(o) > server.hash_max_ziplist_entries)
hashTypeConvert(o, REDIS_ENCODING_HT);
break;
default: default:
redisPanic("Unknown encoding"); redisPanic("Unknown encoding");
break; break;
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#define REDIS_RDB_TYPE_LIST_ZIPLIST 10 #define REDIS_RDB_TYPE_LIST_ZIPLIST 10
#define REDIS_RDB_TYPE_SET_INTSET 11 #define REDIS_RDB_TYPE_SET_INTSET 11
#define REDIS_RDB_TYPE_ZSET_ZIPLIST 12 #define REDIS_RDB_TYPE_ZSET_ZIPLIST 12
#define REDIS_RDB_TYPE_HASH_ZIPLIST 13
/* Test if a type is an object type. */ /* Test if a type is an object type. */
#define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 12)) #define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 12))
......
...@@ -895,8 +895,8 @@ void initServerConfig() { ...@@ -895,8 +895,8 @@ void initServerConfig() {
server.maxmemory = 0; server.maxmemory = 0;
server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
server.maxmemory_samples = 3; server.maxmemory_samples = 3;
server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES; server.hash_max_ziplist_entries = REDIS_HASH_MAX_ZIPLIST_ENTRIES;
server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE; server.hash_max_ziplist_value = REDIS_HASH_MAX_ZIPLIST_VALUE;
server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES; server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES;
server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE; server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES; server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "adlist.h" /* Linked lists */ #include "adlist.h" /* Linked lists */
#include "zmalloc.h" /* total memory usage aware version of malloc/free */ #include "zmalloc.h" /* total memory usage aware version of malloc/free */
#include "anet.h" /* Networking the easy way */ #include "anet.h" /* Networking the easy way */
#include "zipmap.h" /* Compact string -> string data structure */
#include "ziplist.h" /* Compact list data structure */ #include "ziplist.h" /* Compact list data structure */
#include "intset.h" /* Compact integer set structure */ #include "intset.h" /* Compact integer set structure */
#include "version.h" /* Version macro */ #include "version.h" /* Version macro */
...@@ -194,8 +193,8 @@ ...@@ -194,8 +193,8 @@
#define AOF_FSYNC_EVERYSEC 2 #define AOF_FSYNC_EVERYSEC 2
/* Zip structure related defaults */ /* Zip structure related defaults */
#define REDIS_HASH_MAX_ZIPMAP_ENTRIES 512 #define REDIS_HASH_MAX_ZIPLIST_ENTRIES 512
#define REDIS_HASH_MAX_ZIPMAP_VALUE 64 #define REDIS_HASH_MAX_ZIPLIST_VALUE 64
#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512 #define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512
#define REDIS_LIST_MAX_ZIPLIST_VALUE 64 #define REDIS_LIST_MAX_ZIPLIST_VALUE 64
#define REDIS_SET_MAX_INTSET_ENTRIES 512 #define REDIS_SET_MAX_INTSET_ENTRIES 512
...@@ -610,8 +609,8 @@ struct redisServer { ...@@ -610,8 +609,8 @@ struct redisServer {
int sort_alpha; int sort_alpha;
int sort_bypattern; int sort_bypattern;
/* Zip structure config, see redis.conf for more information */ /* Zip structure config, see redis.conf for more information */
size_t hash_max_zipmap_entries; size_t hash_max_ziplist_entries;
size_t hash_max_zipmap_value; size_t hash_max_ziplist_value;
size_t list_max_ziplist_entries; size_t list_max_ziplist_entries;
size_t list_max_ziplist_value; size_t list_max_ziplist_value;
size_t set_max_intset_entries; size_t set_max_intset_entries;
...@@ -715,10 +714,10 @@ typedef struct { ...@@ -715,10 +714,10 @@ typedef struct {
* not both are required, store pointers in the iterator to avoid * not both are required, store pointers in the iterator to avoid
* unnecessary memory allocation for fields/values. */ * unnecessary memory allocation for fields/values. */
typedef struct { typedef struct {
robj *subject;
int encoding; int encoding;
unsigned char *zi;
unsigned char *zk, *zv; unsigned char *fptr, *vptr;
unsigned int zklen, zvlen;
dictIterator *di; dictIterator *di;
dictEntry *de; dictEntry *de;
...@@ -934,10 +933,9 @@ unsigned long setTypeSize(robj *subject); ...@@ -934,10 +933,9 @@ unsigned long setTypeSize(robj *subject);
void setTypeConvert(robj *subject, int enc); void setTypeConvert(robj *subject, int enc);
/* Hash data type */ /* Hash data type */
void convertToRealHash(robj *o); void hashTypeConvert(robj *o, int enc);
void hashTypeTryConversion(robj *subject, robj **argv, int start, int end); void hashTypeTryConversion(robj *subject, robj **argv, int start, int end);
void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2); void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2);
int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v, unsigned int *vlen);
robj *hashTypeGetObject(robj *o, robj *key); robj *hashTypeGetObject(robj *o, robj *key);
int hashTypeExists(robj *o, robj *key); int hashTypeExists(robj *o, robj *key);
int hashTypeSet(robj *o, robj *key, robj *value); int hashTypeSet(robj *o, robj *key, robj *value);
...@@ -946,7 +944,11 @@ unsigned long hashTypeLength(robj *o); ...@@ -946,7 +944,11 @@ unsigned long hashTypeLength(robj *o);
hashTypeIterator *hashTypeInitIterator(robj *subject); hashTypeIterator *hashTypeInitIterator(robj *subject);
void hashTypeReleaseIterator(hashTypeIterator *hi); void hashTypeReleaseIterator(hashTypeIterator *hi);
int hashTypeNext(hashTypeIterator *hi); int hashTypeNext(hashTypeIterator *hi);
int hashTypeCurrent(hashTypeIterator *hi, int what, robj **objval, unsigned char **v, unsigned int *vlen); void hashTypeCurrentFromZiplist(hashTypeIterator *hi, int what,
unsigned char **vstr,
unsigned int *vlen,
long long *vll);
void hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what, robj **dst);
robj *hashTypeCurrentObject(hashTypeIterator *hi, int what); robj *hashTypeCurrentObject(hashTypeIterator *hi, int what);
robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key); robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key);
......
This diff is collapsed.
...@@ -54,10 +54,10 @@ start_server {tags {"aofrw"}} { ...@@ -54,10 +54,10 @@ start_server {tags {"aofrw"}} {
} }
foreach d {string int} { foreach d {string int} {
foreach e {zipmap hashtable} { foreach e {ziplist hashtable} {
test "AOF rewrite of hash with $e encoding, $d data" { test "AOF rewrite of hash with $e encoding, $d data" {
r flushall r flushall
if {$e eq {zipmap}} {set len 10} else {set len 1000} if {$e eq {ziplist}} {set len 10} else {set len 1000}
for {set j 0} {$j < $len} {incr j} { for {set j 0} {$j < $len} {incr j} {
if {$d eq {string}} { if {$d eq {string}} {
set data [randstring 0 16 alpha] set data [randstring 0 16 alpha]
......
...@@ -14,8 +14,8 @@ start_server {tags {"hash"}} { ...@@ -14,8 +14,8 @@ start_server {tags {"hash"}} {
list [r hlen smallhash] list [r hlen smallhash]
} {8} } {8}
test {Is the small hash encoded with a zipmap?} { test {Is the small hash encoded with a ziplist?} {
assert_encoding zipmap smallhash assert_encoding ziplist smallhash
} }
test {HSET/HLEN - Big hash creation} { test {HSET/HLEN - Big hash creation} {
...@@ -33,7 +33,7 @@ start_server {tags {"hash"}} { ...@@ -33,7 +33,7 @@ start_server {tags {"hash"}} {
list [r hlen bighash] list [r hlen bighash]
} {1024} } {1024}
test {Is the big hash encoded with a zipmap?} { test {Is the big hash encoded with a ziplist?} {
assert_encoding hashtable bighash assert_encoding hashtable bighash
} }
...@@ -252,7 +252,7 @@ start_server {tags {"hash"}} { ...@@ -252,7 +252,7 @@ start_server {tags {"hash"}} {
lappend rv [r hexists bighash nokey] lappend rv [r hexists bighash nokey]
} {1 0 1 0} } {1 0 1 0}
test {Is a zipmap encoded Hash promoted on big payload?} { test {Is a ziplist encoded Hash promoted on big payload?} {
r hset smallhash foo [string repeat a 1024] r hset smallhash foo [string repeat a 1024]
r debug object smallhash r debug object smallhash
} {*hashtable*} } {*hashtable*}
...@@ -382,7 +382,7 @@ start_server {tags {"hash"}} { ...@@ -382,7 +382,7 @@ start_server {tags {"hash"}} {
lappend rv [string match "ERR*not*float*" $bigerr] lappend rv [string match "ERR*not*float*" $bigerr]
} {1 1} } {1 1}
test {Hash zipmap regression test for large keys} { test {Hash ziplist regression test for large keys} {
r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk a r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk a
r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk b r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk b
r hget hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk r hget hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment