From e8614a1a77d2989f7be3cb7b24cd88b01f14f17e Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 7 Jan 2015 11:08:41 +0100 Subject: [PATCH] New RDB v7 opcode: RESIZEDB. The new opcode is an hint about the size of the dataset (keys and number of expires) we are going to load for a given Redis database inside the RDB file. Since hash tables are resized accordingly ASAP, useless rehashing is avoided, speeding up load times significantly, in the order of ~ 20% or more for larger data sets. Related issue: #1719 --- src/rdb.c | 26 +++++++++++++++++++++++++- src/rdb.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/rdb.c b/src/rdb.c index 4c8a2282..3e41d404 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -714,6 +714,21 @@ int rdbSaveRio(rio *rdb, int *error) { if (rdbSaveType(rdb,REDIS_RDB_OPCODE_SELECTDB) == -1) goto werr; if (rdbSaveLen(rdb,j) == -1) goto werr; + /* Write the RESIZE DB opcode. We trim the size to UINT32_MAX, which + * is currently the largest type we are able to represent in RDB sizes. + * However this does not limit the actual size of the DB to load since + * these sizes are just hints to resize the hash tables. */ + uint32_t db_size, expires_size; + db_size = (dictSize(db->dict) <= UINT32_MAX) ? + dictSize(db->dict) : + UINT32_MAX; + expires_size = (dictSize(db->dict) <= UINT32_MAX) ? + dictSize(db->expires) : + UINT32_MAX; + if (rdbSaveType(rdb,REDIS_RDB_OPCODE_RESIZEDB) == -1) goto werr; + if (rdbSaveLen(rdb,db_size) == -1) goto werr; + if (rdbSaveLen(rdb,expires_size) == -1) goto werr; + /* Iterate this DB writing every entry */ while((de = dictNext(di)) != NULL) { sds keystr = dictGetKey(de); @@ -1226,7 +1241,7 @@ int rdbLoad(char *filename) { if (type == REDIS_RDB_OPCODE_EOF) break; - /* Handle SELECT DB opcode as a special case */ + /* Handle special opcodes: SELECTDB, RESIZEDB, AUX. */ if (type == REDIS_RDB_OPCODE_SELECTDB) { if ((dbid = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR) goto eoferr; @@ -1236,6 +1251,15 @@ int rdbLoad(char *filename) { } db = server.db+dbid; continue; + } else if (type == REDIS_RDB_OPCODE_RESIZEDB) { + uint32_t db_size, expires_size; + if ((db_size = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR) + goto eoferr; + if ((expires_size = rdbLoadLen(&rdb,NULL)) == REDIS_RDB_LENERR) + goto eoferr; + dictExpand(db->dict,db_size); + dictExpand(db->expires,expires_size); + continue; } /* Read key */ if ((key = rdbLoadStringObject(&rdb)) == NULL) goto eoferr; diff --git a/src/rdb.h b/src/rdb.h index 55b3d261..99bb19ab 100644 --- a/src/rdb.h +++ b/src/rdb.h @@ -89,6 +89,7 @@ #define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 14)) /* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */ +#define REDIS_RDB_OPCODE_RESIZEDB 251 #define REDIS_RDB_OPCODE_EXPIRETIME_MS 252 #define REDIS_RDB_OPCODE_EXPIRETIME 253 #define REDIS_RDB_OPCODE_SELECTDB 254