From de6287c6c587530a9e0d560f49ef0eb823e040a3 Mon Sep 17 00:00:00 2001 From: femsci Date: Thu, 9 Mar 2023 16:11:43 +0100 Subject: [PATCH] Add overflow error handling to WritableDataPage. Add IO tests. --- src/data/mod.rs | 29 ++++++++++++++++++++++++++++- src/store/local/index.rs | 8 +++++--- src/store/local/io.rs | 27 +++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/data/mod.rs b/src/data/mod.rs index 1cea798..1feeb75 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -3,7 +3,7 @@ use std::io::{Read, Seek, SeekFrom, Write}; pub trait DataPager { fn get_page(&mut self, offset: usize) -> Result<&mut DataPage, String>; - fn update_page(&mut self, page: WritableDataPage) -> Result; + fn update_page(&mut self, page: DataPage) -> Result; } #[derive(PartialEq, Eq, Hash)] @@ -67,6 +67,16 @@ impl Seek for DataPage { } } +impl Clone for DataPage { + fn clone(&self) -> Self { + Self { + offset: self.offset, + pos: self.pos, + data: self.data.clone(), + } + } +} + impl DataPage { pub(crate) fn load(offset: usize, data: Vec) -> Self { DataPage { @@ -108,6 +118,13 @@ impl Write for WritableDataPage<'_> { return Ok(0); } + if pos + buf.len() > self.page.len() { + return Err(std::io::Error::new( + std::io::ErrorKind::OutOfMemory, + "A write operation would overflow the block.", + )); + } + self.page.data[pos..pos + len].copy_from_slice(&buf); Ok(len) @@ -118,6 +135,12 @@ impl Write for WritableDataPage<'_> { } } +impl Seek for WritableDataPage<'_> { + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.page.seek(pos) + } +} + impl WritableDataPage<'_> { pub fn data(&self) -> &[u8] { self.page.buffer() @@ -126,6 +149,10 @@ impl WritableDataPage<'_> { pub fn offset(&self) -> usize { self.page.offset() } + + pub fn finish(&self) -> DataPage { + self.page.clone() + } } #[cfg(test)] diff --git a/src/store/local/index.rs b/src/store/local/index.rs index afb7162..1461f33 100644 --- a/src/store/local/index.rs +++ b/src/store/local/index.rs @@ -1,7 +1,7 @@ use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, - io::{Read, Seek, SeekFrom}, + io::{Read, Seek, SeekFrom, Write}, }; use crate::data::{DataPage, DataPager}; @@ -179,10 +179,12 @@ impl LocalStore { node.children.push(entry); + let mut block = block.mutate(); block.seek(SeekFrom::Start(position)).unwrap(); - node.serialize(&self.meta); + block.write(&node.serialize(&self.meta)).unwrap(); + let page = block.finish(); - //todo serialize + self.io.update_page(page).unwrap(); todo!() } diff --git a/src/store/local/io.rs b/src/store/local/io.rs index 740992a..e692034 100644 --- a/src/store/local/io.rs +++ b/src/store/local/io.rs @@ -32,9 +32,9 @@ impl DataPager for DataAccessor { Ok(self.cache.get_mut(&offset).unwrap()) } - fn update_page(&mut self, page: crate::data::WritableDataPage) -> Result { + fn update_page(&mut self, page: crate::data::DataPage) -> Result { self.dirty_pages - .push(DataPage::load(page.offset(), page.data().to_vec())); + .push(DataPage::load(page.offset(), page.buffer().to_vec())); return Ok(1); } } @@ -60,3 +60,26 @@ impl DataAccessor { } } } + +#[cfg(test)] +mod tests { + use std::io::{Seek, Write}; + + use crate::data::DataPage; + + #[test] + fn data_page_update() { + let data = vec![2, 1, 3, 7, 0, 0, 0]; + let mut page = DataPage::load(127, data); + page.seek(std::io::SeekFrom::Start(2)).unwrap(); + + let mut writable = page.mutate(); + + writable.write(&[4, 8, 6, 9, 5]).unwrap(); + let page_mod = writable.finish(); + + println!("{:?}", page.buffer()); + assert!(page.buffer().eq(&[2, 1, 4, 8, 6, 9, 5])); + assert!(page_mod.buffer().eq(&[2, 1, 4, 8, 6, 9, 5])); + } +}