heliosdb_proxy/schema_routing/
mod.rs1pub mod admin;
40pub mod analyzer;
41pub mod classifier;
42pub mod discovery;
43pub mod metrics;
44pub mod registry;
45pub mod router;
46
47pub use admin::{AdminError, SchemaRoutingAdmin};
48pub use analyzer::{QueryAnalysis, QueryAnalyzer, ShardKeyValue, TableRef};
49pub use classifier::{
50 ClassificationModel, LearningClassifier, QueryHistory, QueryType, TableClassification,
51};
52pub use discovery::{DiscoveryConfig, DiscoveryError, SchemaDiscovery};
53pub use metrics::{
54 AIWorkloadStats, MetricsReport, RAGStats, RoutingStats, SchemaRoutingMetrics, TableStats,
55 WorkloadStats,
56};
57pub use registry::{
58 AccessPattern, ColumnSchema, DataTemperature, IndexSchema, NodeCapabilities, PartitionKey,
59 Relationship, SchemaRegistry, ShardingConfig, TableSchema, WorkloadType,
60};
61pub use router::{
62 AIWorkloadType, RAGStage, RouteTarget, RoutingDecision, RoutingPreference, RoutingReason,
63 SchemaAwareRouter,
64};
65
66use std::collections::HashMap;
67use std::time::Duration;
68
69#[derive(Debug, Clone)]
71pub struct SchemaRoutingConfig {
72 pub enabled: bool,
74 pub auto_discover: bool,
76 pub refresh_interval: Duration,
78 pub learning_enabled: bool,
80 pub classification_threshold: u64,
82 pub default_temperature: DataTemperature,
84 pub default_workload: WorkloadType,
86 pub tables: Vec<TableConfig>,
88 pub node_capabilities: HashMap<String, NodeCapabilities>,
90}
91
92impl Default for SchemaRoutingConfig {
93 fn default() -> Self {
94 Self {
95 enabled: true,
96 auto_discover: true,
97 refresh_interval: Duration::from_secs(300),
98 learning_enabled: true,
99 classification_threshold: 1000,
100 default_temperature: DataTemperature::Warm,
101 default_workload: WorkloadType::Mixed,
102 tables: Vec::new(),
103 node_capabilities: HashMap::new(),
104 }
105 }
106}
107
108#[derive(Debug, Default)]
110pub struct SchemaRoutingConfigBuilder {
111 config: SchemaRoutingConfig,
112}
113
114impl SchemaRoutingConfigBuilder {
115 pub fn new() -> Self {
117 Self::default()
118 }
119
120 pub fn enabled(mut self, enabled: bool) -> Self {
122 self.config.enabled = enabled;
123 self
124 }
125
126 pub fn auto_discover(mut self, auto_discover: bool) -> Self {
128 self.config.auto_discover = auto_discover;
129 self
130 }
131
132 pub fn refresh_interval(mut self, interval: Duration) -> Self {
134 self.config.refresh_interval = interval;
135 self
136 }
137
138 pub fn learning_enabled(mut self, enabled: bool) -> Self {
140 self.config.learning_enabled = enabled;
141 self
142 }
143
144 pub fn classification_threshold(mut self, threshold: u64) -> Self {
146 self.config.classification_threshold = threshold;
147 self
148 }
149
150 pub fn default_temperature(mut self, temp: DataTemperature) -> Self {
152 self.config.default_temperature = temp;
153 self
154 }
155
156 pub fn default_workload(mut self, workload: WorkloadType) -> Self {
158 self.config.default_workload = workload;
159 self
160 }
161
162 pub fn add_table(mut self, table: TableConfig) -> Self {
164 self.config.tables.push(table);
165 self
166 }
167
168 pub fn add_node_capability(
170 mut self,
171 node_name: impl Into<String>,
172 caps: NodeCapabilities,
173 ) -> Self {
174 self.config.node_capabilities.insert(node_name.into(), caps);
175 self
176 }
177
178 pub fn build(self) -> SchemaRoutingConfig {
180 self.config
181 }
182}
183
184impl SchemaRoutingConfig {
185 pub fn builder() -> SchemaRoutingConfigBuilder {
187 SchemaRoutingConfigBuilder::new()
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct TableConfig {
194 pub name: String,
196 pub temperature: DataTemperature,
198 pub workload: WorkloadType,
200 pub access_pattern: AccessPattern,
202 pub shard_key: Option<String>,
204 pub shard_count: Option<u32>,
206 pub preferred_nodes: Vec<String>,
208}
209
210impl TableConfig {
211 pub fn new(name: impl Into<String>) -> Self {
213 Self {
214 name: name.into(),
215 temperature: DataTemperature::Warm,
216 workload: WorkloadType::Mixed,
217 access_pattern: AccessPattern::Mixed,
218 shard_key: None,
219 shard_count: None,
220 preferred_nodes: Vec::new(),
221 }
222 }
223
224 pub fn with_temperature(mut self, temp: DataTemperature) -> Self {
226 self.temperature = temp;
227 self
228 }
229
230 pub fn with_workload(mut self, workload: WorkloadType) -> Self {
232 self.workload = workload;
233 self
234 }
235
236 pub fn with_access_pattern(mut self, pattern: AccessPattern) -> Self {
238 self.access_pattern = pattern;
239 self
240 }
241
242 pub fn with_shard_key(mut self, key: impl Into<String>, count: u32) -> Self {
244 self.shard_key = Some(key.into());
245 self.shard_count = Some(count);
246 self
247 }
248
249 pub fn with_preferred_node(mut self, node: impl Into<String>) -> Self {
251 self.preferred_nodes.push(node.into());
252 self
253 }
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
258pub enum SyncMode {
259 Sync,
261 Async,
263 Primary,
265}
266
267#[derive(Debug, Clone)]
269pub struct NodeInfo {
270 pub id: String,
272 pub name: String,
274 pub is_primary: bool,
276 pub sync_mode: SyncMode,
278 pub capabilities: NodeCapabilities,
280 pub current_load: f64,
282 pub current_latency_ms: u64,
284 pub indexes_in_memory: Vec<String>,
286}
287
288impl NodeInfo {
289 pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
291 Self {
292 id: id.into(),
293 name: name.into(),
294 is_primary: false,
295 sync_mode: SyncMode::Async,
296 capabilities: NodeCapabilities::default(),
297 current_load: 0.0,
298 current_latency_ms: 0,
299 indexes_in_memory: Vec::new(),
300 }
301 }
302
303 pub fn as_primary(mut self) -> Self {
305 self.is_primary = true;
306 self.sync_mode = SyncMode::Primary;
307 self
308 }
309
310 pub fn with_sync_mode(mut self, mode: SyncMode) -> Self {
312 self.sync_mode = mode;
313 self
314 }
315
316 pub fn with_capabilities(mut self, caps: NodeCapabilities) -> Self {
318 self.capabilities = caps;
319 self
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326
327 #[test]
328 fn test_config_builder() {
329 let config = SchemaRoutingConfig::builder()
330 .enabled(true)
331 .auto_discover(true)
332 .refresh_interval(Duration::from_secs(60))
333 .learning_enabled(true)
334 .default_temperature(DataTemperature::Hot)
335 .build();
336
337 assert!(config.enabled);
338 assert!(config.auto_discover);
339 assert_eq!(config.refresh_interval, Duration::from_secs(60));
340 assert_eq!(config.default_temperature, DataTemperature::Hot);
341 }
342
343 #[test]
344 fn test_table_config_builder() {
345 let config = TableConfig::new("users")
346 .with_temperature(DataTemperature::Hot)
347 .with_workload(WorkloadType::OLTP)
348 .with_access_pattern(AccessPattern::PointLookup)
349 .with_preferred_node("primary")
350 .with_preferred_node("standby-sync");
351
352 assert_eq!(config.name, "users");
353 assert_eq!(config.temperature, DataTemperature::Hot);
354 assert_eq!(config.workload, WorkloadType::OLTP);
355 assert_eq!(config.preferred_nodes.len(), 2);
356 }
357
358 #[test]
359 fn test_node_info() {
360 let node = NodeInfo::new("node1", "primary")
361 .as_primary()
362 .with_capabilities(NodeCapabilities {
363 vector_search: true,
364 gpu_acceleration: true,
365 ..Default::default()
366 });
367
368 assert!(node.is_primary);
369 assert_eq!(node.sync_mode, SyncMode::Primary);
370 assert!(node.capabilities.vector_search);
371 }
372}