From da727ad445a640950baa097124070468a0316cc9 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 12 Mar 2024 14:47:43 +0800 Subject: [PATCH] Fix redis-check-aof incorrectly considering data in manifest format as MP-AOF (#12958) The check in fileIsManifest misjudged the manifest file. For example, if resp aof contains "file", it will be considered a manifest file and the check will fail: ``` *3 $3 set $4 file $4 file ``` In #12951, if the preamble aof also contains it, it will also fail. Fixes #12951. the bug was happening if the the word "file" is mentioned in the first 1024 lines of the AOF. and now as soon as it finds a non-comment line it'll break (if it contains "file" or doesn't) --- src/aof.c | 4 +++- src/redis-check-aof.c | 10 +++++++++- tests/integration/aof.tcl | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/aof.c b/src/aof.c index c77b3f30c..34385f41e 100644 --- a/src/aof.c +++ b/src/aof.c @@ -117,7 +117,9 @@ aofInfo *aofInfoDup(aofInfo *orig) { return ai; } -/* Format aofInfo as a string and it will be a line in the manifest. */ +/* Format aofInfo as a string and it will be a line in the manifest. + * + * When update this format, make sure to update redis-check-aof as well. */ sds aofInfoFormat(sds buf, aofInfo *ai) { sds filename_repr = NULL; diff --git a/src/redis-check-aof.c b/src/redis-check-aof.c index 9c2eb5eef..0cc9c7b3f 100644 --- a/src/redis-check-aof.c +++ b/src/redis-check-aof.c @@ -234,6 +234,7 @@ int checkSingleAof(char *aof_filename, char *aof_filepath, int last_file, int fi struct redis_stat sb; if (redis_fstat(fileno(fp),&sb) == -1) { printf("Cannot stat file: %s, aborting...\n", aof_filename); + fclose(fp); exit(1); } @@ -345,6 +346,7 @@ int fileIsRDB(char *filepath) { struct redis_stat sb; if (redis_fstat(fileno(fp), &sb) == -1) { printf("Cannot stat file: %s\n", filepath); + fclose(fp); exit(1); } @@ -381,6 +383,7 @@ int fileIsManifest(char *filepath) { struct redis_stat sb; if (redis_fstat(fileno(fp), &sb) == -1) { printf("Cannot stat file: %s\n", filepath); + fclose(fp); exit(1); } @@ -397,15 +400,20 @@ int fileIsManifest(char *filepath) { break; } else { printf("Cannot read file: %s\n", filepath); + fclose(fp); exit(1); } } - /* Skip comments lines */ + /* We will skip comments lines. + * At present, the manifest format is fixed, see aofInfoFormat. + * We will break directly as long as it encounters other items. */ if (buf[0] == '#') { continue; } else if (!memcmp(buf, "file", strlen("file"))) { is_manifest = 1; + } else { + break; } } diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl index 0050ef577..137b2d863 100644 --- a/tests/integration/aof.tcl +++ b/tests/integration/aof.tcl @@ -481,6 +481,18 @@ tags {"aof external:skip"} { assert_match "*Start checking Old-Style AOF*is valid*" $result } + test {Test redis-check-aof for old style resp AOF - has data in the same format as manifest} { + create_aof $aof_dirpath $aof_file { + append_to_aof [formatCommand set file file] + append_to_aof [formatCommand set "file appendonly.aof.2.base.rdb seq 2 type b" "file appendonly.aof.2.base.rdb seq 2 type b"] + } + + catch { + exec src/redis-check-aof $aof_file + } result + assert_match "*Start checking Old-Style AOF*is valid*" $result + } + test {Test redis-check-aof for old style rdb-preamble AOF} { catch { exec src/redis-check-aof tests/assets/rdb-preamble.aof @@ -529,6 +541,19 @@ tags {"aof external:skip"} { assert_match "*Start checking Multi Part AOF*Start to check BASE AOF (RDB format)*DB preamble is OK, proceeding with AOF tail*BASE AOF*is valid*Start to check INCR files*INCR AOF*is valid*All AOF files and manifest are valid*" $result } + test {Test redis-check-aof for Multi Part AOF contains a format error} { + create_aof_manifest $aof_dirpath $aof_manifest_file { + append_to_manifest "file appendonly.aof.1.base.aof seq 1 type b\n" + append_to_manifest "file appendonly.aof.1.incr.aof seq 1 type i\n" + append_to_manifest "!!!\n" + } + + catch { + exec src/redis-check-aof $aof_manifest_file + } result + assert_match "*Invalid AOF manifest file format*" $result + } + test {Test redis-check-aof only truncates the last file for Multi Part AOF in fix mode} { create_aof $aof_dirpath $aof_base_file { append_to_aof [formatCommand set foo hello]