allsource_core/infrastructure/persistence/
performance.rs1use std::time::{Duration, Instant};
2
3pub struct BatchWriter<T> {
29 buffer: Vec<T>,
30 capacity: usize,
31 last_flush: Instant,
32 flush_interval: Duration,
33}
34
35impl<T> BatchWriter<T> {
36 pub fn new(capacity: usize, flush_interval: Duration) -> Self {
42 Self {
43 buffer: Vec::with_capacity(capacity),
44 capacity,
45 last_flush: Instant::now(),
46 flush_interval,
47 }
48 }
49
50 pub fn add(&mut self, item: T) {
52 self.buffer.push(item);
53 }
54
55 pub fn should_flush(&self) -> bool {
57 self.buffer.len() >= self.capacity || self.last_flush.elapsed() >= self.flush_interval
58 }
59
60 pub fn len(&self) -> usize {
62 self.buffer.len()
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.buffer.is_empty()
68 }
69
70 pub fn flush(&mut self) -> Vec<T> {
72 self.last_flush = Instant::now();
73 std::mem::take(&mut self.buffer)
74 }
75
76 pub fn time_since_flush(&self) -> Duration {
78 self.last_flush.elapsed()
79 }
80}
81
82#[derive(Debug, Clone)]
84pub struct PerformanceMetrics {
85 pub operations: u64,
86 pub total_duration: Duration,
87 pub min_duration: Option<Duration>,
88 pub max_duration: Option<Duration>,
89}
90
91impl PerformanceMetrics {
92 pub fn new() -> Self {
93 Self {
94 operations: 0,
95 total_duration: Duration::ZERO,
96 min_duration: None,
97 max_duration: None,
98 }
99 }
100
101 pub fn record(&mut self, duration: Duration) {
102 self.operations += 1;
103 self.total_duration += duration;
104
105 self.min_duration = Some(match self.min_duration {
106 Some(min) => min.min(duration),
107 None => duration,
108 });
109
110 self.max_duration = Some(match self.max_duration {
111 Some(max) => max.max(duration),
112 None => duration,
113 });
114 }
115
116 pub fn avg_duration(&self) -> Option<Duration> {
117 if self.operations == 0 {
118 None
119 } else {
120 Some(self.total_duration / self.operations as u32)
121 }
122 }
123
124 pub fn throughput_per_sec(&self) -> f64 {
125 if self.total_duration.as_secs_f64() == 0.0 {
126 0.0
127 } else {
128 self.operations as f64 / self.total_duration.as_secs_f64()
129 }
130 }
131}
132
133impl Default for PerformanceMetrics {
134 fn default() -> Self {
135 Self::new()
136 }
137}
138
139pub struct MemoryPool<T> {
148 pool: Vec<Vec<T>>,
149 capacity: usize,
150 max_pool_size: usize,
151}
152
153impl<T> MemoryPool<T> {
154 pub fn new(capacity: usize, max_pool_size: usize) -> Self {
155 Self {
156 pool: Vec::new(),
157 capacity,
158 max_pool_size,
159 }
160 }
161
162 pub fn get(&mut self) -> Vec<T> {
164 self.pool
165 .pop()
166 .unwrap_or_else(|| Vec::with_capacity(self.capacity))
167 }
168
169 pub fn put(&mut self, mut buffer: Vec<T>) {
171 if self.pool.len() < self.max_pool_size {
172 buffer.clear();
173 self.pool.push(buffer);
174 }
175 }
176
177 pub fn pool_size(&self) -> usize {
179 self.pool.len()
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn test_batch_writer_capacity() {
189 let mut writer = BatchWriter::new(3, Duration::from_secs(10));
190
191 writer.add(1);
192 writer.add(2);
193 assert!(!writer.should_flush());
194
195 writer.add(3);
196 assert!(writer.should_flush());
197
198 let items = writer.flush();
199 assert_eq!(items, vec![1, 2, 3]);
200 assert!(writer.is_empty());
201 }
202
203 #[test]
204 fn test_batch_writer_time_threshold() {
205 let mut writer = BatchWriter::new(100, Duration::from_millis(1));
206
207 writer.add(1);
208 std::thread::sleep(Duration::from_millis(2));
209
210 assert!(writer.should_flush());
211 }
212
213 #[test]
214 fn test_performance_metrics() {
215 let mut metrics = PerformanceMetrics::new();
216
217 metrics.record(Duration::from_millis(10));
218 metrics.record(Duration::from_millis(20));
219 metrics.record(Duration::from_millis(30));
220
221 assert_eq!(metrics.operations, 3);
222 assert_eq!(metrics.avg_duration(), Some(Duration::from_millis(20)));
223 assert_eq!(metrics.min_duration, Some(Duration::from_millis(10)));
224 assert_eq!(metrics.max_duration, Some(Duration::from_millis(30)));
225 }
226
227 #[test]
228 fn test_performance_metrics_throughput() {
229 let mut metrics = PerformanceMetrics::new();
230
231 for _ in 0..100 {
232 metrics.record(Duration::from_millis(10));
233 }
234
235 let throughput = metrics.throughput_per_sec();
236 assert!(throughput > 90.0 && throughput < 110.0); }
238
239 #[test]
240 fn test_memory_pool() {
241 let mut pool: MemoryPool<i32> = MemoryPool::new(10, 5);
242
243 let buf1 = pool.get();
244 assert_eq!(buf1.capacity(), 10);
245
246 let mut buf2 = pool.get();
247 buf2.push(1);
248 buf2.push(2);
249
250 pool.put(buf2);
251 assert_eq!(pool.pool_size(), 1);
252
253 let buf3 = pool.get();
254 assert_eq!(buf3.len(), 0); assert_eq!(buf3.capacity(), 10);
256 }
257
258 #[test]
259 fn test_memory_pool_max_size() {
260 let mut pool: MemoryPool<i32> = MemoryPool::new(10, 2);
261
262 pool.put(vec![]);
263 pool.put(vec![]);
264 pool.put(vec![]); assert_eq!(pool.pool_size(), 2);
267 }
268
269 #[test]
270 fn test_batch_writer_len() {
271 let mut writer = BatchWriter::new(10, Duration::from_secs(10));
272
273 assert_eq!(writer.len(), 0);
274 writer.add(1);
275 assert_eq!(writer.len(), 1);
276 writer.add(2);
277 assert_eq!(writer.len(), 2);
278
279 writer.flush();
280 assert_eq!(writer.len(), 0);
281 }
282}