Skip to main content

llm_optimizer_processor/storage/
redis.rs

1//! Redis storage backend implementation
2//!
3//! This module provides a production-ready Redis storage backend with comprehensive
4//! features including connection pooling, TTL support, atomic operations, pub/sub,
5//! distributed locking, and cache statistics.
6//!
7//! # Features
8//!
9//! - Connection pooling with deadpool-redis
10//! - TTL (time-to-live) support for all entries
11//! - Atomic operations (INCR, DECR, CAS)
12//! - Key prefix namespacing
13//! - Pub/Sub support for real-time messaging
14//! - Pipeline operations for batching
15//! - Lua scripting for complex atomic operations
16//! - Cache statistics (hits, misses, evictions)
17//! - Full CRUD operations with JSON serialization
18//! - Distributed locking support
19//!
20//! # Architecture
21//!
22//! The Redis backend uses a key structure with namespacing:
23//! - `{prefix}:{table}:{key}` -> JSON value
24//! - `{prefix}:{table}:{key}:version` -> version number
25//! - `{prefix}:{table}:{key}:metadata` -> metadata JSON
26//! - `{prefix}:stats` -> cache statistics
27//!
28//! # Example
29//!
30//! ```rust,no_run
31//! use processor::storage::redis::RedisStorage;
32//! use processor::storage::config::RedisConfig;
33//! use processor::storage::traits::Storage;
34//!
35//! #[tokio::main]
36//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
37//!     let config = RedisConfig::default();
38//!     let mut storage = RedisStorage::new(config).await?;
39//!     storage.initialize().await?;
40//!
41//!     // Use storage operations
42//!     storage.insert("users", "user:1", &user).await?;
43//!
44//!     Ok(())
45//! }
46//! ```
47
48use 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/// Redis storage backend with connection pooling and advanced features
69#[derive(Debug)]
70pub struct RedisStorage {
71    /// Connection pool
72    pool: Pool,
73
74    /// Configuration
75    config: RedisConfig,
76
77    /// Storage statistics
78    stats: Arc<RwLock<StorageStats>>,
79
80    /// Cache statistics
81    cache_stats: Arc<RwLock<InternalCacheStats>>,
82
83    /// Active transactions
84    transactions: Arc<RwLock<HashMap<String, Transaction>>>,
85
86    /// Active subscriptions
87    subscriptions: Arc<RwLock<HashMap<String, Arc<Mutex<RedisSubscriber>>>>>,
88
89    /// Lua scripts cache
90    scripts: Arc<LuaScripts>,
91
92    /// Shutdown flag
93    shutdown: Arc<RwLock<bool>>,
94}
95
96/// Internal cache statistics tracking
97#[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/// Lua scripts for atomic operations
107#[derive(Debug)]
108struct LuaScripts {
109    /// Compare-and-swap script
110    cas: Script,
111
112    /// Versioned update script
113    versioned_update: Script,
114
115    /// Conditional delete script
116    conditional_delete: Script,
117
118    /// Batch insert with TTL
119    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
205/// Redis pub/sub subscriber implementation
206struct RedisSubscriber {
207    /// Channel name
208    channel: String,
209
210    /// Pub/Sub connection
211    pubsub: redis::aio::PubSub,
212
213    /// Message buffer
214    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        // Create dedicated client for pub/sub
229        let client = redis::Client::open(redis_url.clone())
230            .map_err(|e| StorageError::ConnectionError {
231                source: Box::new(e),
232            })?;
233
234        // Get connection info and create TCP connection for PubSub
235        let connection_info = client.get_connection_info();
236
237        // Connect to Redis server
238        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        // Create PubSub from stream
255        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        // Check buffer first
272        if !self.buffer.is_empty() {
273            return Ok(Some(self.buffer.remove(0)));
274        }
275
276        // Wait for next message
277        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    /// Create a new Redis storage instance
293    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        // Create connection pool
299        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) // Default pool size
306            .runtime(Runtime::Tokio1)
307            .build()
308            .map_err(|e| StorageError::ConnectionError {
309                source: Box::new(e),
310            })?;
311
312        // Test connection
313        let mut conn = pool.get().await.map_err(|e| StorageError::ConnectionError {
314            source: Box::new(e),
315        })?;
316
317        // Ping to verify connection
318        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    /// Build a namespaced key
340    fn build_key(&self, table: &str, key: &str) -> String {
341        format!("{}:{}:{}", self.config.key_prefix, table, key)
342    }
343
344    /// Build a version key
345    fn build_version_key(&self, table: &str, key: &str) -> String {
346        format!("{}:{}:{}:version", self.config.key_prefix, table, key)
347    }
348
349    /// Build a metadata key
350    fn build_metadata_key(&self, table: &str, key: &str) -> String {
351        format!("{}:{}:{}:metadata", self.config.key_prefix, table, key)
352    }
353
354    /// Build a table pattern for scanning
355    fn build_table_pattern(&self, table: &str) -> String {
356        format!("{}:{}:*", self.config.key_prefix, table)
357    }
358
359    /// Get a connection from the pool
360    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    /// Serialize value to JSON
377    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    /// Deserialize value from JSON
384    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    /// Get current version for a key
391    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    /// Set version for a key
404    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    /// Increment version for a key
414    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    /// Get metadata for a key
427    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    /// Set metadata for a key
444    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    /// Update cache statistics
456    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    /// Update operation statistics
466    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    /// Execute Redis command with retries
476    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    /// Scan keys with pattern
504    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    /// Build storage entry from Redis data
534    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        // Get TTL if available
546        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, // We don't track creation time separately in Redis
566            updated_at: now,
567            expires_at,
568            metadata,
569        })
570    }
571
572    /// Acquire distributed lock
573    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    /// Release distributed lock
601    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        // Get Redis info
646        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        // Parse version from info
655        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                // Try to ping
684                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        // Set value
727        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        // Set initial version
738        self.set_version(&mut conn, table, key, 1).await?;
739
740        // Apply default TTL if configured
741        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        // Set value with TTL using SETEX
774        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        // Set initial version with same TTL
790        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        // Check if key exists
864        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        // Update value
879        conn.set(&redis_key, &value_json)
880            .await
881            .map_err(|e| StorageError::QueryError {
882                message: format!("Failed to update: {}", e),
883            })?;
884
885        // Increment version
886        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        // Use Lua script for atomic versioned update
910        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        // Delete all related keys
946        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                    // Generate a key for the insert (using timestamp + random)
990                    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        // For Redis, we scan keys and filter in memory
1022        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            // Extract the actual key from the full Redis key
1030            if let Some(key_part) = full_key.strip_prefix(&format!("{}:{}:", self.config.key_prefix, query.table)) {
1031                // Skip version and metadata keys
1032                if key_part.ends_with(":version") || key_part.ends_with(":metadata") {
1033                    continue;
1034                }
1035
1036                // Get the value
1037                if let Some(entry) = self.get::<T>(&query.table, key_part).await? {
1038                    results.push(entry);
1039                }
1040            }
1041        }
1042
1043        // Apply limit and offset
1044        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        // Filter out version and metadata keys
1064        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        // Redis doesn't support full ACID transactions across multiple operations
1074        // We simulate it with MULTI/EXEC
1075        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        // Execute all operations in the transaction using MULTI/EXEC
1088        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        // Extract just the key part
1143        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        // Redis doesn't track modification times natively
1251        // We would need to store this in metadata
1252        warn!("get_modified_since is not efficiently supported in Redis");
1253
1254        // Return all entries and let caller filter
1255        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        // Redis automatically handles expiration, so this is a no-op
1301        // We just return the count of how many keys would expire soon
1302        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        // Redis doesn't need compaction, but we can run memory optimization
1311        let mut conn = self.get_connection().await?;
1312
1313        // Run MEMORY PURGE if available (Redis 4.0+)
1314        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        // Redis writes are already persisted based on configuration
1325        // We can optionally call BGSAVE for a background save
1326        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        // Verify connection
1340        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        // Initialize statistics
1348        let mut conn = self.get_connection().await?;
1349        let stats_key = format!("{}:stats", self.config.key_prefix);
1350
1351        // Check if stats exist, if not create them
1352        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        // Mark as shutdown
1367        let mut shutdown = self.shutdown.write().await;
1368        *shutdown = true;
1369
1370        // Close all subscriptions
1371        let mut subscriptions = self.subscriptions.write().await;
1372        subscriptions.clear();
1373
1374        // Save final statistics
1375        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        // TTL returns -2 if key doesn't exist, -1 if no expiration
1402        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        // Get Redis memory info
1489        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        // Parse memory stats
1498        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        // Get key count
1510        let keys_count: usize = redis::cmd("DBSIZE")
1511            .query_async(&mut *conn)
1512            .await
1513            .unwrap_or(0);
1514
1515        // Get our tracked stats
1516        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        // Subscribe to channel
1555        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        // Store subscription
1567        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
1596/// Wrapper for subscriber to implement Send
1597struct 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, // Use different DB for tests
1626            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        // Should succeed with correct version
1733        storage.update_versioned("test_table", "key4", &updated_data, 1).await.unwrap();
1734
1735        // Should fail with wrong version
1736        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        // Should succeed with correct version
1784        let success = storage.compare_and_swap("test_table", "key6", 1, &new_data).await.unwrap();
1785        assert!(success);
1786
1787        // Should fail with wrong version
1788        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}