]> git.proxmox.com Git - proxmox-backup.git/blame - src/backup/datastore.rs
cleanup nodename()
[proxmox-backup.git] / src / backup / datastore.rs
CommitLineData
529de6c7
DM
1use failure::*;
2
3d5c11e5 3use std::path::{PathBuf, Path};
2c32fdde
DM
4use std::collections::HashMap;
5use lazy_static::lazy_static;
6use std::sync::{Mutex, Arc};
529de6c7
DM
7
8use crate::config::datastore;
9use super::chunk_store::*;
10use super::image_index::*;
0433db19 11use super::archive_index::*;
529de6c7
DM
12
13pub struct DataStore {
1629d2ad 14 chunk_store: Arc<ChunkStore>,
64e53b28 15 gc_mutex: Mutex<bool>,
529de6c7
DM
16}
17
2c32fdde
DM
18lazy_static!{
19 static ref datastore_map: Mutex<HashMap<String, Arc<DataStore>>> = Mutex::new(HashMap::new());
20}
21
529de6c7
DM
22impl 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}