diff --git a/bustubx/src/buffer/buffer_pool.rs b/bustubx/src/buffer/buffer_pool.rs index 23a3eb3..8695cb7 100644 --- a/bustubx/src/buffer/buffer_pool.rs +++ b/bustubx/src/buffer/buffer_pool.rs @@ -20,7 +20,7 @@ pub struct BufferPoolManager { pub replacer: Arc>, pub disk_manager: Arc, // 缓冲池中的页号与frame号的映射 - page_table: DashMap, + page_table: Arc>, // 缓冲池中空闲的frame free_list: Arc>>, } @@ -37,7 +37,7 @@ impl BufferPoolManager { pool, replacer: Arc::new(RwLock::new(LRUKReplacer::new(num_pages, 2))), disk_manager, - page_table: DashMap::new(), + page_table: Arc::new(DashMap::new()), free_list: Arc::new(RwLock::new(free_list)), } } diff --git a/bustubx/src/buffer/page.rs b/bustubx/src/buffer/page.rs index cc0a1fa..6877f91 100644 --- a/bustubx/src/buffer/page.rs +++ b/bustubx/src/buffer/page.rs @@ -1,5 +1,11 @@ +use crate::buffer::buffer_pool::FrameId; +use crate::buffer::replacer::LRUKReplacer; +use dashmap::DashMap; use derive_with::With; +use log::error; +use std::ops::Deref; use std::sync::atomic::AtomicU32; +use std::sync::{Arc, RwLock}; pub type PageId = u32; pub type AtomicPageId = AtomicU32; @@ -52,3 +58,69 @@ impl Page { self.is_dirty = other.is_dirty; } } + +pub struct PageRef { + page: Arc>, + page_table: Arc>, + replacer: Arc>, +} + +impl Deref for PageRef { + type Target = Arc>; + + fn deref(&self) -> &Self::Target { + &self.page + } +} + +impl Drop for PageRef { + fn drop(&mut self) { + if self.page.read().unwrap().pin_count == 0 { + return; + } + let page_id = self.page.read().unwrap().page_id; + if let Some(frame_id) = self.page_table.get(&page_id) { + self.page.write().unwrap().pin_count -= 1; + if self.page.read().unwrap().pin_count == 0 { + if let Err(e) = self + .replacer + .write() + .unwrap() + .set_evictable(*frame_id, true) + { + panic!( + "Failed to set evictable to frame {}, err: {:?}", + *frame_id, e + ); + } + } + } else { + error!("Cannot unpin page id {} as it is not in the pool", page_id); + } + } +} + +#[cfg(test)] +mod tests { + use crate::buffer::replacer::LRUKReplacer; + use crate::buffer::{Page, PageRef}; + use dashmap::DashMap; + use std::sync::{Arc, RwLock}; + + #[test] + fn page_ref() { + let page = Arc::new(RwLock::new(Page::new(1))); + let page_table = Arc::new(DashMap::new()); + let replacer = Arc::new(RwLock::new(LRUKReplacer::new(10, 2))); + + let page_ref = PageRef { + page: page.clone(), + page_table, + replacer, + }; + assert_eq!(Arc::strong_count(&page), 2); + assert_eq!(page_ref.read().unwrap().page_id, 1); + drop(page_ref); + assert_eq!(Arc::strong_count(&page), 1); + } +}