From fbd9dc6039a0cae03472839b3e21657915eac48d Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Sep 2014 10:12:50 +0200 Subject: [PATCH 1/5] Don't propagate SAVE. This is a general fix (check that dirty delta is positive) but actually should have as the only effect fixing the SAVE propagation to AOF and slaves. --- src/redis.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/redis.c b/src/redis.c index 63225955..6fdc2f68 100644 --- a/src/redis.c +++ b/src/redis.c @@ -1914,6 +1914,7 @@ void call(redisClient *c, int flags) { c->cmd->proc(c); duration = ustime()-start; dirty = server.dirty-dirty; + if (dirty < 0) dirty = 0; /* When EVAL is called loading the AOF we don't want commands called * from Lua to go into the slowlog or to populate statistics. */ From 9faeff02151c8d6f0c943feb7e771d0ae292ada9 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Sep 2014 10:32:58 +0200 Subject: [PATCH 2/5] On AOF end of file, truncate the AOF to last valid command. Recently we introduced the ability to load truncated AOFs, but unfortuantely the support was broken since the server, after loading the truncated AOF, continues appending to the file that is corrupted at the end. The problem is fixed only in the next AOF rewrite. This commit fixes the issue by truncating the AOF to the last valid opcode, and aborting if it is not possible to truncate the file correctly. --- src/aof.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/aof.c b/src/aof.c index 9231812e..350ea8d9 100644 --- a/src/aof.c +++ b/src/aof.c @@ -558,6 +558,7 @@ int loadAppendOnlyFile(char *filename) { struct redis_stat sb; int old_aof_state = server.aof_state; long loops = 0; + off_t valid_up_to = 0; /* Offset of the latest well-formed command loaded. */ if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) { server.aof_current_size = 0; @@ -647,6 +648,7 @@ int loadAppendOnlyFile(char *filename) { /* Clean up. Command code may have changed argv/argc so we use the * argv/argc of the client instead of the local variables. */ freeFakeClientArgv(fakeClient); + if (server.aof_load_truncated) valid_up_to = ftello(fp); } /* This point can only be reached when EOF is reached without errors. @@ -671,9 +673,20 @@ readerr: /* Read error. If feof(fp) is true, fall through to unexpected EOF. */ uxeof: /* Unexpected AOF end of file. */ if (server.aof_load_truncated) { redisLog(REDIS_WARNING,"!!! Warning: short read while loading the AOF file !!!"); - redisLog(REDIS_WARNING, - "AOF loaded anyway because aof-load-truncated is enabled"); - goto loaded_ok; + redisLog(REDIS_WARNING,"!!! Truncating the AOF at offset %llu !!!", + (unsigned long long) valid_up_to); + if (valid_up_to == -1 || truncate(filename,valid_up_to) == -1) { + if (valid_up_to == -1) { + redisLog(REDIS_WARNING,"Last valid command offset is invalid"); + } else { + redisLog(REDIS_WARNING,"Error truncating the AOF file: %s", + strerror(errno)); + } + } else { + redisLog(REDIS_WARNING, + "AOF loaded anyway because aof-load-truncated is enabled"); + goto loaded_ok; + } } redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file. You can: 1) Make a backup of your AOF file, then use ./redis-check-aof --fix . 2) Alternatively you can set the 'aof-load-truncated' configuration option to yes and restart the server."); exit(1); From 01f7db608dbf77c24a9735d686aba35dc250a96f Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Sep 2014 10:57:40 +0200 Subject: [PATCH 3/5] Seek at the end of AOF after truncate call. It is not clear if files open in append only mode will automatically fix their offset after a truncate(2) operation. This commit makes sure that we reposition the AOF file descriptor offset at the end of the file after a truncated AOF is loaded and trimmed to the last valid command. --- src/aof.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/aof.c b/src/aof.c index 350ea8d9..0f9682cd 100644 --- a/src/aof.c +++ b/src/aof.c @@ -683,9 +683,16 @@ uxeof: /* Unexpected AOF end of file. */ strerror(errno)); } } else { - redisLog(REDIS_WARNING, - "AOF loaded anyway because aof-load-truncated is enabled"); - goto loaded_ok; + /* Make sure the AOF file descriptor points to the end of the + * file after the truncate call. */ + if (server.aof_fd != -1 && lseek(server.aof_fd,0,SEEK_END) == -1) { + redisLog(REDIS_WARNING,"Can't seek the end of the AOF file: %s", + strerror(errno)); + } else { + redisLog(REDIS_WARNING, + "AOF loaded anyway because aof-load-truncated is enabled"); + goto loaded_ok; + } } } redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file. You can: 1) Make a backup of your AOF file, then use ./redis-check-aof --fix . 2) Alternatively you can set the 'aof-load-truncated' configuration option to yes and restart the server."); From 5e38bc389c6881cb1ca6f486a71b2606fdfcd771 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Sep 2014 11:05:12 +0200 Subject: [PATCH 4/5] Better truncated AOF loading tests. Now there are tests to write more data after loading a truncated AOF, testing that the loaded data is correct, appending more, and testing again. --- tests/integration/aof.tcl | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl index fe19e97c..4003550d 100644 --- a/tests/integration/aof.tcl +++ b/tests/integration/aof.tcl @@ -39,14 +39,41 @@ tags {"aof"} { ## Should also start with truncated AOF without incomplete MULTI block. create_aof { - append_to_aof [formatCommand set foo hello] - append_to_aof [string range [formatCommand set bar world] 0 end-1] + append_to_aof [formatCommand incr foo] + append_to_aof [formatCommand incr foo] + append_to_aof [formatCommand incr foo] + append_to_aof [formatCommand incr foo] + append_to_aof [formatCommand incr foo] + append_to_aof [string range [formatCommand incr foo] 0 end-1] } start_server_aof [list dir $server_path aof-load-truncated yes] { test "Short read: Server should start if load-truncated is yes" { assert_equal 1 [is_alive $srv] } + + set client [redis [dict get $srv host] [dict get $srv port]] + + test "Truncated AOF loaded: we expect foo to be equal to 5" { + assert {[$client get foo] eq "5"} + } + + test "Append a new command after loading an incomplete AOF" { + $client incr foo + } + } + + # Now the AOF file is expected to be correct + start_server_aof [list dir $server_path aof-load-truncated yes] { + test "Short read + command: Server should start" { + assert_equal 1 [is_alive $srv] + } + + set client [redis [dict get $srv host] [dict get $srv port]] + + test "Truncated AOF loaded: we expect foo to be equal to 6 now" { + assert {[$client get foo] eq "6"} + } } ## Test that the server exits when the AOF contains a format error From a69534967bead5d1ff64abdce99c150fabda6546 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 16 Sep 2014 15:15:53 +0200 Subject: [PATCH 5/5] Redis 2.8.16. --- 00-RELEASENOTES | 33 +++++++++++++++++++++++++++++++++ src/version.h | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/00-RELEASENOTES b/00-RELEASENOTES index a41effad..bd5fb021 100644 --- a/00-RELEASENOTES +++ b/00-RELEASENOTES @@ -14,6 +14,39 @@ HIGH: There is a critical bug that may affect a subset of users. Upgrade! CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP. -------------------------------------------------------------------------------- +--[ Redis 2.8.16 ] Release date: 16 Sep 2014 + +# UPGRADE URGENCY: HIGH for Redis if you are using 2.8.15 + AOF. + LOW for Sentinel. + +* [FIX] The ability to load truncated AOF files introduced with Redis 2.8.15 + contains a bug fixed in this release: after loading the file was not + truncated to the last valid command, so the new commands are appended + after a non well formed command. This means that: + + 1) The first AOF rewrite triggered by the server will automatically + fix the problem. + 2) However, if the server is restarted before the rewrite, Redis may + not be able to load the file and you need to manually fix it. + + In order to fix a corrupted file you should start the redis-check-aof + utility WITHOUT the --fix option, just to check the offset where the + corruption is found. Around the offset reported by the check utility + you'll find, inside your AOF file, a command which is not complete + according to the Redis protocol. Just remove this incomplete command + leafing the file unaltered before and after the offending command, + and restart the server. + + IMPORTANT #1: Redis 2.8.15 is the only stable version of Redis with + this bug so probably no actual real-world problem happened since the + problem is automatically fixed at the first automatic AOF rewrite. + + IMPORTANT #2: Before upgrading to Redis 2.8.16, if you are using Redis + 2.8.15 with AOF enabled, make sure to trigger a manual AOF rewrite + using the BGREWRITEAOF command. + +* [FIX] SAVE is no longer propagated to AOF / slaves. + --[ Redis 2.8.15 ] Release date: 12 Sep 2014 # UPGRADE URGENCY: LOW for Redis, HIGH for Sentinel. diff --git a/src/version.h b/src/version.h index 5834efb1..7ea19b02 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.8.15" +#define REDIS_VERSION "2.8.16"