kstone_core/
memory_wal.rs

1/// In-memory Write-Ahead Log for testing and temporary databases
2///
3/// Provides the same API as the disk-based WAL but stores all records in memory.
4/// All data is lost when the MemoryWal is dropped.
5
6use crate::{Record, Result};
7use std::sync::{Arc, Mutex};
8
9/// Log Sequence Number (LSN) - monotonically increasing record ID
10pub type Lsn = u64;
11
12/// In-memory Write-Ahead Log
13#[derive(Clone)]
14pub struct MemoryWal {
15    inner: Arc<Mutex<MemoryWalInner>>,
16}
17
18struct MemoryWalInner {
19    /// All records stored in memory (LSN -> Record)
20    records: Vec<(Lsn, Record)>,
21    /// Next LSN to assign
22    next_lsn: Lsn,
23}
24
25impl MemoryWal {
26    /// Create a new in-memory WAL
27    pub fn create() -> Result<Self> {
28        Ok(Self {
29            inner: Arc::new(Mutex::new(MemoryWalInner {
30                records: Vec::new(),
31                next_lsn: 1,
32            })),
33        })
34    }
35
36    /// Open is the same as create for in-memory WAL (no persistence)
37    pub fn open() -> Result<Self> {
38        Self::create()
39    }
40
41    /// Append a record to the WAL
42    pub fn append(&self, record: Record) -> Result<Lsn> {
43        let mut inner = self.inner.lock().unwrap();
44        let lsn = inner.next_lsn;
45        inner.next_lsn += 1;
46        inner.records.push((lsn, record));
47        Ok(lsn)
48    }
49
50    /// Flush is a no-op for in-memory WAL
51    pub fn flush(&self) -> Result<()> {
52        Ok(())
53    }
54
55    /// Read all records from the WAL
56    pub fn read_all(&self) -> Result<Vec<(Lsn, Record)>> {
57        let inner = self.inner.lock().unwrap();
58        Ok(inner.records.clone())
59    }
60
61    /// Get the next LSN that will be assigned
62    pub fn next_lsn(&self) -> Lsn {
63        let inner = self.inner.lock().unwrap();
64        inner.next_lsn
65    }
66
67    /// Clear all records (useful for testing)
68    pub fn clear(&self) {
69        let mut inner = self.inner.lock().unwrap();
70        inner.records.clear();
71    }
72
73    /// Get the number of records in the WAL
74    pub fn len(&self) -> usize {
75        let inner = self.inner.lock().unwrap();
76        inner.records.len()
77    }
78
79    /// Check if the WAL is empty
80    pub fn is_empty(&self) -> bool {
81        self.len() == 0
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use crate::{Key, Value};
89    use std::collections::HashMap;
90
91    fn create_test_record(pk: &[u8], seq: u64) -> Record {
92        let mut item = HashMap::new();
93        item.insert("test".to_string(), Value::string("value"));
94        Record::put(Key::new(pk.to_vec()), item, seq)
95    }
96
97    #[test]
98    fn test_memory_wal_create() {
99        let wal = MemoryWal::create().unwrap();
100        assert_eq!(wal.next_lsn(), 1);
101        assert!(wal.is_empty());
102    }
103
104    #[test]
105    fn test_memory_wal_append() {
106        let wal = MemoryWal::create().unwrap();
107
108        let record = create_test_record(b"key1", 1);
109        let lsn = wal.append(record).unwrap();
110        assert_eq!(lsn, 1);
111        assert_eq!(wal.next_lsn(), 2);
112        assert_eq!(wal.len(), 1);
113    }
114
115    #[test]
116    fn test_memory_wal_read_all() {
117        let wal = MemoryWal::create().unwrap();
118
119        let record1 = create_test_record(b"key1", 1);
120        let record2 = create_test_record(b"key2", 2);
121
122        wal.append(record1.clone()).unwrap();
123        wal.append(record2.clone()).unwrap();
124
125        let records = wal.read_all().unwrap();
126        assert_eq!(records.len(), 2);
127        assert_eq!(records[0].0, 1);
128        assert_eq!(records[1].0, 2);
129    }
130
131    #[test]
132    fn test_memory_wal_flush_noop() {
133        let wal = MemoryWal::create().unwrap();
134        let record = create_test_record(b"key1", 1);
135        wal.append(record).unwrap();
136
137        // Flush should succeed but do nothing
138        wal.flush().unwrap();
139        assert_eq!(wal.len(), 1);
140    }
141
142    #[test]
143    fn test_memory_wal_clear() {
144        let wal = MemoryWal::create().unwrap();
145
146        wal.append(create_test_record(b"key1", 1)).unwrap();
147        wal.append(create_test_record(b"key2", 2)).unwrap();
148        assert_eq!(wal.len(), 2);
149
150        wal.clear();
151        assert!(wal.is_empty());
152        assert_eq!(wal.next_lsn(), 3); // LSN counter not reset
153    }
154
155    #[test]
156    fn test_memory_wal_clone() {
157        let wal = MemoryWal::create().unwrap();
158        wal.append(create_test_record(b"key1", 1)).unwrap();
159
160        let wal2 = wal.clone();
161        assert_eq!(wal2.len(), 1);
162
163        // Append to clone affects original (shared Arc)
164        wal2.append(create_test_record(b"key2", 2)).unwrap();
165        assert_eq!(wal.len(), 2);
166    }
167}