* [pbs-devel] [PATCH proxmox-backup] tape: save 'bytes used' in tape inventory
@ 2024-05-13 10:46 Dominik Csapak
2024-05-14 8:08 ` [pbs-devel] applied: " Dietmar Maurer
0 siblings, 1 reply; 2+ messages in thread
From: Dominik Csapak @ 2024-05-13 10:46 UTC (permalink / raw)
To: 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 <d.csapak@proxmox.com>
---
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<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ /// Bytes currently used
+ pub bytes_used: Option<u64>,
}
#[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<pbs_api_types::Lp17VolumeStatistics, Error> {
+ self.volume_statistics()
+ }
}
fn run_sg_tape_cmd(subcmd: &str, args: &[&str], fd: RawFd) -> Result<String, Error> {
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<pbs_api_types::Lp17VolumeStatistics, Error>;
}
/// 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<pbs_api_types::Lp17VolumeStatistics, Error> {
+ 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<MediaLocation>,
#[serde(skip_serializing_if = "Option::is_none")]
status: Option<MediaStatus>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ bytes_used: Option<u64>,
}
/// 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<u64>,
+ ) -> 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<u64> {
+ 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<u64>,
+ ) -> 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<u64>,
}
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<u64>,
+ ) -> 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<u64> {
+ 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
^ permalink raw reply [flat|nested] 2+ messages in thread
* [pbs-devel] applied: [PATCH proxmox-backup] tape: save 'bytes used' in tape inventory
2024-05-13 10:46 [pbs-devel] [PATCH proxmox-backup] tape: save 'bytes used' in tape inventory Dominik Csapak
@ 2024-05-14 8:08 ` Dietmar Maurer
0 siblings, 0 replies; 2+ messages in thread
From: Dietmar Maurer @ 2024-05-14 8:08 UTC (permalink / raw)
To: Proxmox Backup Server development discussion, Dominik Csapak
applied
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-05-14 8:09 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-13 10:46 [pbs-devel] [PATCH proxmox-backup] tape: save 'bytes used' in tape inventory Dominik Csapak
2024-05-14 8:08 ` [pbs-devel] applied: " Dietmar Maurer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal