[pbs-devel] applied: [PATCH proxmox-backup 1/4] tape: media_pool: implement guess_next_writable_media()

Dietmar Maurer dietmar at proxmox.com
Wed Aug 4 11:05:55 CEST 2021


applied all 4 patches
> On 08/04/2021 10:10 AM Dietmar Maurer <dietmar at 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





More information about the pbs-devel mailing list