Skip to content

Commit

Permalink
Changed records to database directory; added directory record
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfierrog committed Nov 14, 2024
1 parent d9ed850 commit 01d8695
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 93 deletions.
43 changes: 41 additions & 2 deletions src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use anyhow::Result;
use std::path::{Path, PathBuf};

use crate::database::model::{Key, SequenceKey, Value};
use crate::solver::RecordType;
use crate::game::model::PlayerCount;

/* RE-EXPORTS */

Expand All @@ -30,6 +30,13 @@ pub mod volatile;
pub mod vector;
pub mod lsmt;

pub mod record {
pub mod mur;
pub mod sur;
pub mod rem;
pub mod dtr;
}

/* DEFINITIONS */

/// Indicates whether the database implementation should store the data it is
Expand All @@ -43,6 +50,8 @@ pub enum Persistence {
/// where each name is unique and the size is a number of bits. This is used to
/// "interpret" the raw data within records into meaningful features.
pub struct Schema {
attribute_count: usize,
table_name: String,
attributes: Vec<Attribute>,
record: Option<RecordType>,
size: usize,
Expand Down Expand Up @@ -79,6 +88,21 @@ pub enum Datatype {
CSTR,
}

/// A record layout that can be used to encode and decode the attributes stored
/// in serialized records. This is stored in database table schemas so that it
/// can be retrieved later for deserialization.
#[derive(Clone, Copy)]
pub enum RecordType {
/// Multi-Utility Remoteness record for a specific number of players.
MUR(PlayerCount),
/// Simple Utility Remoteness record for a specific number of players.
SUR(PlayerCount),
/// Remoteness record (no utilities).
REM,
/// Directory table record.
DTR,
}

/* DATABASE INTERFACES */

/// Represents the behavior of a Key-Value Store generic over a [`Record`] type.
Expand Down Expand Up @@ -159,10 +183,25 @@ impl Schema {
self.size
}

/// Returns the number of attributes in the schema.
pub fn attribute_count(&self) -> usize {
self.attribute_count
}

/// Returns the name of the table this schema belongs to.
pub fn table_name(&self) -> &str {
&self.table_name
}

/// Returns the record type associated with this schema, if any.
pub fn record(&self) -> Option<RecordType> {
pub fn datatype(&self) -> Option<RecordType> {
self.record
}

/// Returns the attributes contained in this schema.
pub fn attributes(&self) -> &[Attribute] {
&self.attributes
}
}

impl Attribute {
Expand Down
161 changes: 161 additions & 0 deletions src/database/record/dtr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//! # Directory Table Record (DTR) Module
//!
//! TODO

use anyhow::Result;
use bitvec::order::Msb0;
use bitvec::slice::BitSlice;
use bitvec::{bitarr, BitArr};

use crate::database::util::SchemaBuilder;
use crate::database::{Attribute, Datatype, Record, RecordType, Schema};
use crate::util::min_ubits;

/* CONSTANTS */

/// The maximum number of ASCII characters (bytes) that can be used for
/// attribute names. This is needed to determine the minimum bits needed to
/// persist attributes' names.
pub const MAX_ATTRIBUTE_NAME_BYTES: usize = 80;

/// The highest number of record data types that can ever be added to the
/// `DataType` enumeration. This is necessary to recover the programmatic
/// representation of an attribute datatype from a serialized source, keeping
/// in mind an extent of backwards and forwards compatibility.
pub const MAX_SUPPORTED_DATA_TYPES: usize = 1024;

/// The highest number of record type variants that can ever be added to the
/// `RecordType` enumeration. This is necessary to recover the programmatic
/// representation of a table record type from a serialized source, keeping in
/// mind an extent of backwards and forwards compatibility.
pub const MAX_SUPPORTED_RECORD_TYPES: usize = 1024;

/// The maximum number of ASCII characters (bytes) that can be used for a table
/// name (including a null terminator).
pub const MAX_TABLE_NAME_BYTES: usize = 80;

/// The highest number of attributes that can be present in a single table. This
/// needs to be known to fix the directory table record width at a constant.
pub const MAX_SCHEMA_ATTRIBUTES: usize = 128;

/// The maximum bit length of a single attribute. This needs to be known to
/// determine the minimum bits needed to persist attribute sizes.
pub const MAX_ATTRIBUTE_SIZE: usize = 512;

/// The total size of a directory table record in bits. About 10 kB.
pub const BUFFER_SIZE: usize = (MAX_TABLE_NAME_BYTES * 8)
+ min_ubits(MAX_SUPPORTED_RECORD_TYPES as u64)
+ min_ubits(MAX_SCHEMA_ATTRIBUTES as u64)
+ (((MAX_ATTRIBUTE_NAME_BYTES * 8)
+ min_ubits(MAX_ATTRIBUTE_SIZE as u64)
+ min_ubits(MAX_SUPPORTED_DATA_TYPES as u64))
* MAX_SCHEMA_ATTRIBUTES);

/* SCHEMA GENERATOR */

/// Return the database table schema associated with a record instance.
pub fn schema(name: &str) -> Result<Schema> {
let mut schema = SchemaBuilder::new(name)
.of(RecordType::DTR)
.add(Attribute::new(
"table_name",
Datatype::CSTR,
MAX_TABLE_NAME_BYTES * 8,
))?
.add(Attribute::new(
"record_type",
Datatype::ENUM,
min_ubits(MAX_SUPPORTED_RECORD_TYPES as u64),
))?
.add(Attribute::new(
"attr_count",
Datatype::UINT,
min_ubits(MAX_SCHEMA_ATTRIBUTES as u64),
))?;

for i in 0..MAX_SCHEMA_ATTRIBUTES {
let name_prefix = format!("attr{}", i);
schema = schema
.add(Attribute::new(
&format!("{}_name", name_prefix),
Datatype::CSTR,
MAX_ATTRIBUTE_NAME_BYTES * 8,
))?
.add(Attribute::new(
&format!("{}_size", name_prefix),
Datatype::UINT,
min_ubits(MAX_ATTRIBUTE_SIZE as u64),
))?
.add(Attribute::new(
&format!("{}_type", name_prefix),
Datatype::ENUM,
min_ubits(MAX_SUPPORTED_DATA_TYPES as u64),
))?;
}

Ok(schema.build())
}

/* RECORD IMPLEMENTATION */

/// TODO
pub struct RecordBuffer {
buf: BitArr!(for BUFFER_SIZE, in u8, Msb0),
}

impl RecordBuffer {
fn new() -> Self {
Self {
buf: bitarr!(u8, Msb0; 0; BUFFER_SIZE),
}
}
}

impl Record for RecordBuffer {
#[inline(always)]
fn raw(&self) -> &BitSlice<u8, Msb0> {
&self.buf
}
}

impl TryInto<RecordBuffer> for Schema {
type Error = anyhow::Error;

fn try_into(self) -> Result<RecordBuffer> {
let mut buf = RecordBuffer::new();
buf.set_datatype(self.datatype())?;
buf.set_table_name(&self.table_name())?;
buf.set_attribute_count(self.attribute_count())?;

for attr in self.attributes() {
buf.set_attribute(attr)?;
}

Ok(buf)
}
}

impl TryInto<Schema> for RecordBuffer {
type Error = anyhow::Error;
fn try_into(self) -> Result<Schema> {
todo!()
}
}

impl RecordBuffer {
fn set_table_name(&mut self, name: &str) -> Result<()> {
todo!()
}

fn set_datatype(&mut self, variant: Option<RecordType>) -> Result<()> {
todo!()
}

fn set_attribute_count(&mut self, count: usize) -> Result<()> {
todo!()
}

fn set_attribute(&mut self, attribute: &Attribute) -> Result<()> {
todo!()
}
}
6 changes: 3 additions & 3 deletions src/solver/record/mur.rs → src/database/record/mur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use bitvec::order::Msb0;
use bitvec::slice::BitSlice;
use bitvec::{bitarr, BitArr};

use crate::database::RecordType;
use crate::database::{Attribute, Datatype, Record, Schema, SchemaBuilder};
use crate::game::model::{Player, PlayerCount};
use crate::solver::error::SolverError::RecordViolation;
use crate::solver::model::{IUtility, Remoteness};
use crate::solver::RecordType;
use crate::util;

/* CONSTANTS */
Expand All @@ -32,7 +32,7 @@ pub const UTILITY_SIZE: usize = 8;

/// Return the database table schema associated with a record instance with
/// a specific number of `players` under this record implementation.
pub fn schema(players: PlayerCount) -> Result<Schema> {
pub fn schema(players: PlayerCount, name: &str) -> Result<Schema> {
if RecordBuffer::bit_size(players) > BUFFER_SIZE {
bail!(RecordViolation {
name: RecordType::MUR(players).to_string(),
Expand All @@ -44,7 +44,7 @@ pub fn schema(players: PlayerCount) -> Result<Schema> {
),
})
} else {
let mut schema = SchemaBuilder::new().of(RecordType::MUR(players));
let mut schema = SchemaBuilder::new(name).of(RecordType::MUR(players));

for i in 0..players {
let name = &format!("P{i} utility");
Expand Down
6 changes: 3 additions & 3 deletions src/solver/record/rem.rs → src/database/record/rem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use bitvec::order::Msb0;
use bitvec::slice::BitSlice;
use bitvec::{bitarr, BitArr};

use crate::database::RecordType;
use crate::database::{Attribute, Datatype, Record, Schema, SchemaBuilder};
use crate::solver::error::SolverError::RecordViolation;
use crate::solver::model::Remoteness;
use crate::solver::RecordType;
use crate::util;

/* CONSTANTS */
Expand All @@ -25,8 +25,8 @@ pub const BUFFER_SIZE: usize = 16;
/* SCHEMA GENERATOR */

/// Return the database table schema associated with a record instance
pub fn schema() -> Result<Schema> {
let mut schema = SchemaBuilder::new().of(RecordType::REM);
pub fn schema(name: &str) -> Result<Schema> {
let mut schema = SchemaBuilder::new(name).of(RecordType::REM);

let name = "State remoteness";
let data = Datatype::UINT;
Expand Down
7 changes: 3 additions & 4 deletions src/solver/record/sur.rs → src/database/record/sur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use bitvec::order::Msb0;
use bitvec::slice::BitSlice;
use bitvec::{bitarr, BitArr};

use crate::database::RecordType;
use crate::database::{Attribute, Datatype, Record, Schema, SchemaBuilder};
use crate::game::model::{Player, PlayerCount};
use crate::solver::error::SolverError::RecordViolation;
use crate::solver::model::{Remoteness, SUtility};
use crate::solver::RecordType;
use crate::util;

/* CONSTANTS */
Expand All @@ -32,7 +32,7 @@ pub const UTILITY_SIZE: usize = 2;

/// Return the database table schema associated with a record instance with
/// a specific number of `players` under this record implementation.
pub fn schema(players: PlayerCount) -> Result<Schema> {
pub fn schema(players: PlayerCount, name: &str) -> Result<Schema> {
if RecordBuffer::bit_size(players) > BUFFER_SIZE {
bail!(RecordViolation {
name: RecordType::SUR(players).to_string(),
Expand All @@ -44,8 +44,7 @@ pub fn schema(players: PlayerCount) -> Result<Schema> {
),
})
} else {
let mut schema = SchemaBuilder::new().of(RecordType::SUR(players));

let mut schema = SchemaBuilder::new(name).of(RecordType::SUR(players));
for i in 0..players {
let name = &format!("P{i} utility");
let data = Datatype::ENUM;
Expand Down
Loading

0 comments on commit 01d8695

Please sign in to comment.