@@ -19,10 +19,12 @@ extern "C" {
19
19
#include " server/search/doc_index.h"
20
20
#include " server/server_state.h"
21
21
#include " server/tiered_storage.h"
22
+ #include " server/tiering/common.h"
22
23
#include " server/transaction.h"
23
24
#include " util/fibers/proactor_base.h"
24
25
25
26
using namespace std ;
27
+ using namespace ::dfly::tiering::literals;
26
28
27
29
ABSL_FLAG (float , mem_defrag_threshold, 0.7 ,
28
30
" Minimum percentage of used memory relative to maxmemory cap before running "
@@ -65,6 +67,9 @@ ABSL_FLAG(double, eviction_memory_budget_threshold, 0.1,
65
67
" Eviction starts when the free memory (including RSS memory) drops below "
66
68
" eviction_memory_budget_threshold * max_memory_limit." );
67
69
70
+ ABSL_FLAG (uint64_t , force_decommit_threshold, 8_MB,
71
+ " The threshold of memory to force decommit when memory is under pressure." );
72
+
68
73
ABSL_DECLARE_FLAG (uint32_t , max_eviction_per_heartbeat);
69
74
70
75
namespace dfly {
@@ -216,45 +221,6 @@ size_t CalculateHowManyBytesToEvictOnShard(size_t global_memory_limit, size_t gl
216
221
return shard_budget < shard_memory_threshold ? (shard_memory_threshold - shard_budget) : 0 ;
217
222
}
218
223
219
- /* Calculates the number of bytes to evict based on memory and rss memory usage. */
220
- size_t CalculateEvictionBytes () {
221
- const size_t shards_count = shard_set->size ();
222
- const double eviction_memory_budget_threshold = GetFlag (FLAGS_eviction_memory_budget_threshold);
223
-
224
- const size_t shard_memory_budget_threshold =
225
- size_t (max_memory_limit * eviction_memory_budget_threshold) / shards_count;
226
-
227
- const size_t global_used_memory = used_mem_current.load (memory_order_relaxed);
228
-
229
- // Calculate how many bytes we need to evict on this shard
230
- size_t goal_bytes = CalculateHowManyBytesToEvictOnShard (max_memory_limit, global_used_memory,
231
- shard_memory_budget_threshold);
232
-
233
- // TODO: Eviction due to rss usage is not working well as it causes eviction
234
- // of to many keys untill we finally see decrease in rss. We need to improve
235
- // this logic before we enable it.
236
- /*
237
- const double rss_oom_deny_ratio = ServerState::tlocal()->rss_oom_deny_ratio;
238
- // If rss_oom_deny_ratio is set, we should evict depending on rss memory too
239
- if (rss_oom_deny_ratio > 0.0) {
240
- const size_t max_rss_memory = size_t(rss_oom_deny_ratio * max_memory_limit);
241
- // We start eviction when we have less than eviction_memory_budget_threshold * 100% of free rss
242
- memory const size_t shard_rss_memory_budget_threshold =
243
- size_t(max_rss_memory * eviction_memory_budget_threshold) / shards_count;
244
-
245
- // Calculate how much rss memory is used by all shards
246
- const size_t global_used_rss_memory = rss_mem_current.load(memory_order_relaxed);
247
-
248
- // Try to evict more bytes if we are close to the rss memory limit
249
- goal_bytes = std::max(
250
- goal_bytes, CalculateHowManyBytesToEvictOnShard(max_rss_memory, global_used_rss_memory,
251
- shard_rss_memory_budget_threshold));
252
- }
253
- */
254
-
255
- return goal_bytes;
256
- }
257
-
258
224
} // namespace
259
225
260
226
__thread EngineShard* EngineShard::shard_ = nullptr ;
@@ -347,6 +313,18 @@ bool EngineShard::DefragTaskState::CheckRequired() {
347
313
return false ;
348
314
}
349
315
316
+ std::optional<ShardMemUsage> shard_mem_usage;
317
+
318
+ if (GetFlag (FLAGS_enable_heartbeat_eviction)) {
319
+ shard_mem_usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
320
+ const static double eviction_waste_threshold = 0.05 ;
321
+ if (shard_mem_usage->wasted_mem >
322
+ (uint64_t (shard_mem_usage->commited * eviction_waste_threshold))) {
323
+ VLOG (1 ) << " memory issue found for memory " << shard_mem_usage.value ();
324
+ return true ;
325
+ }
326
+ }
327
+
350
328
const std::size_t global_threshold = max_memory_limit * GetFlag (FLAGS_mem_defrag_threshold);
351
329
if (global_threshold > rss_mem_current.load (memory_order_relaxed)) {
352
330
return false ;
@@ -361,11 +339,15 @@ bool EngineShard::DefragTaskState::CheckRequired() {
361
339
}
362
340
last_check_time = now;
363
341
364
- ShardMemUsage usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
342
+ if (!shard_mem_usage) {
343
+ shard_mem_usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
344
+ }
345
+
346
+ DCHECK (shard_mem_usage.has_value ());
365
347
366
348
const double waste_threshold = GetFlag (FLAGS_mem_defrag_waste_threshold);
367
- if (usage. wasted_mem > (uint64_t (usage. commited * waste_threshold))) {
368
- VLOG (1 ) << " memory issue found for memory " << usage ;
349
+ if (shard_mem_usage-> wasted_mem > (uint64_t (shard_mem_usage-> commited * waste_threshold))) {
350
+ VLOG (1 ) << " memory issue found for memory " << shard_mem_usage. value () ;
369
351
return true ;
370
352
}
371
353
@@ -800,6 +782,7 @@ void EngineShard::RetireExpiredAndEvict() {
800
782
DbContext db_cntx;
801
783
db_cntx.time_now_ms = GetCurrentTimeMs ();
802
784
785
+ size_t deleted_bytes = 0 ;
803
786
size_t eviction_goal = GetFlag (FLAGS_enable_heartbeat_eviction) ? CalculateEvictionBytes () : 0 ;
804
787
805
788
for (unsigned i = 0 ; i < db_slice.db_array_size (); ++i) {
@@ -811,6 +794,7 @@ void EngineShard::RetireExpiredAndEvict() {
811
794
if (expt->size () > 0 ) {
812
795
DbSlice::DeleteExpiredStats stats = db_slice.DeleteExpiredStep (db_cntx, ttl_delete_target);
813
796
797
+ deleted_bytes += stats.deleted_bytes ;
814
798
eviction_goal -= std::min (eviction_goal, size_t (stats.deleted_bytes ));
815
799
counter_[TTL_TRAVERSE].IncBy (stats.traversed );
816
800
counter_[TTL_DELETE].IncBy (stats.deleted );
@@ -832,9 +816,75 @@ void EngineShard::RetireExpiredAndEvict() {
832
816
<< " bytes. Max eviction per heartbeat: "
833
817
<< GetFlag (FLAGS_max_eviction_per_heartbeat);
834
818
819
+ deleted_bytes += evicted_bytes;
835
820
eviction_goal -= std::min (eviction_goal, evicted_bytes);
836
821
}
837
822
}
823
+
824
+ auto & deleted_bytes_before_decommit = eviction_state_.deleted_bytes_before_decommit ;
825
+ eviction_state_.deleted_bytes_before_rss_update += deleted_bytes;
826
+ deleted_bytes_before_decommit += deleted_bytes;
827
+
828
+ if (deleted_bytes_before_decommit >= absl::GetFlag (FLAGS_force_decommit_threshold)) {
829
+ // Decommit with force
830
+ deleted_bytes_before_decommit = 0 ;
831
+ ServerState::tlocal ()->DecommitMemory (ServerState::kAllMemory );
832
+ }
833
+ }
834
+
835
+ size_t EngineShard::CalculateEvictionBytes () {
836
+ const size_t shards_count = shard_set->size ();
837
+ const double eviction_memory_budget_threshold = GetFlag (FLAGS_eviction_memory_budget_threshold);
838
+
839
+ const size_t shard_memory_budget_threshold =
840
+ size_t (max_memory_limit * eviction_memory_budget_threshold) / shards_count;
841
+
842
+ const size_t global_used_memory = used_mem_current.load (memory_order_relaxed);
843
+
844
+ // Calculate how many bytes we need to evict on this shard
845
+ size_t goal_bytes = CalculateHowManyBytesToEvictOnShard (max_memory_limit, global_used_memory,
846
+ shard_memory_budget_threshold);
847
+
848
+ LOG_IF_EVERY_N (INFO, goal_bytes > 0 , 10 )
849
+ << " Memory goal bytes: " << goal_bytes << " , used memory: " << global_used_memory
850
+ << " , memory limit: " << max_memory_limit;
851
+
852
+ // If rss_oom_deny_ratio is set, we should evict depending on rss memory too
853
+ const double rss_oom_deny_ratio = ServerState::tlocal ()->rss_oom_deny_ratio ;
854
+ if (rss_oom_deny_ratio > 0.0 ) {
855
+ const size_t max_rss_memory = size_t (rss_oom_deny_ratio * max_memory_limit);
856
+ /* We start eviction when we have less than eviction_memory_budget_threshold * 100% of free rss
857
+ * memory */
858
+ const size_t shard_rss_memory_budget_threshold =
859
+ size_t (max_rss_memory * eviction_memory_budget_threshold) / shards_count;
860
+
861
+ // Calculate how much rss memory is used by all shards
862
+ const size_t global_used_rss_memory = rss_mem_current.load (memory_order_relaxed);
863
+
864
+ auto & global_rss_memory_at_prev_eviction = eviction_state_.global_rss_memory_at_prev_eviction ;
865
+ auto & deleted_bytes_before_rss_update = eviction_state_.deleted_bytes_before_rss_update ;
866
+ if (global_used_rss_memory < eviction_state_.global_rss_memory_at_prev_eviction ) {
867
+ deleted_bytes_before_rss_update -=
868
+ std::min (deleted_bytes_before_rss_update,
869
+ (global_rss_memory_at_prev_eviction - global_used_rss_memory) / shards_count);
870
+ }
871
+
872
+ global_rss_memory_at_prev_eviction = global_used_rss_memory;
873
+
874
+ // Try to evict more bytes if we are close to the rss memory limit
875
+ const size_t rss_goal_bytes = CalculateHowManyBytesToEvictOnShard (
876
+ max_rss_memory, global_used_rss_memory - deleted_bytes_before_rss_update * shards_count,
877
+ shard_rss_memory_budget_threshold);
878
+
879
+ LOG_IF_EVERY_N (INFO, goal_bytes > 0 , 10 )
880
+ << " Rss memory goal bytes: " << rss_goal_bytes
881
+ << " , rss used memory: " << global_used_rss_memory
882
+ << " , rss memory limit: " << max_rss_memory
883
+ << " , deleted_bytes_before_rss_update: " << deleted_bytes_before_rss_update;
884
+
885
+ goal_bytes = std::max (goal_bytes, rss_goal_bytes);
886
+ }
887
+ return goal_bytes;
838
888
}
839
889
840
890
void EngineShard::CacheStats () {
0 commit comments