akar_storage/
shadow_file.rs1use crate::buffer_manager::BufferManager;
8use std::collections::HashMap;
9use std::sync::{Arc, Mutex};
10
11#[derive(Debug, Clone)]
13pub struct ShadowEntry {
14 pub original_page_id: u64,
15 pub shadow_data: Vec<u8>,
16 pub is_dirty: bool,
17}
18
19#[derive(Debug, Default)]
21pub struct ShadowFile {
22 entries: HashMap<u64, ShadowEntry>,
23 file_name: Option<String>,
25}
26
27impl ShadowFile {
28 pub fn new() -> Self {
29 Self {
30 entries: HashMap::new(),
31 file_name: None,
32 }
33 }
34
35 pub fn set_file_name(&mut self, name: &str) {
37 self.file_name = Some(name.to_string());
38 }
39
40 pub fn create_shadow(&mut self, page_id: u64, data: Vec<u8>) {
41 self.entries.insert(
42 page_id,
43 ShadowEntry {
44 original_page_id: page_id,
45 shadow_data: data,
46 is_dirty: true,
47 },
48 );
49 }
50
51 pub fn get_shadow(&self, page_id: u64) -> Option<&ShadowEntry> {
52 self.entries.get(&page_id)
53 }
54
55 pub fn has_shadow(&self, page_id: u64) -> bool {
56 self.entries.contains_key(&page_id)
57 }
58
59 pub fn len(&self) -> usize {
61 self.entries.len()
62 }
63
64 pub fn is_empty(&self) -> bool {
65 self.entries.is_empty()
66 }
67
68 pub fn clear(&mut self) {
70 self.entries.clear();
71 }
72
73 pub fn apply(&self, buffer_manager: &Arc<Mutex<BufferManager>>) -> std::io::Result<()> {
80 let file_name = match &self.file_name {
81 Some(n) => n.clone(),
82 None => return Ok(()), };
84
85 let mut bm = buffer_manager
86 .lock()
87 .map_err(|e| std::io::Error::other(format!("Lock poisoned: {e}")))?;
88 for entry in self.entries.values().filter(|e| e.is_dirty) {
89 let frame = bm.pin_mut(&file_name, entry.original_page_id)?;
90 let copy_len = entry.shadow_data.len().min(frame.data.len());
92 frame.data[..copy_len].copy_from_slice(&entry.shadow_data[..copy_len]);
93 frame.mark_dirty();
94 bm.unpin(&file_name, entry.original_page_id);
95 }
96 Ok(())
97 }
98
99 pub fn discard(&mut self) {
104 self.entries.clear();
105 }
106
107 pub fn dirty_pages(&self) -> impl Iterator<Item = &ShadowEntry> {
108 self.entries.values().filter(|e| e.is_dirty)
109 }
110}