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
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()
|
|
}
|
|
}
|