diff --git a/src/borg/archive.py b/src/borg/archive.py index 584f5f030..172f43cae 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -2079,8 +2079,9 @@ class ArchiveRecreater: if self.recompress and not self.always_recompress and chunk_id in self.cache.chunks: # Check if this chunk is already compressed the way we want it old_chunk = self.key.decrypt(chunk_id, self.repository.get(chunk_id), decompress=False) - if Compressor.detect(old_chunk).name == self.key.compressor.decide(data).name: - # Stored chunk has the same compression we wanted + compressor_cls, level = Compressor.detect(old_chunk) + if compressor_cls.name == self.key.compressor.decide(data).name and level == self.key.compressor.level: + # Stored chunk has the same compression method and level as we wanted overwrite = False chunk_entry = self.cache.add_chunk(chunk_id, data, target.stats, overwrite=overwrite, wait=False) self.cache.repository.async_response(wait=False) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index f4f2ef355..c4831b875 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -4801,9 +4801,8 @@ class Archiver: help='recompress data chunks according to `MODE` and ``--compression``. ' 'Possible modes are ' '`if-different`: recompress if current compression is with a different ' - 'compression algorithm (the level is not considered); ' - '`always`: recompress even if current compression is with the same ' - 'compression algorithm (use this to change the compression level); and ' + 'compression algorithm or different level; ' + '`always`: recompress unconditionally; and ' '`never`: do not recompress (use this option to explicitly prevent ' 'recompression). ' 'If no MODE is given, `if-different` will be used. ' diff --git a/src/borg/compress.pyx b/src/borg/compress.pyx index c63a04df3..824b11402 100644 --- a/src/borg/compress.pyx +++ b/src/borg/compress.pyx @@ -66,6 +66,7 @@ cdef class CompressorBase: def __init__(self, level=255, **kwargs): assert 0 <= level <= 255 + self.level = level if self.ID is not None: self.id_level = self.ID + bytes((level, )) # level 255 means "unknown level" assert len(self.id_level) == 2 @@ -539,7 +540,8 @@ class ObfuscateSize(CompressorBase): compr_size = self.header_fmt.unpack(obfuscated_data[0:self.header_len])[0] compressed_data = obfuscated_data[self.header_len:self.header_len+compr_size] if self.compressor is None: - self.compressor = Compressor.detect(compressed_data)() + compressor_cls = Compressor.detect(compressed_data)[0] + self.compressor = compressor_cls() return self.compressor.decompress(compressed_data) # decompress data @@ -578,15 +580,16 @@ class Compressor: return self.compressor.compress(data) def decompress(self, data): - compressor_cls = self.detect(data) + compressor_cls = self.detect(data)[0] return compressor_cls(**self.params).decompress(data) @staticmethod def detect(data): hdr = bytes(data[:2]) # detect() does not work with memoryview + level = hdr[1] # usually the level, but not for zlib_legacy for cls in COMPRESSOR_LIST: if cls.detect(hdr): - return cls + return cls, (255 if cls.name == 'zlib_legacy' else level) else: raise ValueError('No decompressor for this data found: %r.', data[:2]) diff --git a/src/borg/testsuite/compress.py b/src/borg/testsuite/compress.py index 3e3730b22..4d6cdafc8 100644 --- a/src/borg/testsuite/compress.py +++ b/src/borg/testsuite/compress.py @@ -133,11 +133,11 @@ def test_auto(): compressed_lz4 = compressor_lz4.compress(data) compressed_zlib = compressor_zlib.compress(data) ratio = len(compressed_zlib) / len(compressed_lz4) - assert Compressor.detect(compressed_auto_zlib) == ZLIB if ratio < 0.99 else LZ4 + assert Compressor.detect(compressed_auto_zlib)[0] == ZLIB if ratio < 0.99 else LZ4 data = b'\x00\xb8\xa3\xa2-O\xe1i\xb6\x12\x03\xc21\xf3\x8a\xf78\\\x01\xa5b\x07\x95\xbeE\xf8\xa3\x9ahm\xb1~' compressed = compressor_auto_zlib.compress(data) - assert Compressor.detect(compressed) == CNONE + assert Compressor.detect(compressed)[0] == CNONE def test_obfuscate():