parent
d0d7d0aca5
commit
1b0cdae404
27 changed files with 536 additions and 336 deletions
@ -0,0 +1,101 @@ |
|||||||
|
use super::{Error, FileMeta}; |
||||||
|
use once_cell::sync::Lazy; |
||||||
|
use parking_lot::Mutex; |
||||||
|
use std::collections::HashMap; |
||||||
|
use std::env::temp_dir; |
||||||
|
use std::fs; |
||||||
|
use std::path::PathBuf; |
||||||
|
|
||||||
|
// index format: given_name -> payload_meta
|
||||||
|
type Index = HashMap<String, FileMeta>; |
||||||
|
|
||||||
|
static IDX_FILE_NAME: Lazy<PathBuf> = Lazy::new(|| temp_dir().join(".i")); |
||||||
|
static INDEX: Lazy<Mutex<Index>> = Lazy::new(|| { |
||||||
|
let idx_name = &*IDX_FILE_NAME; |
||||||
|
let deserialized_idx = fs::read(idx_name) |
||||||
|
.map_err(|e| Error::new(e, idx_name)) |
||||||
|
.and_then(|raw_idx| { |
||||||
|
bincode::deserialize::<Index>(&raw_idx).map_err(|e| Error::new(e, idx_name)) |
||||||
|
}); |
||||||
|
|
||||||
|
let idx = match deserialized_idx { |
||||||
|
Ok(idx) => idx, |
||||||
|
Err(e) => { |
||||||
|
error!("index loading failed: {e}"); |
||||||
|
HashMap::new() |
||||||
|
} |
||||||
|
}; |
||||||
|
Mutex::new(idx) |
||||||
|
}); |
||||||
|
|
||||||
|
mod sync { |
||||||
|
use super::{Index, IDX_FILE_NAME}; |
||||||
|
use std::fs; |
||||||
|
|
||||||
|
pub(super) fn deleted(index: &mut Index) { |
||||||
|
let files_to_delete: Vec<String> = index |
||||||
|
.iter() |
||||||
|
.filter_map(|(name, meta)| { |
||||||
|
if meta.path.exists() { |
||||||
|
None |
||||||
|
} else { |
||||||
|
Some(name.to_string()) |
||||||
|
} |
||||||
|
}) |
||||||
|
.collect(); |
||||||
|
|
||||||
|
files_to_delete.into_iter().for_each(|f| { |
||||||
|
index.remove(&f); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
pub(super) fn index2fs(index: &Index) { |
||||||
|
let serialized_idx = bincode::serialize(index).expect("broken index"); |
||||||
|
if let Err(e) = fs::write(&*IDX_FILE_NAME, serialized_idx) { |
||||||
|
error!("index dumping failed: {e}"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(name: impl AsRef<str>) -> Option<FileMeta> { |
||||||
|
let mut index = INDEX.lock(); |
||||||
|
|
||||||
|
sync::deleted(&mut index); |
||||||
|
|
||||||
|
index.get(name.as_ref()).cloned() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_by_hash(hash: impl AsRef<[u8]>) -> Option<(String, FileMeta)> { |
||||||
|
let mut index = INDEX.lock(); |
||||||
|
|
||||||
|
sync::deleted(&mut index); |
||||||
|
|
||||||
|
index |
||||||
|
.iter() |
||||||
|
.find(|(_name, meta)| meta.hash == hash.as_ref()) |
||||||
|
.map(|(n, m)| (n.to_owned(), m.clone())) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn insert(name: impl Into<String>, meta: FileMeta) { |
||||||
|
let mut index = INDEX.lock(); |
||||||
|
|
||||||
|
sync::deleted(&mut index); |
||||||
|
|
||||||
|
index.insert(name.into(), meta); |
||||||
|
|
||||||
|
#[cfg(any(feature = "panel", feature = "server"))] |
||||||
|
sync::index2fs(&mut index); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn remove(name: impl AsRef<str>) -> Option<FileMeta> { |
||||||
|
let mut index = INDEX.lock(); |
||||||
|
|
||||||
|
sync::deleted(&mut index); |
||||||
|
|
||||||
|
let result = index.remove(name.as_ref()); |
||||||
|
|
||||||
|
#[cfg(any(feature = "panel", feature = "server"))] |
||||||
|
sync::index2fs(&mut index); |
||||||
|
|
||||||
|
result |
||||||
|
} |
Loading…
Reference in new issue