[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