public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v5 proxmox-backup 27/28] catalog: use format version 2 conditionally
Date: Wed, 15 Nov 2023 16:48:12 +0100	[thread overview]
Message-ID: <20231115154813.281564-28-c.ebner@proxmox.com> (raw)
In-Reply-To: <20231115154813.281564-1-c.ebner@proxmox.com>

Only use the catalog format version 2 when performing backups with the
change detection mode set to metadata.

This makes sure to remain compatible with older clients which do not
support the format version 2 at least for backups created using the
regular mode.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
Changes since version 4:
- not present in version 4

 pbs-datastore/src/catalog.rs      | 71 +++++++++++++++++++++++++------
 proxmox-backup-client/src/main.rs | 29 ++++++++++---
 2 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/pbs-datastore/src/catalog.rs b/pbs-datastore/src/catalog.rs
index fe076a94..93457302 100644
--- a/pbs-datastore/src/catalog.rs
+++ b/pbs-datastore/src/catalog.rs
@@ -65,6 +65,12 @@ pub enum CatalogEntryType {
     Socket = b's',
 }
 
+#[derive(PartialEq)]
+pub enum CatalogFormatVersion {
+    V1,
+    V2,
+}
+
 impl TryFrom<u8> for CatalogEntryType {
     type Error = Error;
 
@@ -556,17 +562,22 @@ pub struct CatalogWriter<W> {
     writer: W,
     dirstack: Vec<DirInfo>,
     pos: u64,
+    version: CatalogFormatVersion,
 }
 
 impl<W: Write> CatalogWriter<W> {
     /// Create a new  CatalogWriter instance
-    pub fn new(writer: W) -> Result<Self, Error> {
+    pub fn new(writer: W, version: CatalogFormatVersion) -> Result<Self, Error> {
         let mut me = Self {
             writer,
             dirstack: vec![DirInfo::new_rootdir()],
             pos: 0,
+            version,
         };
-        me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_2_0)?;
+        match me.version {
+            CatalogFormatVersion::V1 => me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_1_0)?,
+            CatalogFormatVersion::V2 => me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_2_0)?,
+        }
         Ok(me)
     }
 
@@ -600,6 +611,10 @@ impl<W: Write> CatalogWriter<W> {
 
 impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
     fn start_archive(&mut self, name: &CStr) -> Result<(), Error> {
+        if self.version == CatalogFormatVersion::V1 {
+            return self.start_directory(name);
+        }
+
         let new = DirInfo::new(name.to_owned());
         self.dirstack.push(new);
         Ok(())
@@ -609,6 +624,9 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
         &mut self,
         appendix: Option<pxar::encoder::AppendixStartOffset>,
     ) -> Result<(), Error> {
+        if self.version == CatalogFormatVersion::V1 {
+            return self.end_directory();
+        }
         let (start, name) = match self.dirstack.pop() {
             Some(dir) => {
                 let start = self.pos;
@@ -689,17 +707,32 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
             .last_mut()
             .ok_or_else(|| format_err!("outside root"))?;
         let name = name.to_bytes().to_vec();
-        let file_offset = FileOffset {
-            offset: file_offset.raw(),
+        let entry = match self.version {
+            CatalogFormatVersion::V1 => {
+                DirEntry {
+                    name,
+                    attr: DirEntryAttribute::File {
+                        size,
+                        mtime,
+                        extension: None,
+                    },
+                }
+            }
+            CatalogFormatVersion::V2 => {
+                let file_offset = FileOffset {
+                    offset: file_offset.raw(),
+                };
+                DirEntry {
+                    name,
+                    attr: DirEntryAttribute::File {
+                        size,
+                        mtime,
+                        extension: Some(CatalogV2Extension { ctime, file_offset }),
+                    },
+                }
+            }
         };
-        dir.entries.push(DirEntry {
-            name,
-            attr: DirEntryAttribute::File {
-                size,
-                mtime,
-                extension: Some(CatalogV2Extension { ctime, file_offset }),
-            },
-        });
+        dir.entries.push(entry);
         Ok(())
     }
 
@@ -711,6 +744,9 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
         ctime: i64,
         appendix_ref_offset: pxar::encoder::AppendixRefOffset,
     ) -> Result<(), Error> {
+        if self.version == CatalogFormatVersion::V1 {
+            bail!("unsupported by catalog format version 1");
+        }
         let dir = self
             .dirstack
             .last_mut()
@@ -857,6 +893,17 @@ impl<R: Read + Seek> CatalogReader<R> {
         })
     }
 
+    pub fn format_version(&mut self) -> Result<CatalogFormatVersion, Error> {
+        self.reader.seek(SeekFrom::Start(0))?;
+        let mut magic = [0u8; 8];
+        self.reader.read_exact(&mut magic)?;
+        match magic {
+            PROXMOX_CATALOG_FILE_MAGIC_1_0 => Ok(CatalogFormatVersion::V1),
+            PROXMOX_CATALOG_FILE_MAGIC_2_0 => Ok(CatalogFormatVersion::V2),
+            _ => bail!("got unexpected magic number for catalog"),
+        }
+    }
+
     pub fn appendix_offset(
         &mut self,
         archive_name: &[u8],
diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
index 65d3308a..0a2e0c8b 100644
--- a/proxmox-backup-client/src/main.rs
+++ b/proxmox-backup-client/src/main.rs
@@ -49,7 +49,7 @@ use pbs_client::{
     BackupStats, BackupWriter, ChunkStream, FixedChunkStream, HttpClient, PxarBackupStream,
     RemoteChunkReader, UploadOptions, BACKUP_DETECTION_MODE_SPEC, BACKUP_SOURCE_SCHEMA,
 };
-use pbs_datastore::catalog::{CatalogReader, CatalogWriter};
+use pbs_datastore::catalog::{CatalogFormatVersion, CatalogReader, CatalogWriter};
 use pbs_datastore::chunk_store::verify_chunk_size;
 use pbs_datastore::dynamic_index::{BufferedDynamicReader, DynamicIndexReader};
 use pbs_datastore::fixed_index::FixedIndexReader;
@@ -536,6 +536,7 @@ struct CatalogUploadResult {
 fn spawn_catalog_upload(
     client: Arc<BackupWriter>,
     encrypt: bool,
+    catalog_format_version: CatalogFormatVersion,
 ) -> Result<CatalogUploadResult, Error> {
     let (catalog_tx, catalog_rx) = std::sync::mpsc::sync_channel(10); // allow to buffer 10 writes
     let catalog_stream = proxmox_async::blocking::StdChannelStream(catalog_rx);
@@ -549,9 +550,10 @@ fn spawn_catalog_upload(
         injections.clone(),
     );
 
-    let catalog_writer = Arc::new(Mutex::new(CatalogWriter::new(TokioWriterAdapter::new(
-        StdChannelWriter::new(catalog_tx),
-    ))?));
+    let catalog_writer = Arc::new(Mutex::new(CatalogWriter::new(
+        TokioWriterAdapter::new(StdChannelWriter::new(catalog_tx)),
+        catalog_format_version,
+    )?));
 
     let (catalog_result_tx, catalog_result_rx) = tokio::sync::oneshot::channel();
 
@@ -1015,8 +1017,16 @@ async fn create_backup(
             (BackupSpecificationType::PXAR, false) => {
                 // start catalog upload on first use
                 if catalog.is_none() {
-                    let catalog_upload_res =
-                        spawn_catalog_upload(client.clone(), crypto.mode == CryptMode::Encrypt)?;
+                    let catalog_format_version = if let BackupDetectionMode::Metadata(_) = detection_mode {
+                        CatalogFormatVersion::V2
+                    } else {
+                        CatalogFormatVersion::V1
+                    };
+                    let catalog_upload_res = spawn_catalog_upload(
+                        client.clone(),
+                        crypto.mode == CryptMode::Encrypt,
+                        catalog_format_version,
+                    )?;
                     catalog = Some(catalog_upload_res.catalog_writer);
                     catalog_result_rx = Some(catalog_upload_res.result);
                 }
@@ -1214,8 +1224,13 @@ async fn download_reference_catalog(
         .map_err(|err| format_err!("failed to download reference catalog - {}", err))?;
 
     catalogfile.seek(SeekFrom::Start(0))?;
+    let mut reader = CatalogReader::new(catalogfile);
 
-    Ok(CatalogReader::new(catalogfile))
+    match reader.format_version() {
+        Ok(CatalogFormatVersion::V2) => Ok(reader),
+        Ok(CatalogFormatVersion::V1) => Err(format_err!("unsupported catalog format version")),
+        Err(err) => Err(err),
+    }
 }
 
 async fn dump_image<W: Write>(
-- 
2.39.2





  parent reply	other threads:[~2023-11-15 15:48 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-15 15:47 [pbs-devel] [PATCH-SERIES v5 pxar proxmox-backup proxmox-widget-toolkit 00/28] fix #3174: improve file-level backup Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 1/28] fix #3174: decoder: factor out skip_bytes from skip_entry Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 2/28] fix #3174: decoder: impl skip_bytes for sync dec Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 3/28] fix #3174: encoder: calc filename + metadata byte size Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 4/28] fix #3174: enc/dec: impl PXAR_APPENDIX_REF entrytype Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 5/28] fix #3174: enc/dec: impl PXAR_APPENDIX entrytype Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 6/28] fix #3174: encoder: helper to add to encoder position Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 7/28] fix #3174: enc/dec: impl PXAR_APPENDIX_TAIL entrytype Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 pxar 8/28] fix #3174: enc/dec: introduce pxar format version 2 Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 09/28] fix #3174: index: add fn index list from start/end-offsets Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 10/28] fix #3174: index: add fn digest for DynamicEntry Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 11/28] fix #3174: api: double catalog upload size Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 12/28] fix #3174: catalog: introduce extended format v2 Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 13/28] fix #3174: archiver/extractor: impl appendix ref Christian Ebner
2023-11-15 15:47 ` [pbs-devel] [PATCH v5 proxmox-backup 14/28] fix #3174: catalog: add specialized Archive entry Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 15/28] fix #3174: extractor: impl seq restore from appendix Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 16/28] fix #3174: archiver: store ref to previous backup Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 17/28] fix #3174: upload stream: impl reused chunk injector Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 18/28] fix #3174: chunker: add forced boundaries Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 19/28] fix #3174: backup writer: inject queued chunk in upload steam Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 20/28] fix #3174: archiver: reuse files with unchanged metadata Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 21/28] fix #3174: specs: add backup detection mode specification Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 22/28] fix #3174: client: Add detection mode to backup creation Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 23/28] test-suite: add detection mode change benchmark Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 24/28] test-suite: Add bin to deb, add shell completions Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 25/28] catalog: fetch offset and size for files and refs Christian Ebner
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-backup 26/28] pxar: add heuristic to reduce reused chunk fragmentation Christian Ebner
2023-11-15 15:48 ` Christian Ebner [this message]
2023-11-15 15:48 ` [pbs-devel] [PATCH v5 proxmox-widget-toolkit 28/28] file-browser: support pxar archive and fileref types Christian Ebner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231115154813.281564-28-c.ebner@proxmox.com \
    --to=c.ebner@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal