ursula_runtime/
cold_worker.rs1use crate::PlanGroupColdFlushRequest;
6use crate::ShardRuntime;
7
8pub fn spawn_cold_compaction_worker_if_configured(
10 runtime: &ShardRuntime,
11 config: &ursula_config::ColdConfig,
12) {
13 if !config.compaction_enabled {
14 return;
15 }
16 let interval = config.compaction_interval.as_duration();
17 let target_bytes = config.compaction_target_size.as_bytes();
18 let max_bytes = config.compaction_max_size.as_bytes();
19 let max_streams = config.compaction_max_streams_per_pass.max(1);
20 let gc_grace_ms =
21 u64::try_from(config.compaction_gc_grace.as_duration().as_millis()).unwrap_or(u64::MAX);
22 let runtime = runtime.clone();
23 tokio::spawn(async move {
24 loop {
25 match runtime
26 .compact_cold_once(target_bytes, max_bytes, max_streams, gc_grace_ms)
27 .await
28 {
29 Ok(compacted) if compacted > 0 => {
30 tracing::info!(compacted, "cold chunk compaction pass completed");
31 }
32 Ok(_) => {}
33 Err(err) => tracing::error!("cold compaction worker error: {err}"),
34 }
35 tokio::time::sleep(interval).await;
36 }
37 });
38}
39
40pub fn spawn_cold_flush_worker_if_configured(
42 runtime: &ShardRuntime,
43 config: &ursula_config::ColdConfig,
44) {
45 let interval = config.flush_interval.as_duration();
46 if interval.is_zero() {
47 return;
48 }
49 let min_hot_bytes = usize::try_from(config.flush_min_hot_size().as_bytes())
50 .expect("config validation ensures flush sizes fit usize");
51 let max_flush_bytes = usize::try_from(config.flush_max_size().as_bytes())
52 .expect("config validation ensures flush sizes fit usize");
53 let max_concurrency = config.flush_max_concurrency.max(1);
54 let runtime = runtime.clone();
55 tokio::spawn(async move {
56 loop {
57 if let Err(err) = runtime
58 .flush_cold_all_groups_once_bounded(
59 PlanGroupColdFlushRequest {
60 min_hot_bytes,
61 max_flush_bytes,
62 max_batch_bytes: max_flush_bytes,
63 },
64 max_concurrency,
65 )
66 .await
67 {
68 tracing::error!("cold flush worker error: {err}");
69 }
70 tokio::time::sleep(interval).await;
71 }
72 });
73}
74
75pub fn spawn_cold_gc_worker_if_configured(
77 runtime: &ShardRuntime,
78 config: &ursula_config::ColdConfig,
79) {
80 let interval = config.gc_interval.as_duration();
81 if interval.is_zero() {
82 return;
83 }
84 let max_entries = config.gc_max_entries.max(1);
85 let runtime = runtime.clone();
86 tokio::spawn(async move {
87 loop {
88 if let Err(err) = runtime.run_cold_gc_all_groups_once(max_entries).await {
89 tracing::error!("cold gc worker error: {err}");
90 }
91 tokio::time::sleep(interval).await;
92 }
93 });
94}