pbs-datastore: use ConfigVersionCache for datastore
instead of relying on the content of some configs previously, we always read and parsed the config file, and only generated a new config object when the path or the 'verify-new' option changed. now, we increase the datastore generation on config save, and if that changed (or the last load is 1 minute in the past), we always generate a new object Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
9c96e5368a
commit
118deb4db8
|
@ -24,10 +24,12 @@ struct ConfigVersionCacheData {
|
||||||
user_cache_generation: AtomicUsize,
|
user_cache_generation: AtomicUsize,
|
||||||
// Traffic control (traffic-control.cfg) generation/version.
|
// Traffic control (traffic-control.cfg) generation/version.
|
||||||
traffic_control_generation: AtomicUsize,
|
traffic_control_generation: AtomicUsize,
|
||||||
|
// datastore (datastore.cfg) generation/version
|
||||||
|
datastore_generation: AtomicUsize,
|
||||||
|
|
||||||
// Add further atomics here (and reduce padding size)
|
// Add further atomics here (and reduce padding size)
|
||||||
|
|
||||||
padding: [u8; 4096 - 3*8],
|
padding: [u8; 4096 - 4*8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,4 +120,18 @@ impl ConfigVersionCache {
|
||||||
.fetch_add(1, Ordering::AcqRel);
|
.fetch_add(1, Ordering::AcqRel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the datastore generation number.
|
||||||
|
pub fn datastore_generation(&self) -> usize {
|
||||||
|
self.shmem
|
||||||
|
.data()
|
||||||
|
.datastore_generation
|
||||||
|
.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the datastore generation number.
|
||||||
|
pub fn increase_datastore_generation(&self) -> usize {
|
||||||
|
self.shmem
|
||||||
|
.data()
|
||||||
|
.datastore_generation.fetch_add(1, Ordering::Acquire)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use proxmox_section_config::{SectionConfig, SectionConfigData, SectionConfigPlug
|
||||||
|
|
||||||
use pbs_api_types::{DataStoreConfig, DATASTORE_SCHEMA};
|
use pbs_api_types::{DataStoreConfig, DATASTORE_SCHEMA};
|
||||||
|
|
||||||
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard};
|
use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard, ConfigVersionCache};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CONFIG: SectionConfig = init();
|
pub static ref CONFIG: SectionConfig = init();
|
||||||
|
@ -46,7 +46,14 @@ pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
|
pub fn save_config(config: &SectionConfigData) -> Result<(), Error> {
|
||||||
let raw = CONFIG.write(DATASTORE_CFG_FILENAME, config)?;
|
let raw = CONFIG.write(DATASTORE_CFG_FILENAME, config)?;
|
||||||
replace_backup_config(DATASTORE_CFG_FILENAME, raw.as_bytes())
|
replace_backup_config(DATASTORE_CFG_FILENAME, raw.as_bytes())?;
|
||||||
|
|
||||||
|
// increase datastore version
|
||||||
|
// We use this in pbs-datastore
|
||||||
|
let version_cache = ConfigVersionCache::new()?;
|
||||||
|
version_cache.increase_datastore_generation();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// shell completion helper
|
// shell completion helper
|
||||||
|
|
|
@ -21,7 +21,7 @@ use pbs_api_types::{
|
||||||
UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte,
|
UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte,
|
||||||
ChunkOrder, DatastoreTuning,
|
ChunkOrder, DatastoreTuning,
|
||||||
};
|
};
|
||||||
use pbs_config::{open_backup_lockfile, BackupLockGuard};
|
use pbs_config::{open_backup_lockfile, BackupLockGuard, ConfigVersionCache};
|
||||||
|
|
||||||
use crate::DataBlob;
|
use crate::DataBlob;
|
||||||
use crate::backup_info::{BackupGroup, BackupDir};
|
use crate::backup_info::{BackupGroup, BackupDir};
|
||||||
|
@ -63,26 +63,30 @@ pub struct DataStore {
|
||||||
last_gc_status: Mutex<GarbageCollectionStatus>,
|
last_gc_status: Mutex<GarbageCollectionStatus>,
|
||||||
verify_new: bool,
|
verify_new: bool,
|
||||||
chunk_order: ChunkOrder,
|
chunk_order: ChunkOrder,
|
||||||
|
last_generation: usize,
|
||||||
|
last_update: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataStore {
|
impl DataStore {
|
||||||
pub fn lookup_datastore(name: &str) -> Result<Arc<DataStore>, Error> {
|
pub fn lookup_datastore(name: &str) -> Result<Arc<DataStore>, Error> {
|
||||||
|
let version_cache = ConfigVersionCache::new()?;
|
||||||
|
let generation = version_cache.datastore_generation();
|
||||||
|
let now = proxmox_time::epoch_i64();
|
||||||
|
|
||||||
|
let mut map = DATASTORE_MAP.lock().unwrap();
|
||||||
|
let entry = map.get(name);
|
||||||
|
|
||||||
|
if let Some(datastore) = &entry {
|
||||||
|
if datastore.last_generation == generation && now < (datastore.last_update + 60) {
|
||||||
|
return Ok(Arc::clone(datastore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (config, _digest) = pbs_config::datastore::config()?;
|
let (config, _digest) = pbs_config::datastore::config()?;
|
||||||
let config: DataStoreConfig = config.lookup("datastore", name)?;
|
let config: DataStoreConfig = config.lookup("datastore", name)?;
|
||||||
let path = PathBuf::from(&config.path);
|
let path = PathBuf::from(&config.path);
|
||||||
|
|
||||||
let mut map = DATASTORE_MAP.lock().unwrap();
|
let datastore = DataStore::open_with_path(name, &path, config, generation, now)?;
|
||||||
|
|
||||||
if let Some(datastore) = map.get(name) {
|
|
||||||
// Compare Config - if changed, create new Datastore object!
|
|
||||||
if datastore.chunk_store.base() == path &&
|
|
||||||
datastore.verify_new == config.verify_new.unwrap_or(false)
|
|
||||||
{
|
|
||||||
return Ok(datastore.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let datastore = DataStore::open_with_path(name, &path, config)?;
|
|
||||||
|
|
||||||
let datastore = Arc::new(datastore);
|
let datastore = Arc::new(datastore);
|
||||||
map.insert(name.to_string(), datastore.clone());
|
map.insert(name.to_string(), datastore.clone());
|
||||||
|
@ -102,7 +106,13 @@ impl DataStore {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_with_path(store_name: &str, path: &Path, config: DataStoreConfig) -> Result<Self, Error> {
|
fn open_with_path(
|
||||||
|
store_name: &str,
|
||||||
|
path: &Path,
|
||||||
|
config: DataStoreConfig,
|
||||||
|
last_generation: usize,
|
||||||
|
last_update: i64,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let chunk_store = ChunkStore::open(store_name, path)?;
|
let chunk_store = ChunkStore::open(store_name, path)?;
|
||||||
|
|
||||||
let mut gc_status_path = chunk_store.base_path();
|
let mut gc_status_path = chunk_store.base_path();
|
||||||
|
@ -131,6 +141,8 @@ impl DataStore {
|
||||||
last_gc_status: Mutex::new(gc_status),
|
last_gc_status: Mutex::new(gc_status),
|
||||||
verify_new: config.verify_new.unwrap_or(false),
|
verify_new: config.verify_new.unwrap_or(false),
|
||||||
chunk_order,
|
chunk_order,
|
||||||
|
last_generation,
|
||||||
|
last_update,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue