From 26285d3dd5d010759ed7fb16e4417c8f0432d368 Mon Sep 17 00:00:00 2001 From: Pim van den Broek <32633377+pimvandenbroek@users.noreply.github.com> Date: Thu, 6 Jul 2023 00:37:35 +0200 Subject: [PATCH 01/34] Fix redis-cli symlink (#689) --- pkg/docker/Dockerfile | 1 + pkg/docker/Dockerfile_Alpine | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/docker/Dockerfile b/pkg/docker/Dockerfile index 0f2a63ba8..120a76c15 100644 --- a/pkg/docker/Dockerfile +++ b/pkg/docker/Dockerfile @@ -83,6 +83,7 @@ RUN \ sed -i 's/^\(logfile .*\)$/# \1/' /etc/keydb/keydb.conf; \ sed -i 's/protected-mode yes/protected-mode no/g' /etc/keydb/keydb.conf; \ sed -i 's/^\(bind .*\)$/# \1/' /etc/keydb/keydb.conf; \ + cd /usr/local/bin; \ ln -s keydb-cli redis-cli; \ cd /etc/keydb; \ ln -s keydb.conf redis.conf; \ diff --git a/pkg/docker/Dockerfile_Alpine b/pkg/docker/Dockerfile_Alpine index 80b35819c..a6ff9b031 100644 --- a/pkg/docker/Dockerfile_Alpine +++ b/pkg/docker/Dockerfile_Alpine @@ -54,6 +54,7 @@ RUN set -eux; \ sed -i 's/^\(logfile .*\)$/# \1/' /etc/keydb/keydb.conf; \ sed -i 's/protected-mode yes/protected-mode no/g' /etc/keydb/keydb.conf; \ sed -i 's/^\(bind .*\)$/# \1/' /etc/keydb/keydb.conf; \ + cd /usr/local/bin; \ ln -s keydb-cli redis-cli; \ cd /etc/keydb; \ ln -s keydb.conf redis.conf; \ From 8e052f728cc9d896cdf6f768b5230c83c4a1b715 Mon Sep 17 00:00:00 2001 From: Philipp Trulson Date: Thu, 6 Jul 2023 00:38:14 +0200 Subject: [PATCH 02/34] Enable KeyDB FLASH in Docker images (#687) --- pkg/docker/Dockerfile | 2 +- pkg/docker/Dockerfile_Alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/docker/Dockerfile b/pkg/docker/Dockerfile index 120a76c15..9dc57b95b 100644 --- a/pkg/docker/Dockerfile +++ b/pkg/docker/Dockerfile @@ -53,7 +53,7 @@ RUN set -eux; \ grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' ./src/config.cpp; \ sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' ./src/config.cpp; \ grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' ./src/config.cpp; \ - make -j$(nproc) BUILD_TLS=yes; \ + make -j$(nproc) BUILD_TLS=yes ENABLE_FLASH=yes; \ cd src; \ strip keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel keydb-server; \ mv keydb-server keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel /usr/local/bin/; \ diff --git a/pkg/docker/Dockerfile_Alpine b/pkg/docker/Dockerfile_Alpine index a6ff9b031..9fed758cd 100644 --- a/pkg/docker/Dockerfile_Alpine +++ b/pkg/docker/Dockerfile_Alpine @@ -32,7 +32,7 @@ RUN set -eux; \ grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' ./src/config.cpp; \ sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' ./src/config.cpp; \ grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' ./src/config.cpp; \ - make -j$(nproc) BUILD_TLS=yes; \ + make -j$(nproc) BUILD_TLS=yes ENABLE_FLASH=yes; \ cd src; \ strip keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel keydb-server; \ mv keydb-server keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel /usr/local/bin/; \ From 6f77a8248015415bb9c3dcc10d40c4002eec1078 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Thu, 6 Jul 2023 07:38:39 +0900 Subject: [PATCH 03/34] Fix typo in module.cpp (#686) comparision -> comparison --- src/module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module.cpp b/src/module.cpp index 7bd32aebb..eceb80c75 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -7058,7 +7058,7 @@ RedisModuleString *RM_DictPrev(RedisModuleCtx *ctx, RedisModuleDictIter *di, voi /* Compare the element currently pointed by the iterator to the specified * element given by key/keylen, according to the operator 'op' (the set of * valid operators are the same valid for RedisModule_DictIteratorStart). - * If the comparision is successful the command returns REDISMODULE_OK + * If the comparison is successful the command returns REDISMODULE_OK * otherwise REDISMODULE_ERR is returned. * * This is useful when we want to just emit a lexicographical range, so From 501ae473e18056a58ea075bc03da38707b7a6a9e Mon Sep 17 00:00:00 2001 From: Karthick Ariyaratnam Date: Thu, 13 Jul 2023 13:26:00 -0400 Subject: [PATCH 04/34] Fix a bug where a temp rdb file with zero bytes is generated in flash mode. (#696) Co-authored-by: Karthick Ariyaratnam (A) --- src/replication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/replication.cpp b/src/replication.cpp index 56e5596b6..280043ace 100644 --- a/src/replication.cpp +++ b/src/replication.cpp @@ -3732,7 +3732,7 @@ retry_connect: } /* Prepare a suitable temp file for bulk transfer */ - if (!useDisklessLoad()) { + if (!useDisklessLoad() && !mi->isRocksdbSnapshotRepl) { while(maxtries--) { auto dt = std::chrono::system_clock::now().time_since_epoch(); auto dtMillisecond = std::chrono::duration_cast(dt); From 0d01b810c391c272be6e63b18c88eb8affcb09bc Mon Sep 17 00:00:00 2001 From: "Karthick Ariyaratnam (A)" Date: Fri, 14 Jul 2023 12:57:40 -0400 Subject: [PATCH 05/34] Fix a fug where repl-backlog-size config was modifed in keydb.conf with the runtime value during config rewrite. --- src/config.cpp | 2 +- src/server.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 5d1827c5c..ad8425051 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -2933,7 +2933,7 @@ standardConfig configs[] = { createLongLongConfig("latency-monitor-threshold", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, g_pserver->latency_monitor_threshold, 0, INTEGER_CONFIG, NULL, NULL), createLongLongConfig("proto-max-bulk-len", NULL, MODIFIABLE_CONFIG, 1024*1024, LLONG_MAX, g_pserver->proto_max_bulk_len, 512ll*1024*1024, MEMORY_CONFIG, NULL, NULL), /* Bulk request max size */ createLongLongConfig("stream-node-max-entries", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, g_pserver->stream_node_max_entries, 100, INTEGER_CONFIG, NULL, NULL), - createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, g_pserver->repl_backlog_size, 1024*1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */ + createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, g_pserver->repl_backlog_config_size, 1024*1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */ createLongLongConfig("repl-backlog-disk-reserve", NULL, IMMUTABLE_CONFIG, 0, LLONG_MAX, cserver.repl_backlog_disk_size, 0, MEMORY_CONFIG, NULL, NULL), createLongLongConfig("max-snapshot-slip", NULL, MODIFIABLE_CONFIG, 0, 5000, g_pserver->snapshot_slip, 400, 0, NULL, NULL), createLongLongConfig("max-rand-count", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX/2, g_pserver->rand_total_threshold, LONG_MAX/2, 0, NULL, NULL), diff --git a/src/server.cpp b/src/server.cpp index c2a988ae4..663e4e8fc 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -7394,7 +7394,7 @@ static void validateConfiguration() exit(EXIT_FAILURE); } - g_pserver->repl_backlog_config_size = g_pserver->repl_backlog_size; // this is normally set in the update logic, but not on initial config + g_pserver->repl_backlog_size = g_pserver->repl_backlog_config_size; // this is normally set in the update logic, but not on initial config } int iAmMaster(void) { From 821b39acacfb092e0f353489c6fd40dfc139434e Mon Sep 17 00:00:00 2001 From: Rolf Ahrenberg Date: Wed, 26 Jul 2023 07:20:41 +0300 Subject: [PATCH 06/34] Use tini in Alpine-based Docker image (#682) --- pkg/docker/Dockerfile_Alpine | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/docker/Dockerfile_Alpine b/pkg/docker/Dockerfile_Alpine index 9fed758cd..028fea3a5 100644 --- a/pkg/docker/Dockerfile_Alpine +++ b/pkg/docker/Dockerfile_Alpine @@ -5,7 +5,7 @@ RUN mkdir -p /etc/keydb ARG BRANCH RUN set -eux; \ \ - apk add --no-cache su-exec; \ + apk add --no-cache su-exec tini; \ apk add --no-cache --virtual .build-deps \ coreutils \ gcc \ @@ -77,6 +77,6 @@ RUN set -eux; \ chmod +x /usr/local/bin/docker-entrypoint.sh VOLUME /data WORKDIR /data -ENTRYPOINT ["docker-entrypoint.sh"] +ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"] EXPOSE 6379 CMD ["keydb-server", "/etc/keydb/keydb.conf"] From 4c3d9341fd9038a8dac0fed23dec171e17224905 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Tue, 27 Jun 2023 14:18:14 -0700 Subject: [PATCH 07/34] port changes to 6.3 --- src/evict.cpp | 20 +++++++++++++++++++- src/server.cpp | 10 ++++++++++ src/server.h | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/evict.cpp b/src/evict.cpp index 94bc132c1..aa6932e8b 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -421,10 +421,22 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (total) *total = mem_reported; size_t maxmemory = g_pserver->maxmemory; if (fPreSnapshot) - maxmemory = static_cast(maxmemory * 0.9); // derate memory by 10% since we won't be able to free during snapshot + maxmemory = static_cast(maxmemory*0.9); // derate memory by 10% since we won't be able to free during snapshot if (g_pserver->FRdbSaveInProgress()) maxmemory = static_cast(maxmemory*1.2); + /* If there is less than 10% free system memory, force eviction */ + bool mem_rss_max_exceeded; + if (g_pserver->cron_malloc_stats.sys_total) { + size_t mem_rss_max = static_cast(g_pserver->cron_malloc_stats.sys_total * 0.9); + mem_rss_max_exceeded = g_pserver->cron_malloc_stats.process_rss > mem_rss_max; + if (mem_rss_max_exceeded) { + /* This will always set maxmemory < mem_reported */ + float frag_ratio = (float)g_pserver->cron_malloc_stats.process_rss / (float)mem_reported; + maxmemory = static_cast((float)mem_rss_max / frag_ratio); + } + } + /* We may return ASAP if there is no need to compute the level. */ int return_ok_asap = !maxmemory || mem_reported <= maxmemory; if (return_ok_asap && !level) return C_OK; @@ -435,6 +447,12 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev size_t overhead = freeMemoryGetNotCountedMemory(); mem_used = (mem_used > overhead) ? mem_used-overhead : 0; + /* If we've exceeded max RSS memory, we want to force evictions no matter + * what so we also offset the overhead from maxmemory. */ + if (mem_rss_max_exceeded) { + maxmemory = (maxmemory > overhead) ? maxmemory-overhead : 0; + } + /* Compute the ratio of memory usage. */ if (level) { if (!maxmemory) { diff --git a/src/server.cpp b/src/server.cpp index 663e4e8fc..d1ef097c4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -70,6 +70,7 @@ #ifdef __linux__ #include #include +#include #endif int g_fTestMode = false; @@ -2312,6 +2313,15 @@ void cronUpdateMemoryStats() { g_pserver->cron_malloc_stats.allocator_active = g_pserver->cron_malloc_stats.allocator_resident; if (!g_pserver->cron_malloc_stats.allocator_allocated) g_pserver->cron_malloc_stats.allocator_allocated = g_pserver->cron_malloc_stats.zmalloc_used; + + #ifdef __linux__ + struct sysinfo sysinf; + memset(&sysinf, 0, sizeof sysinf); + if (!sysinfo(&sysinf)) { + g_pserver->cron_malloc_stats.sys_total = static_cast(sysinf.totalram); + } + #endif + } } diff --git a/src/server.h b/src/server.h index 422cb9495..3a5ed977f 100644 --- a/src/server.h +++ b/src/server.h @@ -2014,6 +2014,7 @@ struct malloc_stats { size_t allocator_allocated; size_t allocator_active; size_t allocator_resident; + size_t sys_total; }; typedef struct socketFds { From 1f2c179124045e25b4b67686a56ef5caf31aa92a Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Wed, 28 Jun 2023 17:31:40 -0700 Subject: [PATCH 08/34] with config --- src/config.cpp | 1 + src/evict.cpp | 7 ++++--- src/server.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index ad8425051..574cf89cb 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -2968,6 +2968,7 @@ standardConfig configs[] = { createSizeTConfig("semi-ordered-set-bucket-size", NULL, MODIFIABLE_CONFIG, 0, 1024, g_semiOrderedSetTargetBucketSize, 0, INTEGER_CONFIG, NULL, NULL), createSDSConfig("availability-zone", NULL, MODIFIABLE_CONFIG, 0, g_pserver->sdsAvailabilityZone, "", NULL, NULL), createIntConfig("overload-protect-percent", NULL, MODIFIABLE_CONFIG, 0, 200, g_pserver->overload_protect_threshold, 0, INTEGER_CONFIG, NULL, NULL), + createIntConfig("force-eviction-percent", NULL, MODIFIABLE_CONFIG, 0, 100, g_pserver->force_eviction_percent, 0, INTEGER_CONFIG, NULL, NULL), #ifdef USE_OPENSSL createIntConfig("tls-port", NULL, MODIFIABLE_CONFIG, 0, 65535, g_pserver->tls_port, 0, INTEGER_CONFIG, NULL, updateTLSPort), /* TCP port. */ diff --git a/src/evict.cpp b/src/evict.cpp index aa6932e8b..2aa9337a2 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -425,10 +425,11 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (g_pserver->FRdbSaveInProgress()) maxmemory = static_cast(maxmemory*1.2); - /* If there is less than 10% free system memory, force eviction */ + /* If there is less than a configurable percent of free system memory, force eviction */ bool mem_rss_max_exceeded; - if (g_pserver->cron_malloc_stats.sys_total) { - size_t mem_rss_max = static_cast(g_pserver->cron_malloc_stats.sys_total * 0.9); + if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { + float sys_total_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; + size_t mem_rss_max = static_cast(g_pserver->cron_malloc_stats.sys_total * sys_total_ratio); mem_rss_max_exceeded = g_pserver->cron_malloc_stats.process_rss > mem_rss_max; if (mem_rss_max_exceeded) { /* This will always set maxmemory < mem_reported */ diff --git a/src/server.h b/src/server.h index 3a5ed977f..0ad934d8d 100644 --- a/src/server.h +++ b/src/server.h @@ -2577,6 +2577,7 @@ struct redisServer { int maxmemory_policy; /* Policy for key eviction */ int maxmemory_samples; /* Precision of random sampling */ int maxmemory_eviction_tenacity;/* Aggressiveness of eviction processing */ + int force_eviction_percent; /* Force eviction when this percent of system memory is remaining */ int lfu_log_factor; /* LFU logarithmic counter factor. */ int lfu_decay_time; /* LFU counter decay factor. */ long long proto_max_bulk_len; /* Protocol bulk length maximum size. */ From 39e3141a0a1ee7b342bfebb5782ce47c981170a8 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Wed, 28 Jun 2023 23:19:34 -0700 Subject: [PATCH 09/34] revert --- keydb.conf | 6 ++++++ src/evict.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/keydb.conf b/keydb.conf index 59ddf5abb..1a006fcd3 100644 --- a/keydb.conf +++ b/keydb.conf @@ -1145,6 +1145,12 @@ acllog-max-len 128 # # active-expire-effort 1 +# Force evictions when RSS memory reaches this percent of total system memory. +# This is useful as a safeguard to prevent OOM kills when RSS overhead is +# significant (0 to disable). +# +# force-eviction-percent 0 + ############################# LAZY FREEING #################################### # KeyDB has two primitives to delete keys. One is called DEL and is a blocking diff --git a/src/evict.cpp b/src/evict.cpp index 2aa9337a2..f4edb86fd 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -425,10 +425,10 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (g_pserver->FRdbSaveInProgress()) maxmemory = static_cast(maxmemory*1.2); - /* If there is less than a configurable percent of free system memory, force eviction */ + /* If rss memory exceeds configurable percent of system memory, force eviction */ bool mem_rss_max_exceeded; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { - float sys_total_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; + float sys_total_ratio = (float)(g_pserver->force_eviction_percent)/100; size_t mem_rss_max = static_cast(g_pserver->cron_malloc_stats.sys_total * sys_total_ratio); mem_rss_max_exceeded = g_pserver->cron_malloc_stats.process_rss > mem_rss_max; if (mem_rss_max_exceeded) { From c9d63c50c0607c9b34d67cc71b8b3a7293fa131c Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 29 Jun 2023 13:22:47 -0700 Subject: [PATCH 10/34] update --- src/evict.cpp | 20 +++++++++----------- src/server.cpp | 1 + src/server.h | 1 + 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index f4edb86fd..bd9c569ed 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -425,16 +425,14 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (g_pserver->FRdbSaveInProgress()) maxmemory = static_cast(maxmemory*1.2); - /* If rss memory exceeds configurable percent of system memory, force eviction */ - bool mem_rss_max_exceeded; + /* If free system memory is below a certain threshold, force eviction */ + size_t sys_free_mem_buffer; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { - float sys_total_ratio = (float)(g_pserver->force_eviction_percent)/100; - size_t mem_rss_max = static_cast(g_pserver->cron_malloc_stats.sys_total * sys_total_ratio); - mem_rss_max_exceeded = g_pserver->cron_malloc_stats.process_rss > mem_rss_max; - if (mem_rss_max_exceeded) { - /* This will always set maxmemory < mem_reported */ - float frag_ratio = (float)g_pserver->cron_malloc_stats.process_rss / (float)mem_reported; - maxmemory = static_cast((float)mem_rss_max / frag_ratio); + float free_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; + size_t min_free_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * free_mem_ratio); + sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); + if (sys_free_mem_buffer < 0) { + maxmemory = static_cast(mem_reported + sys_free_mem_buffer); } } @@ -448,9 +446,9 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev size_t overhead = freeMemoryGetNotCountedMemory(); mem_used = (mem_used > overhead) ? mem_used-overhead : 0; - /* If we've exceeded max RSS memory, we want to force evictions no matter + /* If system free memory is too low, we want to force evictions no matter * what so we also offset the overhead from maxmemory. */ - if (mem_rss_max_exceeded) { + if (sys_free_mem_buffer < 0) { maxmemory = (maxmemory > overhead) ? maxmemory-overhead : 0; } diff --git a/src/server.cpp b/src/server.cpp index d1ef097c4..9887c0e58 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2319,6 +2319,7 @@ void cronUpdateMemoryStats() { memset(&sysinf, 0, sizeof sysinf); if (!sysinfo(&sysinf)) { g_pserver->cron_malloc_stats.sys_total = static_cast(sysinf.totalram); + g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); } #endif diff --git a/src/server.h b/src/server.h index 0ad934d8d..d04aeccad 100644 --- a/src/server.h +++ b/src/server.h @@ -2015,6 +2015,7 @@ struct malloc_stats { size_t allocator_active; size_t allocator_resident; size_t sys_total; + size_t sys_free; }; typedef struct socketFds { From 22d5ce41f37ea437298d9926c037c5337b7fd846 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 29 Jun 2023 13:23:16 -0700 Subject: [PATCH 11/34] update --- keydb.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keydb.conf b/keydb.conf index 1a006fcd3..8cc020fe4 100644 --- a/keydb.conf +++ b/keydb.conf @@ -1145,7 +1145,7 @@ acllog-max-len 128 # # active-expire-effort 1 -# Force evictions when RSS memory reaches this percent of total system memory. +# Force evictions when used system memory reaches X% of total system memory. # This is useful as a safeguard to prevent OOM kills when RSS overhead is # significant (0 to disable). # From 1dc5ea40f33e40efcca7378e3743f145673a8880 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 29 Jun 2023 13:41:34 -0700 Subject: [PATCH 12/34] update --- src/server.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index 9887c0e58..9cbca9f04 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2315,11 +2315,13 @@ void cronUpdateMemoryStats() { g_pserver->cron_malloc_stats.allocator_allocated = g_pserver->cron_malloc_stats.zmalloc_used; #ifdef __linux__ - struct sysinfo sysinf; - memset(&sysinf, 0, sizeof sysinf); - if (!sysinfo(&sysinf)) { - g_pserver->cron_malloc_stats.sys_total = static_cast(sysinf.totalram); - g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); + if (g_pserver->force_eviction_percent) { + struct sysinfo sysinf; + memset(&sysinf, 0, sizeof sysinf); + if (!sysinfo(&sysinf)) { + g_pserver->cron_malloc_stats.sys_total = static_cast(sysinf.totalram); + g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); + } } #endif From 87012bf98e8ea799d673dba3ea5754a731a0b7ad Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 29 Jun 2023 14:21:00 -0700 Subject: [PATCH 13/34] update sys free --- src/evict.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index bd9c569ed..6877b16f7 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -432,7 +432,8 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev size_t min_free_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * free_mem_ratio); sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); if (sys_free_mem_buffer < 0) { - maxmemory = static_cast(mem_reported + sys_free_mem_buffer); + size_t mem_threshold = static_cast(mem_reported + sys_free_mem_buffer); + maxmemory = (maxmemory < mem_threshold) ? maxmemory : mem_threshold; } } @@ -621,6 +622,18 @@ static unsigned long evictionTimeLimitUs() { return ULONG_MAX; /* No limit to eviction time */ } +static void updateSysFreeMemory() { +#ifdef __linux__ + if (g_pserver->force_eviction_percent) { + struct sysinfo sysinf; + memset(&sysinf, 0, sizeof sysinf); + if (!sysinfo(&sysinf)) { + g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); + } + } +#endif +} + /* Check that memory usage is within the current "maxmemory" limit. If over * "maxmemory", attempt to free memory by evicting data (if it's safe to do so). * @@ -844,6 +857,7 @@ int performEvictions(bool fPreSnapshot) { * across the dbAsyncDelete() call, while the thread can * release the memory all the time. */ if (g_pserver->lazyfree_lazy_eviction) { + updateSysFreeMemory(); if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { break; } @@ -871,9 +885,13 @@ int performEvictions(bool fPreSnapshot) { if (splazy != nullptr && splazy->memory_queued() > 0 && !serverTL->gcEpoch.isReset()) { g_pserver->garbageCollector.enqueue(serverTL->gcEpoch, std::move(splazy)); - } + } cant_free: + if (mem_freed > 0) { + updateSysFreeMemory(); + } + if (g_pserver->m_pstorageFactory) { if (mem_reported < g_pserver->maxmemory*1.2) { From ac7e6c06916b844c87db6f44f751c3d2e11b0163 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 29 Jun 2023 14:58:08 -0700 Subject: [PATCH 14/34] fix compiler errors --- src/evict.cpp | 13 ++++++++----- src/server.cpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index 6877b16f7..73808c41a 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -36,6 +36,9 @@ #include #include #include +#ifdef __linux__ +#include +#endif /* ---------------------------------------------------------------------------- * Data structures @@ -426,14 +429,14 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev maxmemory = static_cast(maxmemory*1.2); /* If free system memory is below a certain threshold, force eviction */ - size_t sys_free_mem_buffer; + long sys_free_mem_buffer; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { float free_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; size_t min_free_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * free_mem_ratio); - sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); + sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); if (sys_free_mem_buffer < 0) { - size_t mem_threshold = static_cast(mem_reported + sys_free_mem_buffer); - maxmemory = (maxmemory < mem_threshold) ? maxmemory : mem_threshold; + long mem_threshold = mem_reported + sys_free_mem_buffer; + maxmemory = (maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); } } @@ -891,7 +894,7 @@ cant_free: if (mem_freed > 0) { updateSysFreeMemory(); } - + if (g_pserver->m_pstorageFactory) { if (mem_reported < g_pserver->maxmemory*1.2) { diff --git a/src/server.cpp b/src/server.cpp index 9cbca9f04..57b5c8a6d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2314,7 +2314,7 @@ void cronUpdateMemoryStats() { if (!g_pserver->cron_malloc_stats.allocator_allocated) g_pserver->cron_malloc_stats.allocator_allocated = g_pserver->cron_malloc_stats.zmalloc_used; - #ifdef __linux__ + #ifdef __linux__ if (g_pserver->force_eviction_percent) { struct sysinfo sysinf; memset(&sysinf, 0, sizeof sysinf); From 65b7fafd2970a21950af63e04d149013a630086b Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 09:39:49 -0700 Subject: [PATCH 15/34] llu --- src/Makefile | 2 +- src/evict.cpp | 4 ++-- src/meminfo.cpp | 31 +++++++++++++++++++++++++++++++ src/server.cpp | 14 +++++--------- src/server.h | 5 ++++- 5 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 src/meminfo.cpp diff --git a/src/Makefile b/src/Makefile index 01c24b0df..007a0879d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -384,7 +384,7 @@ endif REDIS_SERVER_NAME=keydb-server$(PROG_SUFFIX) REDIS_SENTINEL_NAME=keydb-sentinel$(PROG_SUFFIX) -REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o t_nhash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o tracking.o cron.o connection.o tls.o sha256.o motd_server.o timeout.o setcpuaffinity.o AsyncWorkQueue.o snapshot.o storage/teststorageprovider.o keydbutils.o StorageCache.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ) $(STORAGE_OBJ) +REDIS_SERVER_OBJ=adlist.o meminfo.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o t_nhash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o tracking.o cron.o connection.o tls.o sha256.o motd_server.o timeout.o setcpuaffinity.o AsyncWorkQueue.o snapshot.o storage/teststorageprovider.o keydbutils.o StorageCache.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ) $(STORAGE_OBJ) KEYDB_SERVER_OBJ=SnapshotPayloadParseState.o REDIS_CLI_NAME=keydb-cli$(PROG_SUFFIX) REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crcspeed.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o motd_client.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ) diff --git a/src/evict.cpp b/src/evict.cpp index 73808c41a..bfc923ecc 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -429,14 +429,14 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev maxmemory = static_cast(maxmemory*1.2); /* If free system memory is below a certain threshold, force eviction */ - long sys_free_mem_buffer; + long sys_free_mem_buffer = 0; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { float free_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; size_t min_free_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * free_mem_ratio); sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); if (sys_free_mem_buffer < 0) { long mem_threshold = mem_reported + sys_free_mem_buffer; - maxmemory = (maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); + maxmemory = ((long)maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); } } diff --git a/src/meminfo.cpp b/src/meminfo.cpp new file mode 100644 index 000000000..a3ec46805 --- /dev/null +++ b/src/meminfo.cpp @@ -0,0 +1,31 @@ +#include "server.h" +#include + +static size_t getMemKey(std::string key) { +# ifdef __linux__ + std::string token; + std::ifstream f("/proc/meminfo"); + while (f >> token) { + if (token == key) { + size_t mem_val; + if (f >> mem_val) { + return mem_val; + } else { + return 0; + } + f.ignore(std::numeric_limits::max(), '\n'); + } + return 0; // nothing found + } +# else + return 0; +# endif +} + +size_t getMemAvailable() { + return getMemKey("MemAvailable:"); +} + +size_t getMemTotal() { + return getMemKey("MemTotal:"); +} \ No newline at end of file diff --git a/src/server.cpp b/src/server.cpp index 57b5c8a6d..9c671b0a2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2314,17 +2314,10 @@ void cronUpdateMemoryStats() { if (!g_pserver->cron_malloc_stats.allocator_allocated) g_pserver->cron_malloc_stats.allocator_allocated = g_pserver->cron_malloc_stats.zmalloc_used; - #ifdef __linux__ if (g_pserver->force_eviction_percent) { - struct sysinfo sysinf; - memset(&sysinf, 0, sizeof sysinf); - if (!sysinfo(&sysinf)) { - g_pserver->cron_malloc_stats.sys_total = static_cast(sysinf.totalram); - g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); - } + g_pserver->cron_malloc_stats.sys_available = getMemAvailable(); + serverLog(LL_WARNING, "Setting sys_available:%llu", g_pserver->cron_malloc_stats.sys_available); } - #endif - } } @@ -4044,6 +4037,8 @@ void initServer(void) { g_pserver->cron_malloc_stats.allocator_allocated = 0; g_pserver->cron_malloc_stats.allocator_active = 0; g_pserver->cron_malloc_stats.allocator_resident = 0; + g_pserver->cron_malloc_stats.sys_available = 0; + g_pserver->cron_malloc_stats.sys_total = g_pserver->force_eviction_percent ? getMemTotal() : 0; g_pserver->lastbgsave_status = C_OK; g_pserver->aof_last_write_status = C_OK; g_pserver->aof_last_write_errno = 0; @@ -4051,6 +4046,7 @@ void initServer(void) { g_pserver->mvcc_tstamp = 0; + /* Create the timer callback, this is our way to process many background * operations incrementally, like clients timeout, eviction of unaccessed * expired keys and so forth. */ diff --git a/src/server.h b/src/server.h index d04aeccad..475ef3ad3 100644 --- a/src/server.h +++ b/src/server.h @@ -2015,7 +2015,7 @@ struct malloc_stats { size_t allocator_active; size_t allocator_resident; size_t sys_total; - size_t sys_free; + size_t sys_available; }; typedef struct socketFds { @@ -3663,6 +3663,9 @@ unsigned long LFUDecrAndReturn(robj_roptr o); #define EVICT_FAIL 2 int performEvictions(bool fPreSnapshot); +/* meminfo.cpp -- get memory info from /proc/memoryinfo for linux distros */ +size_t getMemAvailable(); +size_t getMemTotal(); /* Keys hashing / comparison functions for dict.c hash tables. */ uint64_t dictSdsHash(const void *key); From 60d74262dc446d2ab8b9be2131c9bbb4f044ae5a Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 09:49:59 -0700 Subject: [PATCH 16/34] fixes --- src/evict.cpp | 18 +++++++++--------- src/meminfo.cpp | 8 ++++---- src/server.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index bfc923ecc..780ec0b63 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -428,14 +428,14 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (g_pserver->FRdbSaveInProgress()) maxmemory = static_cast(maxmemory*1.2); - /* If free system memory is below a certain threshold, force eviction */ - long sys_free_mem_buffer = 0; + /* If available system memory is below a certain threshold, force eviction */ + long sys_available_mem_buffer = 0; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { - float free_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; - size_t min_free_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * free_mem_ratio); - sys_free_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_free - min_free_mem); - if (sys_free_mem_buffer < 0) { - long mem_threshold = mem_reported + sys_free_mem_buffer; + float available_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; + size_t min_available_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * available_mem_ratio); + sys_available_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_available - min_available_mem); + if (sys_available_mem_buffer < 0) { + long mem_threshold = mem_reported + sys_available_mem_buffer; maxmemory = ((long)maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); } } @@ -450,9 +450,9 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev size_t overhead = freeMemoryGetNotCountedMemory(); mem_used = (mem_used > overhead) ? mem_used-overhead : 0; - /* If system free memory is too low, we want to force evictions no matter + /* If system available memory is too low, we want to force evictions no matter * what so we also offset the overhead from maxmemory. */ - if (sys_free_mem_buffer < 0) { + if (sys_available_mem_buffer < 0) { maxmemory = (maxmemory > overhead) ? maxmemory-overhead : 0; } diff --git a/src/meminfo.cpp b/src/meminfo.cpp index a3ec46805..dc9e81b93 100644 --- a/src/meminfo.cpp +++ b/src/meminfo.cpp @@ -2,7 +2,7 @@ #include static size_t getMemKey(std::string key) { -# ifdef __linux__ +// # ifdef __linux__ std::string token; std::ifstream f("/proc/meminfo"); while (f >> token) { @@ -15,11 +15,11 @@ static size_t getMemKey(std::string key) { } f.ignore(std::numeric_limits::max(), '\n'); } - return 0; // nothing found } -# else return 0; -# endif +// # else +// return 0; +// # endif } size_t getMemAvailable() { diff --git a/src/server.cpp b/src/server.cpp index 9c671b0a2..ddb8682da 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2316,7 +2316,7 @@ void cronUpdateMemoryStats() { if (g_pserver->force_eviction_percent) { g_pserver->cron_malloc_stats.sys_available = getMemAvailable(); - serverLog(LL_WARNING, "Setting sys_available:%llu", g_pserver->cron_malloc_stats.sys_available); + serverLog(LL_WARNING, "Setting sys_available:%lu", g_pserver->cron_malloc_stats.sys_available); } } } From e3cdc765a1c8a31365f62ecfca5ccebbe36af74f Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 09:53:44 -0700 Subject: [PATCH 17/34] fix --- src/meminfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meminfo.cpp b/src/meminfo.cpp index dc9e81b93..b9d9458f8 100644 --- a/src/meminfo.cpp +++ b/src/meminfo.cpp @@ -1,4 +1,4 @@ -#include "server.h" +#include #include static size_t getMemKey(std::string key) { From 4c0cf9e5cd70e3899b415b3b04eba1275057a79b Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 10:45:19 -0700 Subject: [PATCH 18/34] fix --- src/evict.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index 780ec0b63..c79c2414b 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -626,15 +626,9 @@ static unsigned long evictionTimeLimitUs() { } static void updateSysFreeMemory() { -#ifdef __linux__ if (g_pserver->force_eviction_percent) { - struct sysinfo sysinf; - memset(&sysinf, 0, sizeof sysinf); - if (!sysinfo(&sysinf)) { - g_pserver->cron_malloc_stats.sys_free = static_cast(sysinf.freeram); - } + g_pserver->cron_malloc_stats.sys_available = getMemAvailable(); } -#endif } /* Check that memory usage is within the current "maxmemory" limit. If over From 271c2cb92cb8ad72b7077cbd466cc2dad873a3ad Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:05:12 -0700 Subject: [PATCH 19/34] meminfo --- src/meminfo.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/meminfo.cpp b/src/meminfo.cpp index b9d9458f8..5808c05b0 100644 --- a/src/meminfo.cpp +++ b/src/meminfo.cpp @@ -2,14 +2,14 @@ #include static size_t getMemKey(std::string key) { -// # ifdef __linux__ +# ifdef __linux__ std::string token; std::ifstream f("/proc/meminfo"); while (f >> token) { if (token == key) { size_t mem_val; if (f >> mem_val) { - return mem_val; + return mem_val * 1024; // values are in kB } else { return 0; } @@ -17,9 +17,9 @@ static size_t getMemKey(std::string key) { } } return 0; -// # else -// return 0; -// # endif +# else + return 0; +# endif } size_t getMemAvailable() { From 3792ffb580d6ce54b798937436f1d5bc83235cef Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:18:34 -0700 Subject: [PATCH 20/34] fix --- src/evict.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index c79c2414b..4e42c85dd 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -429,13 +429,13 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev maxmemory = static_cast(maxmemory*1.2); /* If available system memory is below a certain threshold, force eviction */ - long sys_available_mem_buffer = 0; + long long sys_available_mem_buffer = 0; if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { float available_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; size_t min_available_mem = static_cast(g_pserver->cron_malloc_stats.sys_total * available_mem_ratio); sys_available_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_available - min_available_mem); if (sys_available_mem_buffer < 0) { - long mem_threshold = mem_reported + sys_available_mem_buffer; + long long mem_threshold = mem_reported + sys_available_mem_buffer; maxmemory = ((long)maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); } } From 4da21dd328036e04981158bf6853c517ea37daec Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:20:29 -0700 Subject: [PATCH 21/34] clean --- keydb.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/keydb.conf b/keydb.conf index 8cc020fe4..02e97d4be 100644 --- a/keydb.conf +++ b/keydb.conf @@ -1146,8 +1146,7 @@ acllog-max-len 128 # active-expire-effort 1 # Force evictions when used system memory reaches X% of total system memory. -# This is useful as a safeguard to prevent OOM kills when RSS overhead is -# significant (0 to disable). +# This is useful as a safeguard to prevent OOM kills (0 to disable). # # force-eviction-percent 0 From 329bf17e979e9af60053f8c85152e863eca6e035 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:21:18 -0700 Subject: [PATCH 22/34] fix --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 007a0879d..a3cd741f4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -384,7 +384,7 @@ endif REDIS_SERVER_NAME=keydb-server$(PROG_SUFFIX) REDIS_SENTINEL_NAME=keydb-sentinel$(PROG_SUFFIX) -REDIS_SERVER_OBJ=adlist.o meminfo.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o t_nhash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o tracking.o cron.o connection.o tls.o sha256.o motd_server.o timeout.o setcpuaffinity.o AsyncWorkQueue.o snapshot.o storage/teststorageprovider.o keydbutils.o StorageCache.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ) $(STORAGE_OBJ) +REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o t_nhash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o tracking.o cron.o connection.o tls.o sha256.o motd_server.o timeout.o setcpuaffinity.o AsyncWorkQueue.o snapshot.o storage/teststorageprovider.o keydbutils.o StorageCache.o monotonic.o cli_common.o mt19937-64.o meminfo.o $(ASM_OBJ) $(STORAGE_OBJ) KEYDB_SERVER_OBJ=SnapshotPayloadParseState.o REDIS_CLI_NAME=keydb-cli$(PROG_SUFFIX) REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crcspeed.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o motd_client.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ) From f774a17d8a1605842adb5867312800237ff53b55 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:21:55 -0700 Subject: [PATCH 23/34] fix --- src/evict.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evict.cpp b/src/evict.cpp index 4e42c85dd..35d809e62 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -436,7 +436,7 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev sys_available_mem_buffer = static_cast(g_pserver->cron_malloc_stats.sys_available - min_available_mem); if (sys_available_mem_buffer < 0) { long long mem_threshold = mem_reported + sys_available_mem_buffer; - maxmemory = ((long)maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); + maxmemory = ((long long)maxmemory < mem_threshold) ? maxmemory : static_cast(mem_threshold); } } From e80aba694cf12a74532e1806901f001c14d00630 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:23:00 -0700 Subject: [PATCH 24/34] fix --- src/evict.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index 35d809e62..6c211e444 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -625,7 +625,7 @@ static unsigned long evictionTimeLimitUs() { return ULONG_MAX; /* No limit to eviction time */ } -static void updateSysFreeMemory() { +static void updateSysAvailableMemory() { if (g_pserver->force_eviction_percent) { g_pserver->cron_malloc_stats.sys_available = getMemAvailable(); } @@ -854,7 +854,7 @@ int performEvictions(bool fPreSnapshot) { * across the dbAsyncDelete() call, while the thread can * release the memory all the time. */ if (g_pserver->lazyfree_lazy_eviction) { - updateSysFreeMemory(); + updateSysAvailableMemory(); if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { break; } @@ -886,7 +886,7 @@ int performEvictions(bool fPreSnapshot) { cant_free: if (mem_freed > 0) { - updateSysFreeMemory(); + updateSysAvailableMemory(); } if (g_pserver->m_pstorageFactory) From b2ecf2c856a6b48626b1079b2bdfa6c4792e432d Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 30 Jun 2023 11:23:43 -0700 Subject: [PATCH 25/34] fix --- src/server.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server.cpp b/src/server.cpp index ddb8682da..421513c2f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2316,7 +2316,6 @@ void cronUpdateMemoryStats() { if (g_pserver->force_eviction_percent) { g_pserver->cron_malloc_stats.sys_available = getMemAvailable(); - serverLog(LL_WARNING, "Setting sys_available:%lu", g_pserver->cron_malloc_stats.sys_available); } } } From cf4735b61ef772668c3e340bcc097a90b7fac02f Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Thu, 6 Jul 2023 15:22:52 -0700 Subject: [PATCH 26/34] ok --- src/server.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index 421513c2f..b8dbbf5a8 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -5737,6 +5737,7 @@ sds genRedisInfoString(const char *section) { const char *evict_policy = evictPolicyToString(); long long memory_lua = g_pserver->lua ? (long long)lua_gc(g_pserver->lua,LUA_GCCOUNT,0)*1024 : 0; struct redisMemOverhead *mh = getMemoryOverheadData(); + char available_system_mem[64] = "unavailable"; /* Peak memory is updated from time to time by serverCron() so it * may happen that the instantaneous value is slightly bigger than @@ -5745,6 +5746,10 @@ sds genRedisInfoString(const char *section) { if (zmalloc_used > g_pserver->stat_peak_memory) g_pserver->stat_peak_memory = zmalloc_used; + if (g_pserver->cron_malloc_stats.sys_available) { + snprintf(available_system_mem, 64, "%lu", g_pserver->cron_malloc_stats.sys_available); + } + bytesToHuman(hmem,zmalloc_used,sizeof(hmem)); bytesToHuman(peak_hmem,g_pserver->stat_peak_memory,sizeof(peak_hmem)); bytesToHuman(total_system_hmem,total_system_mem,sizeof(total_system_hmem)); @@ -5797,7 +5802,8 @@ sds genRedisInfoString(const char *section) { "active_defrag_running:%d\r\n" "lazyfree_pending_objects:%zu\r\n" "lazyfreed_objects:%zu\r\n" - "storage_provider:%s\r\n", + "storage_provider:%s\r\n" + "available_system_memory:%s\r\n", zmalloc_used, hmem, g_pserver->cron_malloc_stats.process_rss, @@ -5842,7 +5848,8 @@ sds genRedisInfoString(const char *section) { g_pserver->active_defrag_running, lazyfreeGetPendingObjectsCount(), lazyfreeGetFreedObjectsCount(), - g_pserver->m_pstorageFactory ? g_pserver->m_pstorageFactory->name() : "none" + g_pserver->m_pstorageFactory ? g_pserver->m_pstorageFactory->name() : "none", + available_system_mem ); freeMemoryOverheadData(mh); } From b5a20a4f916435d4bf8deb0bb3ec52493723aa42 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 7 Jul 2023 07:37:07 -0700 Subject: [PATCH 27/34] modify --- src/evict.cpp | 18 ++++++++++++++---- src/server.h | 5 ++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index 6c211e444..cf5046567 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -414,8 +414,13 @@ size_t freeMemoryGetNotCountedMemory(void) { * memory currently used. May be > 1 if we are over the memory * limit. * (Populated both for C_ERR and C_OK) + * + * 'reason' the reason why the memory limit was exceeded + * EVICT_REASON_USER: reported user memory exceeded maxmemory + * EVICT_REASON_SYS: available system memory under configurable threshold + * (Populated when C_ERR is returned) */ -int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, bool fQuickCycle, bool fPreSnapshot) { +int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, int *reason, bool fQuickCycle, bool fPreSnapshot) { size_t mem_reported, mem_used, mem_tofree; /* Check if we are over the memory usage limit. If we are not, no need @@ -480,6 +485,8 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (logical) *logical = mem_used; if (tofree) *tofree = mem_tofree; + if (reason) *reason = sys_available_mem_buffer < 0 ? EVICT_REASON_SYS : EVICT_REASON_USER; + return C_ERR; } @@ -668,10 +675,11 @@ int performEvictions(bool fPreSnapshot) { const bool fEvictToStorage = !cserver.delete_on_evict && g_pserver->db[0]->FStorageProvider(); int result = EVICT_FAIL; int ckeysFailed = 0; + int evictReason; std::unique_ptr splazy = std::make_unique(); - if (getMaxmemoryState(&mem_reported,NULL,&mem_tofree,NULL,false,fPreSnapshot) == C_OK) + if (getMaxmemoryState(&mem_reported,NULL,&mem_tofree,NULL,&evictReason,false,fPreSnapshot) == C_OK) return EVICT_OK; if (g_pserver->maxmemory_policy == MAXMEMORY_NO_EVICTION) @@ -854,7 +862,9 @@ int performEvictions(bool fPreSnapshot) { * across the dbAsyncDelete() call, while the thread can * release the memory all the time. */ if (g_pserver->lazyfree_lazy_eviction) { - updateSysAvailableMemory(); + if (evictReason == EVICT_REASON_SYS) { + updateSysAvailableMemory(); + } if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { break; } @@ -885,7 +895,7 @@ int performEvictions(bool fPreSnapshot) { } cant_free: - if (mem_freed > 0) { + if (mem_freed > 0 && evictReason == EVICT_REASON_SYS) { updateSysAvailableMemory(); } diff --git a/src/server.h b/src/server.h index 475ef3ad3..5d415265c 100644 --- a/src/server.h +++ b/src/server.h @@ -3378,7 +3378,7 @@ int zslLexValueGteMin(sds value, zlexrangespec *spec); int zslLexValueLteMax(sds value, zlexrangespec *spec); /* Core functions */ -int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, bool fQuickCycle = false, bool fPreSnapshot=false); +int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, int *reason=NULL, bool fQuickCycle=false, bool fPreSnapshot=false); size_t freeMemoryGetNotCountedMemory(); int overMaxmemoryAfterAlloc(size_t moremem); int processCommand(client *c, int callFlags); @@ -3662,6 +3662,9 @@ unsigned long LFUDecrAndReturn(robj_roptr o); #define EVICT_RUNNING 1 #define EVICT_FAIL 2 int performEvictions(bool fPreSnapshot); +#define EVICT_REASON_NONE 0 +#define EVICT_REASON_USER 1 +#define EVICT_REASON_SYS 2 /* meminfo.cpp -- get memory info from /proc/memoryinfo for linux distros */ size_t getMemAvailable(); From 872c60566f7c6a7067479993fb61470232cb7715 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 7 Jul 2023 11:07:33 -0700 Subject: [PATCH 28/34] use enum class --- src/evict.cpp | 15 ++++++++++----- src/server.h | 3 --- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index cf5046567..0f8c2bf6b 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -66,6 +66,11 @@ struct evictionPoolEntry { static struct evictionPoolEntry *EvictionPoolLRU; +enum class EvictReason { + User, /* User memory exceeded limit */ + System /* System memory exceeded limit */ +}; + /* ---------------------------------------------------------------------------- * Implementation of eviction, aging and LRU * --------------------------------------------------------------------------*/ @@ -420,7 +425,7 @@ size_t freeMemoryGetNotCountedMemory(void) { * EVICT_REASON_SYS: available system memory under configurable threshold * (Populated when C_ERR is returned) */ -int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, int *reason, bool fQuickCycle, bool fPreSnapshot) { +int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, EvictReason *reason, bool fQuickCycle, bool fPreSnapshot) { size_t mem_reported, mem_used, mem_tofree; /* Check if we are over the memory usage limit. If we are not, no need @@ -485,7 +490,7 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (logical) *logical = mem_used; if (tofree) *tofree = mem_tofree; - if (reason) *reason = sys_available_mem_buffer < 0 ? EVICT_REASON_SYS : EVICT_REASON_USER; + if (reason) *reason = sys_available_mem_buffer < 0 ? EvictReason::System : EvictReason::User; return C_ERR; } @@ -675,7 +680,7 @@ int performEvictions(bool fPreSnapshot) { const bool fEvictToStorage = !cserver.delete_on_evict && g_pserver->db[0]->FStorageProvider(); int result = EVICT_FAIL; int ckeysFailed = 0; - int evictReason; + EvictReason evictReason; std::unique_ptr splazy = std::make_unique(); @@ -862,7 +867,7 @@ int performEvictions(bool fPreSnapshot) { * across the dbAsyncDelete() call, while the thread can * release the memory all the time. */ if (g_pserver->lazyfree_lazy_eviction) { - if (evictReason == EVICT_REASON_SYS) { + if (evictReason == EvictReason::System) { updateSysAvailableMemory(); } if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) { @@ -895,7 +900,7 @@ int performEvictions(bool fPreSnapshot) { } cant_free: - if (mem_freed > 0 && evictReason == EVICT_REASON_SYS) { + if (mem_freed > 0 && evictReason == EvictReason::System) { updateSysAvailableMemory(); } diff --git a/src/server.h b/src/server.h index 5d415265c..612165c0f 100644 --- a/src/server.h +++ b/src/server.h @@ -3662,9 +3662,6 @@ unsigned long LFUDecrAndReturn(robj_roptr o); #define EVICT_RUNNING 1 #define EVICT_FAIL 2 int performEvictions(bool fPreSnapshot); -#define EVICT_REASON_NONE 0 -#define EVICT_REASON_USER 1 -#define EVICT_REASON_SYS 2 /* meminfo.cpp -- get memory info from /proc/memoryinfo for linux distros */ size_t getMemAvailable(); From 0d2f98d6e11dcb4323f2319628f9c3826444f40b Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 7 Jul 2023 11:37:09 -0700 Subject: [PATCH 29/34] fix compile error --- src/evict.cpp | 8 -------- src/server.h | 8 +++++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/evict.cpp b/src/evict.cpp index 0f8c2bf6b..740a6d2b2 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -36,9 +36,6 @@ #include #include #include -#ifdef __linux__ -#include -#endif /* ---------------------------------------------------------------------------- * Data structures @@ -66,11 +63,6 @@ struct evictionPoolEntry { static struct evictionPoolEntry *EvictionPoolLRU; -enum class EvictReason { - User, /* User memory exceeded limit */ - System /* System memory exceeded limit */ -}; - /* ---------------------------------------------------------------------------- * Implementation of eviction, aging and LRU * --------------------------------------------------------------------------*/ diff --git a/src/server.h b/src/server.h index 612165c0f..047834ae2 100644 --- a/src/server.h +++ b/src/server.h @@ -2874,6 +2874,12 @@ typedef struct { #define OBJ_HASH_KEY 1 #define OBJ_HASH_VALUE 2 +/* Used in evict.cpp */ +enum class EvictReason { + User, /* User memory exceeded limit */ + System /* System memory exceeded limit */ +}; + /*----------------------------------------------------------------------------- * Extern declarations *----------------------------------------------------------------------------*/ @@ -3378,7 +3384,7 @@ int zslLexValueGteMin(sds value, zlexrangespec *spec); int zslLexValueLteMax(sds value, zlexrangespec *spec); /* Core functions */ -int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, int *reason=NULL, bool fQuickCycle=false, bool fPreSnapshot=false); +int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, EvictReason *reason=NULL, bool fQuickCycle=false, bool fPreSnapshot=false); size_t freeMemoryGetNotCountedMemory(); int overMaxmemoryAfterAlloc(size_t moremem); int processCommand(client *c, int callFlags); From cc8ed8857752f5c2b35ede8e3db5bf08ea372340 Mon Sep 17 00:00:00 2001 From: Alex Cope Date: Fri, 7 Jul 2023 11:55:49 -0700 Subject: [PATCH 30/34] nullptr --- src/server.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.h b/src/server.h index 047834ae2..9ad1aab8d 100644 --- a/src/server.h +++ b/src/server.h @@ -3384,7 +3384,7 @@ int zslLexValueGteMin(sds value, zlexrangespec *spec); int zslLexValueLteMax(sds value, zlexrangespec *spec); /* Core functions */ -int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, EvictReason *reason=NULL, bool fQuickCycle=false, bool fPreSnapshot=false); +int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, EvictReason *reason=nullptr, bool fQuickCycle=false, bool fPreSnapshot=false); size_t freeMemoryGetNotCountedMemory(); int overMaxmemoryAfterAlloc(size_t moremem); int processCommand(client *c, int callFlags); From 9ab1278cf134f12091fc52c09230d57dea1bc58d Mon Sep 17 00:00:00 2001 From: John Sully Date: Fri, 14 Jul 2023 14:38:39 -0400 Subject: [PATCH 31/34] Prevent a deadlock when running CLIENT KILL with large numbers of clients (#206) --- src/networking.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/networking.cpp b/src/networking.cpp index 90c75a695..1728b5f29 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -3257,16 +3257,18 @@ NULL } else { - int iel = client->iel; freeClientAsync(client); - aePostFunction(g_pserver->rgthreadvar[client->iel].el, [iel] { // note: failure is OK - freeClientsInAsyncFreeQueue(iel); - }); } } killed++; } + for (int iel = 0; iel < cserver.cthreads; ++iel) { + aePostFunction(g_pserver->rgthreadvar[iel].el, [iel] { // note: failure is OK + freeClientsInAsyncFreeQueue(iel); + }); + } + /* Reply according to old/new format. */ if (c->argc == 3) { if (killed == 0) From 06a49a61797052055809196b3681780c017a79e1 Mon Sep 17 00:00:00 2001 From: John Sully Date: Fri, 14 Jul 2023 14:39:09 -0400 Subject: [PATCH 32/34] Fix OOM issues during full sync when fork bgsave is used (#209) --- src/evict.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evict.cpp b/src/evict.cpp index 740a6d2b2..1523b2814 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -427,7 +427,7 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev size_t maxmemory = g_pserver->maxmemory; if (fPreSnapshot) maxmemory = static_cast(maxmemory*0.9); // derate memory by 10% since we won't be able to free during snapshot - if (g_pserver->FRdbSaveInProgress()) + if (g_pserver->FRdbSaveInProgress() && !cserver.fForkBgSave) maxmemory = static_cast(maxmemory*1.2); /* If available system memory is below a certain threshold, force eviction */ From bd6eb379d5282f7f4305c1dc9927eaf7265babf5 Mon Sep 17 00:00:00 2001 From: John Sully Date: Fri, 14 Jul 2023 14:39:23 -0400 Subject: [PATCH 33/34] Prevent crash on free when using repl-disk-buffer-reserve (#207) --- src/replication.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/replication.cpp b/src/replication.cpp index 280043ace..ee3583692 100644 --- a/src/replication.cpp +++ b/src/replication.cpp @@ -345,7 +345,8 @@ void freeReplicationBacklog(void) { client *c = (client*)listNodeValue(ln); serverAssert(c->flags & CLIENT_CLOSE_ASAP || FMasterHost(c)); } - zfree(g_pserver->repl_backlog); + if (g_pserver->repl_backlog != g_pserver->repl_backlog_disk) + zfree(g_pserver->repl_backlog); g_pserver->repl_backlog = NULL; } From aef01878a5a23a955d86bdd7878b4b4d63aac896 Mon Sep 17 00:00:00 2001 From: John Sully Date: Fri, 14 Jul 2023 19:49:46 +0000 Subject: [PATCH 34/34] Build break fix --- src/meminfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meminfo.cpp b/src/meminfo.cpp index 5808c05b0..4d2b63e36 100644 --- a/src/meminfo.cpp +++ b/src/meminfo.cpp @@ -1,5 +1,6 @@ #include #include +#include static size_t getMemKey(std::string key) { # ifdef __linux__