1use async_trait::async_trait;
49use chrono::{DateTime, Utc};
50use deadpool_redis::{Config as PoolConfig, Connection, Pool, Runtime};
51use futures::StreamExt;
52use redis::{AsyncCommands, RedisError, Script};
53use serde::{de::DeserializeOwned, Deserialize, Serialize};
54use std::collections::HashMap;
55use std::sync::Arc;
56use std::time::Instant;
57use tokio::sync::{Mutex, RwLock};
58use tracing::{debug, error, info, trace, warn};
59
60use super::config::RedisConfig;
61use super::error::{StorageError, StorageResult};
62use super::traits::{CacheStats, CacheStorage, PubSubStorage, Storage, Subscriber};
63use super::types::{
64 Batch, Operation, Query, StorageBackend, StorageEntry, StorageHealth, StorageMetadata,
65 StorageStats, Transaction, TransactionState,
66};
67
68#[derive(Debug)]
70pub struct RedisStorage {
71 pool: Pool,
73
74 config: RedisConfig,
76
77 stats: Arc<RwLock<StorageStats>>,
79
80 cache_stats: Arc<RwLock<InternalCacheStats>>,
82
83 transactions: Arc<RwLock<HashMap<String, Transaction>>>,
85
86 subscriptions: Arc<RwLock<HashMap<String, Arc<Mutex<RedisSubscriber>>>>>,
88
89 scripts: Arc<LuaScripts>,
91
92 shutdown: Arc<RwLock<bool>>,
94}
95
96#[derive(Debug, Clone, Default, Serialize, Deserialize)]
98struct InternalCacheStats {
99 hits: u64,
100 misses: u64,
101 evictions: u64,
102 sets: u64,
103 deletes: u64,
104}
105
106#[derive(Debug)]
108struct LuaScripts {
109 cas: Script,
111
112 versioned_update: Script,
114
115 conditional_delete: Script,
117
118 batch_insert_ttl: Script,
120}
121
122impl LuaScripts {
123 fn new() -> Self {
124 Self {
125 cas: Script::new(
126 r#"
127 local key = KEYS[1]
128 local expected_version = tonumber(ARGV[1])
129 local new_value = ARGV[2]
130 local new_version = tonumber(ARGV[3])
131
132 local current_version = redis.call('GET', key .. ':version')
133 if not current_version then
134 return 0
135 end
136
137 if tonumber(current_version) ~= expected_version then
138 return 0
139 end
140
141 redis.call('SET', key, new_value)
142 redis.call('SET', key .. ':version', new_version)
143 return 1
144 "#,
145 ),
146 versioned_update: Script::new(
147 r#"
148 local key = KEYS[1]
149 local expected_version = tonumber(ARGV[1])
150 local new_value = ARGV[2]
151
152 local current_version = redis.call('GET', key .. ':version')
153 if not current_version then
154 return 0
155 end
156
157 if tonumber(current_version) ~= expected_version then
158 return 0
159 end
160
161 local new_version = expected_version + 1
162 redis.call('SET', key, new_value)
163 redis.call('SET', key .. ':version', new_version)
164 return new_version
165 "#,
166 ),
167 conditional_delete: Script::new(
168 r#"
169 local key = KEYS[1]
170 local expected_version = tonumber(ARGV[1])
171
172 local current_version = redis.call('GET', key .. ':version')
173 if not current_version then
174 return 0
175 end
176
177 if tonumber(current_version) == expected_version then
178 redis.call('DEL', key)
179 redis.call('DEL', key .. ':version')
180 redis.call('DEL', key .. ':metadata')
181 return 1
182 end
183
184 return 0
185 "#,
186 ),
187 batch_insert_ttl: Script::new(
188 r#"
189 local ttl = tonumber(ARGV[1])
190 for i = 1, #KEYS do
191 local key = KEYS[i]
192 local value = ARGV[i + 1]
193 redis.call('SET', key, value)
194 if ttl > 0 then
195 redis.call('EXPIRE', key, ttl)
196 end
197 end
198 return #KEYS
199 "#,
200 ),
201 }
202 }
203}
204
205struct RedisSubscriber {
207 channel: String,
209
210 pubsub: redis::aio::PubSub,
212
213 buffer: Vec<Vec<u8>>,
215}
216
217impl std::fmt::Debug for RedisSubscriber {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 f.debug_struct("RedisSubscriber")
220 .field("channel", &self.channel)
221 .field("buffer_len", &self.buffer.len())
222 .finish()
223 }
224}
225
226impl RedisSubscriber {
227 async fn new(redis_url: String, channel: String) -> StorageResult<Self> {
228 let client = redis::Client::open(redis_url.clone())
230 .map_err(|e| StorageError::ConnectionError {
231 source: Box::new(e),
232 })?;
233
234 let connection_info = client.get_connection_info();
236
237 let addr = match &connection_info.addr {
239 redis::ConnectionAddr::Tcp(host, port) => format!("{}:{}", host, port),
240 redis::ConnectionAddr::TcpTls { host, port, .. } => format!("{}:{}", host, port),
241 redis::ConnectionAddr::Unix(_) => {
242 return Err(StorageError::UnsupportedOperation {
243 operation: "PubSub over Unix sockets".to_string(),
244 backend: "Redis".to_string(),
245 });
246 }
247 };
248
249 let stream = tokio::net::TcpStream::connect(&addr).await
250 .map_err(|e| StorageError::ConnectionError {
251 source: Box::new(e),
252 })?;
253
254 let pubsub = redis::aio::PubSub::new(&connection_info.redis, stream).await
256 .map_err(|e| StorageError::ConnectionError {
257 source: Box::new(e),
258 })?;
259
260 Ok(Self {
261 channel,
262 pubsub,
263 buffer: Vec::new(),
264 })
265 }
266}
267
268#[async_trait]
269impl Subscriber for RedisSubscriber {
270 async fn next_message(&mut self) -> StorageResult<Option<Vec<u8>>> {
271 if !self.buffer.is_empty() {
273 return Ok(Some(self.buffer.remove(0)));
274 }
275
276 match self.pubsub.on_message().next().await {
278 Some(msg) => {
279 let payload = msg.get_payload_bytes().to_vec();
280 trace!("Received pub/sub message on channel {}: {} bytes", self.channel, payload.len());
281 Ok(Some(payload))
282 }
283 None => {
284 debug!("Pub/sub stream ended");
285 Ok(None)
286 }
287 }
288 }
289}
290
291impl RedisStorage {
292 pub async fn new(config: RedisConfig) -> StorageResult<Self> {
294 info!("Initializing Redis storage backend");
295 debug!("Redis configuration: host={}:{}, database={}, key_prefix={}",
296 config.host, config.port, config.database, config.key_prefix);
297
298 let pool_config = PoolConfig::from_url(&config.connection_url());
300 let pool = pool_config
301 .builder()
302 .map_err(|e| StorageError::InvalidConfiguration {
303 message: format!("Failed to create pool builder: {}", e),
304 })?
305 .max_size(16) .runtime(Runtime::Tokio1)
307 .build()
308 .map_err(|e| StorageError::ConnectionError {
309 source: Box::new(e),
310 })?;
311
312 let mut conn = pool.get().await.map_err(|e| StorageError::ConnectionError {
314 source: Box::new(e),
315 })?;
316
317 let _: String = redis::cmd("PING")
319 .query_async(&mut *conn)
320 .await
321 .map_err(|e| StorageError::ConnectionError {
322 source: Box::new(e),
323 })?;
324
325 info!("Successfully connected to Redis");
326
327 Ok(Self {
328 pool,
329 config,
330 stats: Arc::new(RwLock::new(StorageStats::new())),
331 cache_stats: Arc::new(RwLock::new(InternalCacheStats::default())),
332 transactions: Arc::new(RwLock::new(HashMap::new())),
333 subscriptions: Arc::new(RwLock::new(HashMap::new())),
334 scripts: Arc::new(LuaScripts::new()),
335 shutdown: Arc::new(RwLock::new(false)),
336 })
337 }
338
339 fn build_key(&self, table: &str, key: &str) -> String {
341 format!("{}:{}:{}", self.config.key_prefix, table, key)
342 }
343
344 fn build_version_key(&self, table: &str, key: &str) -> String {
346 format!("{}:{}:{}:version", self.config.key_prefix, table, key)
347 }
348
349 fn build_metadata_key(&self, table: &str, key: &str) -> String {
351 format!("{}:{}:{}:metadata", self.config.key_prefix, table, key)
352 }
353
354 fn build_table_pattern(&self, table: &str) -> String {
356 format!("{}:{}:*", self.config.key_prefix, table)
357 }
358
359 async fn get_connection(&self) -> StorageResult<Connection> {
361 let start = Instant::now();
362
363 let conn = self.pool.get().await.map_err(|e| {
364 error!("Failed to get connection from pool: {}", e);
365 StorageError::ConnectionError {
366 source: Box::new(e),
367 }
368 })?;
369
370 let elapsed = start.elapsed().as_millis() as f64;
371 trace!("Acquired connection from pool in {:.2}ms", elapsed);
372
373 Ok(conn)
374 }
375
376 fn serialize_value<T: Serialize>(&self, value: &T) -> StorageResult<String> {
378 serde_json::to_string(value).map_err(|e| StorageError::SerializationError {
379 source: Box::new(e),
380 })
381 }
382
383 fn deserialize_value<T: DeserializeOwned>(&self, data: &str) -> StorageResult<T> {
385 serde_json::from_str(data).map_err(|e| StorageError::DeserializationError {
386 source: Box::new(e),
387 })
388 }
389
390 async fn get_version(&self, conn: &mut Connection, table: &str, key: &str) -> StorageResult<u64> {
392 let version_key = self.build_version_key(table, key);
393 let version: Option<u64> = conn
394 .get(&version_key)
395 .await
396 .map_err(|e| StorageError::QueryError {
397 message: format!("Failed to get version: {}", e),
398 })?;
399
400 Ok(version.unwrap_or(0))
401 }
402
403 async fn set_version(&self, conn: &mut Connection, table: &str, key: &str, version: u64) -> StorageResult<()> {
405 let version_key = self.build_version_key(table, key);
406 conn.set(&version_key, version)
407 .await
408 .map_err(|e| StorageError::QueryError {
409 message: format!("Failed to set version: {}", e),
410 })
411 }
412
413 async fn increment_version(&self, conn: &mut Connection, table: &str, key: &str) -> StorageResult<u64> {
415 let version_key = self.build_version_key(table, key);
416 let new_version: u64 = conn
417 .incr(&version_key, 1)
418 .await
419 .map_err(|e| StorageError::QueryError {
420 message: format!("Failed to increment version: {}", e),
421 })?;
422
423 Ok(new_version)
424 }
425
426 async fn get_metadata(&self, conn: &mut Connection, table: &str, key: &str) -> StorageResult<HashMap<String, String>> {
428 let metadata_key = self.build_metadata_key(table, key);
429 let metadata_json: Option<String> = conn
430 .get(&metadata_key)
431 .await
432 .map_err(|e| StorageError::QueryError {
433 message: format!("Failed to get metadata: {}", e),
434 })?;
435
436 if let Some(json) = metadata_json {
437 self.deserialize_value(&json)
438 } else {
439 Ok(HashMap::new())
440 }
441 }
442
443 async fn set_metadata(&self, conn: &mut Connection, table: &str, key: &str, metadata: &HashMap<String, String>) -> StorageResult<()> {
445 let metadata_key = self.build_metadata_key(table, key);
446 let metadata_json = self.serialize_value(metadata)?;
447
448 conn.set(&metadata_key, metadata_json)
449 .await
450 .map_err(|e| StorageError::QueryError {
451 message: format!("Failed to set metadata: {}", e),
452 })
453 }
454
455 async fn update_cache_stats(&self, hit: bool) {
457 let mut stats = self.cache_stats.write().await;
458 if hit {
459 stats.hits += 1;
460 } else {
461 stats.misses += 1;
462 }
463 }
464
465 async fn update_operation_stats(&self, success: bool, latency_ms: f64, bytes: u64) {
467 let mut stats = self.stats.write().await;
468 if success {
469 stats.record_success(latency_ms, bytes);
470 } else {
471 stats.record_failure();
472 }
473 }
474
475 async fn execute_with_retry<F, T>(&self, operation: F) -> StorageResult<T>
477 where
478 F: Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<T, RedisError>> + Send>> + Send,
479 {
480 let max_retries = 3;
481 let mut last_error = None;
482
483 for attempt in 0..max_retries {
484 match operation().await {
485 Ok(result) => return Ok(result),
486 Err(e) => {
487 warn!("Redis operation failed (attempt {}/{}): {}", attempt + 1, max_retries, e);
488 last_error = Some(e);
489
490 if attempt < max_retries - 1 {
491 let delay = std::time::Duration::from_millis(100 * (2_u64.pow(attempt as u32)));
492 tokio::time::sleep(delay).await;
493 }
494 }
495 }
496 }
497
498 Err(StorageError::QueryError {
499 message: format!("Operation failed after {} retries: {}", max_retries, last_error.unwrap()),
500 })
501 }
502
503 async fn scan_keys(&self, pattern: &str) -> StorageResult<Vec<String>> {
505 let mut conn = self.get_connection().await?;
506 let mut keys = Vec::new();
507 let mut cursor = 0u64;
508
509 loop {
510 let (new_cursor, batch): (u64, Vec<String>) = redis::cmd("SCAN")
511 .arg(cursor)
512 .arg("MATCH")
513 .arg(pattern)
514 .arg("COUNT")
515 .arg(100)
516 .query_async(&mut *conn)
517 .await
518 .map_err(|e| StorageError::QueryError {
519 message: format!("SCAN failed: {}", e),
520 })?;
521
522 keys.extend(batch);
523 cursor = new_cursor;
524
525 if cursor == 0 {
526 break;
527 }
528 }
529
530 Ok(keys)
531 }
532
533 async fn build_entry<T: DeserializeOwned + Send + Sync>(
535 &self,
536 conn: &mut Connection,
537 table: &str,
538 key: &str,
539 value_json: String,
540 ) -> StorageResult<StorageEntry<T>> {
541 let value: T = self.deserialize_value(&value_json)?;
542 let version = self.get_version(conn, table, key).await?;
543 let metadata = self.get_metadata(conn, table, key).await?;
544
545 let redis_key = self.build_key(table, key);
547 let ttl: i64 = conn
548 .ttl(&redis_key)
549 .await
550 .map_err(|e| StorageError::QueryError {
551 message: format!("Failed to get TTL: {}", e),
552 })?;
553
554 let expires_at = if ttl > 0 {
555 Some(Utc::now() + chrono::Duration::seconds(ttl))
556 } else {
557 None
558 };
559
560 let now = Utc::now();
561 Ok(StorageEntry {
562 key: key.to_string(),
563 value,
564 version,
565 created_at: now, updated_at: now,
567 expires_at,
568 metadata,
569 })
570 }
571
572 async fn acquire_lock(&self, lock_key: &str, ttl_seconds: i64) -> StorageResult<String> {
574 let mut conn = self.get_connection().await?;
575 let lock_value = uuid::Uuid::new_v4().to_string();
576 let full_key = format!("{}:lock:{}", self.config.key_prefix, lock_key);
577
578 let result: bool = redis::cmd("SET")
579 .arg(&full_key)
580 .arg(&lock_value)
581 .arg("NX")
582 .arg("EX")
583 .arg(ttl_seconds)
584 .query_async(&mut *conn)
585 .await
586 .map_err(|e| StorageError::LockError {
587 message: format!("Failed to acquire lock: {}", e),
588 })?;
589
590 if result {
591 debug!("Acquired lock: {}", lock_key);
592 Ok(lock_value)
593 } else {
594 Err(StorageError::LockError {
595 message: format!("Lock already held: {}", lock_key),
596 })
597 }
598 }
599
600 async fn release_lock(&self, lock_key: &str, lock_value: &str) -> StorageResult<()> {
602 let mut conn = self.get_connection().await?;
603 let full_key = format!("{}:lock:{}", self.config.key_prefix, lock_key);
604
605 let script = Script::new(
606 r#"
607 if redis.call("GET", KEYS[1]) == ARGV[1] then
608 return redis.call("DEL", KEYS[1])
609 else
610 return 0
611 end
612 "#,
613 );
614
615 let result: i32 = script
616 .key(&full_key)
617 .arg(lock_value)
618 .invoke_async(&mut *conn)
619 .await
620 .map_err(|e| StorageError::LockError {
621 message: format!("Failed to release lock: {}", e),
622 })?;
623
624 if result == 1 {
625 debug!("Released lock: {}", lock_key);
626 Ok(())
627 } else {
628 warn!("Lock not held or already released: {}", lock_key);
629 Err(StorageError::LockError {
630 message: format!("Lock not held: {}", lock_key),
631 })
632 }
633 }
634}
635
636#[async_trait]
637impl Storage for RedisStorage {
638 fn backend(&self) -> StorageBackend {
639 StorageBackend::Redis
640 }
641
642 async fn metadata(&self) -> StorageResult<StorageMetadata> {
643 let mut conn = self.get_connection().await?;
644
645 let info: String = redis::cmd("INFO")
647 .arg("server")
648 .query_async(&mut *conn)
649 .await
650 .map_err(|e| StorageError::QueryError {
651 message: format!("Failed to get server info: {}", e),
652 })?;
653
654 let version = info
656 .lines()
657 .find(|line| line.starts_with("redis_version:"))
658 .and_then(|line| line.split(':').nth(1))
659 .unwrap_or("unknown")
660 .to_string();
661
662 Ok(StorageMetadata {
663 backend: StorageBackend::Redis,
664 version,
665 capabilities: vec![
666 "ttl".to_string(),
667 "pubsub".to_string(),
668 "atomic".to_string(),
669 "pipeline".to_string(),
670 "lua".to_string(),
671 "cache".to_string(),
672 ],
673 status: StorageHealth::Healthy,
674 last_health_check: Utc::now(),
675 })
676 }
677
678 async fn health_check(&self) -> StorageResult<StorageHealth> {
679 let start = Instant::now();
680
681 match self.get_connection().await {
682 Ok(mut conn) => {
683 match redis::cmd("PING").query_async::<String>(&mut *conn).await {
685 Ok(_) => {
686 let elapsed = start.elapsed().as_millis();
687 if elapsed < 100 {
688 Ok(StorageHealth::Healthy)
689 } else if elapsed < 500 {
690 Ok(StorageHealth::Degraded)
691 } else {
692 Ok(StorageHealth::Unhealthy)
693 }
694 }
695 Err(e) => {
696 error!("Health check ping failed: {}", e);
697 Ok(StorageHealth::Unhealthy)
698 }
699 }
700 }
701 Err(e) => {
702 error!("Health check connection failed: {}", e);
703 Ok(StorageHealth::Unhealthy)
704 }
705 }
706 }
707
708 async fn stats(&self) -> StorageResult<StorageStats> {
709 let stats = self.stats.read().await;
710 Ok(stats.clone())
711 }
712
713 async fn insert<T: Serialize + Send + Sync>(
714 &self,
715 table: &str,
716 key: &str,
717 value: &T,
718 ) -> StorageResult<()> {
719 let start = Instant::now();
720 let redis_key = self.build_key(table, key);
721 let value_json = self.serialize_value(value)?;
722 let bytes = value_json.len() as u64;
723
724 let mut conn = self.get_connection().await?;
725
726 let result: Result<(), RedisError> = conn.set(&redis_key, &value_json).await;
728
729 if let Err(e) = result {
730 let elapsed = start.elapsed().as_millis() as f64;
731 self.update_operation_stats(false, elapsed, 0).await;
732 return Err(StorageError::QueryError {
733 message: format!("Failed to insert: {}", e),
734 });
735 }
736
737 self.set_version(&mut conn, table, key, 1).await?;
739
740 if let Some(ttl) = self.config.default_ttl {
742 conn.expire(&redis_key, ttl)
743 .await
744 .map_err(|e| StorageError::QueryError {
745 message: format!("Failed to set TTL: {}", e),
746 })?;
747 }
748
749 let elapsed = start.elapsed().as_millis() as f64;
750 self.update_operation_stats(true, elapsed, bytes).await;
751
752 let mut cache_stats = self.cache_stats.write().await;
753 cache_stats.sets += 1;
754
755 debug!("Inserted key {} in table {} ({} bytes)", key, table, bytes);
756 Ok(())
757 }
758
759 async fn insert_with_ttl<T: Serialize + Send + Sync>(
760 &self,
761 table: &str,
762 key: &str,
763 value: &T,
764 ttl_seconds: i64,
765 ) -> StorageResult<()> {
766 let start = Instant::now();
767 let redis_key = self.build_key(table, key);
768 let value_json = self.serialize_value(value)?;
769 let bytes = value_json.len() as u64;
770
771 let mut conn = self.get_connection().await?;
772
773 let result: Result<(), RedisError> = redis::cmd("SETEX")
775 .arg(&redis_key)
776 .arg(ttl_seconds)
777 .arg(&value_json)
778 .query_async(&mut *conn)
779 .await;
780
781 if let Err(e) = result {
782 let elapsed = start.elapsed().as_millis() as f64;
783 self.update_operation_stats(false, elapsed, 0).await;
784 return Err(StorageError::QueryError {
785 message: format!("Failed to insert with TTL: {}", e),
786 });
787 }
788
789 let version_key = self.build_version_key(table, key);
791 redis::cmd("SETEX")
792 .arg(&version_key)
793 .arg(ttl_seconds)
794 .arg(1u64)
795 .query_async(&mut *conn)
796 .await
797 .map_err(|e: redis::RedisError| StorageError::QueryError {
798 message: format!("Failed to set version: {}", e),
799 })?;
800
801 let elapsed = start.elapsed().as_millis() as f64;
802 self.update_operation_stats(true, elapsed, bytes).await;
803
804 let mut cache_stats = self.cache_stats.write().await;
805 cache_stats.sets += 1;
806
807 debug!("Inserted key {} in table {} with TTL {}s ({} bytes)", key, table, ttl_seconds, bytes);
808 Ok(())
809 }
810
811 async fn get<T: DeserializeOwned + Serialize + Send + Sync>(
812 &self,
813 table: &str,
814 key: &str,
815 ) -> StorageResult<Option<StorageEntry<T>>> {
816 let start = Instant::now();
817 let redis_key = self.build_key(table, key);
818
819 let mut conn = self.get_connection().await?;
820
821 let value_json: Option<String> = conn
822 .get(&redis_key)
823 .await
824 .map_err(|e| StorageError::QueryError {
825 message: format!("Failed to get value: {}", e),
826 })?;
827
828 let elapsed = start.elapsed().as_millis() as f64;
829
830 if let Some(json) = value_json {
831 let entry = self.build_entry(&mut conn, table, key, json).await?;
832 let bytes = serde_json::to_string(&entry.value)
833 .map(|s| s.len())
834 .unwrap_or(0) as u64;
835
836 self.update_operation_stats(true, elapsed, bytes).await;
837 self.update_cache_stats(true).await;
838
839 trace!("Cache hit for key {} in table {}", key, table);
840 Ok(Some(entry))
841 } else {
842 self.update_operation_stats(true, elapsed, 0).await;
843 self.update_cache_stats(false).await;
844
845 trace!("Cache miss for key {} in table {}", key, table);
846 Ok(None)
847 }
848 }
849
850 async fn update<T: Serialize + Send + Sync>(
851 &self,
852 table: &str,
853 key: &str,
854 value: &T,
855 ) -> StorageResult<()> {
856 let start = Instant::now();
857 let redis_key = self.build_key(table, key);
858 let value_json = self.serialize_value(value)?;
859 let bytes = value_json.len() as u64;
860
861 let mut conn = self.get_connection().await?;
862
863 let exists: bool = conn
865 .exists(&redis_key)
866 .await
867 .map_err(|e| StorageError::QueryError {
868 message: format!("Failed to check existence: {}", e),
869 })?;
870
871 if !exists {
872 return Err(StorageError::NotFound {
873 entity: table.to_string(),
874 key: key.to_string(),
875 });
876 }
877
878 conn.set(&redis_key, &value_json)
880 .await
881 .map_err(|e| StorageError::QueryError {
882 message: format!("Failed to update: {}", e),
883 })?;
884
885 self.increment_version(&mut conn, table, key).await?;
887
888 let elapsed = start.elapsed().as_millis() as f64;
889 self.update_operation_stats(true, elapsed, bytes).await;
890
891 debug!("Updated key {} in table {} ({} bytes)", key, table, bytes);
892 Ok(())
893 }
894
895 async fn update_versioned<T: Serialize + Send + Sync>(
896 &self,
897 table: &str,
898 key: &str,
899 value: &T,
900 expected_version: u64,
901 ) -> StorageResult<()> {
902 let start = Instant::now();
903 let redis_key = self.build_key(table, key);
904 let value_json = self.serialize_value(value)?;
905 let bytes = value_json.len() as u64;
906
907 let mut conn = self.get_connection().await?;
908
909 let result: i64 = self
911 .scripts
912 .versioned_update
913 .key(&redis_key)
914 .arg(expected_version)
915 .arg(&value_json)
916 .invoke_async(&mut *conn)
917 .await
918 .map_err(|e| StorageError::QueryError {
919 message: format!("Versioned update failed: {}", e),
920 })?;
921
922 let elapsed = start.elapsed().as_millis() as f64;
923
924 if result == 0 {
925 self.update_operation_stats(false, elapsed, 0).await;
926 return Err(StorageError::ConstraintViolation {
927 message: format!("Version mismatch for key {}: expected {}", key, expected_version),
928 });
929 }
930
931 self.update_operation_stats(true, elapsed, bytes).await;
932
933 debug!("Updated key {} in table {} with version check (new version: {})", key, table, result);
934 Ok(())
935 }
936
937 async fn delete(&self, table: &str, key: &str) -> StorageResult<()> {
938 let start = Instant::now();
939 let redis_key = self.build_key(table, key);
940 let version_key = self.build_version_key(table, key);
941 let metadata_key = self.build_metadata_key(table, key);
942
943 let mut conn = self.get_connection().await?;
944
945 let deleted: u32 = conn
947 .del(&[&redis_key, &version_key, &metadata_key])
948 .await
949 .map_err(|e| StorageError::QueryError {
950 message: format!("Failed to delete: {}", e),
951 })?;
952
953 let elapsed = start.elapsed().as_millis() as f64;
954 self.update_operation_stats(true, elapsed, 0).await;
955
956 let mut cache_stats = self.cache_stats.write().await;
957 cache_stats.deletes += 1;
958
959 debug!("Deleted {} keys for {} in table {}", deleted, key, table);
960 Ok(())
961 }
962
963 async fn exists(&self, table: &str, key: &str) -> StorageResult<bool> {
964 let redis_key = self.build_key(table, key);
965 let mut conn = self.get_connection().await?;
966
967 let exists: bool = conn
968 .exists(&redis_key)
969 .await
970 .map_err(|e| StorageError::QueryError {
971 message: format!("Failed to check existence: {}", e),
972 })?;
973
974 Ok(exists)
975 }
976
977 async fn execute_batch(&self, batch: Batch) -> StorageResult<()> {
978 if batch.operations.is_empty() {
979 return Ok(());
980 }
981
982 let start = Instant::now();
983 let mut conn = self.get_connection().await?;
984 let mut pipe = redis::pipe();
985
986 for operation in &batch.operations {
987 match operation {
988 Operation::Insert { table, data } => {
989 let key = format!("{}_{}", Utc::now().timestamp_millis(), uuid::Uuid::new_v4());
991 let redis_key = self.build_key(table, &key);
992 pipe.set(&redis_key, data);
993 }
994 Operation::Update { table, key, data } => {
995 let redis_key = self.build_key(table, key);
996 pipe.set(&redis_key, data);
997 }
998 Operation::Delete { table, key } => {
999 let redis_key = self.build_key(table, key);
1000 pipe.del(&redis_key);
1001 }
1002 }
1003 }
1004
1005 pipe.query_async(&mut *conn)
1006 .await
1007 .map_err(|e: redis::RedisError| StorageError::QueryError {
1008 message: format!("Batch execution failed: {}", e),
1009 })?;
1010
1011 let elapsed = start.elapsed().as_millis() as f64;
1012 self.update_operation_stats(true, elapsed, 0).await;
1013
1014 debug!("Executed batch with {} operations", batch.operations.len());
1015 Ok(())
1016 }
1017
1018 async fn query<T: DeserializeOwned + Serialize + Send + Sync + 'static>(&self, query: Query) -> StorageResult<Vec<StorageEntry<T>>> {
1019 let start = Instant::now();
1020
1021 let pattern = format!("{}:{}:*", self.config.key_prefix, query.table);
1023 let keys = self.scan_keys(&pattern).await?;
1024
1025 let mut results = Vec::new();
1026 let mut conn = self.get_connection().await?;
1027
1028 for full_key in keys {
1029 if let Some(key_part) = full_key.strip_prefix(&format!("{}:{}:", self.config.key_prefix, query.table)) {
1031 if key_part.ends_with(":version") || key_part.ends_with(":metadata") {
1033 continue;
1034 }
1035
1036 if let Some(entry) = self.get::<T>(&query.table, key_part).await? {
1038 results.push(entry);
1039 }
1040 }
1041 }
1042
1043 if let Some(offset) = query.offset {
1045 results = results.into_iter().skip(offset).collect();
1046 }
1047
1048 if let Some(limit) = query.limit {
1049 results.truncate(limit);
1050 }
1051
1052 let elapsed = start.elapsed().as_millis() as f64;
1053 self.update_operation_stats(true, elapsed, 0).await;
1054
1055 debug!("Query returned {} results from table {}", results.len(), query.table);
1056 Ok(results)
1057 }
1058
1059 async fn count(&self, query: Query) -> StorageResult<usize> {
1060 let pattern = format!("{}:{}:*", self.config.key_prefix, query.table);
1061 let keys = self.scan_keys(&pattern).await?;
1062
1063 let count = keys
1065 .iter()
1066 .filter(|k| !k.ends_with(":version") && !k.ends_with(":metadata"))
1067 .count();
1068
1069 Ok(count)
1070 }
1071
1072 async fn begin_transaction(&self) -> StorageResult<Transaction> {
1073 let transaction = Transaction::new();
1076
1077 let mut transactions = self.transactions.write().await;
1078 transactions.insert(transaction.id.clone(), transaction.clone());
1079
1080 debug!("Started transaction {}", transaction.id);
1081 Ok(transaction)
1082 }
1083
1084 async fn commit_transaction(&self, mut transaction: Transaction) -> StorageResult<()> {
1085 let start = Instant::now();
1086
1087 let mut conn = self.get_connection().await?;
1089 let mut pipe = redis::pipe();
1090 pipe.atomic();
1091
1092 for operation in &transaction.operations {
1093 match operation {
1094 Operation::Insert { table, data } => {
1095 let key = format!("{}_{}", Utc::now().timestamp_millis(), uuid::Uuid::new_v4());
1096 let redis_key = self.build_key(table, &key);
1097 pipe.set(&redis_key, data);
1098 }
1099 Operation::Update { table, key, data } => {
1100 let redis_key = self.build_key(table, key);
1101 pipe.set(&redis_key, data);
1102 }
1103 Operation::Delete { table, key } => {
1104 let redis_key = self.build_key(table, key);
1105 pipe.del(&redis_key);
1106 }
1107 }
1108 }
1109
1110 pipe.query_async(&mut *conn)
1111 .await
1112 .map_err(|e: redis::RedisError| StorageError::TransactionError {
1113 message: format!("Transaction commit failed: {}", e),
1114 })?;
1115
1116 transaction.state = TransactionState::Committed;
1117
1118 let mut transactions = self.transactions.write().await;
1119 transactions.remove(&transaction.id);
1120
1121 let elapsed = start.elapsed().as_millis() as f64;
1122 self.update_operation_stats(true, elapsed, 0).await;
1123
1124 debug!("Committed transaction {} with {} operations", transaction.id, transaction.operations.len());
1125 Ok(())
1126 }
1127
1128 async fn rollback_transaction(&self, mut transaction: Transaction) -> StorageResult<()> {
1129 transaction.state = TransactionState::RolledBack;
1130
1131 let mut transactions = self.transactions.write().await;
1132 transactions.remove(&transaction.id);
1133
1134 debug!("Rolled back transaction {}", transaction.id);
1135 Ok(())
1136 }
1137
1138 async fn scan_prefix(&self, table: &str, prefix: &str) -> StorageResult<Vec<String>> {
1139 let pattern = format!("{}:{}:{}*", self.config.key_prefix, table, prefix);
1140 let keys = self.scan_keys(&pattern).await?;
1141
1142 let extracted_keys: Vec<String> = keys
1144 .into_iter()
1145 .filter_map(|full_key| {
1146 full_key
1147 .strip_prefix(&format!("{}:{}:", self.config.key_prefix, table))
1148 .map(|s| s.to_string())
1149 })
1150 .filter(|k| !k.ends_with(":version") && !k.ends_with(":metadata"))
1151 .collect();
1152
1153 debug!("Scan prefix {} in table {} returned {} keys", prefix, table, extracted_keys.len());
1154 Ok(extracted_keys)
1155 }
1156
1157 async fn get_multi<T: DeserializeOwned + Serialize + Send + Sync>(
1158 &self,
1159 table: &str,
1160 keys: Vec<String>,
1161 ) -> StorageResult<Vec<Option<StorageEntry<T>>>> {
1162 let start = Instant::now();
1163
1164 let mut results = Vec::new();
1165 for key in keys {
1166 let entry = self.get(table, &key).await?;
1167 results.push(entry);
1168 }
1169
1170 let elapsed = start.elapsed().as_millis() as f64;
1171 self.update_operation_stats(true, elapsed, 0).await;
1172
1173 Ok(results)
1174 }
1175
1176 async fn delete_multi(&self, table: &str, keys: Vec<String>) -> StorageResult<()> {
1177 let start = Instant::now();
1178
1179 let mut conn = self.get_connection().await?;
1180 let mut pipe = redis::pipe();
1181
1182 for key in &keys {
1183 let redis_key = self.build_key(table, key);
1184 let version_key = self.build_version_key(table, key);
1185 let metadata_key = self.build_metadata_key(table, key);
1186
1187 pipe.del(&redis_key);
1188 pipe.del(&version_key);
1189 pipe.del(&metadata_key);
1190 }
1191
1192 pipe.query_async(&mut *conn)
1193 .await
1194 .map_err(|e: redis::RedisError| StorageError::QueryError {
1195 message: format!("Multi-delete failed: {}", e),
1196 })?;
1197
1198 let elapsed = start.elapsed().as_millis() as f64;
1199 self.update_operation_stats(true, elapsed, 0).await;
1200
1201 debug!("Deleted {} keys from table {}", keys.len(), table);
1202 Ok(())
1203 }
1204
1205 async fn compare_and_swap<T: Serialize + Send + Sync>(
1206 &self,
1207 table: &str,
1208 key: &str,
1209 expected_version: u64,
1210 new_value: &T,
1211 ) -> StorageResult<bool> {
1212 let start = Instant::now();
1213 let redis_key = self.build_key(table, key);
1214 let value_json = self.serialize_value(new_value)?;
1215 let new_version = expected_version + 1;
1216
1217 let mut conn = self.get_connection().await?;
1218
1219 let result: i32 = self
1220 .scripts
1221 .cas
1222 .key(&redis_key)
1223 .arg(expected_version)
1224 .arg(&value_json)
1225 .arg(new_version)
1226 .invoke_async(&mut *conn)
1227 .await
1228 .map_err(|e| StorageError::QueryError {
1229 message: format!("CAS operation failed: {}", e),
1230 })?;
1231
1232 let elapsed = start.elapsed().as_millis() as f64;
1233 let success = result == 1;
1234 self.update_operation_stats(success, elapsed, if success { value_json.len() as u64 } else { 0 }).await;
1235
1236 if success {
1237 debug!("CAS succeeded for key {} in table {}", key, table);
1238 } else {
1239 debug!("CAS failed for key {} in table {} (version mismatch)", key, table);
1240 }
1241
1242 Ok(success)
1243 }
1244
1245 async fn get_modified_since<T: DeserializeOwned + Serialize + Send + Sync + 'static>(
1246 &self,
1247 table: &str,
1248 since: DateTime<Utc>,
1249 ) -> StorageResult<Vec<StorageEntry<T>>> {
1250 warn!("get_modified_since is not efficiently supported in Redis");
1253
1254 let query = Query::new(table);
1256 self.query(query).await
1257 }
1258
1259 async fn get_expiring_before<T: DeserializeOwned + Serialize + Send + Sync + 'static>(
1260 &self,
1261 table: &str,
1262 before: DateTime<Utc>,
1263 ) -> StorageResult<Vec<StorageEntry<T>>> {
1264 let pattern = format!("{}:{}:*", self.config.key_prefix, table);
1265 let keys = self.scan_keys(&pattern).await?;
1266
1267 let mut results = Vec::new();
1268 let mut conn = self.get_connection().await?;
1269 let before_timestamp = before.timestamp();
1270
1271 for full_key in keys {
1272 if full_key.ends_with(":version") || full_key.ends_with(":metadata") {
1273 continue;
1274 }
1275
1276 let ttl: i64 = conn
1277 .ttl(&full_key)
1278 .await
1279 .map_err(|e| StorageError::QueryError {
1280 message: format!("Failed to get TTL: {}", e),
1281 })?;
1282
1283 if ttl > 0 {
1284 let expiration_timestamp = Utc::now().timestamp() + ttl;
1285 if expiration_timestamp < before_timestamp {
1286 if let Some(key_part) = full_key.strip_prefix(&format!("{}:{}:", self.config.key_prefix, table)) {
1287 if let Some(entry) = self.get::<T>(table, key_part).await? {
1288 results.push(entry);
1289 }
1290 }
1291 }
1292 }
1293 }
1294
1295 debug!("Found {} entries expiring before {} in table {}", results.len(), before, table);
1296 Ok(results)
1297 }
1298
1299 async fn cleanup_expired(&self, table: &str) -> StorageResult<usize> {
1300 let before = Utc::now() + chrono::Duration::minutes(5);
1303 let expiring: Vec<StorageEntry<serde_json::Value>> = self.get_expiring_before(table, before).await?;
1304
1305 debug!("Found {} entries that will expire soon in table {}", expiring.len(), table);
1306 Ok(expiring.len())
1307 }
1308
1309 async fn compact(&self) -> StorageResult<()> {
1310 let mut conn = self.get_connection().await?;
1312
1313 let _: Result<String, RedisError> = redis::cmd("MEMORY")
1315 .arg("PURGE")
1316 .query_async(&mut *conn)
1317 .await;
1318
1319 info!("Ran memory purge on Redis");
1320 Ok(())
1321 }
1322
1323 async fn flush(&self) -> StorageResult<()> {
1324 let mut conn = self.get_connection().await?;
1327
1328 let _: Result<String, RedisError> = redis::cmd("BGSAVE")
1329 .query_async(&mut *conn)
1330 .await;
1331
1332 info!("Initiated background save");
1333 Ok(())
1334 }
1335
1336 async fn initialize(&mut self) -> StorageResult<()> {
1337 info!("Initializing Redis storage");
1338
1339 let health = self.health_check().await?;
1341 if health != StorageHealth::Healthy {
1342 return Err(StorageError::InvalidState {
1343 message: format!("Redis is not healthy: {:?}", health),
1344 });
1345 }
1346
1347 let mut conn = self.get_connection().await?;
1349 let stats_key = format!("{}:stats", self.config.key_prefix);
1350
1351 let exists: bool = conn.exists(&stats_key).await.unwrap_or(false);
1353 if !exists {
1354 let initial_stats = InternalCacheStats::default();
1355 let stats_json = serde_json::to_string(&initial_stats).unwrap();
1356 let _: Result<(), RedisError> = conn.set(&stats_key, stats_json).await;
1357 }
1358
1359 info!("Redis storage initialized successfully");
1360 Ok(())
1361 }
1362
1363 async fn shutdown(&mut self) -> StorageResult<()> {
1364 info!("Shutting down Redis storage");
1365
1366 let mut shutdown = self.shutdown.write().await;
1368 *shutdown = true;
1369
1370 let mut subscriptions = self.subscriptions.write().await;
1372 subscriptions.clear();
1373
1374 let stats = self.cache_stats.read().await;
1376 let stats_json = serde_json::to_string(&*stats).unwrap();
1377
1378 if let Ok(mut conn) = self.get_connection().await {
1379 let stats_key = format!("{}:stats", self.config.key_prefix);
1380 let _: Result<(), RedisError> = conn.set(&stats_key, stats_json).await;
1381 }
1382
1383 info!("Redis storage shutdown complete");
1384 Ok(())
1385 }
1386}
1387
1388#[async_trait]
1389impl CacheStorage for RedisStorage {
1390 async fn ttl(&self, table: &str, key: &str) -> StorageResult<Option<i64>> {
1391 let redis_key = self.build_key(table, key);
1392 let mut conn = self.get_connection().await?;
1393
1394 let ttl: i64 = conn
1395 .ttl(&redis_key)
1396 .await
1397 .map_err(|e| StorageError::QueryError {
1398 message: format!("Failed to get TTL: {}", e),
1399 })?;
1400
1401 if ttl == -2 {
1403 Ok(None)
1404 } else if ttl == -1 {
1405 Ok(Some(-1))
1406 } else {
1407 Ok(Some(ttl))
1408 }
1409 }
1410
1411 async fn expire(&self, table: &str, key: &str, ttl_seconds: i64) -> StorageResult<()> {
1412 let redis_key = self.build_key(table, key);
1413 let mut conn = self.get_connection().await?;
1414
1415 let result: bool = conn
1416 .expire(&redis_key, ttl_seconds)
1417 .await
1418 .map_err(|e| StorageError::QueryError {
1419 message: format!("Failed to set expiration: {}", e),
1420 })?;
1421
1422 if !result {
1423 return Err(StorageError::NotFound {
1424 entity: table.to_string(),
1425 key: key.to_string(),
1426 });
1427 }
1428
1429 debug!("Set TTL of {}s for key {} in table {}", ttl_seconds, key, table);
1430 Ok(())
1431 }
1432
1433 async fn persist(&self, table: &str, key: &str) -> StorageResult<()> {
1434 let redis_key = self.build_key(table, key);
1435 let mut conn = self.get_connection().await?;
1436
1437 let result: bool = conn
1438 .persist(&redis_key)
1439 .await
1440 .map_err(|e| StorageError::QueryError {
1441 message: format!("Failed to persist: {}", e),
1442 })?;
1443
1444 if !result {
1445 return Err(StorageError::NotFound {
1446 entity: table.to_string(),
1447 key: key.to_string(),
1448 });
1449 }
1450
1451 debug!("Removed expiration from key {} in table {}", key, table);
1452 Ok(())
1453 }
1454
1455 async fn increment(&self, table: &str, key: &str, delta: i64) -> StorageResult<i64> {
1456 let redis_key = self.build_key(table, key);
1457 let mut conn = self.get_connection().await?;
1458
1459 let new_value: i64 = conn
1460 .incr(&redis_key, delta)
1461 .await
1462 .map_err(|e| StorageError::QueryError {
1463 message: format!("Failed to increment: {}", e),
1464 })?;
1465
1466 debug!("Incremented key {} in table {} by {} (new value: {})", key, table, delta, new_value);
1467 Ok(new_value)
1468 }
1469
1470 async fn decrement(&self, table: &str, key: &str, delta: i64) -> StorageResult<i64> {
1471 let redis_key = self.build_key(table, key);
1472 let mut conn = self.get_connection().await?;
1473
1474 let new_value: i64 = conn
1475 .decr(&redis_key, delta)
1476 .await
1477 .map_err(|e| StorageError::QueryError {
1478 message: format!("Failed to decrement: {}", e),
1479 })?;
1480
1481 debug!("Decremented key {} in table {} by {} (new value: {})", key, table, delta, new_value);
1482 Ok(new_value)
1483 }
1484
1485 async fn cache_stats(&self) -> StorageResult<CacheStats> {
1486 let mut conn = self.get_connection().await?;
1487
1488 let info: String = redis::cmd("INFO")
1490 .arg("memory")
1491 .query_async(&mut *conn)
1492 .await
1493 .map_err(|e| StorageError::QueryError {
1494 message: format!("Failed to get memory info: {}", e),
1495 })?;
1496
1497 let mut memory_used = 0u64;
1499 let mut memory_available = 0u64;
1500
1501 for line in info.lines() {
1502 if let Some(value) = line.strip_prefix("used_memory:") {
1503 memory_used = value.trim().parse().unwrap_or(0);
1504 } else if let Some(value) = line.strip_prefix("maxmemory:") {
1505 memory_available = value.trim().parse().unwrap_or(0);
1506 }
1507 }
1508
1509 let keys_count: usize = redis::cmd("DBSIZE")
1511 .query_async(&mut *conn)
1512 .await
1513 .unwrap_or(0);
1514
1515 let cache_stats = self.cache_stats.read().await;
1517
1518 Ok(CacheStats {
1519 hits: cache_stats.hits,
1520 misses: cache_stats.misses,
1521 evictions: cache_stats.evictions,
1522 memory_used_bytes: memory_used,
1523 memory_available_bytes: memory_available,
1524 keys_count,
1525 })
1526 }
1527}
1528
1529#[async_trait]
1530impl PubSubStorage for RedisStorage {
1531 async fn publish(&self, channel: &str, message: &[u8]) -> StorageResult<usize> {
1532 let mut conn = self.get_connection().await?;
1533 let full_channel = format!("{}:pubsub:{}", self.config.key_prefix, channel);
1534
1535 let subscribers: usize = conn
1536 .publish(&full_channel, message)
1537 .await
1538 .map_err(|e| StorageError::QueryError {
1539 message: format!("Failed to publish message: {}", e),
1540 })?;
1541
1542 debug!("Published message to channel {} ({} subscribers, {} bytes)",
1543 channel, subscribers, message.len());
1544
1545 Ok(subscribers)
1546 }
1547
1548 async fn subscribe(&self, channel: &str) -> StorageResult<Box<dyn Subscriber>> {
1549 let redis_url = self.config.connection_url();
1550 let full_channel = format!("{}:pubsub:{}", self.config.key_prefix, channel);
1551
1552 let mut subscriber = RedisSubscriber::new(redis_url, full_channel.clone()).await?;
1553
1554 subscriber.pubsub
1556 .subscribe(&full_channel)
1557 .await
1558 .map_err(|e| StorageError::QueryError {
1559 message: format!("Failed to subscribe to channel: {}", e),
1560 })?;
1561
1562 info!("Subscribed to channel {}", channel);
1563
1564 let subscriber_arc = Arc::new(Mutex::new(subscriber));
1565
1566 let mut subscriptions = self.subscriptions.write().await;
1568 subscriptions.insert(channel.to_string(), subscriber_arc.clone());
1569
1570 Ok(Box::new(SubscriberWrapper {
1571 inner: subscriber_arc,
1572 }))
1573 }
1574
1575 async fn unsubscribe(&self, channel: &str) -> StorageResult<()> {
1576 let mut subscriptions = self.subscriptions.write().await;
1577
1578 if let Some(subscriber_arc) = subscriptions.remove(channel) {
1579 let mut subscriber = subscriber_arc.lock().await;
1580 let full_channel = format!("{}:pubsub:{}", self.config.key_prefix, channel);
1581
1582 subscriber.pubsub
1583 .unsubscribe(&full_channel)
1584 .await
1585 .map_err(|e| StorageError::QueryError {
1586 message: format!("Failed to unsubscribe from channel: {}", e),
1587 })?;
1588
1589 info!("Unsubscribed from channel {}", channel);
1590 }
1591
1592 Ok(())
1593 }
1594}
1595
1596struct SubscriberWrapper {
1598 inner: Arc<Mutex<RedisSubscriber>>,
1599}
1600
1601#[async_trait]
1602impl Subscriber for SubscriberWrapper {
1603 async fn next_message(&mut self) -> StorageResult<Option<Vec<u8>>> {
1604 let mut subscriber = self.inner.lock().await;
1605 subscriber.next_message().await
1606 }
1607}
1608
1609#[cfg(test)]
1610mod tests {
1611 use super::*;
1612 use serde::{Deserialize, Serialize};
1613
1614 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1615 struct TestData {
1616 id: String,
1617 value: i32,
1618 name: String,
1619 }
1620
1621 async fn create_test_storage() -> RedisStorage {
1622 let config = RedisConfig {
1623 host: "localhost".to_string(),
1624 port: 6379,
1625 database: 15, key_prefix: "test:".to_string(),
1627 ..Default::default()
1628 };
1629
1630 let mut storage = RedisStorage::new(config).await.expect("Failed to create storage");
1631 storage.initialize().await.expect("Failed to initialize");
1632 storage
1633 }
1634
1635 async fn cleanup_test_data(storage: &RedisStorage) {
1636 let mut conn = storage.get_connection().await.unwrap();
1637 let _: Result<(), RedisError> = redis::cmd("FLUSHDB").query_async(&mut *conn).await;
1638 }
1639
1640 #[tokio::test]
1641 async fn test_insert_and_get() {
1642 let storage = create_test_storage().await;
1643
1644 let data = TestData {
1645 id: "test1".to_string(),
1646 value: 42,
1647 name: "Test Data".to_string(),
1648 };
1649
1650 storage.insert("test_table", "key1", &data).await.unwrap();
1651
1652 let result: Option<StorageEntry<TestData>> = storage.get("test_table", "key1").await.unwrap();
1653 assert!(result.is_some());
1654
1655 let entry = result.unwrap();
1656 assert_eq!(entry.value, data);
1657 assert_eq!(entry.version, 1);
1658
1659 cleanup_test_data(&storage).await;
1660 }
1661
1662 #[tokio::test]
1663 async fn test_insert_with_ttl() {
1664 let storage = create_test_storage().await;
1665
1666 let data = TestData {
1667 id: "test2".to_string(),
1668 value: 100,
1669 name: "TTL Test".to_string(),
1670 };
1671
1672 storage.insert_with_ttl("test_table", "key2", &data, 10).await.unwrap();
1673
1674 let result: Option<StorageEntry<TestData>> = storage.get("test_table", "key2").await.unwrap();
1675 assert!(result.is_some());
1676
1677 let ttl = storage.ttl("test_table", "key2").await.unwrap();
1678 assert!(ttl.is_some());
1679 assert!(ttl.unwrap() > 0 && ttl.unwrap() <= 10);
1680
1681 cleanup_test_data(&storage).await;
1682 }
1683
1684 #[tokio::test]
1685 async fn test_update() {
1686 let storage = create_test_storage().await;
1687
1688 let data = TestData {
1689 id: "test3".to_string(),
1690 value: 50,
1691 name: "Original".to_string(),
1692 };
1693
1694 storage.insert("test_table", "key3", &data).await.unwrap();
1695
1696 let updated_data = TestData {
1697 id: "test3".to_string(),
1698 value: 75,
1699 name: "Updated".to_string(),
1700 };
1701
1702 storage.update("test_table", "key3", &updated_data).await.unwrap();
1703
1704 let result: Option<StorageEntry<TestData>> = storage.get("test_table", "key3").await.unwrap();
1705 assert!(result.is_some());
1706
1707 let entry = result.unwrap();
1708 assert_eq!(entry.value.name, "Updated");
1709 assert_eq!(entry.version, 2);
1710
1711 cleanup_test_data(&storage).await;
1712 }
1713
1714 #[tokio::test]
1715 async fn test_versioned_update() {
1716 let storage = create_test_storage().await;
1717
1718 let data = TestData {
1719 id: "test4".to_string(),
1720 value: 10,
1721 name: "Version Test".to_string(),
1722 };
1723
1724 storage.insert("test_table", "key4", &data).await.unwrap();
1725
1726 let updated_data = TestData {
1727 id: "test4".to_string(),
1728 value: 20,
1729 name: "Version Updated".to_string(),
1730 };
1731
1732 storage.update_versioned("test_table", "key4", &updated_data, 1).await.unwrap();
1734
1735 let result = storage.update_versioned("test_table", "key4", &updated_data, 1).await;
1737 assert!(result.is_err());
1738
1739 cleanup_test_data(&storage).await;
1740 }
1741
1742 #[tokio::test]
1743 async fn test_delete() {
1744 let storage = create_test_storage().await;
1745
1746 let data = TestData {
1747 id: "test5".to_string(),
1748 value: 99,
1749 name: "To Delete".to_string(),
1750 };
1751
1752 storage.insert("test_table", "key5", &data).await.unwrap();
1753
1754 let exists = storage.exists("test_table", "key5").await.unwrap();
1755 assert!(exists);
1756
1757 storage.delete("test_table", "key5").await.unwrap();
1758
1759 let exists = storage.exists("test_table", "key5").await.unwrap();
1760 assert!(!exists);
1761
1762 cleanup_test_data(&storage).await;
1763 }
1764
1765 #[tokio::test]
1766 async fn test_compare_and_swap() {
1767 let storage = create_test_storage().await;
1768
1769 let data = TestData {
1770 id: "test6".to_string(),
1771 value: 30,
1772 name: "CAS Test".to_string(),
1773 };
1774
1775 storage.insert("test_table", "key6", &data).await.unwrap();
1776
1777 let new_data = TestData {
1778 id: "test6".to_string(),
1779 value: 40,
1780 name: "CAS Updated".to_string(),
1781 };
1782
1783 let success = storage.compare_and_swap("test_table", "key6", 1, &new_data).await.unwrap();
1785 assert!(success);
1786
1787 let success = storage.compare_and_swap("test_table", "key6", 1, &new_data).await.unwrap();
1789 assert!(!success);
1790
1791 cleanup_test_data(&storage).await;
1792 }
1793
1794 #[tokio::test]
1795 async fn test_increment_decrement() {
1796 let storage = create_test_storage().await;
1797
1798 let value = storage.increment("counters", "counter1", 5).await.unwrap();
1799 assert_eq!(value, 5);
1800
1801 let value = storage.increment("counters", "counter1", 3).await.unwrap();
1802 assert_eq!(value, 8);
1803
1804 let value = storage.decrement("counters", "counter1", 2).await.unwrap();
1805 assert_eq!(value, 6);
1806
1807 cleanup_test_data(&storage).await;
1808 }
1809
1810 #[tokio::test]
1811 async fn test_scan_prefix() {
1812 let storage = create_test_storage().await;
1813
1814 let data = TestData {
1815 id: "test".to_string(),
1816 value: 1,
1817 name: "Test".to_string(),
1818 };
1819
1820 storage.insert("test_table", "user:1", &data).await.unwrap();
1821 storage.insert("test_table", "user:2", &data).await.unwrap();
1822 storage.insert("test_table", "user:3", &data).await.unwrap();
1823 storage.insert("test_table", "admin:1", &data).await.unwrap();
1824
1825 let keys = storage.scan_prefix("test_table", "user:").await.unwrap();
1826 assert_eq!(keys.len(), 3);
1827
1828 cleanup_test_data(&storage).await;
1829 }
1830
1831 #[tokio::test]
1832 async fn test_get_multi() {
1833 let storage = create_test_storage().await;
1834
1835 let data1 = TestData {
1836 id: "1".to_string(),
1837 value: 1,
1838 name: "One".to_string(),
1839 };
1840 let data2 = TestData {
1841 id: "2".to_string(),
1842 value: 2,
1843 name: "Two".to_string(),
1844 };
1845
1846 storage.insert("test_table", "k1", &data1).await.unwrap();
1847 storage.insert("test_table", "k2", &data2).await.unwrap();
1848
1849 let results: Vec<Option<StorageEntry<TestData>>> = storage
1850 .get_multi("test_table", vec!["k1".to_string(), "k2".to_string(), "k3".to_string()])
1851 .await
1852 .unwrap();
1853
1854 assert_eq!(results.len(), 3);
1855 assert!(results[0].is_some());
1856 assert!(results[1].is_some());
1857 assert!(results[2].is_none());
1858
1859 cleanup_test_data(&storage).await;
1860 }
1861
1862 #[tokio::test]
1863 async fn test_delete_multi() {
1864 let storage = create_test_storage().await;
1865
1866 let data = TestData {
1867 id: "test".to_string(),
1868 value: 1,
1869 name: "Test".to_string(),
1870 };
1871
1872 storage.insert("test_table", "k1", &data).await.unwrap();
1873 storage.insert("test_table", "k2", &data).await.unwrap();
1874 storage.insert("test_table", "k3", &data).await.unwrap();
1875
1876 storage.delete_multi("test_table", vec!["k1".to_string(), "k2".to_string()]).await.unwrap();
1877
1878 let exists1 = storage.exists("test_table", "k1").await.unwrap();
1879 let exists2 = storage.exists("test_table", "k2").await.unwrap();
1880 let exists3 = storage.exists("test_table", "k3").await.unwrap();
1881
1882 assert!(!exists1);
1883 assert!(!exists2);
1884 assert!(exists3);
1885
1886 cleanup_test_data(&storage).await;
1887 }
1888
1889 #[tokio::test]
1890 async fn test_transaction() {
1891 let storage = create_test_storage().await;
1892
1893 let mut transaction = storage.begin_transaction().await.unwrap();
1894
1895 let data = TestData {
1896 id: "test".to_string(),
1897 value: 1,
1898 name: "Test".to_string(),
1899 };
1900 let data_bytes = serde_json::to_vec(&data).unwrap();
1901
1902 transaction.add_operation(Operation::Insert {
1903 table: "test_table".to_string(),
1904 data: data_bytes.clone(),
1905 });
1906 transaction.add_operation(Operation::Insert {
1907 table: "test_table".to_string(),
1908 data: data_bytes,
1909 });
1910
1911 storage.commit_transaction(transaction).await.unwrap();
1912
1913 cleanup_test_data(&storage).await;
1914 }
1915
1916 #[tokio::test]
1917 async fn test_cache_stats() {
1918 let storage = create_test_storage().await;
1919
1920 let data = TestData {
1921 id: "test".to_string(),
1922 value: 1,
1923 name: "Test".to_string(),
1924 };
1925
1926 storage.insert("test_table", "key1", &data).await.unwrap();
1927
1928 let _: Option<StorageEntry<TestData>> = storage.get("test_table", "key1").await.unwrap();
1929 let _: Option<StorageEntry<TestData>> = storage.get("test_table", "missing").await.unwrap();
1930
1931 let stats = storage.cache_stats().await.unwrap();
1932 assert!(stats.hits > 0);
1933 assert!(stats.misses > 0);
1934 assert!(stats.hit_rate() > 0.0 && stats.hit_rate() <= 1.0);
1935
1936 cleanup_test_data(&storage).await;
1937 }
1938
1939 #[tokio::test]
1940 async fn test_health_check() {
1941 let storage = create_test_storage().await;
1942
1943 let health = storage.health_check().await.unwrap();
1944 assert_eq!(health, StorageHealth::Healthy);
1945
1946 cleanup_test_data(&storage).await;
1947 }
1948
1949 #[tokio::test]
1950 async fn test_metadata() {
1951 let storage = create_test_storage().await;
1952
1953 let metadata = storage.metadata().await.unwrap();
1954 assert_eq!(metadata.backend, StorageBackend::Redis);
1955 assert!(metadata.capabilities.contains(&"ttl".to_string()));
1956 assert!(metadata.capabilities.contains(&"pubsub".to_string()));
1957
1958 cleanup_test_data(&storage).await;
1959 }
1960}