From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 4B39B6372C for ; Fri, 25 Feb 2022 15:26:14 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 414B422B57 for ; Fri, 25 Feb 2022 15:26:14 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 88E1222B4C for ; Fri, 25 Feb 2022 15:26:12 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 55BA541AFD for ; Fri, 25 Feb 2022 15:26:12 +0100 (CET) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Fri, 25 Feb 2022 15:26:11 +0100 Message-Id: <20220225142611.1802375-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.156 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pbs-devel] [PATCH proxmox-backup] pbs-datastore: use ConfigVersionCache for datastore X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Feb 2022 14:26:14 -0000 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 --- i'm a bit torn by removing the checks for the changed config parts... on one hand, this fixes the 'we forgot to add our new option' problem, but on the other hand, we now basically create a new datastore object every minute pbs-config/src/config_version_cache.rs | 18 ++++++++++++- pbs-config/src/datastore.rs | 11 ++++++-- pbs-datastore/src/datastore.rs | 36 +++++++++++++++++--------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/pbs-config/src/config_version_cache.rs b/pbs-config/src/config_version_cache.rs index c0d181d6..39a433ed 100644 --- a/pbs-config/src/config_version_cache.rs +++ b/pbs-config/src/config_version_cache.rs @@ -24,10 +24,12 @@ struct ConfigVersionCacheData { user_cache_generation: AtomicUsize, // Traffic control (traffic-control.cfg) generation/version. traffic_control_generation: AtomicUsize, + // datastore (datastore.cfg) generation/version + datastore_generation: AtomicUsize, // 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); } + /// 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) + } } diff --git a/pbs-config/src/datastore.rs b/pbs-config/src/datastore.rs index 12071a9f..6d17da63 100644 --- a/pbs-config/src/datastore.rs +++ b/pbs-config/src/datastore.rs @@ -7,7 +7,7 @@ use proxmox_section_config::{SectionConfig, SectionConfigData, SectionConfigPlug 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! { 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> { 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 diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs index 8397da00..d416c8d8 100644 --- a/pbs-datastore/src/datastore.rs +++ b/pbs-datastore/src/datastore.rs @@ -21,7 +21,7 @@ use pbs_api_types::{ UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte, ChunkOrder, DatastoreTuning, }; -use pbs_config::{open_backup_lockfile, BackupLockGuard}; +use pbs_config::{open_backup_lockfile, BackupLockGuard, ConfigVersionCache}; use crate::DataBlob; use crate::backup_info::{BackupGroup, BackupDir}; @@ -63,26 +63,30 @@ pub struct DataStore { last_gc_status: Mutex, verify_new: bool, chunk_order: ChunkOrder, + last_generation: usize, + last_update: i64, } impl DataStore { pub fn lookup_datastore(name: &str) -> Result, Error> { - let (config, _digest) = pbs_config::datastore::config()?; - let config: DataStoreConfig = config.lookup("datastore", name)?; - let path = PathBuf::from(&config.path); + 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) = 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()); + if let Some(datastore) = &entry { + if datastore.last_generation == generation && now < (datastore.last_update + 60) { + return Ok(Arc::clone(datastore)); } } - let datastore = DataStore::open_with_path(name, &path, config)?; + let (config, _digest) = pbs_config::datastore::config()?; + let config: DataStoreConfig = config.lookup("datastore", name)?; + let path = PathBuf::from(&config.path); + + let datastore = DataStore::open_with_path(name, &path, config, generation, now)?; let datastore = Arc::new(datastore); map.insert(name.to_string(), datastore.clone()); @@ -102,7 +106,13 @@ impl DataStore { Ok(()) } - fn open_with_path(store_name: &str, path: &Path, config: DataStoreConfig) -> Result { + fn open_with_path( + store_name: &str, + path: &Path, + config: DataStoreConfig, + last_generation: usize, + last_update: i64, + ) -> Result { let chunk_store = ChunkStore::open(store_name, path)?; let mut gc_status_path = chunk_store.base_path(); @@ -131,6 +141,8 @@ impl DataStore { last_gc_status: Mutex::new(gc_status), verify_new: config.verify_new.unwrap_or(false), chunk_order, + last_generation, + last_update, }) } -- 2.30.2