Merge 2954eb0e29dd65688d2aec1ea1332d1ba2374cae into 26c6f1af9b29d525831c7fa9840ab3e47ed7b700

This commit is contained in:
kronwerk 2025-02-02 18:01:31 +02:00 committed by GitHub
commit 8fb48e9222
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 103 additions and 8 deletions

View File

@ -1011,16 +1011,22 @@ int startAppendOnly(void) {
* the first call is short, there is a end-of-space condition, so the next
* is likely to fail. However apparently in modern systems this is no longer
* true, and in general it looks just more resilient to retry the write. If
* there is an actual error condition we'll get it at the next try. */
ssize_t aofWrite(int fd, const char *buf, size_t len) {
ssize_t nwritten = 0, totwritten = 0;
* there is an actual error condition we'll get it at the next try.
* We also check for aof-max-size limit here returning custom error on exceed. */
ssize_t aofWrite(int fd, const char *buf, size_t len, off_t aof_current_size, unsigned long long aof_max_size) {
ssize_t nwritten = 0, totwritten = 0, nonewritten = -1;
if (aof_max_size && (unsigned long long)aof_current_size >= aof_max_size) {
errno = EFBIG;
return nonewritten;
}
while (len) {
nwritten = write(fd, buf, len);
if (nwritten < 0) {
if (errno == EINTR) continue;
return totwritten ? totwritten : -1;
return totwritten ? totwritten : nonewritten;
}
len -= nwritten;
@ -1120,7 +1126,7 @@ void flushAppendOnlyFile(int force) {
}
latencyStartMonitor(latency);
nwritten = aofWrite(server.aof_fd, server.aof_buf, sdslen(server.aof_buf));
nwritten = aofWrite(server.aof_fd, server.aof_buf, sdslen(server.aof_buf), server.aof_current_size, server.aof_max_size);
latencyEndMonitor(latency);
/* We want to capture different events for delayed writes:
* when the delay happens with a pending fsync, or with a saving child
@ -1152,7 +1158,7 @@ void flushAppendOnlyFile(int force) {
/* Log the AOF write error and record the error code. */
if (nwritten == -1) {
if (can_log) {
serverLog(LL_WARNING, "Error writing to the AOF file: %s", strerror(errno));
serverLog(LL_WARNING, "Error writing to the AOF file: %s", getAofWriteErrStr(errno));
}
server.aof_last_write_errno = errno;
} else {

View File

@ -3328,6 +3328,7 @@ standardConfig static_configs[] = {
/* Unsigned Long Long configs */
createULongLongConfig("maxmemory", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.maxmemory, 0, MEMORY_CONFIG, NULL, updateMaxmemory),
createULongLongConfig("cluster-link-sendbuf-limit", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.cluster_link_msg_queue_limit_bytes, 0, MEMORY_CONFIG, NULL, NULL),
createULongLongConfig("aof-max-size", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.aof_max_size, 0, INTEGER_CONFIG, NULL, NULL),
/* Size_t configs */
createSizeTConfig("hash-max-listpack-entries", "hash-max-ziplist-entries", MODIFIABLE_CONFIG, 0, LONG_MAX, server.hash_max_listpack_entries, 512, INTEGER_CONFIG, NULL, NULL),

View File

@ -179,7 +179,7 @@ int scriptPrepareForRun(scriptRunCtx *run_ctx,
"Writable scripts are blocked. Use 'no-writes' flag for read only scripts. "
"AOF error: %s",
server.extended_redis_compat ? "Redis" : SERVER_TITLE,
strerror(server.aof_last_write_errno));
getAofWriteErrStr(server.aof_last_write_errno));
return C_ERR;
}

View File

@ -4626,13 +4626,17 @@ int writeCommandsDeniedByDiskError(void) {
return DISK_ERROR_TYPE_NONE;
}
char *getAofWriteErrStr(int error_code) {
return (errno == EFBIG) ? "Reached aof-max-size" : strerror(error_code);
}
sds writeCommandsGetDiskErrorMessage(int error_code) {
sds ret = NULL;
if (error_code == DISK_ERROR_TYPE_RDB) {
ret = sdsdup(shared.bgsaveerr->ptr);
} else {
ret = sdscatfmt(sdsempty(), "-MISCONF Errors writing to the AOF file: %s\r\n",
strerror(server.aof_last_write_errno));
getAofWriteErrStr(server.aof_last_write_errno));
}
return ret;
}
@ -5837,10 +5841,17 @@ sds genValkeyInfoString(dict *section_dict, int all_sections, int everything) {
"module_fork_last_cow_size:%zu\r\n", server.stat_module_cow_bytes));
if (server.aof_enabled) {
char aof_current_size_hdsk[64];
char aof_max_size_hdsk[64];
bytesToHuman(aof_current_size_hdsk, sizeof(aof_current_size_hdsk), (unsigned long long)server.aof_current_size);
bytesToHuman(aof_max_size_hdsk, sizeof(aof_max_size_hdsk), server.aof_max_size);
info = sdscatprintf(
info,
FMTARGS(
"aof_current_size:%lld\r\n", (long long)server.aof_current_size,
"aof_current_size_human:%s\r\n", aof_current_size_hdsk,
"aof_max_size:%lld\r\n", server.aof_max_size,
"aof_max_size_human:%s\r\n", aof_max_size_hdsk,
"aof_base_size:%lld\r\n", (long long)server.aof_rewrite_base_size,
"aof_pending_rewrite:%d\r\n", server.aof_rewrite_scheduled,
"aof_buffer_length:%zu\r\n", sdslen(server.aof_buf),
@ -7150,6 +7161,14 @@ __attribute__((weak)) int main(int argc, char **argv) {
server.maxmemory);
}
/* Warning the user about suspicious aof-max-size setting. */
if (server.aof_max_size > 0 && server.aof_max_size < 1024 * 1024) {
serverLog(LL_WARNING,
"WARNING: You specified a aof-max-size value that is less than 1MB (current value is %llu bytes). Are "
"you sure this is what you really want?",
server.aof_max_size);
}
serverSetCpuAffinity(server.server_cpulist);
setOOMScoreAdj(-1);

View File

@ -1811,6 +1811,7 @@ struct valkeyServer {
off_t aof_rewrite_min_size; /* the AOF file is at least N bytes. */
off_t aof_rewrite_base_size; /* AOF size on latest startup or rewrite. */
off_t aof_current_size; /* AOF current size (Including BASE + INCRs). */
unsigned long long aof_max_size; /* Max number of disk bytes to use for AOF */
off_t aof_last_incr_size; /* The size of the latest incr AOF. */
off_t aof_last_incr_fsync_offset; /* AOF offset which is already requested to be synced to disk.
* Compare with the aof_last_incr_size. */
@ -2968,6 +2969,7 @@ int allPersistenceDisabled(void);
#define DISK_ERROR_TYPE_RDB 2 /* Don't accept writes: RDB errors. */
#define DISK_ERROR_TYPE_NONE 0 /* No problems, we can accept writes. */
int writeCommandsDeniedByDiskError(void);
char *getAofWriteErrStr(int);
sds writeCommandsGetDiskErrorMessage(int);
/* RDB persistence */

View File

@ -0,0 +1,64 @@
proc setup {{size 1}} {
r set k v
r config set aof-max-size $size
r set k2 v2
}
proc cleanup {} {
r config set aof-max-size 0
r flushall
}
start_server {tags {"external:skip"}} {
r config set auto-aof-rewrite-percentage 0 ; # disable auto-rewrite
r config set appendonly yes ; # enable AOF
set master_host [srv 0 host]
set master_port [srv 0 port]
test "Low aof-max-size stops writing AOF with EFBIG" {
setup
wait_for_log_messages 0 {"*Error writing to the AOF file: Reached aof-max-size*"} 0 100 10
cleanup
}
test "New write attempts when limited with aof-max-size fail and doesn't insrease AOF buffer anymore" {
setup
set info1 [r info]
set buf1 [getInfoProperty $info1 mem_aof_buffer]
set len1 [getInfoProperty $info1 aof_buffer_length]
catch {r set somelongerkey somelongrvalue} err
assert {$err eq "MISCONF Errors writing to the AOF file: Reached aof-max-size"}
assert_equal [r get somelongerkey] ""
set info2 [r info]
set buf2 [getInfoProperty $info2 mem_aof_buffer]
set len2 [getInfoProperty $info2 aof_buffer_length]
assert_equal $buf1 $buf2
assert_equal $len1 $len2
cleanup
}
test "Increasing aof-max-size fixes AOF write error" {
setup
set loglines [count_log_lines 0] ; # want to check new line, not from previous test
r config set aof-max-size 1000
wait_for_log_messages 0 {"*AOF write error looks solved. The server can write again.*"} $loglines 100 10
assert_equal [r set k3 v3] "OK"
assert_equal [r get k3] "v3"
cleanup
}
test "Meeting aof-max-size does not prevent AOF rewrite" {
setup 200
set loglines [count_log_lines 0] ; # want to check new line, not from previous test
waitForBgrewriteaof r
r bgrewriteaof
wait_for_log_messages 0 {"*Background AOF rewrite finished successfully*"} $loglines 100 10
wait_for_log_messages 0 {"*AOF write error looks solved. The server can write again.*"} $loglines 100 10
cleanup
}
}

View File

@ -1662,6 +1662,9 @@ aof-use-rdb-preamble yes
# the AOF format in a way that may not be compatible with existing AOF parsers.
aof-timestamp-enabled no
# Maximum size for AOF files on disk in bytes. Ignored, if set to 0.
aof-max-size 0
################################ SHUTDOWN #####################################
# Maximum time to wait for replicas when shutting down, in seconds.