Skip to content

Commit 206cd21

Browse files
committed
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.
1 parent 1a30e7d commit 206cd21

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/rdb.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,34 @@ int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,
682682
return 1;
683683
}
684684

685+
/* Save an AUX field. */
686+
int rdbSaveAuxField(rio *rdb, void *key, size_t keylen, void *val, size_t vallen) {
687+
if (rdbSaveType(rdb,REDIS_RDB_OPCODE_AUX) == -1) return -1;
688+
if (rdbSaveRawString(rdb,key,keylen) == -1) return -1;
689+
if (rdbSaveRawString(rdb,val,vallen) == -1) return -1;
690+
return 1;
691+
}
692+
693+
/* Wrapper for rdbSaveAuxField() used when key/val length can be obtained
694+
* with strlen(). */
695+
int rdbSaveAuxFieldStrStr(rio *rdb, char *key, char *val) {
696+
return rdbSaveAuxField(rdb,key,strlen(key),val,strlen(val));
697+
}
698+
699+
/* Wrapper for strlen(key) + integer type (up to long long range). */
700+
int rdbSaveAuxFieldStrInt(rio *rdb, char *key, long long val) {
701+
char buf[REDIS_LONGSTR_SIZE];
702+
int vlen = ll2string(buf,sizeof(buf),val);
703+
return rdbSaveAuxField(rdb,key,strlen(key),buf,vlen);
704+
}
705+
706+
/* Save a few default AUX fields with information about the RDB generated. */
707+
int rdbSaveInfoAuxFields(rio *rdb) {
708+
if (rdbSaveAuxFieldStrStr(rdb,"redis-ver",REDIS_VERSION) == -1) return -1;
709+
if (rdbSaveAuxFieldStrInt(rdb,"ctime",time(NULL)) == -1) return -1;
710+
return 1;
711+
}
712+
685713
/* Produces a dump of the database in RDB format sending it to the specified
686714
* Redis I/O channel. On success REDIS_OK is returned, otherwise REDIS_ERR
687715
* is returned and part of the output, or all the output, can be
@@ -702,6 +730,7 @@ int rdbSaveRio(rio *rdb, int *error) {
702730
rdb->update_cksum = rioGenericUpdateChecksum;
703731
snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);
704732
if (rdbWriteRaw(rdb,magic,9) == -1) goto werr;
733+
if (rdbSaveInfoAuxFields(rdb) == -1) goto werr;
705734

706735
for (j = 0; j < server.dbnum; j++) {
707736
redisDb *db = server.db+j;
@@ -1268,6 +1297,31 @@ int rdbLoad(char *filename) {
12681297
dictExpand(db->dict,db_size);
12691298
dictExpand(db->expires,expires_size);
12701299
continue; /* Read type again. */
1300+
} else if (type == REDIS_RDB_OPCODE_AUX) {
1301+
/* AUX: generic string-string fields. Use to add state to RDB
1302+
* which is backward compatible. Implementations of RDB loading
1303+
* are requierd to skip AUX fields they don't understand.
1304+
*
1305+
* An AUX field is composed of two strings: key and value. */
1306+
robj *auxkey, *auxval;
1307+
if ((auxkey = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
1308+
if ((auxval = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
1309+
1310+
if (((char*)auxkey->ptr)[0] == '%') {
1311+
/* All the fields with a name staring with '%' are considered
1312+
* information fields and are logged at startup with a log
1313+
* level of NOTICE. */
1314+
redisLog(REDIS_NOTICE,"RDB '%s': %s", auxkey->ptr, auxval->ptr);
1315+
} else {
1316+
/* We ignore fields we don't understand, as by AUX field
1317+
* contract. */
1318+
redisLog(REDIS_DEBUG,"Unrecognized RDB AUX field: '%s'",
1319+
auxkey->ptr);
1320+
}
1321+
1322+
zfree(auxkey);
1323+
zfree(auxval);
1324+
continue; /* Read type again. */
12711325
}
12721326

12731327
/* Read key */

src/rdb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 14))
9090

9191
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
92+
#define REDIS_RDB_OPCODE_AUX 250
9293
#define REDIS_RDB_OPCODE_RESIZEDB 251
9394
#define REDIS_RDB_OPCODE_EXPIRETIME_MS 252
9495
#define REDIS_RDB_OPCODE_EXPIRETIME 253

0 commit comments

Comments
 (0)