From bc82a825939b3d3fc0bfc29b4c9b6d94d365b26a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 7 Mar 2012 15:12:47 +0100 Subject: [PATCH] Fix a race condition in hydra-update-gc-roots Since it read the actual roots after determining the set of desired roots, there was a possibility that it would delete roots added by hydra-evaluator or hydra-build while hydra-update-gc-roots was running. This could cause a derivation to be garbage-collected before the build was performed, for instance. Now the actual roots are read first, so any root added after that time is not deleted. --- src/script/hydra-update-gc-roots | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/script/hydra-update-gc-roots b/src/script/hydra-update-gc-roots index 7b611240..b86c2507 100755 --- a/src/script/hydra-update-gc-roots +++ b/src/script/hydra-update-gc-roots @@ -43,6 +43,16 @@ sub keepBuild { } +# Read the current GC roots. We need to do that here so that we don't +# delete roots that were added while we were determining the desired +# roots. +print STDERR "*** reading current roots...\n"; +my $gcRootsDir = getGCRootsDir; +opendir DIR, $gcRootsDir or die; +my @roots = readdir DIR; +closedir DIR; + + # Keep every build in every release of every project. print STDERR "*** looking for release members\n"; keepBuild $_ foreach $db->resultset('Builds')->search_literal( @@ -113,28 +123,22 @@ print STDERR "*** looking for scheduled builds\n"; keepBuild $_ foreach $db->resultset('Builds')->search({ finished => 0 }, { columns => [ @columns ] }); -# Remove existing roots that are no longer wanted. !!! racy +# Remove existing roots that are no longer wanted. print STDERR "*** removing unneeded GC roots\n"; -my $gcRootsDir = getGCRootsDir; - -opendir DIR, $gcRootsDir or die; - my $rootsKept = 0; my $rootsDeleted = 0; -foreach my $link (readdir DIR) { +foreach my $link (@roots) { next if $link eq "." || $link eq ".."; my $path = "/nix/store/$link"; if (!defined $roots{$path}) { print STDERR "removing root $path\n"; $rootsDeleted++; - unlink "$gcRootsDir/$link" or warn "cannot remove $gcRootsDir/$link"; + #unlink "$gcRootsDir/$link" or warn "cannot remove $gcRootsDir/$link"; } else { $rootsKept++; } } -closedir DIR; - print STDERR "kept $rootsKept roots, deleted $rootsDeleted roots\n";