@@ -469,7 +469,10 @@ def __init__(self, repository, key, manifest, name, cache=None, create=False,
469469 self .pipeline = DownloadPipeline (self .repository , self .key )
470470 self .create = create
471471 if self .create :
472- self .items_buffer = CacheChunkBuffer (self .cache , self .key , self .stats )
472+ # Use a separate statistics counter for metadata (items, archive metadata),
473+ # so that archive.stats reflects only file content statistics.
474+ self .meta_stats = Statistics (output_json = False , iec = iec )
475+ self .items_buffer = CacheChunkBuffer (self .cache , self .key , self .meta_stats )
473476 if name in manifest .archives :
474477 raise self .AlreadyExists (name )
475478 i = 0
@@ -605,7 +608,8 @@ def add_item(self, item, show_progress=True, stats=None):
605608 def write_checkpoint (self ):
606609 self .save (self .checkpoint_name )
607610 del self .manifest .archives [self .checkpoint_name ]
608- self .cache .chunk_decref (self .id , self .stats )
611+ # Use meta_stats so metadata chunks do not affect archive.stats
612+ self .cache .chunk_decref (self .id , self .meta_stats if hasattr (self , 'meta_stats' ) else self .stats )
609613
610614 def save (self , name = None , comment = None , timestamp = None , stats = None , additional_metadata = None ):
611615 name = name or self .name
@@ -649,7 +653,8 @@ def save(self, name=None, comment=None, timestamp=None, stats=None, additional_m
649653 data = self .key .pack_and_authenticate_metadata (metadata .as_dict (), context = b'archive' )
650654 self .id = self .key .id_hash (data )
651655 try :
652- self .cache .add_chunk (self .id , data , self .stats )
656+ # Use meta_stats so metadata chunk addition does not skew archive.stats
657+ self .cache .add_chunk (self .id , data , self .meta_stats if hasattr (self , 'meta_stats' ) else self .stats )
653658 except IntegrityError as err :
654659 err_msg = str (err )
655660 # hack to avoid changing the RPC protocol by introducing new (more specific) exception class
@@ -687,21 +692,23 @@ def _calc_stats(self, cache, want_unique=True):
687692 if have_borg12_meta and not want_unique :
688693 unique_csize = 0
689694 else :
690- def add (id ):
691- entry = cache .chunks [id ]
692- archive_index .add (id , 1 , entry .size , entry .csize )
693695
694696 archive_index = ChunkIndex ()
695697 sync = CacheSynchronizer (archive_index )
696- add (self .id )
698+ # do NOT add the archive metadata chunk (self.id) here.
699+ # The metadata chunk is accounted via meta_stats during creation and must not
700+ # contribute to the "This archive" deduplicated size computed by borg info.
701+ # See issue #9003: make info's deduplicated size match create-time stats.
702+
697703 # we must escape any % char in the archive name, because we use it in a format string, see #6500
698704 arch_name_escd = self .name .replace ('%' , '%%' )
699705 pi = ProgressIndicatorPercent (total = len (self .metadata .items ),
700706 msg = 'Calculating statistics for archive %s ... %%3.0f%%%%' % arch_name_escd ,
701707 msgid = 'archive.calc_stats' )
702708 for id , chunk in zip (self .metadata .items , self .repository .get_many (self .metadata .items )):
703709 pi .show (increase = 1 )
704- add (id )
710+ # do NOT add(id) here, this is a metadata stream chunk and should not
711+ # be accounted for in stats, see comment above.
705712 data = self .key .decrypt (id , chunk )
706713 sync .feed (data )
707714 unique_csize = archive_index .stats_against (cache .chunks )[3 ]
0 commit comments