summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-01-08 08:56:35 +0100
committerantirez <antirez@gmail.com>2015-01-08 08:56:35 +0100
commitdee2318469e0de308a0a3b0e475bbeab47c40fcb (patch)
treec67cd41601f3c6666f59446013101c9bcdea7112
parent734480be1427cd83495b20724e8b589b714a979f (diff)
downloadredis-dee2318469e0de308a0a3b0e475bbeab47c40fcb.tar.gz
RDB AUX fields support.
This commit introduces a new RDB data type called 'aux'. It is used in order to insert inside an RDB file key-value pairs that may serve different needs, without breaking backward compatibility when new informations are embedded inside an RDB file. The contract between Redis versions is to ignore unknown aux fields when encountered. Aux fields can be used in order to: 1. Augment the RDB file with info like version of Redis that created the RDB file, creation time, used memory while the RDB was created, and so forth. 2. Add state about Redis inside the RDB file that we need to reload later: replication offset, previos master run ID, in order to improve failovers safety and allow partial resynchronization after a slave restart. 3. Anything that we may want to add to RDB files without breaking the ability of past versions of Redis to load the file.
-rw-r--r--src/rdb.c54
-rw-r--r--src/rdb.h1
2 files changed, 55 insertions, 0 deletions
diff --git a/src/rdb.c b/src/rdb.c
index cda4c8921..23dc89833 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -682,6 +682,34 @@ int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,
return 1;
}
+/* Save an AUX field. */
+int rdbSaveAuxField(rio *rdb, void *key, size_t keylen, void *val, size_t vallen) {
+ if (rdbSaveType(rdb,REDIS_RDB_OPCODE_AUX) == -1) return -1;
+ if (rdbSaveRawString(rdb,key,keylen) == -1) return -1;
+ if (rdbSaveRawString(rdb,val,vallen) == -1) return -1;
+ return 1;
+}
+
+/* Wrapper for rdbSaveAuxField() used when key/val length can be obtained
+ * with strlen(). */
+int rdbSaveAuxFieldStrStr(rio *rdb, char *key, char *val) {
+ return rdbSaveAuxField(rdb,key,strlen(key),val,strlen(val));
+}
+
+/* Wrapper for strlen(key) + integer type (up to long long range). */
+int rdbSaveAuxFieldStrInt(rio *rdb, char *key, long long val) {
+ char buf[REDIS_LONGSTR_SIZE];
+ int vlen = ll2string(buf,sizeof(buf),val);
+ return rdbSaveAuxField(rdb,key,strlen(key),buf,vlen);
+}
+
+/* Save a few default AUX fields with information about the RDB generated. */
+int rdbSaveInfoAuxFields(rio *rdb) {
+ if (rdbSaveAuxFieldStrStr(rdb,"redis-ver",REDIS_VERSION) == -1) return -1;
+ if (rdbSaveAuxFieldStrInt(rdb,"ctime",time(NULL)) == -1) return -1;
+ return 1;
+}
+
/* Produces a dump of the database in RDB format sending it to the specified
* Redis I/O channel. On success REDIS_OK is returned, otherwise REDIS_ERR
* is returned and part of the output, or all the output, can be
@@ -702,6 +730,7 @@ int rdbSaveRio(rio *rdb, int *error) {
rdb->update_cksum = rioGenericUpdateChecksum;
snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);
if (rdbWriteRaw(rdb,magic,9) == -1) goto werr;
+ if (rdbSaveInfoAuxFields(rdb) == -1) goto werr;
for (j = 0; j < server.dbnum; j++) {
redisDb *db = server.db+j;
@@ -1268,6 +1297,31 @@ int rdbLoad(char *filename) {
dictExpand(db->dict,db_size);
dictExpand(db->expires,expires_size);
continue; /* Read type again. */
+ } else if (type == REDIS_RDB_OPCODE_AUX) {
+ /* AUX: generic string-string fields. Use to add state to RDB
+ * which is backward compatible. Implementations of RDB loading
+ * are requierd to skip AUX fields they don't understand.
+ *
+ * An AUX field is composed of two strings: key and value. */
+ robj *auxkey, *auxval;
+ if ((auxkey = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
+ if ((auxval = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
+
+ if (((char*)auxkey->ptr)[0] == '%') {
+ /* All the fields with a name staring with '%' are considered
+ * information fields and are logged at startup with a log
+ * level of NOTICE. */
+ redisLog(REDIS_NOTICE,"RDB '%s': %s", auxkey->ptr, auxval->ptr);
+ } else {
+ /* We ignore fields we don't understand, as by AUX field
+ * contract. */
+ redisLog(REDIS_DEBUG,"Unrecognized RDB AUX field: '%s'",
+ auxkey->ptr);
+ }
+
+ zfree(auxkey);
+ zfree(auxval);
+ continue; /* Read type again. */
}
/* Read key */
diff --git a/src/rdb.h b/src/rdb.h
index 99bb19abe..6319f5d02 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_AUX 250
#define REDIS_RDB_OPCODE_RESIZEDB 251
#define REDIS_RDB_OPCODE_EXPIRETIME_MS 252
#define REDIS_RDB_OPCODE_EXPIRETIME 253