velesdb_core/guardrails/
limits.rs1use serde::{Deserialize, Serialize};
7
8pub const DEFAULT_MAX_DEPTH: u32 = 10;
10
11pub const DEFAULT_MAX_CARDINALITY: usize = 100_000;
13
14pub const DEFAULT_MEMORY_LIMIT_BYTES: usize = 100 * 1024 * 1024;
16
17pub const DEFAULT_RATE_LIMIT_QPS: u32 = 100_000;
19
20pub const DEFAULT_CIRCUIT_FAILURE_THRESHOLD: u32 = 5;
22
23pub const DEFAULT_CIRCUIT_RECOVERY_SECONDS: u64 = 30;
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(default)]
29pub struct QueryLimits {
30 pub max_depth: u32,
32 pub max_cardinality: usize,
34 pub memory_limit_bytes: usize,
36 pub timeout_ms: u64,
42 pub rate_limit_qps: u32,
44 pub circuit_failure_threshold: u32,
46 pub circuit_recovery_seconds: u64,
48}
49
50impl Default for QueryLimits {
51 fn default() -> Self {
52 Self {
53 max_depth: DEFAULT_MAX_DEPTH,
54 max_cardinality: DEFAULT_MAX_CARDINALITY,
55 memory_limit_bytes: DEFAULT_MEMORY_LIMIT_BYTES,
56 timeout_ms: 30_000,
57 rate_limit_qps: DEFAULT_RATE_LIMIT_QPS,
58 circuit_failure_threshold: DEFAULT_CIRCUIT_FAILURE_THRESHOLD,
59 circuit_recovery_seconds: DEFAULT_CIRCUIT_RECOVERY_SECONDS,
60 }
61 }
62}
63
64impl QueryLimits {
65 #[must_use]
67 pub fn new() -> Self {
68 Self::default()
69 }
70
71 #[must_use]
73 pub fn with_max_depth(mut self, depth: u32) -> Self {
74 self.max_depth = depth;
75 self
76 }
77
78 #[must_use]
80 pub fn with_max_cardinality(mut self, cardinality: usize) -> Self {
81 self.max_cardinality = cardinality;
82 self
83 }
84
85 #[must_use]
87 pub fn with_memory_limit(mut self, bytes: usize) -> Self {
88 self.memory_limit_bytes = bytes;
89 self
90 }
91
92 #[must_use]
94 pub fn with_timeout_ms(mut self, ms: u64) -> Self {
95 self.timeout_ms = ms;
96 self
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
102#[non_exhaustive]
103pub enum GuardRailViolation {
104 DepthExceeded {
106 max: u32,
108 actual: u32,
110 },
111 CardinalityExceeded {
113 max: usize,
115 actual: usize,
117 },
118 MemoryExceeded {
120 max_bytes: usize,
122 used_bytes: usize,
124 },
125 Timeout {
127 max_ms: u64,
129 elapsed_ms: u64,
131 },
132 RateLimitExceeded {
134 limit_qps: u32,
136 },
137 CircuitOpen {
139 recovery_in_seconds: u64,
141 },
142}
143
144impl std::fmt::Display for GuardRailViolation {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 match self {
147 Self::DepthExceeded { max, actual } => {
148 write!(f, "Traversal depth exceeded: max={max}, actual={actual}")
149 }
150 Self::CardinalityExceeded { max, actual } => {
151 write!(f, "Cardinality exceeded: max={max}, actual={actual}")
152 }
153 Self::MemoryExceeded {
154 max_bytes,
155 used_bytes,
156 } => {
157 write!(
158 f,
159 "Memory limit exceeded: max={}MB, used={}MB",
160 max_bytes / (1024 * 1024),
161 used_bytes / (1024 * 1024)
162 )
163 }
164 Self::Timeout { max_ms, elapsed_ms } => {
165 write!(f, "Query timed out: max={max_ms}ms, elapsed={elapsed_ms}ms")
166 }
167 Self::RateLimitExceeded { limit_qps } => {
168 write!(f, "Rate limit exceeded: {limit_qps} queries/second")
169 }
170 Self::CircuitOpen {
171 recovery_in_seconds,
172 } => {
173 write!(
174 f,
175 "Circuit breaker open, recovery in {recovery_in_seconds}s"
176 )
177 }
178 }
179 }
180}
181
182impl std::error::Error for GuardRailViolation {}