Compare commits

...

6 Commits

Author SHA1 Message Date
c5f31a9922 Updated pager.rs 2023-08-15 19:49:59 +02:00
5c086c10b9 Added tempfile dep 2023-08-15 19:49:34 +02:00
ef7a802993 Added some statement tests 2023-08-15 19:49:22 +02:00
b4a86dca9f Added Position type for cursor 2023-08-13 13:17:09 +02:00
53870fecce Accept bigger variety of paths for pager 2023-08-13 13:16:36 +02:00
c4ce04d700 Implement table cursor 2023-08-13 13:14:53 +02:00
7 changed files with 274 additions and 16 deletions

168
Cargo.lock generated
View File

@ -8,14 +8,81 @@ version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "cc"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "dbonk"
version = "0.1.0"
dependencies = [
"anyhow",
"tempfile",
"thiserror",
]
[[package]]
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fastrand"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "proc-macro2"
version = "1.0.66"
@ -34,6 +101,28 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "rustix"
version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "syn"
version = "2.0.28"
@ -45,6 +134,19 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix",
"windows-sys",
]
[[package]]
name = "thiserror"
version = "1.0.44"
@ -70,3 +172,69 @@ name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

View File

@ -6,3 +6,6 @@ edition = "2021"
[dependencies]
anyhow = "1.0.72"
thiserror = "1.0.44"
[dev-dependencies]
tempfile = "3.7.1"

40
src/cursor.rs Normal file
View File

@ -0,0 +1,40 @@
use crate::table::Table;
pub type Position = (usize, usize);
pub struct Cursor<'a> {
pub table: &'a mut Table,
pub row_num: usize,
pub end_of_table: bool,
}
impl<'a> Cursor<'a> {
pub fn at_table_start(table: &'a mut Table) -> Self {
let end_of_table = table.row_count == 0;
Self {
table,
row_num: 0,
end_of_table,
}
}
pub fn at_table_end(table: &'a mut Table) -> Self {
let row_count = table.row_count;
Self {
table,
row_num: row_count,
end_of_table: true,
}
}
pub fn position(&self) -> Position {
self.table.row_slot(self.row_num)
}
pub fn advance(&mut self) {
self.row_num += 1;
if self.row_num >= self.table.row_count {
self.end_of_table = true;
}
}
}

View File

@ -1,3 +1,4 @@
pub mod cursor;
pub mod layout;
pub mod pager;
pub mod row;

View File

@ -1,9 +1,10 @@
use std::{
fs::{File, OpenOptions},
os::unix::prelude::FileExt,
path::Path,
};
use crate::layout::*;
use crate::{cursor::Position, layout::*};
use anyhow::Result;
use thiserror::Error;
@ -23,7 +24,7 @@ pub struct Pager {
}
impl Pager {
pub fn new(file_path: &str) -> Result<Self> {
pub fn new<T: AsRef<Path>>(file_path: T) -> Result<Self> {
let file = OpenOptions::new()
.read(true)
.write(true)
@ -41,7 +42,7 @@ impl Pager {
metadata.len() as usize
}
pub fn row_location(&self, row_num: usize) -> (usize, usize) {
pub fn row_location(&self, row_num: usize) -> Position {
let page_num = row_num / ROWS_PER_PAGE;
let row_offset = row_num % ROWS_PER_PAGE;
let byte_offset = row_offset * ROW_SIZE;
@ -61,12 +62,12 @@ impl Pager {
num_pages += 1
}
let mut page: Page = [0; PAGE_SIZE];
if page_num <= num_pages {
let mut page: Page = [0; PAGE_SIZE];
let offset: u64 = (page_num * PAGE_SIZE).try_into()?;
self.file.read_at(&mut page, offset)?;
self.pages[page_num] = Some(page);
}
self.pages[page_num] = Some(page);
}
Ok(self.pages[page_num].as_mut().unwrap())

View File

@ -1,4 +1,5 @@
use crate::{
cursor::Cursor,
layout::{ROW_SIZE, TABLE_MAX_ROWS},
row::{Row, RowBytes},
table::Table,
@ -6,8 +7,6 @@ use crate::{
use anyhow::Result;
use thiserror::Error;
type FilteredRows = Vec<Row>;
#[derive(Debug)]
pub enum StatementType {
Insert(Box<Row>),
@ -73,23 +72,69 @@ pub fn execute_insert(row: Row, table: &mut Table) -> Result<()> {
return Err(ExecutionError::TableFull.into());
}
let cursor = Cursor::at_table_end(table);
let bytes: RowBytes = row.into();
let (page_num, offset) = table.row_slot(table.row_count);
let (page_num, offset) = cursor.position();
let page = table.pager.page(page_num)?;
// let page = table.pager.pages[page_num].as_mut().unwrap();
page[offset..offset + ROW_SIZE].copy_from_slice(&bytes);
table.row_count += 1;
Ok(())
}
pub fn execute_select(table: &mut Table) -> Result<FilteredRows> {
let mut rows: FilteredRows = vec![];
for i in 0..table.row_count {
let (page_num, offset) = table.row_slot(i);
let page = table.pager.page(page_num)?;
pub fn execute_select(table: &mut Table) -> Result<Vec<Row>> {
let mut rows: Vec<Row> = vec![];
let mut cursor = Cursor::at_table_start(table);
while !cursor.end_of_table {
let (page_num, offset) = cursor.position();
let page = cursor.table.pager.page(page_num)?;
let row: RowBytes = page[offset..offset + ROW_SIZE].try_into()?;
rows.push(row.into());
cursor.advance();
}
Ok(rows)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{pager::Pager, row::Row, table::Table};
use tempfile::NamedTempFile;
#[test]
fn execute_select_with_data_succeeds() {
let file = NamedTempFile::new_in("target").unwrap();
let pager = Pager::new(file.path()).unwrap();
let mut table = Table::new(pager);
for _ in 0..5 {
execute_insert(Row::default(), &mut table).unwrap();
}
let rows = execute_select(&mut table).unwrap();
assert_eq!(rows.len(), 5);
}
#[test]
fn execute_insert_exceeding_row_limit_fails() {
let file = NamedTempFile::new_in("target").unwrap();
let pager = Pager::new(file.path()).unwrap();
let mut table = Table::new(pager);
for _ in 0..TABLE_MAX_ROWS {
let row = Row::new(u16::MAX, "a".repeat(32).as_str(), "a".repeat(255).as_str());
execute_insert(row, &mut table).unwrap();
}
let result = execute_insert(Row::default(), &mut table);
assert!(result.is_err());
}
#[test]
#[should_panic]
fn execute_insert_input_exceeding_length_fails() {
let file = NamedTempFile::new_in("target").unwrap();
let pager = Pager::new(file.path()).unwrap();
let mut table = Table::new(pager);
let row = Row::new(u16::MAX, "a".repeat(33).as_str(), "a".repeat(256).as_str());
let result = execute_insert(row, &mut table);
assert!(result.is_err());
}
}

View File

@ -1,4 +1,4 @@
use crate::{layout::*, pager::Pager};
use crate::{cursor::Position, layout::*, pager::Pager};
pub struct Table {
pub row_count: usize,
@ -11,7 +11,7 @@ impl Table {
Self { row_count, pager }
}
pub fn row_slot(&self, index: usize) -> (usize, usize) {
pub fn row_slot(&self, index: usize) -> Position {
self.pager.row_location(index)
}