]> git.proxmox.com Git - proxmox-backup.git/blame - src/backup/datastore.rs
api/router.rs: allow different types of api methods
[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 {
14 chunk_store: 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 {
61 chunk_store: 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
bcd879cf 68 let index = ImageIndexWriter::create(&self.chunk_store, 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
03e4753d 75 let index = ImageIndexReader::open(&self.chunk_store, 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
85 let index = ArchiveIndexWriter::create(&self.chunk_store, filename.as_ref(), chunk_size)?;
86
87 Ok(index)
88 }
89
77703d95
DM
90 pub fn open_archive_reader<P: AsRef<Path>>(&self, filename: P) -> Result<ArchiveIndexReader, Error> {
91
92 let index = ArchiveIndexReader::open(&self.chunk_store, filename.as_ref())?;
93
94 Ok(index)
95 }
96
3d5c11e5
DM
97 pub fn list_images(&self) -> Result<Vec<PathBuf>, Error> {
98 let base = self.chunk_store.base_path();
99
100 let mut list = vec![];
101
102 for entry in std::fs::read_dir(base)? {
103 let entry = entry?;
104 if entry.file_type()?.is_file() {
105 let path = entry.path();
106 if let Some(ext) = path.extension() {
64e53b28 107 if ext == "iidx" {
3d5c11e5 108 list.push(path);
77703d95
DM
109 } else if ext == "aidx" {
110 list.push(path);
3d5c11e5
DM
111 }
112 }
113 }
114 }
115
116 Ok(list)
117 }
118
64e53b28 119 fn mark_used_chunks(&self, status: &mut GarbageCollectionStatus) -> Result<(), Error> {
3d5c11e5
DM
120
121 let image_list = self.list_images()?;
122
123 for path in image_list {
77703d95
DM
124 if let Some(ext) = path.extension() {
125 if ext == "iidx" {
bc616633 126 let index = self.open_image_reader(&path)?;
77703d95
DM
127 index.mark_used_chunks(status)?;
128 } else if ext == "aidx" {
bc616633 129 let index = self.open_archive_reader(&path)?;
77703d95
DM
130 index.mark_used_chunks(status)?;
131 }
132 }
3d5c11e5
DM
133 }
134
135 Ok(())
136 }
137
03e4753d 138 pub fn garbage_collection(&self) -> Result<(), Error> {
3d5c11e5 139
a198d74f 140 if let Ok(ref mut _mutex) = self.gc_mutex.try_lock() {
e95950e4 141
64e53b28
DM
142 let mut gc_status = GarbageCollectionStatus::default();
143 gc_status.used_bytes = 0;
6ea3a0b7 144
64e53b28
DM
145 println!("Start GC phase1 (mark chunks)");
146
147 self.mark_used_chunks(&mut gc_status)?;
148
149 println!("Start GC phase2 (sweep unused chunks)");
77703d95 150 self.chunk_store.sweep_unused_chunks(&mut gc_status)?;
64e53b28
DM
151
152 println!("Used bytes: {}", gc_status.used_bytes);
153 println!("Used chunks: {}", gc_status.used_chunks);
154 println!("Disk bytes: {}", gc_status.disk_bytes);
155 println!("Disk chunks: {}", gc_status.disk_chunks);
156
157 } else {
158 println!("Start GC failed - (already running/locked)");
159 }
3d5c11e5
DM
160
161 Ok(())
162 }
529de6c7 163}