You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.5 KiB

use super::*;
use generational_arena::{
Arena, Index as ArenaIndex,
};
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::ffi::OsString;
use memmap::Mmap;
use bytes::Bytes;
use cryptohelpers::{aes, sha256};
mod entry;
pub use entry::Entry;
mod cache;
pub use cache::DataCacheState;
mod metadata;
pub use metadata::StoreMetadata;
mod freeze;
pub use freeze::Freeze;
#[derive(Debug)]
pub struct Store
{
metadata: StoreMetadata,
data: HashSet<Entry>, // The entry sha256 hash is used as the `key` here, as `Entry` both hasshes to, and `Borrow`s to `Sha256Hash`.
data_hashes: Arena<sha256::Sha256Hash>, // used to lookup in `data`.
tag_mappings: Arena<Vec<ArenaIndex>>,
tags: BTreeMap<String, ArenaIndex>, // string (tags) -> index (tag_mappings) -> index (data_hashes) -> hash used for lookup (data)
}
// Comptime asserts (TODO: Unneeded. Remove.)
impl Store
{
fn _assert_tag_lookup_works(&self, tag: &str) -> &Entry
{
self.data.get(self.data_hashes.get(*self.tag_mappings.get(*self.tags.get(tag).unwrap()).unwrap().first().unwrap()).unwrap()).unwrap() // y-yes this also works...
}
fn _assert_lookup_internal_works(&self, data_idx: ArenaIndex) -> &Entry
{
self.data.get(self.data_hashes.get(data_idx).unwrap()).unwrap() // yes this works..
}
}
// Creating
impl Store
{
/// Create a new empty store with this metadata.
///
/// # Panics
/// If the root directory specified in `metadata` does not exist or is not a directory.
pub fn new(metadata: StoreMetadata) -> Self
{
assert!(metadata.root.exists() && metadata.root.is_dir(), "Metadata root {:?} passed to `new` not existant or not a directory", metadata.root);
Self {
metadata,
data: HashSet::new(),
data_hashes: Arena::new(),
tag_mappings: Arena::new(),
tags: BTreeMap::new(),
}
}
/// Create a new empty store with this metadata and initial storage capacity
///
/// # Panics
/// If the root directory specified in `metadata` does not exist or is not a directory.
pub fn with_capacity(metadata: StoreMetadata, cap: usize) -> Self
{
assert!(metadata.root.exists() && metadata.root.is_dir(), "Metadata root {:?} passed to `with_capacity` not existant or not a directory", metadata.root);
Self {
metadata,
data: HashSet::with_capacity(cap),
data_hashes: Arena::with_capacity(cap),
tag_mappings: Arena::with_capacity(cap),
tags: BTreeMap::new(),
}
}
}
// Freezing
impl Store
{
/// Create a snapshot of this store, cloning all data into a frozen and serialisable version of it.
/// # Notes
/// This method clones the entire store into the new `Freeze`. To avoid this, use `into_freeze` if the store is no longer used after the freeze.
#[inline] pub fn freeze(&self) -> Freeze
{
Freeze::new_ref(self)
}
/// Consume into a snapshot of this store, moving all data into a frozen and serializable version of it.
#[inline] pub fn into_freeze(self) -> Freeze
{
Freeze::new_moved(self)
}
/// Create a new store instance by cloning from a frozen snapshot of it.
/// # Notes
/// This method clones the entire `Freeze` into the new store. To avoid this, use `from_freeze` if the snapshot is no longer used after the unfreeze.
#[inline] pub fn unfreeze(freeze: &Freeze) -> Self
{
freeze.create_new()
}
/// Consume a store snapshot and move its entries into a new store.
#[inline] pub fn from_freeze(freeze: Freeze) -> Self
{
freeze.into_new()
}
}