From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id C92A11FF38E for ; Mon, 13 May 2024 12:46:34 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 7663413893; Mon, 13 May 2024 12:46:44 +0200 (CEST) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Mon, 13 May 2024 12:46:09 +0200 Message-Id: <20240513104609.3109689-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.016 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy 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 Subject: [pbs-devel] [PATCH proxmox-backup] tape: save 'bytes used' in tape inventory 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: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" and show them on the ui. This can help uses with seeing how much a tape is used. The value is updated on 'commit' and when the tape is changed during a backup. For drives not supporting the volume statistics, this is simply skipped. Signed-off-by: Dominik Csapak --- pbs-api-types/src/tape/media.rs | 3 +++ src/api2/tape/media.rs | 3 +++ src/tape/drive/lto/mod.rs | 4 ++++ src/tape/drive/mod.rs | 3 +++ src/tape/drive/virtual_tape.rs | 4 ++++ src/tape/inventory.rs | 30 ++++++++++++++++++++++++++++++ src/tape/media_pool.rs | 32 +++++++++++++++++++++++++++++--- src/tape/pool_writer/mod.rs | 16 +++++++++++++++- www/tape/TapeInventory.js | 7 +++++++ 9 files changed, 98 insertions(+), 4 deletions(-) diff --git a/pbs-api-types/src/tape/media.rs b/pbs-api-types/src/tape/media.rs index 6792cd3c9..6227f4634 100644 --- a/pbs-api-types/src/tape/media.rs +++ b/pbs-api-types/src/tape/media.rs @@ -81,6 +81,9 @@ pub struct MediaListEntry { /// Media Pool #[serde(skip_serializing_if = "Option::is_none")] pub pool: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Bytes currently used + pub bytes_used: Option, } #[api( diff --git a/src/api2/tape/media.rs b/src/api2/tape/media.rs index 07bed86a2..159906ba7 100644 --- a/src/api2/tape/media.rs +++ b/src/api2/tape/media.rs @@ -204,6 +204,7 @@ pub async fn list_media( media_set_uuid, media_set_name, seq_nr, + bytes_used: media.bytes_used(), }); } } @@ -232,6 +233,7 @@ pub async fn list_media( media_set_ctime: None, seq_nr: None, pool: None, + bytes_used: inventory.get_media_bytes_used(&media_id.label.uuid), }); } } @@ -279,6 +281,7 @@ pub async fn list_media( media_set_uuid, media_set_name, seq_nr, + bytes_used: inventory.get_media_bytes_used(&media_id.label.uuid), }); } diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs index 7de07cf95..f3143c907 100644 --- a/src/tape/drive/lto/mod.rs +++ b/src/tape/drive/lto/mod.rs @@ -268,6 +268,10 @@ impl TapeDriver for LtoTapeHandle { } Ok(()) } + + fn get_volume_statistics(&mut self) -> Result { + self.volume_statistics() + } } fn run_sg_tape_cmd(subcmd: &str, args: &[&str], fd: RawFd) -> Result { diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index 39602461f..b21a62d20 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -242,6 +242,9 @@ pub trait TapeDriver { } Ok(()) } + + /// Returns volume statistics from a loaded tape + fn get_volume_statistics(&mut self) -> Result; } /// A boxed implementor of [`MediaChange`]. diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs index b13c58c4e..c183e2681 100644 --- a/src/tape/drive/virtual_tape.rs +++ b/src/tape/drive/virtual_tape.rs @@ -461,6 +461,10 @@ impl TapeDriver for VirtualTapeHandle { let status = VirtualDriveStatus { current_tape: None }; self.store_status(&status) } + + fn get_volume_statistics(&mut self) -> Result { + Ok(Default::default()) + } } impl MediaChange for VirtualTapeHandle { diff --git a/src/tape/inventory.rs b/src/tape/inventory.rs index 7514d76c0..5e4318e21 100644 --- a/src/tape/inventory.rs +++ b/src/tape/inventory.rs @@ -84,6 +84,8 @@ struct MediaStateEntry { location: Option, #[serde(skip_serializing_if = "Option::is_none")] status: Option, + #[serde(skip_serializing_if = "Option::is_none")] + bytes_used: Option, } /// Media Inventory @@ -211,6 +213,7 @@ impl Inventory { } else { previous.status }, + bytes_used: previous.bytes_used, }; self.map.insert(uuid, entry); } else { @@ -218,6 +221,7 @@ impl Inventory { id: media_id, location: None, status: None, + bytes_used: None, }; self.map.insert(uuid, entry); } @@ -720,6 +724,32 @@ impl Inventory { self.set_media_location(uuid, Some(MediaLocation::Offline)) } + /// Lock database, reload database, set bytes used for media, store database + pub fn set_media_bytes_used( + &mut self, + uuid: &Uuid, + bytes_used: Option, + ) -> Result<(), Error> { + let _lock = self.lock()?; + self.map = self.load_media_db()?; + if let Some(entry) = self.map.get_mut(uuid) { + entry.bytes_used = bytes_used; + self.update_helpers(); + self.replace_file()?; + Ok(()) + } else { + bail!("no such media '{}'", uuid); + } + } + + /// Returns bytes used of the given media, if set + pub fn get_media_bytes_used(&self, uuid: &Uuid) -> Option { + match self.map.get(uuid) { + Some(entry) => entry.bytes_used, + None => None, + } + } + /// Update online status pub fn update_online_status(&mut self, online_map: &OnlineStatusMap) -> Result<(), Error> { let _lock = self.lock()?; diff --git a/src/tape/media_pool.rs b/src/tape/media_pool.rs index 8f2b0adda..1e8c739e7 100644 --- a/src/tape/media_pool.rs +++ b/src/tape/media_pool.rs @@ -212,8 +212,11 @@ impl MediaPool { } let (status, location) = self.compute_media_state(&media_id); + let bytes_used = self.inventory.get_media_bytes_used(uuid); - Ok(BackupMedia::with_media_id(media_id, location, status)) + Ok(BackupMedia::with_media_id( + media_id, location, status, bytes_used, + )) } /// List all media associated with this pool @@ -224,7 +227,8 @@ impl MediaPool { .into_iter() .map(|media_id| { let (status, location) = self.compute_media_state(&media_id); - BackupMedia::with_media_id(media_id, location, status) + let bytes_used = self.inventory.get_media_bytes_used(&media_id.label.uuid); + BackupMedia::with_media_id(media_id, location, status, bytes_used) }) .collect() } @@ -238,6 +242,15 @@ impl MediaPool { Ok(()) } + /// Update bytes used for media in inventory + pub fn set_media_bytes_used( + &mut self, + uuid: &Uuid, + bytes_used: Option, + ) -> Result<(), Error> { + self.inventory.set_media_bytes_used(uuid, bytes_used) + } + /// Make sure the current media set is usable for writing /// /// If not, starts a new media set. Also creates a new @@ -715,15 +728,23 @@ pub struct BackupMedia { location: MediaLocation, /// Media status status: MediaStatus, + /// Bytes used + bytes_used: Option, } impl BackupMedia { /// Creates a new instance - pub fn with_media_id(id: MediaId, location: MediaLocation, status: MediaStatus) -> Self { + pub fn with_media_id( + id: MediaId, + location: MediaLocation, + status: MediaStatus, + bytes_used: Option, + ) -> Self { Self { id, location, status, + bytes_used, } } @@ -776,4 +797,9 @@ impl BackupMedia { pub fn label_text(&self) -> &str { &self.id.label.label_text } + + /// Returns the bytes used, if set + pub fn bytes_used(&self) -> Option { + self.bytes_used + } } diff --git a/src/tape/pool_writer/mod.rs b/src/tape/pool_writer/mod.rs index 68e28714a..1df297b68 100644 --- a/src/tape/pool_writer/mod.rs +++ b/src/tape/pool_writer/mod.rs @@ -203,6 +203,14 @@ impl PoolWriter { if let Some(ref mut status) = self.status { status.drive.sync()?; // sync all data to the tape status.bytes_written_after_sync = 0; // reset bytes written + + // not all drives support that + if let Ok(stats) = status.drive.get_volume_statistics() { + self.pool.set_media_bytes_used( + &status.media_uuid, + Some(stats.total_used_native_capacity), + )?; + } } self.catalog_set.lock().unwrap().commit()?; // then commit the catalog Ok(()) @@ -237,7 +245,13 @@ impl PoolWriter { ); if let Some(PoolWriterState { mut drive, .. }) = self.status.take() { - if last_media_uuid.is_some() { + if let Some(uuid) = &last_media_uuid { + // not all drives support that + if let Ok(stats) = drive.get_volume_statistics() { + self.pool + .set_media_bytes_used(uuid, Some(stats.total_used_native_capacity))?; + } + task_log!(worker, "eject current media"); drive.eject_media()?; } diff --git a/www/tape/TapeInventory.js b/www/tape/TapeInventory.js index 47d19acc0..305134e3e 100644 --- a/www/tape/TapeInventory.js +++ b/www/tape/TapeInventory.js @@ -16,6 +16,7 @@ Ext.define('pbs-model-tapes', { 'seq-nr', 'status', 'uuid', + 'bytes-used', ], idProperty: 'uuid', proxy: { @@ -326,5 +327,11 @@ Ext.define('PBS.TapeManagement.TapeInventory', { flex: 1, hidden: true, }, + { + text: gettext("Bytes Used"), + dataIndex: 'bytes-used', + flex: 1, + renderer: Proxmox.Utils.render_size, + }, ], }); -- 2.39.2 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel