1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use std::fs::{create_dir, File, OpenOptions};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::PathBuf;
use appendix::Index;
use bytehash::ByteHash;
use crate::backend::{Backend, PutResult};
pub struct DiskBackend<H: ByteHash> {
index: Index<H::Digest, u64>,
data: File,
data_path: PathBuf,
data_offset: u64,
}
impl<H: ByteHash> DiskBackend<H> {
pub fn new<P: Into<PathBuf>>(path: P) -> io::Result<Self> {
let dir = path.into();
if !dir.exists() {
create_dir(&dir)?;
}
let index_dir = dir.join("index");
if !index_dir.exists() {
create_dir(&index_dir)?;
}
let index = Index::new(&index_dir)?;
let data_path = dir.join("data");
let mut data = OpenOptions::new()
.create(true)
.write(true)
.open(&data_path)?;
let data_offset = data.metadata()?.len();
data.seek(SeekFrom::End(0))?;
Ok(DiskBackend {
index,
data_path,
data,
data_offset,
})
}
}
impl<H: ByteHash> Backend<H> for DiskBackend<H> {
fn get<'a>(&'a self, hash: &H::Digest) -> io::Result<Box<dyn Read + 'a>> {
match self.index.get(hash)? {
Some(offset) => {
let mut file = File::open(&self.data_path)?;
file.seek(SeekFrom::Start(*offset))?;
Ok(Box::new(file))
}
None => {
Err(io::Error::new(io::ErrorKind::NotFound, "Data not found"))
}
}
}
fn put(
&mut self,
hash: H::Digest,
bytes: Vec<u8>,
) -> io::Result<PutResult> {
if self.index.insert(hash, self.data_offset)? {
Ok(PutResult::AlreadyThere)
} else {
self.data.write_all(&bytes)?;
self.data_offset += bytes.len() as u64;
Ok(PutResult::Ok)
}
}
fn flush(&mut self) -> io::Result<()> {
self.data.flush()?;
self.index.flush()
}
fn size(&self) -> usize {
self.index.on_disk_size() + self.data_offset as usize
}
}