summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Lebon <jonathan@jlebon.com>2023-01-30 13:45:50 -0500
committerJonathan Lebon <jonathan@jlebon.com>2023-01-30 15:08:27 -0500
commitfb63f7aba8887ca616274abad35db30d93f5839e (patch)
treeb8131253012de4bbbefe25c1db75b338d7e3ee27
parentaf505336c2e95820c98fc8e32bce665d5a03c795 (diff)
downloadostree-fb63f7aba8887ca616274abad35db30d93f5839e.tar.gz
ostree/prune: Calculate reachability under exclusive lock
When we calculate the reachability set in `ostree prune`, we do this without any locking. This means that between the time we build the set and when we call `ostree_repo_prune_from_reachable`, new content might've been added. This then causes us to immediately prune that content since it's not in the now outdated set. Fix this by calculating the set under an exclusive lock. I think this is what happened in https://github.com/fedora-silverblue/issue-tracker/issues/405. While the pruner was running, the `new-updates-sync` script[1] was importing content into the repo. The newly imported commits were immediately deleted by the many `ostree prune --commit-only` calls the pruner does, breaking the refs. [1] https://pagure.io/fedora-infra/ansible/blob/35b35127e444/f/roles/bodhi2/backend/files/new-updates-sync#_18
-rw-r--r--src/ostree/ot-builtin-prune.c9
-rwxr-xr-xtests/test-prune.sh12
2 files changed, 21 insertions, 0 deletions
diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c
index 73dfe5e5..0b4e8698 100644
--- a/src/ostree/ot-builtin-prune.c
+++ b/src/ostree/ot-builtin-prune.c
@@ -208,6 +208,15 @@ ostree_builtin_prune (int argc, char **argv, OstreeCommandInvocation *invocation
}
else
{
+ /* In this branch, we need to compute the reachability set manually.
+ * While we do this, we can't let new content in since it'll race with
+ * reachability calculations and we may immediately nuke it. So push an
+ * exclusive lock now. */
+ g_autoptr(OstreeRepoAutoLock) lock =
+ ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
+ if (!lock)
+ return FALSE;
+
g_autoptr(GHashTable) all_refs = NULL;
g_autoptr(GHashTable) reachable = ostree_repo_traverse_new_reachable ();
g_autoptr(GHashTable) retain_branch_depth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
diff --git a/tests/test-prune.sh b/tests/test-prune.sh
index bbb77a23..0e628405 100755
--- a/tests/test-prune.sh
+++ b/tests/test-prune.sh
@@ -363,4 +363,16 @@ ${CMD_PREFIX} ostree --repo=repo prune --commit-only --keep-younger-than="1 week
assert_repo_has_n_commits repo 4
assert_repo_has_n_non_commit_objects repo ${orig_obj_count}
tap_ok --commit-only and --keep-younger-than
+
+reinitialize_commit_only_test_repo
+for i in {1..10}; do
+ ${CMD_PREFIX} ostree --repo=repo prune --commit-only --keep-younger-than="1 week ago" &
+ commit=$(${CMD_PREFIX} ostree --repo=repo commit --branch foobar tree)
+ wait $!
+ if ! ostree show --repo=repo ${commit}; then
+ assert_not_reached "commit ${commit} on branch foobar was pruned?"
+ fi
+done
+tap_ok commit and prune together
+
tap_end