From 9fed86b0affe4f246dcf0a41836cf7f6ae6875c1 Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 18 Aug 2026 07:54:47 +0800 Subject: [PATCH 1/4] fix: persist replication state for replica PSYNC after restart (#4412) --- src/rdb.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/rdb.c b/src/rdb.c index 951321db4ca..0bfdc981a21 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -4289,5 +4289,15 @@ rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi) { rsi->repl_stream_db = server.cached_primary->db->id; return rsi; } + + /* If the instance is a replica but has no active primary connection + * and no cached primary (e.g., during a clean shutdown where the + * primary client was freed before the RDB save), we can still save + * the replication info using the server's current state. This allows + * a restarted replica to attempt partial resynchronization. */ + if (server.primary_host) { + rsi->repl_stream_db = 0; /* Safe default, SELECT will be sent */ + return rsi; + } return NULL; } From 1eac2bea46b7bd59249b86f391b927e1f1f6b0f9 Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 18 Aug 2026 07:54:48 +0800 Subject: [PATCH 2/4] fix: persist replication state for replica PSYNC after restart (#4412) --- src/aof.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aof.c b/src/aof.c index 2d18aae8210..46d9b6d0c7e 100644 --- a/src/aof.c +++ b/src/aof.c @@ -1524,7 +1524,7 @@ struct client *createAOFClient(void) { * AOF_NOT_EXIST: AOF file doesn't exist. * AOF_EMPTY: The AOF file is empty (nothing to load). * AOF_FAILED: Failed to load the AOF file. */ -int loadSingleAppendOnlyFile(char *filename) { +int loadSingleAppendOnlyFile(char *filename, rdbSaveInfo *rsi) { struct client *fakeClient; struct valkey_stat sb; int old_aof_state = server.aof_state; @@ -1583,7 +1583,7 @@ int loadSingleAppendOnlyFile(char *filename) { if (fseek(fp, 0, SEEK_SET) == -1) goto readerr; rioInitWithFile(&rdb, fp); - if (rdbLoadRio(&rdb, RDBFLAGS_AOF_PREAMBLE, NULL) != RDB_OK) { + if (rdbLoadRio(&rdb, RDBFLAGS_AOF_PREAMBLE, rsi) != RDB_OK) { if (old_style) serverLog(LL_WARNING, "Error reading the RDB preamble of the AOF file %s, AOF loading aborted", filename); @@ -1777,7 +1777,7 @@ int loadSingleAppendOnlyFile(char *filename) { } /* Load the AOF files according the aofManifest pointed by am. */ -int loadAppendOnlyFiles(aofManifest *am) { +int loadAppendOnlyFiles(aofManifest *am, rdbSaveInfo *rsi) { serverAssert(am != NULL); int status, ret = AOF_OK; long long start; @@ -1831,7 +1831,7 @@ int loadAppendOnlyFiles(aofManifest *am) { base_size = getAppendOnlyFileSize(aof_name, NULL); last_file = ++aof_num == total_num; start = ustime(); - ret = loadSingleAppendOnlyFile(aof_name); + ret = loadSingleAppendOnlyFile(aof_name, rsi); if (ret == AOF_OK || (ret == AOF_TRUNCATED && last_file)) { serverLog(LL_NOTICE, "DB loaded from base file %s: %.3f seconds", aof_name, (float)(ustime() - start) / 1000000); @@ -1861,7 +1861,7 @@ int loadAppendOnlyFiles(aofManifest *am) { updateLoadingFileName(aof_name); last_file = ++aof_num == total_num; start = ustime(); - ret = loadSingleAppendOnlyFile(aof_name); + ret = loadSingleAppendOnlyFile(aof_name, rsi); if (ret == AOF_OK || (ret == AOF_TRUNCATED && last_file)) { serverLog(LL_NOTICE, "DB loaded from incr file %s: %.3f seconds", aof_name, (float)(ustime() - start) / 1000000); From ae949b040831d17936183315c44c8b02b57070fb Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 18 Aug 2026 07:54:51 +0800 Subject: [PATCH 3/4] fix: persist replication state for replica PSYNC after restart (#4412) --- src/server.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/server.c b/src/server.c index 3f68250339e..e206fc41979 100644 --- a/src/server.c +++ b/src/server.c @@ -7333,10 +7333,45 @@ int checkForSentinelMode(int argc, char **argv, char *exec_name) { void loadDataFromDisk(void) { ustime_t start = ustime(); if (server.aof_state == AOF_ON) { - int ret = loadAppendOnlyFiles(server.aof_manifest); + rdbSaveInfo rsi = RDB_SAVE_INFO_INIT; + int rsi_is_valid = 0; + int ret = loadAppendOnlyFiles(server.aof_manifest, &rsi); if (ret == AOF_FAILED || ret == AOF_OPEN_ERR) exit(1); - if (ret != AOF_NOT_EXIST) + if (ret != AOF_NOT_EXIST) { serverLog(LL_NOTICE, "DB loaded from append only file: %.3f seconds", (float)(ustime() - start) / 1000000); + /* Restore the replication ID / offset from the AOF file's RDB preamble. */ + if (rsi.repl_id_is_set && rsi.repl_offset != -1 && + rsi.repl_stream_db != -1) { + rsi_is_valid = 1; + if (!iAmPrimary()) { + memcpy(server.replid, rsi.repl_id, sizeof(server.replid)); + server.primary_repl_offset = rsi.repl_offset; + /* If this is a replica, create a cached primary from this + * information, in order to allow partial resynchronizations + * with primaries. */ + replicationCachePrimaryUsingMyself(); + selectDb(server.cached_primary, rsi.repl_stream_db); + } else { + /* If this is a primary, we can save the replication info + * as secondary ID and offset, in order to allow replicas + * to partial resynchronizations with primaries. */ + memcpy(server.replid2, rsi.repl_id, sizeof(server.replid)); + server.second_replid_offset = rsi.repl_offset + 1; + /* Rebase primary_repl_offset from rsi.repl_offset. */ + server.primary_repl_offset += rsi.repl_offset; + serverAssert(server.repl_backlog); + server.repl_backlog->offset = server.primary_repl_offset - server.repl_backlog->histlen + 1; + rebaseReplicationBuffer(rsi.repl_offset); + server.repl_no_replicas_since = time(NULL); + } + } + } + /* We always create replication backlog if server is a primary, we need + * it because we put DELs in it when loading expired keys in RDB, but + * if AOF doesn't have replication info or there is no AOF, it is not + * possible to support partial resynchronization, to avoid extra memory + * of replication backlog, we drop it. */ + if (!rsi_is_valid && server.repl_backlog) freeReplicationBacklog(); } else { rdbSaveInfo rsi = RDB_SAVE_INFO_INIT; int rsi_is_valid = 0; From c30c8d1755c68e3cdc1566a14ddc0061a2f16c7d Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 18 Aug 2026 07:54:53 +0800 Subject: [PATCH 4/4] fix: persist replication state for replica PSYNC after restart (#4412) --- src/server.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.h b/src/server.h index d34fed6851b..ca412c6a5f6 100644 --- a/src/server.h +++ b/src/server.h @@ -3316,7 +3316,7 @@ void flushAppendOnlyFile(int force); void feedAppendOnlyFile(int dictid, robj **argv, int argc); void aofRemoveTempFile(pid_t childpid, int from_signal); int rewriteAppendOnlyFileBackground(void); -int loadAppendOnlyFiles(aofManifest *am); +int loadAppendOnlyFiles(aofManifest *am, rdbSaveInfo *rsi); void stopAppendOnly(void); int startAppendOnly(void); int restartAOFWithSyncRdb(void);