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