proxmox-backup/src/backup/datastore.rs

137 lines
3.9 KiB
Rust
Raw Normal View History

2018-12-17 12:00:39 +00:00
use failure::*;
2018-12-18 10:06:03 +00:00
use std::path::{PathBuf, Path};
use std::collections::HashMap;
use lazy_static::lazy_static;
use std::sync::{Mutex, Arc};
2018-12-17 12:00:39 +00:00
use crate::config::datastore;
use super::chunk_store::*;
use super::image_index::*;
pub struct DataStore {
chunk_store: ChunkStore,
gc_mutex: Mutex<bool>,
2018-12-17 12:00:39 +00:00
}
lazy_static!{
static ref datastore_map: Mutex<HashMap<String, Arc<DataStore>>> = Mutex::new(HashMap::new());
}
2018-12-17 12:00:39 +00:00
impl DataStore {
pub fn lookup_datastore(name: &str) -> Result<Arc<DataStore>, Error> {
let config = datastore::config()?;
let (_, store_config) = config.sections.get(name)
.ok_or(format_err!("no such datastore '{}'", name))?;
let path = store_config["path"].as_str().unwrap();
let mut map = datastore_map.lock().unwrap();
if let Some(datastore) = map.get(name) {
// Compare Config - if changed, create new Datastore object!
if (datastore.chunk_store.base == PathBuf::from(path)) {
return Ok(datastore.clone());
}
}
if let Ok(datastore) = DataStore::open(name) {
let datastore = Arc::new(datastore);
map.insert(name.to_string(), datastore.clone());
return Ok(datastore);
}
bail!("store not found");
}
2018-12-17 12:00:39 +00:00
pub fn open(store_name: &str) -> Result<Self, Error> {
let config = datastore::config()?;
let (_, store_config) = config.sections.get(store_name)
.ok_or(format_err!("no such datastore '{}'", store_name))?;
let path = store_config["path"].as_str().unwrap();
2018-12-19 12:40:26 +00:00
let chunk_store = ChunkStore::open(store_name, path)?;
2018-12-17 12:00:39 +00:00
Ok(Self {
chunk_store: chunk_store,
gc_mutex: Mutex::new(false),
2018-12-17 12:00:39 +00:00
})
}
pub fn create_image_writer<P: AsRef<Path>>(&mut self, filename: P, size: usize, chunk_size: usize) -> Result<ImageIndexWriter, Error> {
2018-12-17 12:00:39 +00:00
let index = ImageIndexWriter::create(&mut self.chunk_store, filename.as_ref(), size, chunk_size)?;
2018-12-17 12:00:39 +00:00
Ok(index)
}
2018-12-21 11:15:26 +00:00
pub fn open_image_reader<P: AsRef<Path>>(&self, filename: P) -> Result<ImageIndexReader, Error> {
2018-12-17 12:00:39 +00:00
2018-12-21 11:15:26 +00:00
let index = ImageIndexReader::open(&self.chunk_store, filename.as_ref())?;
2018-12-17 12:00:39 +00:00
Ok(index)
}
2018-12-18 10:06:03 +00:00
pub fn list_images(&self) -> Result<Vec<PathBuf>, Error> {
let base = self.chunk_store.base_path();
let mut list = vec![];
for entry in std::fs::read_dir(base)? {
let entry = entry?;
if entry.file_type()?.is_file() {
let path = entry.path();
if let Some(ext) = path.extension() {
if ext == "iidx" {
2018-12-18 10:06:03 +00:00
list.push(path);
}
}
}
}
Ok(list)
}
fn mark_used_chunks(&self, status: &mut GarbageCollectionStatus) -> Result<(), Error> {
2018-12-18 10:06:03 +00:00
let image_list = self.list_images()?;
for path in image_list {
2018-12-21 11:15:26 +00:00
let index = self.open_image_reader(path)?;
index.mark_used_chunks(status)?;
2018-12-18 10:06:03 +00:00
}
Ok(())
}
2018-12-21 11:15:26 +00:00
pub fn garbage_collection(&self) -> Result<(), Error> {
2018-12-18 10:06:03 +00:00
if let Ok(ref mut mutex) = self.gc_mutex.try_lock() {
let mut gc_status = GarbageCollectionStatus::default();
gc_status.used_bytes = 0;
2018-12-18 10:18:55 +00:00
println!("Start GC phase1 (mark chunks)");
self.mark_used_chunks(&mut gc_status)?;
println!("Start GC phase2 (sweep unused chunks)");
self.chunk_store.sweep_used_chunks(&mut gc_status)?;
println!("Used bytes: {}", gc_status.used_bytes);
println!("Used chunks: {}", gc_status.used_chunks);
println!("Disk bytes: {}", gc_status.disk_bytes);
println!("Disk chunks: {}", gc_status.disk_chunks);
} else {
println!("Start GC failed - (already running/locked)");
}
2018-12-18 10:06:03 +00:00
Ok(())
}
2018-12-17 12:00:39 +00:00
}