tape: cache changer state
This commit is contained in:
parent
5b9f575648
commit
4188fd59a0
@ -39,6 +39,11 @@ use crate::{
|
|||||||
name: {
|
name: {
|
||||||
schema: CHANGER_NAME_SCHEMA,
|
schema: CHANGER_NAME_SCHEMA,
|
||||||
},
|
},
|
||||||
|
cache: {
|
||||||
|
description: "Use cached value.",
|
||||||
|
optional: true,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
returns: {
|
returns: {
|
||||||
@ -50,14 +55,17 @@ use crate::{
|
|||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
/// Get tape changer status
|
/// Get tape changer status
|
||||||
pub async fn get_status(name: String) -> Result<Vec<MtxStatusEntry>, Error> {
|
pub async fn get_status(
|
||||||
|
name: String,
|
||||||
|
cache: bool,
|
||||||
|
) -> Result<Vec<MtxStatusEntry>, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?;
|
||||||
|
|
||||||
let status = tokio::task::spawn_blocking(move || {
|
let status = tokio::task::spawn_blocking(move || {
|
||||||
changer_config.status()
|
changer_config.status(cache)
|
||||||
}).await??;
|
}).await??;
|
||||||
|
|
||||||
let state_path = Path::new(TAPE_STATUS_DIR);
|
let state_path = Path::new(TAPE_STATUS_DIR);
|
||||||
|
@ -217,6 +217,12 @@ fn get_config(
|
|||||||
schema: CHANGER_NAME_SCHEMA,
|
schema: CHANGER_NAME_SCHEMA,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
cache: {
|
||||||
|
description: "Use cached value.",
|
||||||
|
type: bool,
|
||||||
|
optional: true,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
|
@ -11,12 +11,20 @@ mod online_status_map;
|
|||||||
pub use online_status_map::*;
|
pub use online_status_map::*;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::api::schema::parse_property_string;
|
use proxmox::{
|
||||||
|
api::schema::parse_property_string,
|
||||||
|
tools::fs::{
|
||||||
|
CreateOptions,
|
||||||
|
replace_file,
|
||||||
|
file_read_optional_string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::api2::types::{
|
use crate::api2::types::{
|
||||||
SLOT_ARRAY_SCHEMA,
|
SLOT_ARRAY_SCHEMA,
|
||||||
@ -158,7 +166,7 @@ impl MtxStatus {
|
|||||||
/// Interface to SCSI changer devices
|
/// Interface to SCSI changer devices
|
||||||
pub trait ScsiMediaChange {
|
pub trait ScsiMediaChange {
|
||||||
|
|
||||||
fn status(&mut self) -> Result<MtxStatus, Error>;
|
fn status(&mut self, use_cache: bool) -> Result<MtxStatus, Error>;
|
||||||
|
|
||||||
fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error>;
|
fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error>;
|
||||||
|
|
||||||
@ -398,12 +406,29 @@ const USE_MTX: bool = false;
|
|||||||
|
|
||||||
impl ScsiMediaChange for ScsiTapeChanger {
|
impl ScsiMediaChange for ScsiTapeChanger {
|
||||||
|
|
||||||
fn status(&mut self) -> Result<MtxStatus, Error> {
|
fn status(&mut self, use_cache: bool) -> Result<MtxStatus, Error> {
|
||||||
if USE_MTX {
|
if use_cache {
|
||||||
|
if let Some(state) = load_changer_state_cache(&self.name)? {
|
||||||
|
return Ok(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = if USE_MTX {
|
||||||
mtx::mtx_status(&self)
|
mtx::mtx_status(&self)
|
||||||
} else {
|
} else {
|
||||||
sg_pt_changer::status(&self)
|
sg_pt_changer::status(&self)
|
||||||
|
};
|
||||||
|
|
||||||
|
match &status {
|
||||||
|
Ok(status) => {
|
||||||
|
save_changer_state_cache(&self.name, status)?;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
delete_changer_state_cache(&self.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error> {
|
fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error> {
|
||||||
@ -434,6 +459,47 @@ impl ScsiMediaChange for ScsiTapeChanger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn save_changer_state_cache(
|
||||||
|
changer: &str,
|
||||||
|
state: &MtxStatus,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut path = PathBuf::from("/run/proxmox-backup/changer-state");
|
||||||
|
std::fs::create_dir_all(&path)?;
|
||||||
|
path.push(changer);
|
||||||
|
|
||||||
|
let backup_user = crate::backup::backup_user()?;
|
||||||
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0644);
|
||||||
|
let options = CreateOptions::new()
|
||||||
|
.perm(mode)
|
||||||
|
.owner(backup_user.uid)
|
||||||
|
.group(backup_user.gid);
|
||||||
|
|
||||||
|
let state = serde_json::to_string_pretty(state)?;
|
||||||
|
|
||||||
|
replace_file(path, state.as_bytes(), options)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_changer_state_cache(changer: &str) {
|
||||||
|
let mut path = PathBuf::from("/run/proxmox-backup/changer-state");
|
||||||
|
path.push(changer);
|
||||||
|
|
||||||
|
let _ = std::fs::remove_file(&path); // ignore errors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_changer_state_cache(changer: &str) -> Result<Option<MtxStatus>, Error> {
|
||||||
|
let mut path = PathBuf::from("/run/proxmox-backup/changer-state");
|
||||||
|
path.push(changer);
|
||||||
|
|
||||||
|
let data = match file_read_optional_string(&path)? {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(data) => data,
|
||||||
|
};
|
||||||
|
|
||||||
|
let state = serde_json::from_str(&data)?;
|
||||||
|
|
||||||
|
Ok(Some(state))
|
||||||
|
}
|
||||||
|
|
||||||
/// Implements MediaChange using 'mtx' linux cli tool
|
/// Implements MediaChange using 'mtx' linux cli tool
|
||||||
pub struct MtxMediaChanger {
|
pub struct MtxMediaChanger {
|
||||||
drive_name: String, // used for error messages
|
drive_name: String, // used for error messages
|
||||||
@ -469,7 +535,7 @@ impl MediaChange for MtxMediaChanger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn status(&mut self) -> Result<MtxStatus, Error> {
|
fn status(&mut self) -> Result<MtxStatus, Error> {
|
||||||
self.config.status()
|
self.config.status(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer_media(&mut self, from: u64, to: u64) -> Result<(), Error> {
|
fn transfer_media(&mut self, from: u64, to: u64) -> Result<(), Error> {
|
||||||
|
@ -142,7 +142,7 @@ pub fn update_online_status(state_path: &Path, changer: Option<&str>) -> Result<
|
|||||||
}
|
}
|
||||||
found_changer = true;
|
found_changer = true;
|
||||||
}
|
}
|
||||||
let status = match changer_config.status() {
|
let status = match changer_config.status(false) {
|
||||||
Ok(status) => status,
|
Ok(status) => status,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("unable to get changer '{}' status - {}", changer_config.name, err);
|
eprintln!("unable to get changer '{}' status - {}", changer_config.name, err);
|
||||||
|
Loading…
Reference in New Issue
Block a user