use crate::page::PAGE_SIZE;
#[derive(Debug)]
pub struct BufferFrame {
pub data: [u8; PAGE_SIZE],
pub page_id: Option<u32>,
pub pin_count: u32,
pub dirty: bool,
pub last_accessed: u64,
}
impl BufferFrame {
pub fn new() -> Self {
Self {
data: [0u8; PAGE_SIZE],
page_id: None,
pin_count: 0,
dirty: false,
last_accessed: 0,
}
}
pub fn pin(&mut self) {
self.pin_count += 1;
}
pub fn unpin(&mut self, dirty: bool) {
debug_assert!(self.pin_count > 0, "unpin called on unpinned frame");
self.pin_count -= 1;
if dirty {
self.dirty = true;
}
}
pub fn is_pinned(&self) -> bool {
self.pin_count > 0
}
pub fn is_free(&self) -> bool {
self.page_id.is_none()
}
pub fn reset(&mut self) {
self.page_id = None;
self.pin_count = 0;
self.dirty = false;
self.last_accessed = 0;
}
}
impl Default for BufferFrame {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_new_is_free() {
let frame = BufferFrame::new();
assert!(frame.is_free());
assert!(!frame.is_pinned());
assert!(!frame.dirty);
}
#[test]
fn test_frame_pin_unpin() {
let mut frame = BufferFrame::new();
frame.pin();
assert!(frame.is_pinned());
assert_eq!(frame.pin_count, 1);
frame.pin();
assert_eq!(frame.pin_count, 2);
frame.unpin(false);
assert_eq!(frame.pin_count, 1);
assert!(frame.is_pinned());
frame.unpin(false);
assert!(!frame.is_pinned());
}
#[test]
fn test_frame_dirty_tracking() {
let mut frame = BufferFrame::new();
frame.pin();
assert!(!frame.dirty);
frame.unpin(true);
assert!(frame.dirty);
frame.pin();
frame.unpin(false);
assert!(frame.dirty); }
#[test]
fn test_frame_reset() {
let mut frame = BufferFrame::new();
frame.page_id = Some(42);
frame.pin();
frame.dirty = true;
frame.last_accessed = 100;
frame.reset();
assert!(frame.is_free());
assert!(!frame.is_pinned());
assert!(!frame.dirty);
assert_eq!(frame.last_accessed, 0);
}
}