Skip to content

Commit

Permalink
Restructured database traits
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfierrog committed Apr 23, 2024
1 parent f85ca92 commit eb432dc
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 90 deletions.
126 changes: 95 additions & 31 deletions src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//! # Database Module [WIP]
//! # Database Module
//!
//! This module contains memory and I/O mechanisms used to store and fetch
//! solution set data, hopefully in an efficient and scalable way.
//! analysis data, hopefully in an efficient and scalable way.
//!
//! #### Authorship
//! - Max Fierro, 4/14/2023 (maxfierro@berkeley.edu)

use anyhow::Result;
use bitvec::prelude::{BitSlice, Msb0};

use std::path::Path;
use std::path::{Path, PathBuf};

use crate::{model::State, solver::RecordType};
use crate::model::{Key, RawRecord, TableID};
use crate::solver::RecordType;

/* RE-EXPORTS */

Expand All @@ -34,8 +34,8 @@ pub mod lsmt;

/// Indicates whether the database implementation should store the data it is
/// managing to disk, or keep it entirely in memory.
pub enum Persistence<'a> {
On(&'a Path),
pub enum Persistence {
On(PathBuf),
Off,
}

Expand Down Expand Up @@ -79,41 +79,105 @@ pub enum Datatype {
CSTR,
}

/* INTERFACE DEFINITIONS */
/* DATABASE INTERFACES */

/// Represents the behavior of a Key-Value Store. No assumptions are made about
/// the size of the records being used, but keys are taken to be fixed-length.
/// Represents the behavior of a Key-Value Store generic over a [`Record`] type.
pub trait KVStore {
fn put<R: Record>(&mut self, key: State, record: &R);
fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>>;
fn del(&mut self, key: State);
/// Replaces the value associated with `key` with the bits of `record`,
/// creating one if it does not already exist. Fails if under any violation
/// of implementation-specific assumptions of record size or contents.
fn put<R>(&mut self, key: Key, record: &R) -> Result<()>
where
R: Record;

/// Returns the bits associated with the value of `key`, or `None` if there
/// is no such association. Infallible due to all possible values of `key`
/// being considered valid (but not necessarily existent).
fn get(&self, key: Key) -> Option<&RawRecord>;

/// Removes the association of `key` to whatever value it is currently bound
/// to, or does nothing if there is no such value.
fn delete(&mut self, key: Key);
}

/// Allows a database to be evicted to persistent media. Implementing this trait
/// requires custom handling of what happens when the database is closed; if it
/// has data on memory, then it should persist any dirty pages to ensure
/// consistency. In terms of file structure, each implementation decides how to
/// organize its persistent content. The only overarching requisite is that it
/// be provided an existing directory's path.
pub trait Persistent {
fn bind_path(&self, path: &Path) -> Result<()>;
fn materialize(&self) -> Result<()>;
/// has data on memory, then it should persist dirty data to ensure consistency
/// via [`Drop`]. Database file structure is implementation-specific.
pub trait Persistent<'a, T>
where
Self: Tabular<'a, T> + Drop,
T: Table,
{
/// Interprets the contents of a directory at `path` to be the contents of
/// a persistent database. Fails if the contents of `path` are unexpected.
fn from(path: &Path) -> Result<Self>
where
Self: Sized;

/// Binds the contents of the database to a particular `path` for the sake
/// of persistence. It is undefined behavior to forego calling this function
/// before pushing data to the underlying database. Fails if the database is
/// already bound to another path, or if `path` is non-empty, or under any
/// I/O failure.
fn bind(&self, path: &Path) -> Result<()>;

/// Evict the contents of `table` to disk in a batch operation, potentially
/// leaving cache space for other table's usage. Calling this on all tables
/// in a database should be equivalent to dropping the database reference.
fn flush(&self, table: &mut T) -> Result<()>;
}

/// Allows for grouping data into collections of fixed-length records called
/// tables. Because of this application's requirements, this does not mean that
/// a database should be optimized for inter-table operations. In fact, this
/// interface's semantics are such that its implementations optimize performance
/// for cases of sequential operations on a single table.
pub trait Tabular {
fn create_table(&self, id: &str, schema: Schema) -> Result<()>;
fn select_table(&self, id: &str) -> Result<()>;
fn delete_table(&self, id: &str) -> Result<()>;
/// Allows for grouping data into [`Table`] implementations, which contain many
/// fixed-length records that share attributes under a single [`Schema`]. This
/// allows consumers of this implementation to have simultaneous references to
/// different mutable tables.
pub trait Tabular<'a, T>
where
T: Table,
{
/// Creates a new table with `id` and `schema`. Fails if another table with
/// the same `id` already exists, or under any I/O failure.
fn create_table(&self, id: &TableID, schema: Schema) -> Result<&mut T>;

/// Obtains a mutable reference to the [`Table`] with `id`. Fails if no such
/// table exists in the underlying database, or under any I/O failure.
fn select_table(&self, id: &TableID) -> Result<&mut T>;

/// Forgets about the association of `id` to any existing table, doing
/// nothing if there is no such table. Fails under any I/O failure.
fn delete_table(&self, table: &mut T) -> Result<()>;
}

/// Allows a database implementation to read raw data from a record buffer.
/* TABLE INTERFACE */

/// A grouping of fixed-length records which share a table [`Schema`] that can
/// be used as a handle to mutate them via [`KVStore`] semantics, in addition
/// to keeping track of useful metadata.
pub trait Table
where
Self: KVStore,
{
/// Returns a reference to the schema associated with `self`.
fn schema(&self) -> &Schema;

/// Returns the number of records currently contained in `self`.
fn count(&self) -> u64;

/// Returns the total number of bytes being used to store the contents of
/// `self`, excluding metadata (both in memory and persistent media).
fn size(&self) -> u64;

/// Returns the identifier associated with `self`.
fn id(&self) -> &TableID;
}

/* RECORD INTERFACE */

/// Represents an in-memory sequence of bits that can be directly accessed.
pub trait Record {
fn raw(&self) -> &BitSlice<u8, Msb0>;
/// Returns a reference to the sequence of bits in `self`.
fn raw(&self) -> &RawRecord;
}

/* IMPLEMENTATIONS */
Expand Down
85 changes: 53 additions & 32 deletions src/database/vector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,69 +16,90 @@
//! - Max Fierro, 4/14/2023 (maxfierro@berkeley.edu)

use anyhow::Result;
use bitvec::order::Msb0;
use bitvec::slice::BitSlice;

use crate::database::Persistence;
use crate::database::Schema;
use crate::database::{KVStore, Record, Tabular};
use crate::model::State;
use std::path::Path;

/* CONSTANTS */
use crate::{
database::{self, KVStore, Persistent, Record, Schema, Tabular},
model::{Key, RawRecord, TableID},
};

const METADATA_TABLE: &'static str = ".metadata";
/* DEFINITIONS */

/* DATABASE DEFINITION */
pub struct Database {}

pub struct Database<'a> {
buffer: Vec<u8>,
table: Table<'a>,
mode: Persistence<'a>,
}
pub struct Table {}

/* IMPLEMENTATIONS */

impl<'a> Persistent<'a, Table> for Database {
fn from(path: &Path) -> Result<Self>
where
Self: Sized,
{
todo!()
}

struct Table<'a> {
dirty: bool,
width: u32,
name: &'a str,
size: u128,
fn bind(&self, path: &Path) -> Result<()> {
todo!()
}

fn flush(&self, table: &mut Table) -> Result<()> {
todo!()
}
}

pub struct Parameters<'a> {
persistence: Persistence<'a>,
impl Drop for Database {
fn drop(&mut self) {
todo!()
}
}

/* IMPLEMENTATION */
impl<'a> Tabular<'a, Table> for Database {
fn create_table(&self, id: &TableID, schema: Schema) -> Result<&mut Table> {
todo!()
}

fn select_table(&self, id: &TableID) -> Result<&mut Table> {
todo!()
}

impl Database<'_> {
fn initialize(params: Parameters) -> Result<Self> {
fn delete_table(&self, id: &mut Table) -> Result<()> {
todo!()
}
}

impl KVStore for Database<'_> {
fn put<R: Record>(&mut self, key: State, value: &R) {
impl database::Table for Table {
fn schema(&self) -> &Schema {
todo!()
}

fn count(&self) -> u64 {
todo!()
}

fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>> {
fn size(&self) -> u64 {
todo!()
}

fn del(&mut self, key: State) {
fn id(&self) -> &TableID {
todo!()
}
}

impl Tabular for Database<'_> {
fn create_table(&self, id: &str, schema: Schema) -> Result<()> {
impl KVStore for Table {
fn put<R>(&mut self, key: Key, value: &R) -> Result<()>
where
R: Record,
{
todo!()
}

fn select_table(&self, id: &str) -> Result<()> {
fn get(&self, key: Key) -> Option<&RawRecord> {
todo!()
}

fn delete_table(&self, id: &str) -> Result<()> {
fn delete(&mut self, key: Key) {
todo!()
}
}
58 changes: 38 additions & 20 deletions src/database/volatile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,69 @@
//! - Max Fierro, 2/24/2024 (maxfierro@berkeley.edu)

use anyhow::Result;
use bitvec::{order::Msb0, slice::BitSlice, store::BitStore};

use std::collections::HashMap;
use bitvec::{order::Msb0, slice::BitSlice};

use crate::{
database::{KVStore, Record, Schema, Tabular},
model::State,
database::{self, KVStore, Record, Schema, Tabular},
model::{State, TableID},
};

pub struct Database<'a> {
memory: HashMap<State, &'a [u8]>,
}
/* DEFINITIONS */

pub struct Database {}

pub struct Table {}

/* IMPLEMENTATIONS */

impl Database<'_> {
impl Database {
pub fn initialize() -> Self {
Self {
memory: HashMap::new(),
}
Database {}
}
}

impl KVStore for Database<'_> {
fn put<R: Record>(&mut self, key: State, value: &R) {
impl<'a> Tabular<'a, Table> for Database {
fn create_table(&self, id: &TableID, schema: Schema) -> Result<&mut Table> {
todo!()
}

fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>> {
fn select_table(&self, id: &TableID) -> Result<&mut Table> {
todo!()
}

fn delete_table(&self, id: &mut Table) -> Result<()> {
todo!()
}
}

impl database::Table for Table {
fn schema(&self) -> &Schema {
todo!()
}

fn count(&self) -> u64 {
todo!()
}

fn del(&mut self, key: State) {
fn size(&self) -> u64 {
todo!()
}

fn id(&self) -> &TableID {
todo!()
}
}

impl Tabular for Database<'_> {
fn create_table(&self, id: &str, schema: Schema) -> Result<()> {
impl KVStore for Table {
fn put<R: Record>(&mut self, key: State, value: &R) -> Result<()> {
todo!()
}

fn select_table(&self, id: &str) -> Result<()> {
fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>> {
todo!()
}

fn delete_table(&self, id: &str) -> Result<()> {
fn delete(&mut self, key: crate::model::Key) {
todo!()
}
}
Loading

0 comments on commit eb432dc

Please sign in to comment.