use cache::{
Cache,
CacheRead,
CacheWrite,
CacheWriteFuture,
Storage,
};
use futures::{self,Future};
use std::ffi::OsStr;
use std::fs::{self,File};
use std::io;
use std::path::{Path,PathBuf};
use std::time::Instant;
#[derive(Clone)]
pub struct DiskCache {
root: PathBuf,
}
impl DiskCache {
pub fn new<T: AsRef<OsStr>>(root: &T) -> DiskCache {
DiskCache {
root: PathBuf::from(root),
}
}
}
fn make_key_path(root: &Path, key: &str) -> PathBuf {
root.join(&key[0..1]).join(&key[1..2]).join(key)
}
impl Storage for DiskCache {
fn get(&self, key: &str) -> Cache {
trace!("DiskCache::get({})", key);
match File::open(make_key_path(&self.root, key))
.and_then(CacheRead::from) {
Err(e) => match e.kind() {
io::ErrorKind::NotFound => Cache::Miss,
_ => Cache::Error(e),
},
Ok(cache_read) => Cache::Hit(cache_read),
}
}
fn start_put(&self, key: &str) -> io::Result<CacheWrite> {
trace!("DiskCache::start_put({})", key);
let path = make_key_path(&self.root, key);
try!(path.parent().ok_or(io::Error::new(io::ErrorKind::Other, "No parent directory?")).and_then(fs::create_dir_all));
File::create(&path)
.or_else(|e| {
error!("Failed to create cache entry `{:?}`: {:?}", path, e);
Err(e)
})
.map(CacheWrite::new)
}
fn finish_put(&self, key: &str, entry: CacheWrite) -> CacheWriteFuture {
trace!("DiskCache::finish_put({})", key);
let start = Instant::now();
drop(entry);
futures::finished(Ok(start.elapsed())).boxed()
}
fn get_location(&self) -> String {
format!("Local disk: {:?}", self.root)
}
}