66daa255a9
These methods were intended for managing cached entries. Sice it was decided not to serve caching in the store, these methods are no longer needed.
212 lines
4.8 KiB
Rust
212 lines
4.8 KiB
Rust
use std::collections::HashMap;
|
|
use std::fs::File;
|
|
use std::ops::Drop;
|
|
use std::path::PathBuf;
|
|
use std::result::Result as RResult;
|
|
use std::sync::Arc;
|
|
use std::sync::{RwLock, Mutex};
|
|
|
|
use fs2::FileExt;
|
|
|
|
use entry::Entry;
|
|
use error::StoreError;
|
|
|
|
/// The Result Type returned by any interaction with the store that could fail
|
|
pub type Result<T> = RResult<T, StoreError>;
|
|
|
|
/// The Index into the Store
|
|
pub type StoreId = PathBuf;
|
|
|
|
/// This Trait allows you to convert various representations to a single one
|
|
/// suitable for usage in the Store
|
|
trait IntoStoreId {
|
|
fn into_storeid(self) -> StoreId;
|
|
}
|
|
|
|
impl<'a> IntoStoreId for &'a str {
|
|
fn into_storeid(self) -> StoreId {
|
|
PathBuf::from(self)
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoStoreId for &'a String{
|
|
fn into_storeid(self) -> StoreId {
|
|
PathBuf::from(self)
|
|
}
|
|
}
|
|
|
|
impl IntoStoreId for String{
|
|
fn into_storeid(self) -> StoreId {
|
|
PathBuf::from(self)
|
|
}
|
|
}
|
|
|
|
impl IntoStoreId for PathBuf {
|
|
fn into_storeid(self) -> StoreId {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoStoreId for &'a PathBuf {
|
|
fn into_storeid(self) -> StoreId {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
|
|
fn into_storeid(self) -> StoreId {
|
|
let (first, second) = self;
|
|
let mut res : StoreId = first.into_storeid();
|
|
res.push(second.into_storeid());
|
|
res
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq)]
|
|
enum StoreEntryPresence {
|
|
Present,
|
|
Borrowed
|
|
}
|
|
|
|
/// A store entry, depending on the option type it is either borrowed currently
|
|
/// or not.
|
|
struct StoreEntry {
|
|
file: File,
|
|
entry: StoreEntryPresence
|
|
}
|
|
|
|
|
|
impl StoreEntry {
|
|
/// The entry is currently borrowed, meaning that some thread is currently
|
|
/// mutating it
|
|
fn is_borrowed(&self) -> bool {
|
|
self.entry == StoreEntryPresence::Borrowed
|
|
}
|
|
}
|
|
|
|
/// The Store itself, through this object one can interact with IMAG's entries
|
|
pub struct Store {
|
|
location: PathBuf,
|
|
|
|
/**
|
|
* Internal Path->File cache map
|
|
*
|
|
* Caches the files, so they remain flock()ed
|
|
*
|
|
* Could be optimized for a threadsafe HashMap
|
|
*/
|
|
entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
|
|
}
|
|
|
|
impl Store {
|
|
/// Creates the Entry at the given location (inside the entry)
|
|
pub fn create(&self, entry: Entry) -> Result<()> {
|
|
unimplemented!();
|
|
}
|
|
|
|
/// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
|
|
/// dropped, the new Entry is written to disk
|
|
pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
|
|
unimplemented!();
|
|
}
|
|
|
|
/// Return the `FileLockEntry` and write to disk
|
|
pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
|
|
self._update(&entry)
|
|
}
|
|
|
|
/// Internal method to write to the filesystem store.
|
|
///
|
|
/// # Assumptions
|
|
/// This method assumes that entry is dropped _right after_ the call, hence
|
|
/// it is not public.
|
|
fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
|
|
unimplemented!();
|
|
}
|
|
|
|
/// Retrieve a copy of a given entry, this cannot be used to mutate
|
|
/// the one on disk
|
|
pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
|
|
unimplemented!();
|
|
}
|
|
|
|
/// Delete an entry
|
|
pub fn delete(&self, id: StoreId) -> Result<()> {
|
|
unimplemented!();
|
|
}
|
|
}
|
|
|
|
impl Drop for Store {
|
|
|
|
/**
|
|
* Unlock all files on drop
|
|
*
|
|
* TODO: Error message when file cannot be unlocked?
|
|
*/
|
|
fn drop(&mut self) {
|
|
self.entries.write().unwrap()
|
|
.iter().map(|f| f.1.file.unlock());
|
|
}
|
|
|
|
}
|
|
|
|
/// A struct that allows you to borrow an Entry
|
|
pub struct FileLockEntry<'a> {
|
|
store: &'a Store,
|
|
entry: Entry,
|
|
key: StoreId,
|
|
}
|
|
|
|
impl<'a> FileLockEntry<'a, > {
|
|
fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
|
|
FileLockEntry {
|
|
store: store,
|
|
entry: entry,
|
|
key: key,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
|
|
type Target = Entry;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.entry
|
|
}
|
|
}
|
|
|
|
impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.entry
|
|
}
|
|
}
|
|
|
|
impl<'a> Drop for FileLockEntry<'a> {
|
|
fn drop(&mut self) {
|
|
self.store._update(self).unwrap()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use std::path::PathBuf;
|
|
use store::{StoreId, IntoStoreId};
|
|
|
|
#[test]
|
|
fn into_storeid_trait() {
|
|
let buf = PathBuf::from("abc/def");
|
|
|
|
let test = ("abc", "def");
|
|
assert_eq!(buf, test.into_storeid());
|
|
|
|
let test = "abc/def";
|
|
assert_eq!(buf, test.into_storeid());
|
|
|
|
let test = String::from("abc/def");
|
|
assert_eq!(buf, test.into_storeid());
|
|
|
|
let test = PathBuf::from("abc/def");
|
|
assert_eq!(buf, test.into_storeid());
|
|
}
|
|
}
|
|
|