1use async_trait::async_trait;
4use std::collections::HashMap;
5use std::path::PathBuf;
6use std::sync::Arc;
7use tokio::sync::RwLock;
8use crate::{DatabaseConfig, DatabaseError, MemoryPool, MemoryPoolManager, PoolStats};
9
10pub struct SqliteMemoryPools {
12 pools: Vec<Arc<SqliteMemoryPool>>,
13 config: DatabaseConfig,
14}
15
16impl SqliteMemoryPools {
17 pub async fn new(config: DatabaseConfig) -> Result<Self, DatabaseError> {
18 tokio::fs::create_dir_all(&config.sqlite.pool_directory).await?;
20
21 let mut pools = Vec::with_capacity(config.memory_pools.pool_count);
23 for i in 0..config.memory_pools.pool_count {
24 let pool = SqliteMemoryPool::new(
25 config.sqlite.pool_directory.join(format!("pool_{}.db", i)),
26 config.memory_pools.max_pool_size_mb,
27 ).await?;
28 pools.push(Arc::new(pool));
29 }
30
31 Ok(Self { pools, config })
32 }
33}
34
35#[async_trait]
36impl MemoryPoolManager for SqliteMemoryPools {
37 async fn get_pool(&self, index: usize) -> Result<Box<dyn MemoryPool>, DatabaseError> {
38 if index >= self.pools.len() {
39 return Err(DatabaseError::InvalidPoolIndex(index));
40 }
41 Ok(Box::new(self.pools[index].clone()))
42 }
43
44 async fn get_pool_for_key(&self, key: &str) -> Result<Box<dyn MemoryPool>, DatabaseError> {
45 let hash = seahash::hash(key.as_bytes());
47 let index = (hash as usize) % self.pools.len();
48 self.get_pool(index).await
49 }
50
51 async fn all_stats(&self) -> Result<Vec<PoolStats>, DatabaseError> {
52 let mut stats = Vec::new();
53 for pool in &self.pools {
54 stats.push(pool.stats().await?);
55 }
56 Ok(stats)
57 }
58
59 async fn rebalance(&self) -> Result<(), DatabaseError> {
60 Ok(())
62 }
63}
64
65#[derive(Clone)]
67pub struct SqliteMemoryPool {
68 pool: Arc<sqlx::SqlitePool>,
69 stats: Arc<RwLock<PoolStats>>,
70 max_size_bytes: usize,
71}
72
73impl SqliteMemoryPool {
74 async fn new(path: PathBuf, max_size_mb: usize) -> Result<Self, DatabaseError> {
75 let pool = sqlx::SqlitePool::connect(&format!("sqlite:{}", path.display())).await?;
76
77 sqlx::query(
79 "CREATE TABLE IF NOT EXISTS memory_pool (
80 key TEXT PRIMARY KEY,
81 value BLOB NOT NULL,
82 created_at INTEGER NOT NULL,
83 accessed_at INTEGER NOT NULL,
84 access_count INTEGER DEFAULT 1
85 )"
86 )
87 .execute(&pool)
88 .await?;
89
90 sqlx::query("CREATE INDEX IF NOT EXISTS idx_accessed_at ON memory_pool(accessed_at)")
92 .execute(&pool)
93 .await?;
94
95 let stats = PoolStats {
96 size: 0,
97 items: 0,
98 hits: 0,
99 misses: 0,
100 evictions: 0,
101 };
102
103 Ok(Self {
104 pool: Arc::new(pool),
105 stats: Arc::new(RwLock::new(stats)),
106 max_size_bytes: max_size_mb * 1024 * 1024,
107 })
108 }
109}
110
111#[async_trait]
112impl MemoryPool for SqliteMemoryPool {
113 async fn store(&self, key: &str, value: &[u8]) -> Result<(), DatabaseError> {
114 let now = chrono::Utc::now().timestamp();
115
116 let current_size = self.get_total_size().await?;
118 if current_size + value.len() > self.max_size_bytes {
119 self.evict_lru().await?;
120 }
121
122 sqlx::query(
123 "INSERT OR REPLACE INTO memory_pool (key, value, created_at, accessed_at)
124 VALUES (?, ?, ?, ?)"
125 )
126 .bind(key)
127 .bind(value)
128 .bind(now)
129 .bind(now)
130 .execute(&*self.pool)
131 .await?;
132
133 let mut stats = self.stats.write().await;
134 stats.items += 1;
135 stats.size += value.len();
136
137 Ok(())
138 }
139
140 async fn retrieve(&self, key: &str) -> Result<Option<Vec<u8>>, DatabaseError> {
141 let now = chrono::Utc::now().timestamp();
142
143 let result: Option<(Vec<u8>,)> = sqlx::query_as(
144 "UPDATE memory_pool
145 SET accessed_at = ?, access_count = access_count + 1
146 WHERE key = ?
147 RETURNING value"
148 )
149 .bind(now)
150 .bind(key)
151 .fetch_optional(&*self.pool)
152 .await?;
153
154 let mut stats = self.stats.write().await;
155 if result.is_some() {
156 stats.hits += 1;
157 } else {
158 stats.misses += 1;
159 }
160
161 Ok(result.map(|r| r.0))
162 }
163
164 async fn delete(&self, key: &str) -> Result<(), DatabaseError> {
165 let result = sqlx::query("DELETE FROM memory_pool WHERE key = ?")
166 .bind(key)
167 .execute(&*self.pool)
168 .await?;
169
170 if result.rows_affected() > 0 {
171 let mut stats = self.stats.write().await;
172 stats.items -= 1;
173 }
174
175 Ok(())
176 }
177
178 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>, DatabaseError> {
179 let pattern = format!("{}%", prefix);
180 let keys: Vec<(String,)> = sqlx::query_as(
181 "SELECT key FROM memory_pool WHERE key LIKE ? ORDER BY key"
182 )
183 .bind(pattern)
184 .fetch_all(&*self.pool)
185 .await?;
186
187 Ok(keys.into_iter().map(|k| k.0).collect())
188 }
189
190 async fn stats(&self) -> Result<PoolStats, DatabaseError> {
191 Ok(self.stats.read().await.clone())
192 }
193}
194
195impl SqliteMemoryPool {
196 async fn get_total_size(&self) -> Result<usize, DatabaseError> {
197 let size: (i64,) = sqlx::query_as(
198 "SELECT COALESCE(SUM(LENGTH(value)), 0) FROM memory_pool"
199 )
200 .fetch_one(&*self.pool)
201 .await?;
202
203 Ok(size.0 as usize)
204 }
205
206 async fn evict_lru(&self) -> Result<(), DatabaseError> {
207 let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM memory_pool")
209 .fetch_one(&*self.pool)
210 .await?;
211
212 let to_evict = (count.0 as f64 * 0.1).ceil() as i64;
213
214 sqlx::query(
215 "DELETE FROM memory_pool
216 WHERE key IN (
217 SELECT key FROM memory_pool
218 ORDER BY accessed_at ASC
219 LIMIT ?
220 )"
221 )
222 .bind(to_evict)
223 .execute(&*self.pool)
224 .await?;
225
226 let mut stats = self.stats.write().await;
227 stats.evictions += to_evict as u64;
228 stats.items -= to_evict as usize;
229
230 Ok(())
231 }
232}
233
234#[cfg(feature = "astra")]
236pub struct AstraMemoryPools {
237 pools: Vec<Arc<AstraMemoryPool>>,
238 config: DatabaseConfig,
239}
240
241#[cfg(feature = "astra")]
242impl AstraMemoryPools {
243 pub async fn new(config: DatabaseConfig) -> Result<Self, DatabaseError> {
244 Err(DatabaseError::NotImplemented)
247 }
248}
249
250#[cfg(feature = "astra")]
251#[async_trait]
252impl MemoryPoolManager for AstraMemoryPools {
253 async fn get_pool(&self, index: usize) -> Result<Box<dyn MemoryPool>, DatabaseError> {
254 if index >= self.pools.len() {
255 return Err(DatabaseError::InvalidPoolIndex(index));
256 }
257 Ok(Box::new(self.pools[index].clone()))
258 }
259
260 async fn get_pool_for_key(&self, key: &str) -> Result<Box<dyn MemoryPool>, DatabaseError> {
261 let hash = seahash::hash(key.as_bytes());
262 let index = (hash as usize) % self.pools.len();
263 self.get_pool(index).await
264 }
265
266 async fn all_stats(&self) -> Result<Vec<PoolStats>, DatabaseError> {
267 let mut stats = Vec::new();
268 for pool in &self.pools {
269 stats.push(pool.stats().await?);
270 }
271 Ok(stats)
272 }
273
274 async fn rebalance(&self) -> Result<(), DatabaseError> {
275 Ok(())
277 }
278}
279
280#[cfg(feature = "astra")]
282#[derive(Clone)]
283pub struct AstraMemoryPool {
284 collection_name: String,
285 stats: Arc<RwLock<PoolStats>>,
286}
287
288#[cfg(feature = "astra")]
289#[async_trait]
290impl MemoryPool for AstraMemoryPool {
291 async fn store(&self, _key: &str, _value: &[u8]) -> Result<(), DatabaseError> {
292 Err(DatabaseError::NotImplemented)
293 }
294
295 async fn retrieve(&self, _key: &str) -> Result<Option<Vec<u8>>, DatabaseError> {
296 Err(DatabaseError::NotImplemented)
297 }
298
299 async fn delete(&self, _key: &str) -> Result<(), DatabaseError> {
300 Err(DatabaseError::NotImplemented)
301 }
302
303 async fn list_keys(&self, _prefix: &str) -> Result<Vec<String>, DatabaseError> {
304 Err(DatabaseError::NotImplemented)
305 }
306
307 async fn stats(&self) -> Result<PoolStats, DatabaseError> {
308 Ok(self.stats.read().await.clone())
309 }
310}
311
312#[async_trait]
314impl MemoryPool for Arc<SqliteMemoryPool> {
315 async fn store(&self, key: &str, value: &[u8]) -> Result<(), DatabaseError> {
316 self.as_ref().store(key, value).await
317 }
318
319 async fn retrieve(&self, key: &str) -> Result<Option<Vec<u8>>, DatabaseError> {
320 self.as_ref().retrieve(key).await
321 }
322
323 async fn delete(&self, key: &str) -> Result<(), DatabaseError> {
324 self.as_ref().delete(key).await
325 }
326
327 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>, DatabaseError> {
328 self.as_ref().list_keys(prefix).await
329 }
330
331 async fn stats(&self) -> Result<PoolStats, DatabaseError> {
332 self.as_ref().stats().await
333 }
334}
335
336mod seahash {
337 pub fn hash(data: &[u8]) -> u64 {
338 let mut hasher = std::collections::hash_map::DefaultHasher::new();
339 hasher.write(data);
340 hasher.finish()
341 }
342
343 use std::hash::Hasher;
344}