use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ptr;
use std::sync::{Arc, Mutex, RwLock};
use crate::constant::PAGE_SIZE;
const RECPTR_SZ: usize = 4;
const MAGIC: u8 = 0xD7;
#[derive(Clone, Debug, PartialEq)]
pub struct Cursor {
pub pageid: u64, pub slotid: u16, }
pub struct MetaPage {
num_pages: u64,
num_items: u64,
read_cursor: Cursor,
write_cursor: Cursor,
mem: usize,
}
impl MetaPage {
pub fn from_mmap_ptr(ptr: usize) -> Self {
let num_pages: u64;
let num_items: u64;
let read_cursor: Cursor;
let write_cursor: Cursor;
unsafe {
let mut offset = 0;
let ptr = ptr as *const u8;
let magic = ptr.read();
assert_eq!(magic, MAGIC);
offset += 1;
num_pages = ptr.offset(offset).cast::<u64>().read();
offset += 8;
num_items = ptr.offset(offset).cast::<u64>().read();
offset += 8;
let pageid = ptr.offset(offset).cast::<u64>().read();
offset += 8;
let slotid = ptr.offset(offset).cast::<u16>().read();
offset += 2;
read_cursor = Cursor { pageid, slotid };
let pageid = ptr.offset(offset).cast::<u64>().read();
offset += 8;
let slotid = ptr.offset(offset).cast::<u16>().read();
write_cursor = Cursor { pageid, slotid };
}
Self {
num_pages,
num_items,
read_cursor,
write_cursor,
mem: ptr,
}
}
pub fn incr_num_pages(&mut self) {
let num_pages = self.num_pages;
self.set_num_pages(num_pages + 1);
}
pub fn incr_num_items(&mut self) {
let num_items = self.num_items;
self.set_num_items(num_items + 1);
}
pub fn get_num_pages(&self) -> u64 {
self.num_pages
}
pub fn get_num_items(&self) -> u64 {
self.num_items
}
pub fn get_read_cursor(&self) -> Cursor {
self.read_cursor.clone()
}
pub fn get_write_cursor(&self) -> Cursor {
self.write_cursor.clone()
}
pub fn set_num_pages(&mut self, v: u64) {
self.num_pages = v;
unsafe {
let ptr = self.mem as *const u8;
(ptr.offset(1) as *mut u64).write(v);
}
}
pub fn set_num_items(&mut self, v: u64) {
self.num_items = v;
unsafe {
let ptr = self.mem as *const u8;
(ptr.offset(9) as *mut u64).write(v);
}
}
pub fn set_read_cursor(&mut self, v: Cursor) {
self.read_cursor = v.clone();
unsafe {
let ptr = self.mem as *const u8;
(ptr.offset(17) as *mut u64).write(v.pageid);
(ptr.offset(25) as *mut u16).write(v.slotid);
}
}
pub fn set_write_cursor(&mut self, v: Cursor) {
self.write_cursor = v.clone();
unsafe {
let ptr = self.mem as *const u8;
(ptr.offset(27) as *mut u64).write(v.pageid);
(ptr.offset(35) as *mut u16).write(v.slotid);
}
}
}
pub struct RecordPage {
shared_mem: bool,
records: Vec<Vec<u8>>,
space_used: u16,
write_offset: u16,
rwlatch: Arc<RwLock<()>>,
mem: usize,
}
impl RecordPage {
pub fn new() -> Self {
Self {
shared_mem: false,
records: vec![],
space_used: 1 + 2,
write_offset: 1,
rwlatch: Arc::new(RwLock::new(())),
mem: 0,
}
}
pub fn from_file(file: Arc<Mutex<File>>, pageid: u64) -> Self {
let mut file = file.lock().unwrap();
let off = (pageid + 1) * PAGE_SIZE as u64;
file.seek(SeekFrom::Start(off)).unwrap();
let mut buf: [u8; PAGE_SIZE] = [0; PAGE_SIZE];
file.read_exact(&mut buf).unwrap();
let page = buf_read_record_page(&buf);
page
}
pub fn from_mmap_ptr(rwlatch: Arc<RwLock<()>>, ptr: usize) -> Self {
let mut space_used = 3;
let mut write_offset = 1;
unsafe {
let _ = rwlatch.read().unwrap();
let ptr = ptr as *const u8;
let magic = ptr.read();
assert_eq!(magic, MAGIC);
let nrecords = ptr
.offset((PAGE_SIZE - 2) as isize)
.cast::<u16>()
.read();
let recptr_sz = RECPTR_SZ as isize;
let mut off = (PAGE_SIZE - 2) as isize;
for _ in 0..nrecords {
off -= recptr_sz;
let rec_len = ptr.offset(off+2).cast::<u16>().read();
space_used += rec_len + 4;
write_offset += rec_len;
}
}
Self {
shared_mem: true,
records: vec![], space_used,
write_offset,
rwlatch,
mem: ptr,
}
}
pub fn save(&self, file: Arc<Mutex<File>>, pageid: u64) {
let mut file = file.lock().unwrap();
let off = (pageid + 1) * PAGE_SIZE as u64;
file.seek(SeekFrom::Start(off)).unwrap();
let mut buf: [u8; PAGE_SIZE] = [0; PAGE_SIZE];
unsafe {
let _ = self.rwlatch.read().unwrap();
ptr::copy(self.mem as *const u8, buf.as_mut_ptr(), PAGE_SIZE);
}
file.write(&buf).unwrap();
}
pub fn reset(&mut self) {
let buf = empty_page_buf();
unsafe {
let _ = self.rwlatch.write().unwrap();
ptr::copy(buf.as_ptr(), self.mem as *mut u8, PAGE_SIZE);
}
self.space_used = 3;
self.write_offset = 1;
}
pub fn num_records(&self) -> usize {
if self.shared_mem {
let num_records;
unsafe {
let _ = self.rwlatch.read().unwrap();
let ptr = self.mem as *const u8;
num_records = ptr
.offset((PAGE_SIZE - 2) as isize)
.cast::<u16>()
.read() as usize;
}
num_records
} else {
self.records.len()
}
}
pub fn get_record(&self, slot: usize) -> Option<Vec<u8>> {
if self.shared_mem {
let record;
unsafe {
let _ = self.rwlatch.read().unwrap();
let ptr = self.mem as *const u8;
let num_records = ptr.offset((PAGE_SIZE - 2) as isize)
.cast::<u16>()
.read() as usize;
assert!(slot < num_records);
let off = (PAGE_SIZE - 2 - (slot + 1) * 4) as isize;
let offset = ptr.offset(off).cast::<u16>().read() as isize;
let size = ptr.offset(off+2).cast::<u16>().read() as usize;
let buf = std::slice::from_raw_parts(ptr.offset(offset), size);
record = buf.to_vec();
}
Some(record)
} else {
self.records.get(slot).map(|x| x.clone())
}
}
pub fn insert(&mut self, record: Vec<u8>) {
assert!(self.space_used + self.record_space(&record) <= PAGE_SIZE as u16);
assert!(self.shared_mem);
unsafe {
assert!(self.mem != 0);
let _ = self.rwlatch.write().unwrap();
let ptr = self.mem as *const u8;
let off = (PAGE_SIZE - 2) as isize;
let num_records = ptr.offset(off)
.cast::<u16>()
.read();
(ptr.offset(off).cast::<u16>() as *mut u16)
.write(num_records + 1);
let off = (PAGE_SIZE - 2 - (num_records as usize + 1) * 4) as isize;
(ptr.offset(off).cast::<u16>() as *mut u16)
.write(self.write_offset);
(ptr.offset(off+2).cast::<u16>() as *mut u16)
.write(record.len() as u16);
let off = self.write_offset as isize;
std::ptr::copy(
record.as_ptr(),
ptr.offset(off) as *mut u8,
record.len()
);
}
self.non_mmap_insert(record.clone());
}
pub fn is_shared_mem(&self) -> bool {
self.shared_mem
}
fn non_mmap_insert(&mut self, record: Vec<u8>) {
self.space_used += self.record_space(&record);
self.write_offset += record.len() as u16;
}
pub fn can_insert(&self, record: &Vec<u8>) -> bool {
assert_eq!(self.shared_mem, true);
self.space_used + self.record_space(&record) <= PAGE_SIZE as u16
}
#[inline(always)]
fn record_space(&self, record: &Vec<u8>) -> u16 {
record.len() as u16 + 4 }
}
#[derive(Debug, PartialEq)]
pub struct Metadata {
pub num_pages: u64,
pub num_items: u64,
pub read_cursor: Cursor,
pub write_cursor: Cursor,
}
pub fn empty_page_buf() -> [u8; PAGE_SIZE] {
let mut buf = [0; PAGE_SIZE];
buf[0] = MAGIC;
buf
}
fn buf_read_record_page(buf: &[u8]) -> RecordPage {
assert_eq!(buf.len(), PAGE_SIZE);
assert_eq!(buf[0], MAGIC);
let ptr: *const u8 = buf.as_ptr();
let offset_top = (PAGE_SIZE - 2) as isize; let mut page;
unsafe {
let sz = ptr.offset(offset_top).cast::<u16>().read();
page = RecordPage::new();
for slot in 0..sz {
let off: isize = offset_top - (slot as isize + 1) * RECPTR_SZ as isize;
let record_off = ptr.offset(off).cast::<u16>().read() as usize;
let record_len = ptr.offset(off+2).cast::<u16>().read() as usize;
let record = buf[record_off..record_off+record_len].to_vec();
page.space_used += page.record_space(&record);
page.write_offset += record.len() as u16;
page.records.push(record);
}
}
page
}
pub fn buf_write_metadata_page(m: &Metadata) -> [u8; PAGE_SIZE] {
let mut buf: [u8; PAGE_SIZE] = [0; PAGE_SIZE];
buf[0] = MAGIC;
let ptr: *mut u8 = buf.as_mut_ptr();
unsafe {
ptr.offset(1).cast::<u64>().write(m.num_pages);
ptr.offset(9).cast::<u64>().write(m.num_items);
ptr.offset(17).cast::<u64>().write(m.read_cursor.pageid);
ptr.offset(25).cast::<u16>().write(m.read_cursor.slotid);
ptr.offset(27).cast::<u64>().write(m.write_cursor.pageid);
ptr.offset(35).cast::<u16>().write(m.write_cursor.slotid);
}
buf
}