]> git.proxmox.com Git - proxmox-backup.git/commitdiff
move src/backup/snapshot_reader.rs to pbs_datastore crate
authorDietmar Maurer <dietmar@proxmox.com>
Mon, 27 Sep 2021 07:58:20 +0000 (09:58 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Mon, 27 Sep 2021 07:58:20 +0000 (09:58 +0200)
pbs-datastore/src/lib.rs
pbs-datastore/src/snapshot_reader.rs [new file with mode: 0644]
src/api2/tape/backup.rs
src/backup/mod.rs
src/backup/snapshot_reader.rs [deleted file]
src/tape/file_formats/snapshot_archive.rs
src/tape/pool_writer/mod.rs
src/tape/pool_writer/new_chunks_iterator.rs

index fc08d00cfbdfc45ab84578e8a22b520f5881dae7..fcc368ff3e65a1cf47a0307d3199fc4581c7e26b 100644 (file)
@@ -198,3 +198,6 @@ pub use store_progress::StoreProgress;
 
 mod datastore;
 pub use datastore::{check_backup_owner, DataStore};
+
+mod snapshot_reader;
+pub use snapshot_reader::SnapshotReader;
diff --git a/pbs-datastore/src/snapshot_reader.rs b/pbs-datastore/src/snapshot_reader.rs
new file mode 100644 (file)
index 0000000..c49cf16
--- /dev/null
@@ -0,0 +1,161 @@
+use std::path::Path;
+use std::sync::Arc;
+use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::fs::File;
+
+use anyhow::{bail, Error};
+use nix::dir::Dir;
+
+use crate::backup_info::BackupDir;
+use crate::index::IndexFile;
+use crate::fixed_index::FixedIndexReader;
+use crate::dynamic_index::DynamicIndexReader;
+use crate::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
+use crate::DataStore;
+use pbs_tools::fs::lock_dir_noblock_shared;
+
+/// Helper to access the contents of a datastore backup snapshot
+///
+/// This make it easy to iterate over all used chunks and files.
+pub struct SnapshotReader {
+    snapshot: BackupDir,
+    datastore_name: String,
+    file_list: Vec<String>,
+    locked_dir: Dir,
+}
+
+impl SnapshotReader {
+
+    /// Lock snapshot, reads the manifest and returns a new instance
+    pub fn new(datastore: Arc<DataStore>, snapshot: BackupDir) -> Result<Self, Error> {
+
+        let snapshot_path = datastore.snapshot_path(&snapshot);
+
+        let locked_dir = lock_dir_noblock_shared(
+            &snapshot_path,
+            "snapshot",
+            "locked by another operation")?;
+
+        let datastore_name = datastore.name().to_string();
+
+        let manifest = match datastore.load_manifest(&snapshot) {
+            Ok((manifest, _)) => manifest,
+            Err(err) => {
+                bail!("manifest load error on datastore '{}' snapshot '{}' - {}",
+                      datastore_name, snapshot, err);
+            }
+        };
+
+        let mut client_log_path = snapshot_path;
+        client_log_path.push(CLIENT_LOG_BLOB_NAME);
+
+        let mut file_list = Vec::new();
+        file_list.push(MANIFEST_BLOB_NAME.to_string());
+        for item in manifest.files() { file_list.push(item.filename.clone()); }
+        if client_log_path.exists() {
+            file_list.push(CLIENT_LOG_BLOB_NAME.to_string());
+        }
+
+        Ok(Self { snapshot, datastore_name, file_list, locked_dir })
+    }
+
+    /// Return the snapshot directory
+    pub fn snapshot(&self) -> &BackupDir {
+        &self.snapshot
+    }
+
+    /// Return the datastore name
+    pub fn datastore_name(&self) -> &str {
+        &self.datastore_name
+    }
+
+    /// Returns the list of files the snapshot refers to.
+    pub fn file_list(&self) -> &Vec<String> {
+        &self.file_list
+    }
+
+    /// Opens a file inside the snapshot (using openat) for reading
+    pub fn open_file(&self, filename: &str) -> Result<File, Error> {
+        let raw_fd = nix::fcntl::openat(
+            self.locked_dir.as_raw_fd(),
+            Path::new(filename),
+            nix::fcntl::OFlag::O_RDONLY,
+            nix::sys::stat::Mode::empty(),
+        )?;
+        let file = unsafe { File::from_raw_fd(raw_fd) };
+        Ok(file)
+    }
+
+    /// Returns an iterator for all used chunks.
+    pub fn chunk_iterator(&self) -> Result<SnapshotChunkIterator, Error> {
+        SnapshotChunkIterator::new(&self)
+    }
+}
+
+/// Iterates over all chunks used by a backup snapshot
+///
+/// Note: The iterator returns a `Result`, and the iterator state is
+/// undefined after the first error. So it make no sense to continue
+/// iteration after the first error.
+pub struct SnapshotChunkIterator<'a> {
+    snapshot_reader: &'a SnapshotReader,
+    todo_list: Vec<String>,
+    current_index: Option<(Arc<Box<dyn IndexFile + Send>>, usize, Vec<(usize, u64)>)>,
+}
+
+impl <'a> Iterator for SnapshotChunkIterator<'a> {
+    type Item = Result<[u8; 32], Error>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        proxmox::try_block!({
+            loop {
+                if self.current_index.is_none() {
+                    if let Some(filename) = self.todo_list.pop() {
+                        let file = self.snapshot_reader.open_file(&filename)?;
+                        let index: Box<dyn IndexFile + Send> = match archive_type(&filename)? {
+                            ArchiveType::FixedIndex => Box::new(FixedIndexReader::new(file)?),
+                            ArchiveType::DynamicIndex => Box::new(DynamicIndexReader::new(file)?),
+                            _ => bail!("SnapshotChunkIterator: got unknown file type - internal error"),
+                        };
+
+                        let datastore =
+                            DataStore::lookup_datastore(self.snapshot_reader.datastore_name())?;
+                        let order = datastore.get_chunks_in_order(&index, |_| false, |_| Ok(()))?;
+
+                        self.current_index = Some((Arc::new(index), 0, order));
+                    } else {
+                        return Ok(None);
+                    }
+                }
+                let (index, pos, list) = self.current_index.take().unwrap();
+                if pos < list.len() {
+                    let (real_pos, _) = list[pos];
+                    let digest = *index.index_digest(real_pos).unwrap();
+                    self.current_index = Some((index, pos + 1, list));
+                    return Ok(Some(digest));
+                } else {
+                    // pop next index
+                }
+            }
+        }).transpose()
+    }
+}
+
+impl <'a> SnapshotChunkIterator<'a> {
+
+    pub fn new(snapshot_reader: &'a SnapshotReader) -> Result<Self, Error> {
+
+        let mut todo_list = Vec::new();
+
+        for filename in snapshot_reader.file_list() {
+            match archive_type(filename)? {
+                ArchiveType::FixedIndex | ArchiveType::DynamicIndex => {
+                    todo_list.push(filename.to_owned());
+                },
+                ArchiveType::Blob => { /* no chunks, do nothing */ },
+            }
+        }
+
+        Ok(Self { snapshot_reader, todo_list, current_index: None })
+    }
+}
index aad5968a105771d5d66abe15909238d215857331..7627e35b8da31e48f462485af9a8f0ef0b580483 100644 (file)
@@ -20,7 +20,7 @@ use pbs_api_types::{
     UPID_SCHEMA, JOB_ID_SCHEMA, PRIV_DATASTORE_READ, PRIV_TAPE_AUDIT, PRIV_TAPE_WRITE,
 };
 
-use pbs_datastore::{DataStore, StoreProgress};
+use pbs_datastore::{DataStore, StoreProgress, SnapshotReader};
 use pbs_datastore::backup_info::{BackupDir, BackupInfo};
 use pbs_tools::{task_log, task_warn, task::WorkerTaskContext};
 use pbs_config::CachedUserInfo;
@@ -36,7 +36,6 @@ use crate::{
             compute_schedule_status,
         },
     },
-    backup::SnapshotReader,
     tape::{
         TAPE_STATUS_DIR,
         Inventory,
index 861010f7b940578f767277445c3e83fa775e501c..59078c1d579964341a8fbf3c360e0768decd3b99 100644 (file)
@@ -9,6 +9,3 @@ pub use read_chunk::*;
 
 mod verify;
 pub use verify::*;
-
-mod snapshot_reader;
-pub use snapshot_reader::SnapshotReader;
diff --git a/src/backup/snapshot_reader.rs b/src/backup/snapshot_reader.rs
deleted file mode 100644 (file)
index 03ca45c..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-use std::path::Path;
-use std::sync::Arc;
-use std::os::unix::io::{AsRawFd, FromRawFd};
-use std::fs::File;
-
-use anyhow::{bail, Error};
-use nix::dir::Dir;
-
-use pbs_datastore::backup_info::BackupDir;
-use pbs_datastore::index::IndexFile;
-use pbs_datastore::fixed_index::FixedIndexReader;
-use pbs_datastore::dynamic_index::DynamicIndexReader;
-use pbs_datastore::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
-use pbs_datastore::DataStore;
-use pbs_tools::fs::lock_dir_noblock_shared;
-
-/// Helper to access the contents of a datastore backup snapshot
-///
-/// This make it easy to iterate over all used chunks and files.
-pub struct SnapshotReader {
-    snapshot: BackupDir,
-    datastore_name: String,
-    file_list: Vec<String>,
-    locked_dir: Dir,
-}
-
-impl SnapshotReader {
-
-    /// Lock snapshot, reads the manifest and returns a new instance
-    pub fn new(datastore: Arc<DataStore>, snapshot: BackupDir) -> Result<Self, Error> {
-
-        let snapshot_path = datastore.snapshot_path(&snapshot);
-
-        let locked_dir = lock_dir_noblock_shared(
-            &snapshot_path,
-            "snapshot",
-            "locked by another operation")?;
-
-        let datastore_name = datastore.name().to_string();
-
-        let manifest = match datastore.load_manifest(&snapshot) {
-            Ok((manifest, _)) => manifest,
-            Err(err) => {
-                bail!("manifest load error on datastore '{}' snapshot '{}' - {}",
-                      datastore_name, snapshot, err);
-            }
-        };
-
-        let mut client_log_path = snapshot_path;
-        client_log_path.push(CLIENT_LOG_BLOB_NAME);
-
-        let mut file_list = Vec::new();
-        file_list.push(MANIFEST_BLOB_NAME.to_string());
-        for item in manifest.files() { file_list.push(item.filename.clone()); }
-        if client_log_path.exists() {
-            file_list.push(CLIENT_LOG_BLOB_NAME.to_string());
-        }
-
-        Ok(Self { snapshot, datastore_name, file_list, locked_dir })
-    }
-
-    /// Return the snapshot directory
-    pub fn snapshot(&self) -> &BackupDir {
-        &self.snapshot
-    }
-
-    /// Return the datastore name
-    pub fn datastore_name(&self) -> &str {
-        &self.datastore_name
-    }
-
-    /// Returns the list of files the snapshot refers to.
-    pub fn file_list(&self) -> &Vec<String> {
-        &self.file_list
-    }
-
-    /// Opens a file inside the snapshot (using openat) for reading
-    pub fn open_file(&self, filename: &str) -> Result<File, Error> {
-        let raw_fd = nix::fcntl::openat(
-            self.locked_dir.as_raw_fd(),
-            Path::new(filename),
-            nix::fcntl::OFlag::O_RDONLY,
-            nix::sys::stat::Mode::empty(),
-        )?;
-        let file = unsafe { File::from_raw_fd(raw_fd) };
-        Ok(file)
-    }
-
-    /// Returns an iterator for all used chunks.
-    pub fn chunk_iterator(&self) -> Result<SnapshotChunkIterator, Error> {
-        SnapshotChunkIterator::new(&self)
-    }
-}
-
-/// Iterates over all chunks used by a backup snapshot
-///
-/// Note: The iterator returns a `Result`, and the iterator state is
-/// undefined after the first error. So it make no sense to continue
-/// iteration after the first error.
-pub struct SnapshotChunkIterator<'a> {
-    snapshot_reader: &'a SnapshotReader,
-    todo_list: Vec<String>,
-    current_index: Option<(Arc<Box<dyn IndexFile + Send>>, usize, Vec<(usize, u64)>)>,
-}
-
-impl <'a> Iterator for SnapshotChunkIterator<'a> {
-    type Item = Result<[u8; 32], Error>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        proxmox::try_block!({
-            loop {
-                if self.current_index.is_none() {
-                    if let Some(filename) = self.todo_list.pop() {
-                        let file = self.snapshot_reader.open_file(&filename)?;
-                        let index: Box<dyn IndexFile + Send> = match archive_type(&filename)? {
-                            ArchiveType::FixedIndex => Box::new(FixedIndexReader::new(file)?),
-                            ArchiveType::DynamicIndex => Box::new(DynamicIndexReader::new(file)?),
-                            _ => bail!("SnapshotChunkIterator: got unknown file type - internal error"),
-                        };
-
-                        let datastore =
-                            DataStore::lookup_datastore(self.snapshot_reader.datastore_name())?;
-                        let order = datastore.get_chunks_in_order(&index, |_| false, |_| Ok(()))?;
-
-                        self.current_index = Some((Arc::new(index), 0, order));
-                    } else {
-                        return Ok(None);
-                    }
-                }
-                let (index, pos, list) = self.current_index.take().unwrap();
-                if pos < list.len() {
-                    let (real_pos, _) = list[pos];
-                    let digest = *index.index_digest(real_pos).unwrap();
-                    self.current_index = Some((index, pos + 1, list));
-                    return Ok(Some(digest));
-                } else {
-                    // pop next index
-                }
-            }
-        }).transpose()
-    }
-}
-
-impl <'a> SnapshotChunkIterator<'a> {
-
-    pub fn new(snapshot_reader: &'a SnapshotReader) -> Result<Self, Error> {
-
-        let mut todo_list = Vec::new();
-
-        for filename in snapshot_reader.file_list() {
-            match archive_type(filename)? {
-                ArchiveType::FixedIndex | ArchiveType::DynamicIndex => {
-                    todo_list.push(filename.to_owned());
-                },
-                ArchiveType::Blob => { /* no chunks, do nothing */ },
-            }
-        }
-
-        Ok(Self { snapshot_reader, todo_list, current_index: None })
-    }
-}
index c898dc4a31563682cb9fe02912afef3a1b89d7f8..c2f289d2ea2f4789771f30f65a7231e9d457c3ee 100644 (file)
@@ -11,8 +11,7 @@ use pbs_tape::{
     PROXMOX_TAPE_BLOCK_SIZE,
     TapeWrite, MediaContentHeader,
 };
-
-use crate::backup::SnapshotReader;
+use pbs_datastore::SnapshotReader;
 
 use crate::tape::file_formats::{
     PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1,
index b3f85a6e889a0f1b37601e2a0daefd4eefb8e7c6..eed0d61e1c24a9f6cc875967f6a36136a4452944 100644 (file)
@@ -19,11 +19,10 @@ use pbs_tape::{
     TapeWrite,
     sg_tape::tape_alert_flags_critical,
 };
-use pbs_datastore::DataStore;
+use pbs_datastore::{DataStore, SnapshotReader};
 use proxmox_rest_server::WorkerTask;
 
 use crate::{
-    backup::SnapshotReader,
     tape::{
         TAPE_STATUS_DIR,
         MAX_CHUNK_ARCHIVE_SIZE,
index 97203fea113ac080aba6fcaac709317eb5a8f4dc..4adf67f9a6451e9eaf1b4d3515abc97272375e6d 100644 (file)
@@ -3,9 +3,8 @@ use std::sync::{Arc, Mutex};
 
 use anyhow::{format_err, Error};
 
-use pbs_datastore::{DataStore, DataBlob};
+use pbs_datastore::{DataStore, DataBlob, SnapshotReader};
 
-use crate::backup::SnapshotReader;
 use crate::tape::CatalogSet;
 
 /// Chunk iterator which use a separate thread to read chunks