]>
Commit | Line | Data |
---|---|---|
529de6c7 DM |
1 | use failure::*; |
2 | ||
3d5c11e5 | 3 | use std::path::{PathBuf, Path}; |
2c32fdde DM |
4 | use std::collections::HashMap; |
5 | use lazy_static::lazy_static; | |
6 | use std::sync::{Mutex, Arc}; | |
529de6c7 DM |
7 | |
8 | use crate::config::datastore; | |
9 | use super::chunk_store::*; | |
10 | use super::image_index::*; | |
0433db19 | 11 | use super::archive_index::*; |
529de6c7 DM |
12 | |
13 | pub struct DataStore { | |
1629d2ad | 14 | chunk_store: Arc<ChunkStore>, |
64e53b28 | 15 | gc_mutex: Mutex<bool>, |
529de6c7 DM |
16 | } |
17 | ||
2c32fdde DM |
18 | lazy_static!{ |
19 | static ref datastore_map: Mutex<HashMap<String, Arc<DataStore>>> = Mutex::new(HashMap::new()); | |
20 | } | |
21 | ||
529de6c7 DM |
22 | impl DataStore { |
23 | ||
2c32fdde DM |
24 | pub fn lookup_datastore(name: &str) -> Result<Arc<DataStore>, Error> { |
25 | ||
26 | let config = datastore::config()?; | |
27 | let (_, store_config) = config.sections.get(name) | |
28 | .ok_or(format_err!("no such datastore '{}'", name))?; | |
29 | ||
30 | let path = store_config["path"].as_str().unwrap(); | |
31 | ||
32 | let mut map = datastore_map.lock().unwrap(); | |
33 | ||
34 | if let Some(datastore) = map.get(name) { | |
35 | // Compare Config - if changed, create new Datastore object! | |
a198d74f | 36 | if datastore.chunk_store.base == PathBuf::from(path) { |
2c32fdde DM |
37 | return Ok(datastore.clone()); |
38 | } | |
39 | } | |
40 | ||
41 | if let Ok(datastore) = DataStore::open(name) { | |
42 | let datastore = Arc::new(datastore); | |
43 | map.insert(name.to_string(), datastore.clone()); | |
44 | return Ok(datastore); | |
45 | } | |
46 | ||
47 | bail!("store not found"); | |
48 | } | |
49 | ||
529de6c7 DM |
50 | pub fn open(store_name: &str) -> Result<Self, Error> { |
51 | ||
52 | let config = datastore::config()?; | |
53 | let (_, store_config) = config.sections.get(store_name) | |
54 | .ok_or(format_err!("no such datastore '{}'", store_name))?; | |
55 | ||
56 | let path = store_config["path"].as_str().unwrap(); | |
57 | ||
277fc5a3 | 58 | let chunk_store = ChunkStore::open(store_name, path)?; |
529de6c7 DM |
59 | |
60 | Ok(Self { | |
1629d2ad | 61 | chunk_store: Arc::new(chunk_store), |
64e53b28 | 62 | gc_mutex: Mutex::new(false), |
529de6c7 DM |
63 | }) |
64 | } | |
65 | ||
bcd879cf | 66 | pub fn create_image_writer<P: AsRef<Path>>(&self, filename: P, size: usize, chunk_size: usize) -> Result<ImageIndexWriter, Error> { |
529de6c7 | 67 | |
150f1bd8 | 68 | let index = ImageIndexWriter::create(self.chunk_store.clone(), filename.as_ref(), size, chunk_size)?; |
529de6c7 DM |
69 | |
70 | Ok(index) | |
71 | } | |
72 | ||
03e4753d | 73 | pub fn open_image_reader<P: AsRef<Path>>(&self, filename: P) -> Result<ImageIndexReader, Error> { |
529de6c7 | 74 | |
150f1bd8 | 75 | let index = ImageIndexReader::open(self.chunk_store.clone(), filename.as_ref())?; |
529de6c7 DM |
76 | |
77 | Ok(index) | |
78 | } | |
3d5c11e5 | 79 | |
0433db19 DM |
80 | pub fn create_archive_writer<P: AsRef<Path>>( |
81 | &self, filename: P, | |
82 | chunk_size: usize | |
83 | ) -> Result<ArchiveIndexWriter, Error> { | |
84 | ||
1629d2ad DM |
85 | let index = ArchiveIndexWriter::create( |
86 | self.chunk_store.clone(), filename.as_ref(), chunk_size)?; | |
0433db19 DM |
87 | |
88 | Ok(index) | |
89 | } | |
1629d2ad | 90 | |
77703d95 DM |
91 | pub fn open_archive_reader<P: AsRef<Path>>(&self, filename: P) -> Result<ArchiveIndexReader, Error> { |
92 | ||
150f1bd8 | 93 | let index = ArchiveIndexReader::open(self.chunk_store.clone(), filename.as_ref())?; |
77703d95 DM |
94 | |
95 | Ok(index) | |
96 | } | |
97 | ||
3d5c11e5 DM |
98 | pub fn list_images(&self) -> Result<Vec<PathBuf>, Error> { |
99 | let base = self.chunk_store.base_path(); | |
100 | ||
101 | let mut list = vec![]; | |
102 | ||
103 | for entry in std::fs::read_dir(base)? { | |
104 | let entry = entry?; | |
105 | if entry.file_type()?.is_file() { | |
106 | let path = entry.path(); | |
107 | if let Some(ext) = path.extension() { | |
64e53b28 | 108 | if ext == "iidx" { |
3d5c11e5 | 109 | list.push(path); |
77703d95 DM |
110 | } else if ext == "aidx" { |
111 | list.push(path); | |
3d5c11e5 DM |
112 | } |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | Ok(list) | |
118 | } | |
119 | ||
64e53b28 | 120 | fn mark_used_chunks(&self, status: &mut GarbageCollectionStatus) -> Result<(), Error> { |
3d5c11e5 DM |
121 | |
122 | let image_list = self.list_images()?; | |
123 | ||
124 | for path in image_list { | |
77703d95 DM |
125 | if let Some(ext) = path.extension() { |
126 | if ext == "iidx" { | |
bc616633 | 127 | let index = self.open_image_reader(&path)?; |
77703d95 DM |
128 | index.mark_used_chunks(status)?; |
129 | } else if ext == "aidx" { | |
bc616633 | 130 | let index = self.open_archive_reader(&path)?; |
77703d95 DM |
131 | index.mark_used_chunks(status)?; |
132 | } | |
133 | } | |
3d5c11e5 DM |
134 | } |
135 | ||
136 | Ok(()) | |
137 | } | |
138 | ||
03e4753d | 139 | pub fn garbage_collection(&self) -> Result<(), Error> { |
3d5c11e5 | 140 | |
a198d74f | 141 | if let Ok(ref mut _mutex) = self.gc_mutex.try_lock() { |
e95950e4 | 142 | |
64e53b28 DM |
143 | let mut gc_status = GarbageCollectionStatus::default(); |
144 | gc_status.used_bytes = 0; | |
6ea3a0b7 | 145 | |
64e53b28 DM |
146 | println!("Start GC phase1 (mark chunks)"); |
147 | ||
148 | self.mark_used_chunks(&mut gc_status)?; | |
149 | ||
150 | println!("Start GC phase2 (sweep unused chunks)"); | |
77703d95 | 151 | self.chunk_store.sweep_unused_chunks(&mut gc_status)?; |
64e53b28 DM |
152 | |
153 | println!("Used bytes: {}", gc_status.used_bytes); | |
154 | println!("Used chunks: {}", gc_status.used_chunks); | |
155 | println!("Disk bytes: {}", gc_status.disk_bytes); | |
156 | println!("Disk chunks: {}", gc_status.disk_chunks); | |
157 | ||
158 | } else { | |
159 | println!("Start GC failed - (already running/locked)"); | |
160 | } | |
3d5c11e5 DM |
161 | |
162 | Ok(()) | |
163 | } | |
529de6c7 | 164 | } |