Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions exam_tester_m1.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

# Check inserted records using select query
for key in records:
# select function will return array of records
# select function will return array of records
# here we are sure that there is only one record in t hat array
# check for retreiving version -1. Should retreive version 0 since only one version exists.
record = query.select_version(key, 0, [1, 1, 1, 1, 1], -1)[0]
Expand Down Expand Up @@ -85,7 +85,7 @@
else:
pass
# print('update on', original, 'and', updated_columns, ':', record)

#check version 0 for record
record = query.select_version(key, 0, [1, 1, 1, 1, 1], 0)[0]
error = False
Expand All @@ -96,7 +96,7 @@
print('update error on', records[key], 'and', updated_columns, ':', record, ', correct:', updated_records[key])

keys = sorted(list(records.keys()))
# aggregate on every column
# aggregate on every column
for c in range(0, grades_table.num_columns):
for i in range(0, number_of_aggregates):
r = sorted(sample(range(0, len(keys)), 2))
Expand Down
258 changes: 187 additions & 71 deletions src/database.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,132 @@
use std::collections::BTreeMap;
use pyo3::prelude::*;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

// Hard code row schema - TODO: make this dynamic schema set by table or something similar
#[derive(Copy, Clone)]
#[pyclass]
pub struct Row {
id: i64,
value: i64,
#[derive(Debug)]
enum DatabaseError {
OutOfBounds,
}

/// This is the place that actually stores the values
///
/// TODO: Keep track of the Base and Tail Pages
#[derive(Clone)]
#[pyclass]
pub enum RowOption {
Empty(),
Some(Row),
pub struct Column {
// TODO: This should be pages later
values: Vec<i64>,
}

impl Column {
fn insert(&mut self, value: i64) {
// TODO: Use pages to do this
self.values.push(value);
}

fn fetch(&self, index: usize) -> i64 {
// TODO: Out of bounds check
return self.values[index];
}

fn new() -> Self {
Column { values: Vec::new() }
}
}

/// Hold a shared reference to every column
/// Have multiple Arc<Mutex> instead of an Arc<Mutex<Vec>> so that each can be locked and unlocked
/// separately by different threads
///
/// Columns and Column are just attractions on Base and Tail Pages
pub struct Columns {
len: usize,
columns: Vec<Arc<Mutex<Column>>>,
}

pub struct Page {
rows: Vec<Row>,
impl Columns {
fn insert(&mut self, col_index: usize, value: i64) -> Result<i64, DatabaseError> {
if col_index >= self.len {
return Err(DatabaseError::OutOfBounds);
}

// Access the index'th column
let m: &Arc<Mutex<Column>> = &self.columns[col_index];
let mut col = m.lock().unwrap();

// Add another value to the column
col.insert(value);

return Ok(value);
}

fn fetch(&mut self, col_index: usize, val_index: usize) -> Result<Option<i64>, DatabaseError> {
if col_index >= self.len {
return Err(DatabaseError::OutOfBounds);
}

// Access the index'th column
let m: &Arc<Mutex<Column>> = &self.columns[col_index];
let col = m.lock().unwrap();

let v = col.fetch(val_index);
Ok(Some(v))
}

fn create_column(&mut self) -> usize {
let c = Arc::new(Mutex::new(Column::new()));
self.columns.push(c);

let index = self.len;
self.len += 1;

index
}

fn new() -> Self {
Columns {
len: 0,
columns: vec![],
}
}
}

pub struct Table {
pub name: String,
pub columns: Columns,
}

impl Table {
fn insert_row(&mut self, values: Vec<i64>) {
let mut i = 0usize;

for value in values {
// TODO: Handle bounds check for cols
let m = &self.columns.columns[i];

let mut col = m.lock().unwrap();

col.insert(value);
i += 1;
}
}

fn fetch_row(&mut self, index: usize) -> Vec<i64> {
let mut row = Vec::<i64>::new();

for m in &self.columns.columns {
let col = m.lock().unwrap();
let val = col.fetch(index);

row.push(val);
}

row
}
}

#[pyclass]
pub struct Database {
#[pyo3(get, set)]
page_size: usize,

pages: BTreeMap<i64, Page>,
tables: Vec<Table>,
}

#[pymethods]
Expand All @@ -34,34 +136,18 @@ impl Database {
return String::from("pong!");
}

fn insert(&mut self, id: i64, value: i64) {
// Make a new row
let r = Row { id, value };

// Make a new page - TODO: look up page to add to existing page
let p = Page { rows: vec![r] };

self.pages.insert(id, p);
#[staticmethod]
fn new() -> Self {
Database { tables: vec![] }
}

fn fetch(&mut self, id: i64) -> RowOption {
let found = self.pages.get(&id);

match found {
Some(page) => {
// Linear search through rows - TODO: Figure out how this is normally done, maybe
// binary search?
for row in &page.rows {
if row.id == id {
return RowOption::Some(*row);
}
}

return RowOption::Empty();
}
fn create_table(&mut self, name: String) {
let t = Table {
name,
columns: Columns::new(),
};

None => RowOption::Empty(),
}
self.tables.push(t);
}
}

Expand All @@ -70,46 +156,76 @@ mod tests {
use super::*;

#[test]
fn insert_found_eq_test() {
let mut db = Database {
page_size: 4096,
pages: BTreeMap::new(),
};
db.insert(0, 100);
fn insert_test() {
let mut db = Database::new();

// Create a table "users"
db.create_table(String::from("users"));

// Create a column
let c: usize = db.tables[0].columns.create_column();

match db.fetch(0) {
RowOption::Some(row) => assert_eq!(row.value, 100),
RowOption::Empty() => assert!(false),
// This is an internal API
match db.tables[0].columns.insert(c, 1) {
Ok(a) => assert_eq!(a, 1),
Err(e) => panic!("{:?}", e),
}
}

#[test]
fn insert_found_ne_test() {
let mut db = Database {
page_size: 4096,
pages: BTreeMap::new(),
};
db.insert(0, 100);
fn fetch_test() {
let mut db = Database::new();

// Create a table "users"
db.create_table(String::from("users"));

// Create a column
let c: usize = db.tables[0].columns.create_column();

match db.tables[0].columns.insert(c, 1) {
Ok(a) => assert_eq!(a, 1),
Err(e) => panic!("{:?}", e),
}

match db.fetch(0) {
RowOption::Some(row) => assert_ne!(row.value, 111),
RowOption::Empty() => assert!(false),
// Try to fetch the 0th id of the c'th column
match db.tables[0].columns.fetch(c, 0) {
Ok(a) => assert_eq!(a, Some(1)),
Err(e) => panic!("{:?}", e),
}
}

#[test]
fn fetch_not_found_test() {
let mut db = Database {
page_size: 4096,
pages: BTreeMap::new(),
};
db.insert(0, 100);
fn insert_row_test() {
let mut db = Database::new();

// Fetch the wrong index and assert true if it's Empty
match db.fetch(1) {
RowOption::Some(_) => assert!(false),
RowOption::Empty() => assert!(true),
}
// Create a table "users"
db.create_table(String::from("users"));

// Create a column
db.tables[0].columns.create_column();
db.tables[0].columns.create_column();
db.tables[0].columns.create_column();

let users: &mut Table = &mut db.tables[0];
users.insert_row(vec![0, 11, 12]);
}
}

#[test]
fn fetch_row_test() {
let mut db = Database::new();

// Create a table "users"
db.create_table(String::from("users"));

// Create a column
db.tables[0].columns.create_column();
db.tables[0].columns.create_column();
db.tables[0].columns.create_column();

let users: &mut Table = &mut db.tables[0];
users.insert_row(vec![0, 11, 12]);

// Fetch the 0th row
assert_eq!(users.fetch_row(0), vec![0, 11, 12]);
}
}
4 changes: 1 addition & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use database::{Database, Row, RowOption};
use database::Database;
use pyo3::prelude::*;

pub mod database;
Expand All @@ -14,8 +14,6 @@ fn hello_from_rust() -> PyResult<String> {
#[pymodule]
fn lstore(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Database>()?;
m.add_class::<Row>()?;
m.add_class::<RowOption>()?;
m.add_function(wrap_pyfunction!(hello_from_rust, m)?)?;
Ok(())
}
2 changes: 0 additions & 2 deletions src/system.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fs::{read_dir, read_to_string};
use std::path::Path;


/// Return a list of all of the ddrives in /dev/
pub fn get_all_drives() -> Vec<String> {
let mut drives = Vec::<String>::new();
Expand Down Expand Up @@ -49,4 +48,3 @@ pub fn get_logical_block_size(drive: &str) -> i16 {
pub fn get_physical_block_size(drive: &str) -> i16 {
read_block_size(drive, "physical")
}