* [pbs-devel] applied: [PATCH proxmox-backup 1/4] tape: media_pool: implement guess_next_writable_media()
@ 2021-08-04 9:05 Dietmar Maurer
0 siblings, 0 replies; only message in thread
From: Dietmar Maurer @ 2021-08-04 9:05 UTC (permalink / raw)
To: pbs-devel
applied all 4 patches
> On 08/04/2021 10:10 AM Dietmar Maurer <dietmar@proxmox.com> wrote:
>
>
> ---
> src/tape/media_pool.rs | 252 ++++++++++++++++++++++++++---------------
> 1 file changed, 160 insertions(+), 92 deletions(-)
>
> diff --git a/src/tape/media_pool.rs b/src/tape/media_pool.rs
> index 7bb7fbdb..64a61b3a 100644
> --- a/src/tape/media_pool.rs
> +++ b/src/tape/media_pool.rs
> @@ -406,93 +406,110 @@ impl MediaPool {
> Ok(())
> }
>
> + // Get next unassigned media (media not assigned to any pool)
> + pub fn next_unassigned_media(&self, media_list: &[MediaId]) -> Option<MediaId> {
> + let mut free_media = Vec::new();
>
> - /// Allocates a writable media to the current media set
> - pub fn alloc_writable_media(&mut self, current_time: i64) -> Result<Uuid, Error> {
> + for media_id in media_list {
>
> - if self.current_media_set_lock.is_none() {
> - bail!("alloc_writable_media: media set is not locked - internal error");
> - }
> -
> - let last_is_writable = self.current_set_usable()?;
> + let (status, location) = self.compute_media_state(&media_id);
> + if media_id.media_set_label.is_some() { continue; } // should not happen
>
> - if last_is_writable {
> - let last_uuid = self.current_media_set.last_media_uuid().unwrap();
> - let media = self.lookup_media(last_uuid)?;
> - return Ok(media.uuid().clone());
> - }
> + if !self.location_is_available(&location) {
> + continue;
> + }
>
> - // try to find empty media in pool, add to media set
> + // only consider writable media
> + if status != MediaStatus::Writable { continue; }
>
> - { // limit pool lock scope
> - let _pool_lock = lock_media_pool(&self.state_path, &self.name)?;
> + free_media.push(media_id);
> + }
>
> - self.inventory.reload()?;
> + // sort free_media, newest first -> oldest last
> + free_media.sort_unstable_by(|a, b| {
> + let mut res = b.label.ctime.cmp(&a.label.ctime);
> + if res == std::cmp::Ordering::Equal {
> + res = b.label.label_text.cmp(&a.label.label_text);
> + }
> + res
> + });
>
> - let media_list = self.list_media();
> + free_media.pop().map(|e| e.clone())
> + }
>
> - let mut empty_media = Vec::new();
> - let mut used_media = Vec::new();
> + // Get next empty media
> + pub fn next_empty_media(&self, media_list: &[BackupMedia]) -> Option<MediaId> {
> + let mut empty_media = Vec::new();
>
> - for media in media_list.into_iter() {
> - if !self.location_is_available(media.location()) {
> - continue;
> - }
> - // already part of a media set?
> - if media.media_set_label().is_some() {
> - used_media.push(media);
> - } else {
> - // only consider writable empty media
> - if media.status() == &MediaStatus::Writable {
> - empty_media.push(media);
> - }
> - }
> + for media in media_list.into_iter() {
> + if !self.location_is_available(media.location()) {
> + continue;
> }
> -
> - // sort empty_media, newest first -> oldest last
> - empty_media.sort_unstable_by(|a, b| {
> - let mut res = b.label().ctime.cmp(&a.label().ctime);
> - if res == std::cmp::Ordering::Equal {
> - res = b.label().label_text.cmp(&a.label().label_text);
> + // already part of a media set?
> + if media.media_set_label().is_none() {
> + // only consider writable empty media
> + if media.status() == &MediaStatus::Writable {
> + empty_media.push(media);
> }
> - res
> - });
> + }
> + }
>
> - if let Some(media) = empty_media.pop() {
> - // found empty media, add to media set an use it
> - let uuid = media.uuid().clone();
> - self.add_media_to_current_set(media.into_id(), current_time)?;
> - return Ok(uuid);
> + // sort empty_media, newest first -> oldest last
> + empty_media.sort_unstable_by(|a, b| {
> + let mut res = b.label().ctime.cmp(&a.label().ctime);
> + if res == std::cmp::Ordering::Equal {
> + res = b.label().label_text.cmp(&a.label().label_text);
> }
> + res
> + });
>
> - println!("no empty media in pool, try to reuse expired media");
> + empty_media.pop().map(|e| e.clone().into_id())
> + }
>
> - let mut expired_media = Vec::new();
> + // Get next expired media
> + pub fn next_expired_media(&self, current_time: i64, media_list: &[BackupMedia]) -> Option<MediaId> {
> + let mut used_media = Vec::new();
>
> - for media in used_media.into_iter() {
> - if let Some(set) = media.media_set_label() {
> - if &set.uuid == self.current_media_set.uuid() {
> - continue;
> - }
> - } else {
> + for media in media_list.into_iter() {
> + if !self.location_is_available(media.location()) {
> + continue;
> + }
> + // already part of a media set?
> + if media.media_set_label().is_some() {
> + used_media.push(media);
> + }
> + }
> +
> + let mut expired_media = Vec::new();
> +
> + for media in used_media.into_iter() {
> + if let Some(set) = media.media_set_label() {
> + if &set.uuid == self.current_media_set.uuid() {
> continue;
> }
> + } else {
> + continue;
> + }
>
> - if self.media_is_expired(&media, current_time) {
> - println!("found expired media on media '{}'", media.label_text());
> - expired_media.push(media);
> - }
> + if !self.media_is_expired(&media, current_time) {
> + continue;
> }
>
> - // sort expired_media, newest first -> oldest last
> - expired_media.sort_unstable_by(|a, b| {
> - let mut res = b.media_set_label().unwrap().ctime.cmp(&a.media_set_label().unwrap().ctime);
> - if res == std::cmp::Ordering::Equal {
> - res = b.label().label_text.cmp(&a.label().label_text);
> - }
> - res
> - });
> + expired_media.push(media);
> + }
> +
> + // sort expired_media, newest first -> oldest last
> + expired_media.sort_unstable_by(|a, b| {
> + let mut res = b.media_set_label().unwrap().ctime.cmp(&a.media_set_label().unwrap().ctime);
> + if res == std::cmp::Ordering::Equal {
> + res = b.label().label_text.cmp(&a.label().label_text);
> + }
> + res
> + });
>
> + if self.no_media_set_locking {
> + expired_media.pop().map(|e| e.clone().into_id())
> + } else {
> while let Some(media) = expired_media.pop() {
> // check if we can modify the media-set (i.e. skip
> // media used by a restore job)
> @@ -501,49 +518,100 @@ impl MediaPool {
> &media.media_set_label().unwrap().uuid,
> Some(std::time::Duration::new(0, 0)), // do not wait
> ) {
> - println!("reuse expired media '{}'", media.label_text());
> - let uuid = media.uuid().clone();
> - self.add_media_to_current_set(media.into_id(), current_time)?;
> - return Ok(uuid);
> + return Some(media.clone().into_id());
> }
> }
> + None
> }
> + }
>
> - println!("no expired media in pool, try to find unassigned/free media");
> + /// Guess next writable media
> + ///
> + /// Like alloc_writable_media(), but does not really allocate
> + /// anything (thus it does not need any locks)
> + // Note: Please keep in sync with alloc_writable_media()
> + pub fn guess_next_writable_media(&self, current_time: i64) -> Result<MediaId, Error> {
> + let last_is_writable = self.current_set_usable()?;
>
> - // try unassigned media
> - let _lock = lock_unassigned_media_pool(&self.state_path)?;
> + if last_is_writable {
> + let last_uuid = self.current_media_set.last_media_uuid().unwrap();
> + let media = self.lookup_media(last_uuid)?;
> + return Ok(media.into_id());
> + }
>
> - self.inventory.reload()?;
> + let media_list = self.list_media();
> + if let Some(media_id) = self.next_empty_media(&media_list) {
> + return Ok(media_id);
> + }
>
> - let mut free_media = Vec::new();
> + if let Some(media_id) = self.next_expired_media(current_time, &media_list) {
> + return Ok(media_id);
> + }
>
> - for media_id in self.inventory.list_unassigned_media() {
> + let unassigned_list = self.inventory.list_unassigned_media();
>
> - let (status, location) = self.compute_media_state(&media_id);
> - if media_id.media_set_label.is_some() { continue; } // should not happen
> + if let Some(media_id) = self.next_unassigned_media(&unassigned_list) {
> + return Ok(media_id);
> + }
>
> - if !self.location_is_available(&location) {
> - continue;
> - }
> + bail!("guess_next_writable_media in pool '{}' failed: no usable media found", self.name());
> + }
>
> - // only consider writable media
> - if status != MediaStatus::Writable { continue; }
> + /// Allocates a writable media to the current media set
> + // Note: Please keep in sync with guess_next_writable_media()
> + pub fn alloc_writable_media(&mut self, current_time: i64) -> Result<Uuid, Error> {
>
> - free_media.push(media_id);
> + if self.current_media_set_lock.is_none() {
> + bail!("alloc_writable_media: media set is not locked - internal error");
> }
>
> - // sort free_media, newest first -> oldest last
> - free_media.sort_unstable_by(|a, b| {
> - let mut res = b.label.ctime.cmp(&a.label.ctime);
> - if res == std::cmp::Ordering::Equal {
> - res = b.label.label_text.cmp(&a.label.label_text);
> + let last_is_writable = self.current_set_usable()?;
> +
> + if last_is_writable {
> + let last_uuid = self.current_media_set.last_media_uuid().unwrap();
> + let media = self.lookup_media(last_uuid)?;
> + return Ok(media.uuid().clone());
> + }
> +
> + { // limit pool lock scope
> + let _pool_lock = lock_media_pool(&self.state_path, &self.name)?;
> +
> + self.inventory.reload()?;
> +
> + let media_list = self.list_media();
> +
> + // try to find empty media in pool, add to media set
> +
> + if let Some(media_id) = self.next_empty_media(&media_list) {
> + // found empty media, add to media set an use it
> + println!("found empty media '{}'", media_id.label.label_text);
> + let uuid = media_id.label.uuid.clone();
> + self.add_media_to_current_set(media_id, current_time)?;
> + return Ok(uuid);
> }
> - res
> - });
>
> - if let Some(media_id) = free_media.pop() {
> - println!("use free media '{}'", media_id.label.label_text);
> + println!("no empty media in pool, try to reuse expired media");
> +
> + if let Some(media_id) = self.next_expired_media(current_time, &media_list) {
> + // found expired media, add to media set an use it
> + println!("reuse expired media '{}'", media_id.label.label_text);
> + let uuid = media_id.label.uuid.clone();
> + self.add_media_to_current_set(media_id, current_time)?;
> + return Ok(uuid);
> + }
> + }
> +
> + println!("no empty or expired media in pool, try to find unassigned/free media");
> +
> + // try unassigned media
> + let _lock = lock_unassigned_media_pool(&self.state_path)?;
> +
> + self.inventory.reload()?;
> +
> + let unassigned_list = self.inventory.list_unassigned_media();
> +
> + if let Some(media_id) = self.next_unassigned_media(&unassigned_list) {
> + println!("use free/unassigned media '{}'", media_id.label.label_text);
> let uuid = media_id.label.uuid.clone();
> self.add_media_to_current_set(media_id, current_time)?;
> return Ok(uuid);
> --
> 2.30.2
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-08-04 9:06 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-04 9:05 [pbs-devel] applied: [PATCH proxmox-backup 1/4] tape: media_pool: implement guess_next_writable_media() 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