diff --git a/redis.c b/redis.c index f213b3b1fdc2dbdcdf84308b34ffddbde8c94e94..f451f9169fc4b1cef87c70476bc5219b85c392a3 100644 --- a/redis.c +++ b/redis.c @@ -226,6 +226,10 @@ #define APPENDFSYNC_ALWAYS 1 #define APPENDFSYNC_EVERYSEC 2 +/* Hashes related defaults */ +#define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64 +#define REDIS_HASH_MAX_ZIPMAP_VALUE 512 + /* We can print the stacktrace, so our assert is defined this way: */ #define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1))) static void _redisAssert(char *estr, char *file, int line); @@ -391,6 +395,9 @@ struct redisServer { off_t vm_page_size; off_t vm_pages; unsigned long long vm_max_memory; + /* Hashes config */ + size_t hash_max_zipmap_entries; + size_t hash_max_zipmap_value; /* Virtual memory state */ FILE *vm_fp; int vm_fd; @@ -1465,6 +1472,8 @@ static void initServerConfig() { server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */ server.vm_max_threads = 4; server.vm_blocked_clients = 0; + server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES; + server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE; resetServerSaveParams(); @@ -1725,6 +1734,12 @@ static void loadServerConfig(char *filename) { server.vm_pages = strtoll(argv[1], NULL, 10); } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) { server.vm_max_threads = strtoll(argv[1], NULL, 10); + } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2){ + server.hash_max_zipmap_entries = strtol(argv[1], NULL, 10); + } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2){ + server.hash_max_zipmap_value = strtol(argv[1], NULL, 10); + } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) { + server.vm_max_threads = strtoll(argv[1], NULL, 10); } else { err = "Bad directive or wrong number of arguments"; goto loaderr; } @@ -2603,7 +2618,17 @@ static void freeZsetObject(robj *o) { } static void freeHashObject(robj *o) { - dictRelease((dict*) o->ptr); + switch (o->encoding) { + case REDIS_ENCODING_HT: + dictRelease((dict*) o->ptr); + break; + case REDIS_ENCODING_ZIPMAP: + zfree(o->ptr); + break; + default: + redisAssert(0); + break; + } } static void incrRefCount(robj *o) { @@ -5577,7 +5602,7 @@ static void zrankCommand(redisClient *c) { } } -/* ==================================== Hash ================================ */ +/* =================================== Hashes =============================== */ static void hsetCommand(redisClient *c) { int update = 0; robj *o = lookupKeyWrite(c->db,c->argv[1]); @@ -5597,6 +5622,7 @@ static void hsetCommand(redisClient *c) { zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr), c->argv[3]->ptr,sdslen(c->argv[3]->ptr),&update); + o->ptr = zm; } else { if (dictAdd(o->ptr,c->argv[2],c->argv[3]) == DICT_OK) { incrRefCount(c->argv[2]); diff --git a/redis.conf b/redis.conf index 2923a3aa4973aea3f778db2980bd1e5d64d1f260..0ed593d2446f0a3222cf7c8bde8a3d3f931db186 100644 --- a/redis.conf +++ b/redis.conf @@ -271,3 +271,10 @@ glueoutputbuf yes # your development environment so that we can test it better. shareobjects no shareobjectspoolsize 1024 + +# Hashes are encoded in a special way (much more memory efficient) when they +# have at max a given numer of elements, and the biggest element does not +# exceed a given threshold. You can configure this limits with the following +# configuration directives. +hash-max-zipmap-entries 64 +hash-max-zipmap-value 512 diff --git a/zipmap.c b/zipmap.c index 05bf6d6d9983d64d4055d43379da1f626b6b642c..5729c18f733faa4deadc104dd23ae6d464236ad4 100644 --- a/zipmap.c +++ b/zipmap.c @@ -405,6 +405,13 @@ int main(void) { unsigned char *zm; zm = zipmapNew(); + + zm = zipmapSet(zm,(unsigned char*) "name",4, (unsigned char*) "foo",3,NULL); + zm = zipmapSet(zm,(unsigned char*) "surname",7, (unsigned char*) "foo",3,NULL); + zm = zipmapSet(zm,(unsigned char*) "age",3, (unsigned char*) "foo",3,NULL); + zipmapRepr(zm); + exit(1); + zm = zipmapSet(zm,(unsigned char*) "hello",5, (unsigned char*) "world!",6,NULL); zm = zipmapSet(zm,(unsigned char*) "foo",3, (unsigned char*) "bar",3,NULL); zm = zipmapSet(zm,(unsigned char*) "foo",3, (unsigned char*) "!",1,NULL);