Skip to main content

walcraft/
iterator.rs

1use crate::error::WalError;
2use crate::storage::iterator::StorageIterator;
3use crate::storage::meta::Meta;
4use crate::wal::{MODE_IDLE, MODE_READ};
5use crate::Wal;
6use std::sync::atomic::Ordering::Relaxed;
7
8/// A log entry in the Write Ahead Log (WAL).
9/// This struct wraps a byte vector and provides methods to access the data
10pub struct LogEntry {
11    inner: Vec<u8>,
12}
13
14impl LogEntry {
15    pub(crate) fn new(inner: Vec<u8>) -> Self {
16        Self { inner }
17    }
18
19    /// Returns the raw byte data of the log entry.
20    pub fn data(&self) -> &[u8] {
21        &self.inner
22    }
23
24    /// Returns the length of the byte vector
25    pub fn len(&self) -> usize {
26        self.inner.len()
27    }
28
29    /// A deserialization method for data written with `append_struct` method
30    /// ## Returns
31    /// - `Ok(T)` if the deserialization is successful
32    /// - `Err(WalError)` if the deserialization fails
33    pub fn to_struct<T: for<'a> serde::Deserialize<'a>>(&self) -> Result<T, WalError> {
34        bincode::deserialize(&self.inner)
35            .map_err(|e| WalError::DeserializationError(format!("Failed to deserialize: {}", e)))
36    }
37}
38
39/// An iterator over the log entries in the Write Ahead Log (WAL).
40///
41/// This struct wraps a `StorageIterator` and provides methods to iterate over the log entries.
42/// ## Usage
43/// ```no_run
44/// use walcraft::Wal;
45///
46/// fn main() {
47///     let wal = Wal::new("/tmp/walcraft", Some(2000)).unwrap();
48///     // get the iterator
49///     let iterator = wal.iter().unwrap();
50///     // Iterate over the log entries
51///     for item in iterator {
52///         println!("{:?}", item.data());
53///     }
54/// }
55///
56/// ```
57pub struct WalIterator {
58    wal: Wal,
59    inner: StorageIterator,
60}
61impl WalIterator {
62    pub(crate) fn new(wal: Wal) -> Result<Self, WalError> {
63        let location = &wal.inner.config.location;
64        let meta = Meta::read_from_file(location)?;
65        let iterator = StorageIterator::new(meta);
66        Ok(Self {
67            wal,
68            inner: iterator,
69        })
70    }
71}
72
73impl Iterator for WalIterator {
74    type Item = LogEntry;
75
76    fn next(&mut self) -> Option<Self::Item> {
77        match self.inner.next() {
78            Some(v) => Some(LogEntry::new(v)),
79            None => {
80                // release read lock when done
81                if self
82                    .wal
83                    .inner
84                    .mode
85                    .compare_exchange(MODE_READ, MODE_IDLE, Relaxed, Relaxed)
86                    .is_err()
87                {
88                    panic!("Walcraft error: unable to release read lock on WAL");
89                }
90                None
91            }
92        }
93    }
94}
95
96impl Drop for WalIterator {
97    fn drop(&mut self) {
98        if self.inner.next().is_none() {
99            return;
100        }
101        if self
102            .wal
103            .inner
104            .mode
105            .compare_exchange(MODE_READ, MODE_IDLE, Relaxed, Relaxed)
106            .is_err()
107        {
108            panic!("Walcraft error: unable to release read lock on WAL");
109        }
110    }
111}