-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6c203d5
commit 77365ad
Showing
9 changed files
with
613 additions
and
95 deletions.
There are no files selected for viewing
Submodule doc
updated
from 2f08ba to 0843ed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,11 @@ | |
//! #### Authorship | ||
//! - Max Fierro, 2/24/2024 ([email protected]) | ||
use anyhow::anyhow; | ||
use anyhow::Result; | ||
|
||
use std::sync::Mutex; | ||
|
||
use crate::database::error::DatabaseError; | ||
use crate::database::Attribute; | ||
use crate::database::Datatype; | ||
|
@@ -33,7 +36,13 @@ pub struct SchemaIterator<'a> { | |
index: usize, | ||
} | ||
|
||
/* BUILDER IMPLEMENTATION */ | ||
/// Thread-safe generator for sequential database keys. | ||
#[derive(Default)] | ||
pub struct KeySequencer { | ||
sequence_key: Mutex<u64>, | ||
} | ||
|
||
/* SCHEMA BUILDER IMPLEMENTATION */ | ||
|
||
impl SchemaBuilder { | ||
/// Returns a new instance of a `SchemaBuilder`, which can be used to | ||
|
@@ -123,6 +132,33 @@ impl SchemaBuilder { | |
} | ||
} | ||
|
||
/* KEY SEQUENCER IMPLEMENTATION */ | ||
|
||
impl KeySequencer { | ||
/// Returns a new instance of `KeySequencer`, which can be used to generate | ||
/// sequential database keys in a thread-safe manner. The first generated | ||
/// key will be `initial`. | ||
pub fn new(initial: u64) -> Self { | ||
Self { | ||
sequence_key: Mutex::new(initial), | ||
} | ||
} | ||
|
||
/// Returns the next sequential database key in a thread-safe manner. | ||
pub fn next(&self) -> Result<u64> { | ||
let mut key = self | ||
.sequence_key | ||
.lock() | ||
.map_err(|_| anyhow!("Key sequencer lock poisoned."))?; | ||
|
||
{ | ||
let cur = *key; | ||
*key += 1; | ||
Ok(cur) | ||
} | ||
} | ||
} | ||
|
||
/* UTILITY IMPLEMENTATIONS */ | ||
|
||
impl ToString for Datatype { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
//! # Volatile Database Error | ||
//! | ||
//! TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,115 +1,85 @@ | ||
//! # Volatile Database | ||
//! | ||
//! This module provides a trivial database implementation backed by a volatile | ||
//! in-memory hashmap. | ||
//! | ||
//! #### Authorship | ||
//! - Max Fierro, 2/24/2024 ([email protected]) | ||
//! - Casey Stanford, 4/10/2024 ([email protected]) | ||
//! in-memory data structure arrangement. | ||
use anyhow::Result; | ||
use bitvec::{order::Msb0, prelude::*, slice::BitSlice, store::BitStore}; | ||
|
||
use std::collections::HashMap; | ||
use std::sync::Arc; | ||
|
||
use crate::{ | ||
database::{KVStore, Record, Schema, Tabular}, | ||
model::State, | ||
solver::record::rem, | ||
}; | ||
use crate::database::util::KeySequencer; | ||
use resource::ResourceManager; | ||
use transaction::TransactionManager; | ||
|
||
/// [`KVStore`] implementation backed by an in-memory [`HashMap`]. | ||
/// Constrained by the space available in memory, growing at O(n) with the number of entries. | ||
pub struct Database { | ||
memory: HashMap<State, BitVec<u8, Msb0>>, | ||
} | ||
/* RE-EXPORTS */ | ||
|
||
impl Database { | ||
pub fn initialize() -> Self { | ||
Self { | ||
memory: HashMap::new(), | ||
} | ||
} | ||
} | ||
pub use resource::Request; | ||
pub use resource::Resource; | ||
pub use transaction::Transaction; | ||
|
||
impl KVStore for Database { | ||
fn put<R: Record>(&mut self, key: State, value: &R) { | ||
let new = BitVec::from(value.raw()).clone(); | ||
self.memory.insert(key, new); | ||
} | ||
/* MODULES */ | ||
|
||
fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>> { | ||
if let Some(vect) = self.memory.get(&key) { | ||
return Some(&vect[..]); | ||
} else { | ||
return None; | ||
} | ||
} | ||
mod transaction; | ||
mod resource; | ||
|
||
fn del(&mut self, key: State) { | ||
self.memory.remove(&key); | ||
} | ||
/* DEFINITIONS */ | ||
|
||
type SequenceKey = u64; | ||
type TransactionID = SequenceKey; | ||
type ResourceID = SequenceKey; | ||
|
||
pub struct Database { | ||
transaction_manager: Arc<TransactionManager>, | ||
resource_manager: Arc<ResourceManager>, | ||
sequencer: Arc<Sequencer>, | ||
} | ||
|
||
impl Tabular for Database { | ||
fn create_table(&self, id: &str, schema: Schema) -> Result<()> { | ||
todo!() | ||
} | ||
#[derive(Default)] | ||
struct Sequencer { | ||
transaction: KeySequencer, | ||
resource: KeySequencer, | ||
} | ||
|
||
/* IMPLEMENTATION */ | ||
|
||
fn select_table(&self, id: &str) -> Result<()> { | ||
todo!() | ||
impl Sequencer { | ||
pub fn next_transaction(&self) -> Result<TransactionID> { | ||
self.transaction.next() | ||
} | ||
|
||
fn delete_table(&self, id: &str) -> Result<()> { | ||
todo!() | ||
pub fn next_resource(&self) -> Result<TransactionID> { | ||
self.transaction.next() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
use crate::database::volatile::tests::rem::RecordBuffer; | ||
|
||
use super::*; | ||
|
||
/// This test: | ||
/// - Creates an example state test_state and Record test_rec. | ||
/// - Checks that that test_state is initially not mapped in the database. | ||
/// - Puts test_rec in the database, with test_state as its key. | ||
/// - Checks that test_state now maps to test_rec. | ||
#[test] | ||
fn put_data_and_get_it() { | ||
let mut db: Database = Database::initialize(); | ||
let test_state: State = 7; | ||
assert!(db.get(test_state).is_none()); | ||
let test_rec: RecordBuffer = RecordBuffer::new().unwrap(); | ||
db.put(test_state, &test_rec); | ||
if let Some(result_rec) = db.get(test_state) { | ||
assert_eq!(result_rec, test_rec.raw()); | ||
} else { | ||
assert_eq!(1, 0); | ||
impl Database { | ||
fn new() -> Self { | ||
let sequencer = Arc::new(Sequencer::default()); | ||
let resource_manager = ResourceManager::new(sequencer.clone()); | ||
let transaction_manager = TransactionManager::new( | ||
resource_manager.clone(), | ||
sequencer.clone(), | ||
); | ||
|
||
Self { | ||
transaction_manager, | ||
resource_manager, | ||
sequencer, | ||
} | ||
} | ||
|
||
/// This test | ||
/// - Creates an example state test_state and Record test_rec. | ||
/// - Puts test_rec in the database, with test_state as its key. | ||
/// - Deletes test_state and any associated Record. | ||
/// - Checks that test_state now, again, maps to nothing. | ||
/// - Puts test_rec BACK in the database, and confirms that test_state now maps to it once again. | ||
#[test] | ||
fn put_remove_and_put() { | ||
let mut db: Database = Database::initialize(); | ||
let test_state: State = 7; | ||
let test_rec: RecordBuffer = RecordBuffer::new().unwrap(); | ||
db.put(test_state, &test_rec); | ||
db.del(test_state); | ||
assert!(db.get(test_state).is_none()); | ||
db.put(test_state, &test_rec); | ||
if let Some(result_rec) = db.get(test_state) { | ||
assert_eq!(result_rec, test_rec.raw()); | ||
} else { | ||
assert_eq!(1, 0); | ||
fn create_transaction(&self, request: Request) -> Result<Arc<Transaction>> { | ||
let transaction = self | ||
.resource_manager | ||
.initialize_transaction( | ||
request, | ||
self.transaction_manager.clone(), | ||
)?; | ||
|
||
{ | ||
self.transaction_manager | ||
.add_transaction(transaction.clone()); | ||
Ok(transaction) | ||
} | ||
} | ||
} |
Oops, something went wrong.