From 9f6afb337540c56b60e7c0d9f5da3f3b712693b8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 21 Feb 2017 18:11:53 +0100 Subject: [PATCH] Lock paths in the scm cache This is necessary now that hydra-evaluator runs multiple evaluations in parallel, to prevent corruption of Git/Mercurial clones. --- src/lib/Hydra/Plugin/GitInput.pm | 40 ++++++++++++-------------- src/lib/Hydra/Plugin/MercurialInput.pm | 4 +++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/lib/Hydra/Plugin/GitInput.pm b/src/lib/Hydra/Plugin/GitInput.pm index f7322b9d..1be98361 100644 --- a/src/lib/Hydra/Plugin/GitInput.pm +++ b/src/lib/Hydra/Plugin/GitInput.pm @@ -7,6 +7,7 @@ use File::Path; use Hydra::Helper::Nix; use Nix::Store; use Encode; +use Fcntl qw(:flock); sub supportedInputTypes { my ($self, $inputTypes) = @_; @@ -18,14 +19,28 @@ sub _isHash { return length($rev) == 40 && $rev =~ /^[0-9a-f]+$/; } -# Clone or update a branch of a repository into our SCM cache. -sub _cloneRepo { - my ($self, $uri, $branch, $deepClone) = @_; +sub _parseValue { + my ($value) = @_; + (my $uri, my $branch, my $deepClone) = split ' ', $value; + $branch = defined $branch ? $branch : "master"; + return ($uri, $branch, $deepClone); +} +sub fetchInput { + my ($self, $type, $name, $value) = @_; + + return undef if $type ne "git"; + + my ($uri, $branch, $deepClone) = _parseValue($value); + + # Clone or update a branch of the repository into our SCM cache. my $cacheDir = getSCMCacheDir . "/git"; mkpath($cacheDir); my $clonePath = $cacheDir . "/" . sha256_hex($uri); + open(my $lock, ">", "$clonePath.lock") or die; + flock($lock, LOCK_EX) or die; + my $res; if (! -d $clonePath) { # Clone everything and fetch the branch. @@ -61,25 +76,6 @@ sub _cloneRepo { } } - return $clonePath; -} - -sub _parseValue { - my ($value) = @_; - (my $uri, my $branch, my $deepClone) = split ' ', $value; - $branch = defined $branch ? $branch : "master"; - return ($uri, $branch, $deepClone); -} - -sub fetchInput { - my ($self, $type, $name, $value) = @_; - - return undef if $type ne "git"; - - my ($uri, $branch, $deepClone) = _parseValue($value); - - my $clonePath = $self->_cloneRepo($uri, $branch, $deepClone); - my $timestamp = time; my $sha256; my $storePath; diff --git a/src/lib/Hydra/Plugin/MercurialInput.pm b/src/lib/Hydra/Plugin/MercurialInput.pm index b6f6c5af..372a20d9 100644 --- a/src/lib/Hydra/Plugin/MercurialInput.pm +++ b/src/lib/Hydra/Plugin/MercurialInput.pm @@ -6,6 +6,7 @@ use Digest::SHA qw(sha256_hex); use File::Path; use Hydra::Helper::Nix; use Nix::Store; +use Fcntl qw(:flock); sub supportedInputTypes { my ($self, $inputTypes) = @_; @@ -40,6 +41,9 @@ sub fetchInput { my $clonePath = _clonePath($uri); + open(my $lock, ">", "$clonePath.lock") or die; + flock($lock, LOCK_EX) or die; + if (! -d $clonePath) { (my $res, $stdout, $stderr) = captureStdoutStderr(600, "hg", "clone", $uri, $clonePath);