diff --git a/NEWS b/NEWS index 0c524299..4b9b3fb0 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ * #1054: Allow the Btrfs hook to create and delete snapshots even when running as a non-root user. See the documentation for more information: https://torsion.org/borgmatic/reference/configuration/data-sources/btrfs/#non-root-user + * #1122: To prevent the user from inadvertently excluding the "bootstrap" action's manifest, always + error and exit when the borgmatic runtime directory overlaps with the configured excludes. * #1179: Add a "file_list_format" option for setting the "list" action's output format and an "archive_list_format" option for setting the "repo-list" action's format. * #1192: Fix for over-aggressive deduplication of source directories that contain the borgmatic @@ -24,8 +26,8 @@ * #1203: Fix that errors and exits when the borgmatic runtime directory is partially excluded by configured excludes. Previously, borgmatic only errored when the runtime directory was completely excluded. - * #1122: To prevent the user from inadvertently excluding the "bootstrap" action's manifest, always - error and exit when the borgmatic runtime directory overlaps with the configured excludes. + * #1206: Adjust Btrfs snapshot paths so that Borg 1.x gets file cache hits when backing them up, + improving performance. * Update the sample systemd timer with a shorter random delay when catching up on a missed run. 2.0.12 diff --git a/borgmatic/hooks/data_source/btrfs.py b/borgmatic/hooks/data_source/btrfs.py index 20538296..cab8beb9 100644 --- a/borgmatic/hooks/data_source/btrfs.py +++ b/borgmatic/hooks/data_source/btrfs.py @@ -193,16 +193,16 @@ def make_snapshot_exclude_pattern(subvolume_path): # pragma: no cover directory within the snapshot itself. For instance, if you have a Btrfs subvolume at /mnt and make a snapshot of it at: - /mnt/.borgmatic-snapshot-1234/mnt + /mnt/.borgmatic-snapshot/mnt ... then the snapshot itself will have an empty directory at: - /mnt/.borgmatic-snapshot-1234/mnt/.borgmatic-snapshot-1234 + /mnt/.borgmatic-snapshot/mnt/.borgmatic-snapshot So to prevent that from ending up in the Borg archive, this function produces an exclude pattern to exclude that path. ''' - snapshot_directory = f'{BORGMATIC_SNAPSHOT_PREFIX}{os.getpid()}' + snapshot_directory = f'{BORGMATIC_SNAPSHOT_PREFIX}' return borgmatic.borg.pattern.Pattern( os.path.join( diff --git a/tests/integration/hooks/data_source/test_btrfs.py b/tests/integration/hooks/data_source/test_btrfs.py index 4f932507..796c1ad1 100644 --- a/tests/integration/hooks/data_source/test_btrfs.py +++ b/tests/integration/hooks/data_source/test_btrfs.py @@ -24,7 +24,6 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns(): module.Subvolume('/mnt/subvol2', contained_patterns=(Pattern('/mnt/subvol2'),)), ), ) - flexmock(module.os).should_receive('getpid').and_return(1234) flexmock(module).should_receive('snapshot_subvolume').with_args( 'btrfs', '/mnt/subvol1', diff --git a/tests/unit/hooks/data_source/test_btrfs.py b/tests/unit/hooks/data_source/test_btrfs.py index 46ab36dd..f36886cc 100644 --- a/tests/unit/hooks/data_source/test_btrfs.py +++ b/tests/unit/hooks/data_source/test_btrfs.py @@ -339,8 +339,6 @@ def test_make_snapshot_path_includes_stripped_subvolume_path( subvolume_path, expected_snapshot_path, ): - flexmock(module.os).should_receive('getpid').and_return(1234) - assert module.make_snapshot_path(subvolume_path) == expected_snapshot_path @@ -385,8 +383,6 @@ def test_make_borg_snapshot_pattern_includes_slashdot_hack_and_stripped_pattern_ pattern, expected_pattern, ): - flexmock(module.os).should_receive('getpid').and_return(1234) - assert module.make_borg_snapshot_pattern(subvolume_path, pattern) == expected_pattern @@ -704,16 +700,12 @@ def test_remove_data_source_dumps_deletes_snapshots(): flexmock(module.glob).should_receive('glob').with_args( '/mnt/subvol1/.borgmatic-*/mnt/subvol1', ).and_return( - ( - '/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1', - ), + ('/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',), ) flexmock(module.glob).should_receive('glob').with_args( '/mnt/subvol2/.borgmatic-*/mnt/subvol2', ).and_return( - ( - '/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2', - ), + ('/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',), ) flexmock(module.os.path).should_receive('isdir').with_args( '/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1', @@ -1089,26 +1081,15 @@ def test_remove_data_source_dumps_with_root_subvolume_skips_duplicate_removal(): ('/.borgmatic-snapshot', '/.borgmatic-snapshot'), ) - flexmock(module.os.path).should_receive('isdir').with_args( - '/.borgmatic-snapshot' - ).and_return( - True, - ).and_return(False) - flexmock(module.os.path).should_receive('isdir').with_args( - '/.borgmatic-snapshot' - ).and_return( - True, + flexmock(module.os.path).should_receive('isdir').with_args('/.borgmatic-snapshot').and_return( + True ).and_return(False) - flexmock(module).should_receive('delete_snapshot').with_args( - 'btrfs', '/.borgmatic-snapshot' - ).once() flexmock(module).should_receive('delete_snapshot').with_args( 'btrfs', '/.borgmatic-snapshot' ).once() flexmock(module.os.path).should_receive('isdir').with_args('').and_return(False) - flexmock(module.shutil).should_receive('rmtree').never() module.remove_data_source_dumps(