chryso_core/
system_params.rs1use parking_lot::RwLock;
2use std::collections::HashMap;
3use std::sync::Arc;
4
5const DEFAULT_TENANT: &str = "__default__";
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum SystemParamValue {
9 Float(f64),
10 Int(i64),
11 Bool(bool),
12 String(String),
13}
14
15impl SystemParamValue {
16 pub fn as_f64(&self) -> Option<f64> {
17 match self {
18 SystemParamValue::Float(value) => Some(*value),
19 SystemParamValue::Int(value) => Some(*value as f64),
20 _ => None,
21 }
22 }
23}
24
25#[derive(Debug, Default)]
26pub struct SystemParamRegistry {
27 tenants: RwLock<HashMap<String, HashMap<String, SystemParamValue>>>,
28}
29
30impl SystemParamRegistry {
31 pub fn new() -> Self {
32 Self {
33 tenants: RwLock::new(HashMap::new()),
34 }
35 }
36
37 pub fn shared() -> Arc<Self> {
38 Arc::new(Self::new())
39 }
40
41 pub fn set_param(&self, tenant: &str, key: impl Into<String>, value: SystemParamValue) {
42 let mut guard = self.tenants.write();
43 let entry = guard.entry(tenant.to_string()).or_default();
44 entry.insert(key.into(), value);
45 }
46
47 pub fn set_default_param(&self, key: impl Into<String>, value: SystemParamValue) {
48 self.set_param(DEFAULT_TENANT, key, value);
49 }
50
51 pub fn get_param(&self, tenant: Option<&str>, key: &str) -> Option<SystemParamValue> {
52 let guard = self.tenants.read();
53 if let Some(tenant) = tenant {
54 if let Some(params) = guard.get(tenant) {
55 if let Some(value) = params.get(key) {
56 return Some(value.clone());
57 }
58 }
59 }
60 guard
61 .get(DEFAULT_TENANT)
62 .and_then(|params| params.get(key))
63 .cloned()
64 }
65
66 pub fn get_f64(&self, tenant: Option<&str>, key: &str) -> Option<f64> {
67 self.get_param(tenant, key).and_then(|value| value.as_f64())
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::{SystemParamRegistry, SystemParamValue};
74
75 #[test]
76 fn registry_uses_default_fallback() {
77 let registry = SystemParamRegistry::new();
78 registry.set_default_param("optimizer.cost.scan", SystemParamValue::Float(2.0));
79 assert_eq!(
80 registry.get_f64(Some("tenant-a"), "optimizer.cost.scan"),
81 Some(2.0)
82 );
83 }
84
85 #[test]
86 fn registry_prefers_tenant_specific_value() {
87 let registry = SystemParamRegistry::new();
88 registry.set_default_param("optimizer.cost.scan", SystemParamValue::Float(2.0));
89 registry.set_param(
90 "tenant-a",
91 "optimizer.cost.scan",
92 SystemParamValue::Float(3.0),
93 );
94 assert_eq!(
95 registry.get_f64(Some("tenant-a"), "optimizer.cost.scan"),
96 Some(3.0)
97 );
98 }
99}