@@ -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 ;
@@ -359,6 +325,18 @@ bool EngineShard::DefragTaskState::CheckRequired() {
359
325
return false ;
360
326
}
361
327
328
+ std::optional<ShardMemUsage> shard_mem_usage;
329
+
330
+ if (GetFlag (FLAGS_enable_heartbeat_eviction)) {
331
+ shard_mem_usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
332
+ const static double eviction_waste_threshold = 0.05 ;
333
+ if (shard_mem_usage->wasted_mem >
334
+ (uint64_t (shard_mem_usage->commited * eviction_waste_threshold))) {
335
+ VLOG (1 ) << " memory issue found for memory " << shard_mem_usage.value ();
336
+ return true ;
337
+ }
338
+ }
339
+
362
340
const std::size_t global_threshold = max_memory_limit * GetFlag (FLAGS_mem_defrag_threshold);
363
341
if (global_threshold > rss_mem_current.load (memory_order_relaxed)) {
364
342
return false ;
@@ -373,11 +351,15 @@ bool EngineShard::DefragTaskState::CheckRequired() {
373
351
}
374
352
last_check_time = now;
375
353
376
- ShardMemUsage usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
354
+ if (!shard_mem_usage) {
355
+ shard_mem_usage = ReadShardMemUsage (GetFlag (FLAGS_mem_defrag_page_utilization_threshold));
356
+ }
357
+
358
+ DCHECK (shard_mem_usage.has_value ());
377
359
378
360
const double waste_threshold = GetFlag (FLAGS_mem_defrag_waste_threshold);
379
- if (usage. wasted_mem > (uint64_t (usage. commited * waste_threshold))) {
380
- VLOG (1 ) << " memory issue found for memory " << usage ;
361
+ if (shard_mem_usage-> wasted_mem > (uint64_t (shard_mem_usage-> commited * waste_threshold))) {
362
+ VLOG (1 ) << " memory issue found for memory " << shard_mem_usage. value () ;
381
363
return true ;
382
364
}
383
365
@@ -812,6 +794,7 @@ void EngineShard::RetireExpiredAndEvict() {
812
794
DbContext db_cntx;
813
795
db_cntx.time_now_ms = GetCurrentTimeMs ();
814
796
797
+ size_t deleted_bytes = 0 ;
815
798
size_t eviction_goal = GetFlag (FLAGS_enable_heartbeat_eviction) ? CalculateEvictionBytes () : 0 ;
816
799
817
800
for (unsigned i = 0 ; i < db_slice.db_array_size (); ++i) {
@@ -823,6 +806,7 @@ void EngineShard::RetireExpiredAndEvict() {
823
806
if (expt->size () > 0 ) {
824
807
DbSlice::DeleteExpiredStats stats = db_slice.DeleteExpiredStep (db_cntx, ttl_delete_target);
825
808
809
+ deleted_bytes += stats.deleted_bytes ;
826
810
eviction_goal -= std::min (eviction_goal, size_t (stats.deleted_bytes ));
827
811
counter_[TTL_TRAVERSE].IncBy (stats.traversed );
828
812
counter_[TTL_DELETE].IncBy (stats.deleted );
@@ -844,9 +828,71 @@ void EngineShard::RetireExpiredAndEvict() {
844
828
<< " bytes. Max eviction per heartbeat: "
845
829
<< GetFlag (FLAGS_max_eviction_per_heartbeat);
846
830
831
+ deleted_bytes += evicted_bytes;
847
832
eviction_goal -= std::min (eviction_goal, evicted_bytes);
848
833
}
849
834
}
835
+
836
+ eviction_state_.deleted_bytes_before_rss_update += deleted_bytes;
837
+ }
838
+
839
+ size_t EngineShard::CalculateEvictionBytes () {
840
+ const size_t shards_count = shard_set->size ();
841
+ const double eviction_memory_budget_threshold = GetFlag (FLAGS_eviction_memory_budget_threshold);
842
+
843
+ const size_t shard_memory_budget_threshold =
844
+ size_t (max_memory_limit * eviction_memory_budget_threshold) / shards_count;
845
+
846
+ const size_t global_used_memory = used_mem_current.load (memory_order_relaxed);
847
+
848
+ // Calculate how many bytes we need to evict on this shard
849
+ size_t goal_bytes = CalculateHowManyBytesToEvictOnShard (max_memory_limit, global_used_memory,
850
+ shard_memory_budget_threshold);
851
+
852
+ LOG_IF_EVERY_N (INFO, goal_bytes > 0 , 50 )
853
+ << " Memory goal bytes: " << goal_bytes << " , used memory: " << global_used_memory
854
+ << " , memory limit: " << max_memory_limit;
855
+
856
+ // If rss_oom_deny_ratio is set, we should evict depending on rss memory too
857
+ const double rss_oom_deny_ratio = ServerState::tlocal ()->rss_oom_deny_ratio ;
858
+ if (rss_oom_deny_ratio > 0.0 ) {
859
+ const size_t max_rss_memory = size_t (rss_oom_deny_ratio * max_memory_limit);
860
+ /* We start eviction when we have less than eviction_memory_budget_threshold * 100% of free rss
861
+ * memory */
862
+ const size_t shard_rss_memory_budget_threshold =
863
+ size_t (max_rss_memory * eviction_memory_budget_threshold) / shards_count;
864
+
865
+ // Calculate how much rss memory is used by all shards
866
+ const size_t global_used_rss_memory = rss_mem_current.load (memory_order_relaxed);
867
+
868
+ auto & global_rss_memory_at_prev_eviction = eviction_state_.global_rss_memory_at_prev_eviction ;
869
+ auto & deleted_bytes_before_rss_update = eviction_state_.deleted_bytes_before_rss_update ;
870
+ if (global_used_rss_memory < eviction_state_.global_rss_memory_at_prev_eviction ) {
871
+ deleted_bytes_before_rss_update -=
872
+ std::min (deleted_bytes_before_rss_update,
873
+ (global_rss_memory_at_prev_eviction - global_used_rss_memory) / shards_count);
874
+ }
875
+
876
+ /* if (global_used_rss_memory == global_rss_memory_at_prev_eviction) {
877
+
878
+ } */
879
+
880
+ global_rss_memory_at_prev_eviction = global_used_rss_memory;
881
+
882
+ // Try to evict more bytes if we are close to the rss memory limit
883
+ const size_t rss_goal_bytes = CalculateHowManyBytesToEvictOnShard (
884
+ max_rss_memory, global_used_rss_memory - deleted_bytes_before_rss_update * shards_count,
885
+ shard_rss_memory_budget_threshold);
886
+
887
+ LOG_IF_EVERY_N (INFO, rss_goal_bytes > 0 , 50 )
888
+ << " Rss memory goal bytes: " << rss_goal_bytes
889
+ << " , rss used memory: " << global_used_rss_memory
890
+ << " , rss memory limit: " << max_rss_memory
891
+ << " , deleted_bytes_before_rss_update: " << deleted_bytes_before_rss_update;
892
+
893
+ goal_bytes = std::max (goal_bytes, rss_goal_bytes);
894
+ }
895
+ return goal_bytes;
850
896
}
851
897
852
898
void EngineShard::CacheStats () {
0 commit comments