public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Christian Ebner <c.ebner@proxmox.com>
To: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>,
	pbs-devel@lists.proxmox.com
Subject: Re: [pbs-devel] [PATCH v3 proxmox-backup 43/58] client: pxar: implement store to insert chunks on caching
Date: Tue, 9 Apr 2024 11:12:14 +0200	[thread overview]
Message-ID: <d7ffe9c0-1638-4e30-b5cb-cfe3a6bf01a5@proxmox.com> (raw)
In-Reply-To: <171230352147.1926770.11495722007301966318@yuna.proxmox.com>

On 4/5/24 09:52, Fabian Grünbichler wrote:
> Quoting Christian Ebner (2024-03-28 13:36:52)
>> In preparation for the look-ahead caching used to temprarily store
>> entries before encoding them in the pxar archive, being able to
>> decide wether to re-use or re-encode regular file entries.
>>
>> Allows to insert and store reused chunks in the archiver,
>> deduplicating chunks upon insert when possible.
>>
>> Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
>> ---
>> changes since version 2:
>> - Strongly adapted and refactored: keep track also of paddings
>>    introduced by reusing the chunks, making a suggestion whether to
>>    re-use, re-encode or check next entry based on threshold
>> - completely removed code which allowed to calculate offsets based on
>>    chunks found in the middle, they must either be a continuation of the
>>    end or be added after, otherwise offsets are not monotonically
>>    increasing, which is required for sequential restore
>>
>>   pbs-client/src/pxar/create.rs | 126 +++++++++++++++++++++++++++++++++-
>>   1 file changed, 125 insertions(+), 1 deletion(-)
>>
>> diff --git a/pbs-client/src/pxar/create.rs b/pbs-client/src/pxar/create.rs
>> index 335e3556f..95a91a59b 100644
>> --- a/pbs-client/src/pxar/create.rs
>> +++ b/pbs-client/src/pxar/create.rs
>> @@ -20,7 +20,7 @@ use pathpatterns::{MatchEntry, MatchFlag, MatchList, MatchType, PatternFlag};
>>   use pbs_datastore::index::IndexFile;
>>   use proxmox_sys::error::SysError;
>>   use pxar::accessor::aio::Accessor;
>> -use pxar::encoder::{LinkOffset, SeqWrite};
>> +use pxar::encoder::{LinkOffset, PayloadOffset, SeqWrite};
>>   use pxar::Metadata;
>>   
>>   use proxmox_io::vec;
>> @@ -36,6 +36,128 @@ use crate::pxar::metadata::errno_is_unsupported;
>>   use crate::pxar::tools::assert_single_path_component;
>>   use crate::pxar::Flags;
>>   
>> +const CHUNK_PADDING_THRESHOLD: f64 = 0.1;
>> +
>> +#[derive(Default)]
>> +struct ReusedChunks {
>> +    start_boundary: PayloadOffset,
>> +    total: PayloadOffset,
>> +    padding: u64,
>> +    chunks: Vec<(u64, ReusableDynamicEntry)>,
>> +    must_flush_first: bool,
>> +    suggestion: Suggested,
>> +}
>> +
>> +#[derive(Copy, Clone, Default)]
>> +enum Suggested {
>> +    #[default]
>> +    CheckNext,
>> +    Reuse,
>> +    Reencode,
>> +}
> 
> this is a bit of a misnomer - it's not a suggestion, it's what is going to
> happen ;) maybe `action` or even `result` or something similar might be a
> better fit? or something going into the direction of "decision"?
> 

Renamed this to `Action`, as this seemed better fitting of the two 
suggested options, and I could not come up with a better name.

>> +
>> +impl ReusedChunks {
>> +    fn new() -> Self {
>> +        Self::default()
>> +    }
> 
> this is not needed, can just use default()

Removed

> 
>> +
>> +    fn start_boundary(&self) -> PayloadOffset {
>> +        self.start_boundary
>> +    }
> 
> is this needed? access is only local anyway, and we don't have a similar helper
> for self.chunks ;)

Yes, removed it... my intention was to move this maybe to a different 
sub-module, but in the end it remained where it is now.

> 
>> +
>> +    fn is_empty(&self) -> bool {
>> +        self.chunks.is_empty()
>> +    }
>> +
>> +    fn suggested(&self) -> Suggested {
>> +        self.suggestion
> 
> same question here..

same as above

> 
>> +    }
>> +
>> +    fn insert(
>> +        &mut self,
>> +        indices: Vec<ReusableDynamicEntry>,
>> +        boundary: PayloadOffset,
>> +        start_padding: u64,
>> +        end_padding: u64,
>> +    ) -> PayloadOffset {
> 
> another fn that definitely would benefit from some comments describing the
> thought processes behind the logic :)

added some more explanation as comments

> 
>> +        if self.is_empty() {
>> +            self.start_boundary = boundary;
>> +        }
> 
> okay, so this is actually just set
> 
>> +
>> +        if let Some(offset) = self.last_digest_matched(&indices) {
>> +            if let Some((padding, last)) = self.chunks.last_mut() {
> 
> we already know a last chunk must exist (else last_digest_matched wouldn't have
> returned). that means last_digest_matched could just return the last chunk?

True, but than there is the mutable reference of self blocking further 
modifications, therefore kept this as is.

> 
>> +                // Existing chunk, update padding based on pre-existing one
>> +                // Start padding is expected to be larger than previous padding
> 
> should we validate this expectation? or is it already validated somewhere else?
> and also, isn't start_padding by definition always smaller than last.size()?

Will opt for incorporating the padding into the `ReusableDynamicEntry` 
itself, therefore not needing to check this independently, as it is then 
inherent.

> 
>> +                *padding += start_padding - last.size();
>> +                self.padding += start_padding - last.size();
> 
> (see below) here we correct the per-chunk padding, but only for a partial chunk that is continued..
> 
> if I understand this part correctly, here we basically want to adapt from a
> potential end_padding of the last chunk, if it was:
> 
> A|A|A|P|P|P|P
> 
> and we now have
> 
> P|P|P|P|P|B|B
> 
> we want to end up with just 2 'P's in the middle? isn't start_padding - size
> the count of the payload? so what we actually want is
> 
> *padding -= (last.size() - start_padding)
> 
> ? IMHO that makes the intention much more readable, especially if you factor out

Yes, in this case it was possible to deduplicate the first chunk of the 
list to append, meaning that at least the last chunk of the last file 
and the first chunk of the new file are the same (this if both files are 
fully or partially contained within this chunk).

Therefore the chunk is not inserted again, but rather the padding of the 
already present entry updated, by first subtracting the used and 
possible end_padding (note that this is not equal to the payload size, 
which might even cover more than one chunk), the end_padding being 
readded afterwards.

> 
> let payload_size = last.size() - start_padding;
> *padding -= payload_size;
> self.padding -= payload_size;

makes it more readable, agreed, but this is not the payload_size, so 
this will be referred to as remaining in the upcoming version of the 
patches.

So we have:

chunk_size = start_padding + used + end_padding

and call:

remaining = used + end_padding = chunk_size - start_padding

where these can be start_padding >= 0 and end_padding >=0 if all the 
payload is contained within one chunk. If the file payload covers 
multiple chunks, this is covered by updating the corresponding paddings 
for just the start and end chunk in the list.

> 
> if we want to be extra careful, we could even add the three checks/assertions here:
> - start_padding must be smaller than the chunk size
> - both chunk and total padding must be bigger than the payload size
> 
>> +            }
>> +
>> +            for chunk in indices.into_iter().skip(1) {
>> +                self.total = self.total.add(chunk.size());
>> +                self.chunks.push((0, chunk));
> 
> here we push the second and later chunks with 0 padding
> 
>> +            }
>> +
>> +            if let Some((padding, _last)) = self.chunks.last_mut() {
>> +                *padding += end_padding;
>> +                self.padding += end_padding;
> 
> and here we account for the end_padding of the last chunk, which might actually
> be the same as the first chunk, but that works out..

Yes, this is intentionally updated here, to not have to double account 
for the end padding if there is only that one chunk, as it is 
in-depended of whether this is also the first chunk.

> 
>> +            }
>> +
>> +            let padding_ratio = self.padding as f64 / self.total.raw() as f64;
>> +            if self.chunks.len() > 1 && padding_ratio < CHUNK_PADDING_THRESHOLD {
>> +                self.suggestion = Suggested::Reuse;
>> +            }
> 
> see below
> 
>> +
>> +            self.start_boundary.add(offset + start_padding)
>> +        } else {
>> +            let offset = self.total.raw();
>> +
>> +            if let Some(first) = indices.first() {
>> +                self.total = self.total.add(first.size());
>> +                self.chunks.push((start_padding, first.clone()));
>> +                // New chunk, all start padding counts
>> +                self.padding += start_padding;
>> +            }
>> +
>> +            for chunk in indices.into_iter().skip(1) {
>> +                self.total = self.total.add(chunk.size());
>> +                self.chunks.push((chunk.size(), chunk));
> 
> so here we count the full chunk size as padding (for the per-chunk stats), but
> don't count it for the total padding? I think this should be 0 just like above?

Yes, this is indeed incorrect and should be set to 0 here. These chunks 
don't add padding since they are fully used.

> 
> this and the handling of the first chunk could actually be combined:
> 
> for (idx, chunk) in indices.into_iter().enumerate() {
> 	self.total = self.total.add(chunk.size());
> 	let chunk_padding = if idx == 0 { self.padding += start_padding; start_padding } else { 0 };
> 	self.chunks.push((chunk_padding, chunk));
> }

Yeah, that is more compact, requires however the index check for each 
item in the iteration? But that should not be that much cost I guess. 
Will also add the end_padding accounting in here using the same logic

> 
> or we could make start_padding mut, and do
> 
> self.padding += start_padding;
> for chunk in indices.into_iter() {
> 	self.total = self.total.add(chunk.size());
> 	self.chunks.push((start_padding, chunk));
> 	start_padding = 0; // only first chunk counts
> }
> 
>> +            }
>> +
>> +            if let Some((padding, _last)) = self.chunks.last_mut() {
>> +                *padding += end_padding;
>> +                self.padding += end_padding;
>> +            }
>> +
>> +            if self.chunks.len() > 2 {
> 
> so if we insert more than two chunks without a continuation, all of them are
> accounted for as full of padding but they are still re-used if start and end
> padding are below the threshold ;)

If a file covers more than one chunk, adding less than the given 
threshold value in padding, than it should be reused, yes. Now that the 
paddings are actually set correctly for this branch, that is the intention.

> 
>> +                let padding_ratio = self.padding as f64 / self.total.raw() as f64;
>> +                if padding_ratio < CHUNK_PADDING_THRESHOLD {
>> +                    self.suggestion = Suggested::Reuse;
>> +                } else {
>> +                    self.suggestion = Suggested::Reencode;
>> +                }
> 
> we could just return the suggestion instead of storing it - it's only ever needed right after `insert` anyway?

Agreed, opted for that one

> 
> this calculation above seems to not handle some corner cases though.
> 
>   if I have the following sequence
> 
> |P|A|A|A|A|A|B|P|P|P|P|P|
> |    C1     |    C2     |
> 
> where P represent padding parts, A and B are file contents of two files, and C1
> and C2 are two chunks. let's say both A and B are re-usable files. first A is
> resolved via the index and inserted, but since it's the first chunk, there is
> no "suggestion" yet (CheckNext). now B is resolved and inserted - it doesn't
> continue a partial previous chunk, so we take the else branch. but now the
> (total) padding ratio is skewed because of B, even though A on its own would
> have been perfectly fine to be re-used.. (let's say we then insert another
> chunk different to C1 and C2, depending on the exact ratios that one might lead
> to the whole sequence being re-used or not, even though C2 should not be
> re-used, C1 should, and the hypothetical C3 might or might not!)
> 
> basically, as soon as we have a break in the chunk sequence (file A followed by
> file B, with no chunk overlap) we can treat each part on its own?

True, adapted the check here so that already the single chunk padding 
threshold reach results in a reuse.





  reply	other threads:[~2024-04-09  9:12 UTC|newest]

Thread overview: 122+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-28 12:36 [pbs-devel] [PATCH v3 pxar proxmox-backup 00/58] fix #3174: improve file-level backup Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 01/58] encoder: fix two typos in comments Christian Ebner
2024-04-03  9:12   ` [pbs-devel] applied: " Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 02/58] format/examples: add PXAR_PAYLOAD_REF entry header Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 03/58] decoder: add method to read payload references Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 04/58] decoder: factor out skip part from skip_entry Christian Ebner
2024-04-03  9:18   ` Fabian Grünbichler
2024-04-03 11:02     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 05/58] encoder: add optional output writer for file payloads Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 06/58] encoder: move to stack based state tracking Christian Ebner
2024-04-03  9:54   ` Fabian Grünbichler
2024-04-03 11:01     ` Christian Ebner
2024-04-04  8:48       ` Fabian Grünbichler
2024-04-04  9:04         ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 07/58] decoder/accessor: add optional payload input stream Christian Ebner
2024-04-03 10:38   ` Fabian Grünbichler
2024-04-03 11:47     ` Christian Ebner
2024-04-03 12:18     ` Christian Ebner
2024-04-04  8:46       ` Fabian Grünbichler
2024-04-04  9:49         ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 08/58] encoder: add payload reference capability Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 09/58] encoder: add payload position capability Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 10/58] encoder: add payload advance capability Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 11/58] encoder/format: finish payload stream with marker Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 12/58] format: add payload stream start marker Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 13/58] format: add pxar format version entry Christian Ebner
2024-04-03 11:41   ` Fabian Grünbichler
2024-04-03 13:31     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 pxar 14/58] format/encoder/decoder: add entry type cli params Christian Ebner
2024-04-03 12:01   ` Fabian Grünbichler
2024-04-03 14:41     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 15/58] client: pxar: switch to stack based encoder state Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 16/58] client: backup writer: only borrow http client Christian Ebner
2024-04-08  9:04   ` [pbs-devel] applied: " Fabian Grünbichler
2024-04-08  9:17     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 17/58] client: backup: factor out extension from backup target Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 18/58] client: backup: early check for fixed index type Christian Ebner
2024-04-08  9:05   ` [pbs-devel] applied: " Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 19/58] client: pxar: combine writer params into struct Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 20/58] client: backup: split payload to dedicated stream Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 21/58] client: helper: add helpers for creating reader instances Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 22/58] client: helper: add method for split archive name mapping Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 23/58] client: restore: read payload from dedicated index Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 24/58] tools: cover meta extension for pxar archives Christian Ebner
2024-04-04  9:01   ` Fabian Grünbichler
2024-04-04  9:06     ` Christian Ebner
2024-04-04  9:10       ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 25/58] restore: " Christian Ebner
2024-04-04  9:02   ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 26/58] client: mount: make split pxar archives mountable Christian Ebner
2024-04-04  9:43   ` Fabian Grünbichler
2024-04-04 13:29     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 27/58] api: datastore: refactor getting local chunk reader Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 28/58] api: datastore: attach optional payload " Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 29/58] catalog: shell: factor out pxar fuse reader instantiation Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 30/58] catalog: shell: redirect payload reader for split streams Christian Ebner
2024-04-04  9:49   ` Fabian Grünbichler
2024-04-04 15:52     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 31/58] www: cover meta extension for pxar archives Christian Ebner
2024-04-04 10:01   ` Fabian Grünbichler
2024-04-04 14:51     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 32/58] pxar: add optional payload input for achive restore Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 33/58] pxar: add more context to extraction error Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 34/58] client: pxar: include payload offset in output Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 35/58] pxar: show padding in debug output on archive list Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 36/58] datastore: dynamic index: add method to get digest Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 37/58] client: pxar: helper for lookup of reusable dynamic entries Christian Ebner
2024-04-04 12:54   ` Fabian Grünbichler
2024-04-04 17:13     ` Christian Ebner
2024-04-05  7:22       ` Christian Ebner
2024-04-05 11:28   ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 38/58] upload stream: impl reused chunk injector Christian Ebner
2024-04-04 14:24   ` Fabian Grünbichler
2024-04-05 10:26     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 39/58] client: chunk stream: add struct to hold injection state Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 40/58] client: chunk stream: add dynamic entries injection queues Christian Ebner
2024-04-04 14:52   ` Fabian Grünbichler
2024-04-08 13:54     ` Christian Ebner
2024-04-09  7:19       ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 41/58] specs: add backup detection mode specification Christian Ebner
2024-04-04 14:54   ` Fabian Grünbichler
2024-04-08 13:36     ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 42/58] client: implement prepare reference method Christian Ebner
2024-04-05  8:01   ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 43/58] client: pxar: implement store to insert chunks on caching Christian Ebner
2024-04-05  7:52   ` Fabian Grünbichler
2024-04-09  9:12     ` Christian Ebner [this message]
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 44/58] client: pxar: add previous reference to archiver Christian Ebner
2024-04-04 15:04   ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 45/58] client: pxar: add method for metadata comparison Christian Ebner
2024-04-05  8:08   ` Fabian Grünbichler
2024-04-05  8:14     ` Christian Ebner
2024-04-09 12:52       ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 46/58] pxar: caching: add look-ahead cache types Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 47/58] client: pxar: add look-ahead caching Christian Ebner
2024-04-05  8:33   ` Fabian Grünbichler
2024-04-09 14:53     ` Christian Ebner
     [not found]       ` <<dce38c53-f3e7-47ac-b1fd-a63daaabbcec@proxmox.com>
2024-04-10  7:03         ` Fabian Grünbichler
2024-04-10  7:11           ` Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 48/58] fix #3174: client: pxar: enable caching and meta comparison Christian Ebner
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 49/58] client: backup: increase average chunk size for metadata Christian Ebner
2024-04-05  9:42   ` Fabian Grünbichler
2024-04-05 10:49     ` Dietmar Maurer
2024-04-08  8:28       ` Fabian Grünbichler
2024-03-28 12:36 ` [pbs-devel] [PATCH v3 proxmox-backup 50/58] client: backup writer: add injected chunk count to stats Christian Ebner
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 51/58] pxar: create: show chunk injection stats debug output Christian Ebner
2024-04-05  9:47   ` Fabian Grünbichler
2024-04-10 10:00     ` Christian Ebner
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 52/58] client: pxar: add entry kind format version Christian Ebner
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 53/58] client: pxar: opt encode cli exclude patterns as CliParams Christian Ebner
2024-04-05  9:49   ` Fabian Grünbichler
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 54/58] client: pxar: add flow chart for metadata change detection Christian Ebner
2024-04-05 10:16   ` Fabian Grünbichler
2024-04-10 10:04     ` Christian Ebner
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 55/58] docs: describe file format for split payload files Christian Ebner
2024-04-05 10:26   ` Fabian Grünbichler
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 56/58] docs: add section describing change detection mode Christian Ebner
2024-04-05 11:22   ` Fabian Grünbichler
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 57/58] test-suite: add detection mode change benchmark Christian Ebner
2024-03-28 12:37 ` [pbs-devel] [PATCH v3 proxmox-backup 58/58] test-suite: add bin to deb, add shell completions Christian Ebner
2024-04-05 11:39 ` [pbs-devel] [PATCH v3 pxar proxmox-backup 00/58] fix #3174: improve file-level backup Fabian Grünbichler
2024-04-29 12:13 ` 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=d7ffe9c0-1638-4e30-b5cb-cfe3a6bf01a5@proxmox.com \
    --to=c.ebner@proxmox.com \
    --cc=f.gruenbichler@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