Skip to content

Commit

Permalink
Support RDB compatability with Redis 7.2.4 RDB format (valkey-io#665)
Browse files Browse the repository at this point in the history
This PR makes our current RDB format compatible with the Redis 7.2.4 RDB
format. there are 2 changes introduced in this PR:
1. Move back the RDB version to 11
2. Make slot info section persist as AUX data instead of dedicated
section.

We have introduced slot-info as part of the work to replace cluster
metadata with slot specific dictionaries. This caused us to bump the RDB
version and thus we prevent downgrade (which is conceptualy O.K but
better be prevented). We do not require the slot-info section to exist,
so making it an AUX section will help suppport version downgrade from
Valkey 8.

fixes: [valkey-io#645](valkey-io#645)

NOTE: tested manually by:
1. connecting Redis 7.2.4 replica to a Valkey 8(RC) 
2. upgrade/downgrade Redis 7.2.4 cluster and Valkey 8(RC) cluster

---------

Signed-off-by: ranshid <[email protected]>
Co-authored-by: Viktor Söderqvist <[email protected]>
  • Loading branch information
ranshid and zuiderkwast authored Jun 18, 2024
1 parent a2cc2fe commit be2c321
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 30 deletions.
47 changes: 25 additions & 22 deletions src/rdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,15 +1349,14 @@ ssize_t rdbSaveDb(rio *rdb, int dbid, int rdbflags, long *key_counter) {
int curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it);
/* Save slot info. */
if (server.cluster_enabled && curr_slot != last_slot) {
if ((res = rdbSaveType(rdb, RDB_OPCODE_SLOT_INFO)) < 0) goto werr;
written += res;
if ((res = rdbSaveLen(rdb, curr_slot)) < 0) goto werr;
written += res;
if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->keys, curr_slot))) < 0) goto werr;
written += res;
if ((res = rdbSaveLen(rdb, kvstoreDictSize(db->expires, curr_slot))) < 0) goto werr;
written += res;
sds slot_info = sdscatprintf(sdsempty(), "%i,%lu,%lu", curr_slot, kvstoreDictSize(db->keys, curr_slot),
kvstoreDictSize(db->expires, curr_slot));
if ((res = rdbSaveAuxFieldStrStr(rdb, "slot-info", slot_info)) < 0) {
sdsfree(slot_info);
goto werr;
}
last_slot = curr_slot;
sdsfree(slot_info);
}
sds keystr = dictGetKey(de);
robj key, *o = dictGetVal(de);
Expand Down Expand Up @@ -3078,20 +3077,6 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
if ((expires_size = rdbLoadLen(rdb, NULL)) == RDB_LENERR) goto eoferr;
should_expand_db = 1;
continue; /* Read next opcode. */
} else if (type == RDB_OPCODE_SLOT_INFO) {
uint64_t slot_id, slot_size, expires_slot_size;
if ((slot_id = rdbLoadLen(rdb, NULL)) == RDB_LENERR) goto eoferr;
if ((slot_size = rdbLoadLen(rdb, NULL)) == RDB_LENERR) goto eoferr;
if ((expires_slot_size = rdbLoadLen(rdb, NULL)) == RDB_LENERR) goto eoferr;
if (!server.cluster_enabled) {
continue; /* Ignore gracefully. */
}
/* In cluster mode we resize individual slot specific dictionaries based on the number of keys that slot
* holds. */
kvstoreDictExpand(db->keys, slot_id, slot_size);
kvstoreDictExpand(db->expires, slot_id, expires_slot_size);
should_expand_db = 0;
continue; /* Read next opcode. */
} else if (type == RDB_OPCODE_AUX) {
/* AUX: generic string-string fields. Use to add state to RDB
* which is backward compatible. Implementations of RDB loading
Expand Down Expand Up @@ -3141,6 +3126,24 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
if (isbase) serverLog(LL_NOTICE, "RDB is base AOF");
} else if (!strcasecmp(auxkey->ptr, "redis-bits")) {
/* Just ignored. */
} else if (!strcasecmp(auxkey->ptr, "slot-info")) {
int slot_id;
unsigned long slot_size, expires_slot_size;
/* Try to parse the slot information. In case the number of parsed arguments is smaller than expected
* we'll fail the RDB load. */
if (sscanf(auxval->ptr, "%i,%lu,%lu", &slot_id, &slot_size, &expires_slot_size) < 3) {
decrRefCount(auxkey);
decrRefCount(auxval);
goto eoferr;
}

if (server.cluster_enabled) {
/* In cluster mode we resize individual slot specific dictionaries based on the number of keys that
* slot holds. */
kvstoreDictExpand(db->keys, slot_id, slot_size);
kvstoreDictExpand(db->expires, slot_id, expires_slot_size);
should_expand_db = 0;
}
} else {
/* Check if this is a dynamic aux field */
int handled = 0;
Expand Down
3 changes: 1 addition & 2 deletions src/rdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

/* The current RDB version. When the format changes in a way that is no longer
* backward compatible this number gets incremented. */
#define RDB_VERSION 12
#define RDB_VERSION 11

/* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of
Expand Down Expand Up @@ -101,7 +101,6 @@
#define rdbIsObjectType(t) (((t) >= 0 && (t) <= 7) || ((t) >= 9 && (t) <= 21))

/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
#define RDB_OPCODE_SLOT_INFO 244 /* Individual slot info, such as slot id and size (cluster mode only). */
#define RDB_OPCODE_FUNCTION2 245 /* function library data */
#define RDB_OPCODE_FUNCTION_PRE_GA 246 /* old function library data for 7.0 rc1 and rc2 */
#define RDB_OPCODE_MODULE_AUX 247 /* Module auxiliary data. */
Expand Down
6 changes: 0 additions & 6 deletions src/valkey-check-rdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,6 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
if ((db_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR) goto eoferr;
if ((expires_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR) goto eoferr;
continue; /* Read type again. */
} else if (type == RDB_OPCODE_SLOT_INFO) {
uint64_t slot_id, slot_size, expires_slot_size;
if ((slot_id = rdbLoadLen(&rdb, NULL)) == RDB_LENERR) goto eoferr;
if ((slot_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR) goto eoferr;
if ((expires_slot_size = rdbLoadLen(&rdb, NULL)) == RDB_LENERR) goto eoferr;
continue; /* Read type again. */
} else if (type == RDB_OPCODE_AUX) {
/* AUX: generic string-string fields. Use to add state to RDB
* which is backward compatible. Implementations of RDB loading
Expand Down

0 comments on commit be2c321

Please sign in to comment.