1use std::collections::HashMap;
12use std::sync::{Arc, Mutex};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum CachingStrategy {
17 Disabled,
19 Redis,
21 InMemory,
23 None,
25}
26
27pub trait StorageAccess<K, V>: Send + Sync
31where
32 K: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
33 V: Clone + Send + Sync + 'static,
34{
35 fn get(&self, key: &K) -> Option<V>;
37 fn put(&self, key: K, value: V);
39 fn invalidate(&self, key: &K);
41 fn contains(&self, key: &K) -> bool {
43 self.get(key).is_some()
44 }
45 fn clear(&self);
47}
48
49pub struct InMemoryStorageAccess<K, V>
56where
57 K: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
58 V: Clone + Send + Sync + 'static,
59{
60 cache: Arc<Mutex<HashMap<K, V>>>,
61 max_capacity: usize,
62}
63
64impl<K, V> InMemoryStorageAccess<K, V>
65where
66 K: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
67 V: Clone + Send + Sync + 'static,
68{
69 pub fn new(max_capacity: u64) -> Self {
71 Self {
72 cache: Arc::new(Mutex::new(HashMap::new())),
73 max_capacity: max_capacity as usize,
74 }
75 }
76
77 pub fn for_region(_region: &str) -> Self {
79 Self::new(1024)
80 }
81}
82
83impl<K, V> StorageAccess<K, V> for InMemoryStorageAccess<K, V>
84where
85 K: std::hash::Hash + Eq + Clone + Send + Sync + 'static,
86 V: Clone + Send + Sync + 'static,
87{
88 fn get(&self, key: &K) -> Option<V> {
89 self.cache.lock().unwrap().get(key).cloned()
90 }
91 fn put(&self, key: K, value: V) {
92 let mut map = self.cache.lock().unwrap();
93 if map.len() >= self.max_capacity {
94 if let Some(k) = map.keys().next().cloned() {
95 map.remove(&k);
96 }
97 }
98 map.insert(key, value);
99 }
100 fn invalidate(&self, key: &K) {
101 self.cache.lock().unwrap().remove(key);
102 }
103 fn clear(&self) {
104 self.cache.lock().unwrap().clear();
105 }
106}
107
108use redis::{AsyncCommands, Client, RedisResult};
111
112#[derive(Clone)]
116pub struct RedisStorage {
117 client: Client,
118}
119
120impl RedisStorage {
121 pub fn new(url: &str) -> RedisResult<Self> {
123 Ok(Self {
124 client: Client::open(url)?,
125 })
126 }
127
128 pub fn from_env() -> RedisResult<Self> {
130 let url = std::env::var("REDIS_URL")
131 .or_else(|_| std::env::var("REDIS_URI"))
132 .unwrap_or_else(|_| "redis://127.0.0.1:6379/".to_string());
133 Self::new(&url)
134 }
135
136 pub fn client(&self) -> &Client {
138 &self.client
139 }
140
141 async fn conn(&self) -> RedisResult<redis::aio::MultiplexedConnection> {
142 self.client.get_multiplexed_async_connection().await
143 }
144
145 pub async fn get_value(&self, key: &str) -> RedisResult<Option<String>> {
149 let mut conn = self.conn().await?;
150 conn.get(key).await
151 }
152
153 pub async fn set_value(&self, key: &str, value: &str) -> RedisResult<()> {
155 let mut conn = self.conn().await?;
156 conn.set::<_, _, ()>(key, value).await
157 }
158
159 pub async fn set_value_with_expiration(&self, key: &str, value: &str, seconds: u64) -> RedisResult<()> {
161 let mut conn = self.conn().await?;
162 conn.set_ex::<_, _, ()>(key, value, seconds).await
163 }
164
165 pub async fn set_value_if_absent(&self, key: &str, value: &str) -> RedisResult<bool> {
167 let mut conn = self.conn().await?;
168 let res: Option<String> = redis::cmd("SET")
170 .arg(key)
171 .arg(value)
172 .arg("NX")
173 .query_async(&mut conn)
174 .await?;
175 Ok(res.is_some())
176 }
177
178 pub async fn delete_key(&self, key: &str) -> RedisResult<i64> {
180 let mut conn = self.conn().await?;
181 conn.del(key).await
182 }
183
184 pub async fn unlink_key(&self, key: &str) -> RedisResult<i64> {
186 let mut conn = self.conn().await?;
187 redis::cmd("UNLINK").arg(key).query_async(&mut conn).await
188 }
189
190 pub async fn delete_keys(&self, keys: &[String]) -> RedisResult<i64> {
192 if keys.is_empty() {
193 return Ok(0);
194 }
195 let mut conn = self.conn().await?;
196 conn.del(keys).await
197 }
198
199 pub async fn key_exists(&self, key: &str) -> RedisResult<bool> {
201 let mut conn = self.conn().await?;
202 let v: i64 = conn.exists(key).await?;
203 Ok(v == 1)
204 }
205
206 pub async fn increment_value(&self, key: &str) -> RedisResult<i64> {
208 let mut conn = self.conn().await?;
209 conn.incr(key, 1i64).await
210 }
211
212 pub async fn increment_value_by(&self, key: &str, delta: i64) -> RedisResult<i64> {
214 let mut conn = self.conn().await?;
215 conn.incr(key, delta).await
216 }
217
218 pub async fn decrement_value(&self, key: &str) -> RedisResult<i64> {
220 let mut conn = self.conn().await?;
221 conn.decr(key, 1i64).await
222 }
223
224 pub async fn decrement_value_by(&self, key: &str, delta: i64) -> RedisResult<i64> {
226 let mut conn = self.conn().await?;
227 conn.decr(key, delta).await
228 }
229
230 pub async fn idle_time(&self, key: &str) -> RedisResult<i64> {
232 let mut conn = self.conn().await?;
233 redis::cmd("OBJECT")
234 .arg("IDLETIME")
235 .arg(key)
236 .query_async(&mut conn)
237 .await
238 }
239
240 pub async fn set_expiration(&self, key: &str, seconds: u64) -> RedisResult<bool> {
242 let mut conn = self.conn().await?;
243 let v: i64 = conn.expire(key, seconds as i64).await?;
244 Ok(v == 1)
245 }
246
247 pub async fn get_time_to_live(&self, key: &str) -> RedisResult<i64> {
249 let mut conn = self.conn().await?;
250 conn.ttl(key).await
251 }
252
253 pub async fn get_multiple_values(&self, keys: &[String]) -> RedisResult<Vec<Option<String>>> {
255 if keys.is_empty() {
256 return Ok(vec![]);
257 }
258 let mut conn = self.conn().await?;
259 conn.mget(keys).await
260 }
261
262 pub async fn set_multiple_values(&self, kv: &HashMap<String, String>) -> RedisResult<()> {
264 if kv.is_empty() {
265 return Ok(());
266 }
267 let mut conn = self.conn().await?;
268 let mut args: Vec<String> = Vec::with_capacity(kv.len() * 2);
270 for (k, v) in kv {
271 args.push(k.clone());
272 args.push(v.clone());
273 }
274 redis::cmd("MSET").arg(args).query_async::<()>(&mut conn).await?;
276 Ok(())
277 }
278
279 pub async fn get_hash_value(&self, key: &str, field: &str) -> RedisResult<Option<String>> {
283 let mut conn = self.conn().await?;
284 conn.hget(key, field).await
285 }
286
287 pub async fn set_hash_value(&self, key: &str, field: &str, value: &str) -> RedisResult<()> {
289 let mut conn = self.conn().await?;
290 conn.hset::<_, _, _, ()>(key, field, value).await
291 }
292
293 pub async fn delete_hash_field(&self, key: &str, field: &str) -> RedisResult<i64> {
295 let mut conn = self.conn().await?;
296 conn.hdel(key, field).await
297 }
298
299 pub async fn set_hash_values(&self, key: &str, field_values: &HashMap<String, String>) -> RedisResult<()> {
301 if field_values.is_empty() {
302 return Ok(());
303 }
304 let mut conn = self.conn().await?;
305 let mut cmd = redis::cmd("HSET");
307 cmd.arg(key);
308 for (f, v) in field_values {
309 cmd.arg(f).arg(v);
310 }
311 cmd.query_async::<()>(&mut conn).await?;
312 Ok(())
313 }
314
315 pub async fn set_hash_value_if_absent(&self, key: &str, field: &str, value: &str) -> RedisResult<bool> {
317 let mut conn = self.conn().await?;
318 let v: i64 = conn.hset_nx(key, field, value).await?;
319 Ok(v == 1)
320 }
321
322 pub async fn increment_hash_field(&self, key: &str, field: &str, delta: i64) -> RedisResult<i64> {
324 let mut conn = self.conn().await?;
325 conn.hincr(key, field, delta).await
326 }
327
328 pub async fn decrement_hash_field(&self, key: &str, field: &str, delta: i64) -> RedisResult<i64> {
330 self.increment_hash_field(key, field, -delta).await
331 }
332
333 pub async fn get_all_hash_fields(&self, key: &str) -> RedisResult<HashMap<String, String>> {
335 let mut conn = self.conn().await?;
336 conn.hgetall(key).await
337 }
338
339 pub async fn get_hash_keys(&self, key: &str) -> RedisResult<Vec<String>> {
341 let mut conn = self.conn().await?;
342 conn.hkeys(key).await
343 }
344
345 pub async fn get_hash_values(&self, key: &str) -> RedisResult<Vec<String>> {
347 let mut conn = self.conn().await?;
348 conn.hvals(key).await
349 }
350
351 pub async fn hash_field_exists(&self, key: &str, field: &str) -> RedisResult<bool> {
353 let mut conn = self.conn().await?;
354 let v: bool = conn.hexists(key, field).await?;
355 Ok(v)
356 }
357
358 pub async fn push_to_list_start(&self, key: &str, value: &str) -> RedisResult<i64> {
362 let mut conn = self.conn().await?;
363 conn.lpush(key, value).await
364 }
365
366 pub async fn push_to_list_end(&self, key: &str, value: &str) -> RedisResult<i64> {
368 let mut conn = self.conn().await?;
369 conn.rpush(key, value).await
370 }
371
372 pub async fn pop_from_list_start(&self, key: &str) -> RedisResult<Option<String>> {
374 let mut conn = self.conn().await?;
375 conn.lpop(key, None).await
376 }
377
378 pub async fn pop_from_list_end(&self, key: &str) -> RedisResult<Option<String>> {
380 let mut conn = self.conn().await?;
381 conn.rpop(key, None).await
382 }
383
384 pub async fn get_list_length(&self, key: &str) -> RedisResult<i64> {
386 let mut conn = self.conn().await?;
387 conn.llen(key).await
388 }
389
390 pub async fn get_list_range(&self, key: &str, start: i64, stop: i64) -> RedisResult<Vec<String>> {
392 let mut conn = self.conn().await?;
393 conn.lrange(key, start as isize, stop as isize).await
394 }
395
396 pub async fn add_to_set(&self, key: &str, member: &str) -> RedisResult<i64> {
400 let mut conn = self.conn().await?;
401 conn.sadd(key, member).await
402 }
403
404 pub async fn remove_from_set(&self, key: &str, member: &str) -> RedisResult<i64> {
406 let mut conn = self.conn().await?;
407 conn.srem(key, member).await
408 }
409
410 pub async fn get_set_members(&self, key: &str) -> RedisResult<Vec<String>> {
412 let mut conn = self.conn().await?;
413 conn.smembers(key).await
414 }
415
416 pub async fn is_set_member(&self, key: &str, member: &str) -> RedisResult<bool> {
418 let mut conn = self.conn().await?;
419 conn.sismember(key, member).await
420 }
421
422 pub async fn get_set_size(&self, key: &str) -> RedisResult<i64> {
424 let mut conn = self.conn().await?;
425 conn.scard(key).await
426 }
427
428 pub async fn add_to_sorted_set(&self, key: &str, score: f64, member: &str) -> RedisResult<i64> {
432 let mut conn = self.conn().await?;
433 conn.zadd(key, member, score).await
434 }
435
436 pub async fn get_sorted_set_range(&self, key: &str, start: i64, stop: i64) -> RedisResult<Vec<String>> {
438 let mut conn = self.conn().await?;
439 conn.zrange(key, start as isize, stop as isize).await
440 }
441
442 pub async fn remove_from_sorted_set(&self, key: &str, member: &str) -> RedisResult<i64> {
444 let mut conn = self.conn().await?;
445 conn.zrem(key, member).await
446 }
447
448 pub async fn get_sorted_set_score(&self, key: &str, member: &str) -> RedisResult<Option<f64>> {
450 let mut conn = self.conn().await?;
451 conn.zscore(key, member).await
452 }
453
454 pub async fn get_sorted_set_size(&self, key: &str) -> RedisResult<i64> {
456 let mut conn = self.conn().await?;
457 conn.zcard(key).await
458 }
459
460 pub async fn remove_expiration(&self, key: &str) -> RedisResult<bool> {
464 let mut conn = self.conn().await?;
465 let v: i64 = redis::cmd("PERSIST").arg(key).query_async(&mut conn).await?;
466 Ok(v == 1)
467 }
468
469 pub async fn rename_key(&self, old_key: &str, new_key: &str) -> RedisResult<()> {
471 let mut conn = self.conn().await?;
472 redis::cmd("RENAME").arg(old_key).arg(new_key).query_async::<()>(&mut conn).await?;
473 Ok(())
474 }
475
476 pub async fn scan_keys(&self, pattern: &str, count: usize) -> RedisResult<Vec<String>> {
480 let mut conn = self.conn().await?;
481 let mut cursor: u64 = 0;
482 let mut all = Vec::new();
483 loop {
484 let (next_cursor, keys): (u64, Vec<String>) = redis::cmd("SCAN")
485 .arg(cursor)
486 .arg("MATCH")
487 .arg(pattern)
488 .arg("COUNT")
489 .arg(count)
490 .query_async(&mut conn)
491 .await?;
492 all.extend(keys);
493 if next_cursor == 0 {
494 break;
495 }
496 cursor = next_cursor;
497 }
498 Ok(all)
499 }
500
501 pub async fn scan_keys_default(&self, pattern: &str) -> RedisResult<Vec<String>> {
503 self.scan_keys(pattern, 250).await
504 }
505
506 #[deprecated(note = "Use scan_keys instead to avoid blocking Redis")]
508 pub async fn find_keys(&self, pattern: &str) -> RedisResult<Vec<String>> {
509 self.scan_keys_default(pattern).await
510 }
511}
512
513pub struct RedisStorageAccess {
520 storage: RedisStorage,
521 prefix: String,
522 ttl_seconds: u64,
523}
524
525impl RedisStorageAccess {
526 pub fn new(storage: RedisStorage, region_name: &str) -> Self {
528 Self {
529 storage,
530 prefix: format!("hibernate:cache:{}:", region_name),
531 ttl_seconds: 3600,
532 }
533 }
534
535 pub fn from_url(url: &str, region_name: &str) -> RedisResult<Self> {
537 Ok(Self::new(RedisStorage::new(url)?, region_name))
538 }
539
540 pub fn with_ttl(mut self, ttl_seconds: u64) -> Self {
542 self.ttl_seconds = ttl_seconds;
543 self
544 }
545
546 fn build_key<K: ToString>(&self, key: &K) -> String {
547 format!("{}{}", self.prefix, key.to_string())
548 }
549
550 fn serialize<T: serde::Serialize>(value: &T) -> Result<Vec<u8>, serde_json::Error> {
551 serde_json::to_vec(value)
553 }
554
555 fn deserialize<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> Result<T, serde_json::Error> {
556 serde_json::from_slice(bytes)
557 }
558
559 pub async fn contains_async<K: ToString + Send + Sync>(&self, key: &K) -> RedisResult<bool> {
563 self.storage.key_exists(&self.build_key(key)).await
564 }
565
566 pub async fn get_from_cache_async<K, V>(&self, key: &K) -> RedisResult<Option<V>>
570 where
571 K: ToString + Send + Sync,
572 V: serde::de::DeserializeOwned,
573 {
574 let raw: Option<Vec<u8>> = {
575 let mut conn = self.storage.conn().await?;
576 let k = self.build_key(key);
577 conn.get(k).await?
578 };
579 match raw {
580 None => Ok(None),
581 Some(bytes) => match Self::deserialize::<V>(&bytes) {
582 Ok(v) => Ok(Some(v)),
583 Err(_) => Ok(None),
584 },
585 }
586 }
587
588 pub async fn put_into_cache_async<K, V>(&self, key: &K, value: &V) -> RedisResult<()>
592 where
593 K: ToString + Send + Sync,
594 V: serde::Serialize,
595 {
596 let bytes = Self::serialize(value).map_err(|e| {
597 redis::RedisError::from((
598 redis::ErrorKind::Io,
599 "serialization failed",
600 e.to_string(),
601 ))
602 })?;
603 let mut conn = self.storage.conn().await?;
604 let k = self.build_key(key);
605 conn.set_ex::<_, _, ()>(k, bytes, self.ttl_seconds).await
607 }
608
609 pub async fn remove_from_cache_async<K: ToString + Send + Sync>(&self, key: &K) -> RedisResult<()> {
611 self.storage.unlink_key(&self.build_key(key)).await.map(|_| ())
612 }
613
614 pub async fn clear_cache_async(&self) -> RedisResult<()> {
616 let pattern = format!("{}*", self.prefix);
617 let keys = self.storage.scan_keys(&pattern, 750).await?;
618 if keys.is_empty() {
619 return Ok(());
620 }
621 let mut conn = self.storage.conn().await?;
622 for key in keys {
623 let _: () = redis::cmd("UNLINK").arg(key).query_async(&mut conn).await?;
624 }
625 Ok(())
626 }
627
628 fn block_on<F: Future>(fut: F) -> F::Output {
631 if let Ok(handle) = tokio::runtime::Handle::try_current() {
633 tokio::task::block_in_place(|| handle.block_on(fut))
634 } else {
635 tokio::runtime::Builder::new_current_thread()
636 .enable_all()
637 .build()
638 .unwrap()
639 .block_on(fut)
640 }
641 }
642}
643
644impl<K, V> StorageAccess<K, V> for RedisStorageAccess
645where
646 K: std::hash::Hash + Eq + Clone + ToString + Send + Sync + 'static,
647 V: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static,
648{
649 fn get(&self, key: &K) -> Option<V> {
650 Self::block_on(self.get_from_cache_async(key)).ok().flatten()
651 }
652
653 fn put(&self, key: K, value: V) {
654 let _ = Self::block_on(self.put_into_cache_async(&key, &value));
655 }
656
657 fn invalidate(&self, key: &K) {
658 let _ = Self::block_on(self.remove_from_cache_async(key));
659 }
660
661 fn clear(&self) {
662 let _ = Self::block_on(self.clear_cache_async());
663 }
664}
665
666use std::collections::hash_map::Entry;
669
670pub struct InMemoryRegionFactory {
674 regions: Mutex<HashMap<String, Arc<InMemoryStorageAccess<String, Vec<u8>>>>>,
675}
676
677impl InMemoryRegionFactory {
678 pub fn new() -> Self {
680 Self {
681 regions: Mutex::new(HashMap::new()),
682 }
683 }
684
685 pub fn get_or_create(&self, region_name: &str) -> Arc<InMemoryStorageAccess<String, Vec<u8>>> {
687 let mut map = self.regions.lock().unwrap();
688 match map.entry(region_name.to_string()) {
689 Entry::Occupied(o) => o.get().clone(),
690 Entry::Vacant(v) => {
691 let access = Arc::new(InMemoryStorageAccess::for_region(region_name));
692 v.insert(access.clone());
693 access
694 }
695 }
696 }
697
698 pub fn clear_all(&self) {
700 let map = self.regions.lock().unwrap();
701 for access in map.values() {
702 access.clear();
703 }
704 }
705}
706
707impl Default for InMemoryRegionFactory {
708 fn default() -> Self {
709 Self::new()
710 }
711}
712
713pub struct RedisRegionFactory {
715 storage: RedisStorage,
716 regions: Mutex<HashMap<String, Arc<RedisStorageAccess>>>,
717}
718
719impl RedisRegionFactory {
720 pub fn new(storage: RedisStorage) -> Self {
722 Self {
723 storage,
724 regions: Mutex::new(HashMap::new()),
725 }
726 }
727
728 pub fn from_url(url: &str) -> RedisResult<Self> {
730 Ok(Self::new(RedisStorage::new(url)?))
731 }
732
733 pub fn get_or_create(&self, region_name: &str) -> Arc<RedisStorageAccess> {
735 let mut map = self.regions.lock().unwrap();
736 match map.entry(region_name.to_string()) {
737 Entry::Occupied(o) => o.get().clone(),
738 Entry::Vacant(v) => {
739 let access = Arc::new(RedisStorageAccess::new(self.storage.clone(), region_name));
740 v.insert(access.clone());
741 access
742 }
743 }
744 }
745}