From 675cd0a98b3815b30b0e4d4e4352debdd5c1eb01 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 28 Apr 2016 21:25:14 -0700 Subject: [PATCH] Working version of forking central commit. Note that due to the fact that Git::Repository calls System::Command, you have to be careful about when you install the child signal handler. You only want it in the parent, after the parent has done its operations with Git commands, and note that the child must also disable the handler. --- extract-code-added-in-commits.plx | 52 ++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/extract-code-added-in-commits.plx b/extract-code-added-in-commits.plx index 74d6347..b047229 100755 --- a/extract-code-added-in-commits.plx +++ b/extract-code-added-in-commits.plx @@ -143,7 +143,7 @@ while (my $line = ) { my %childProcesses; my %finishedOperations; -my $childHandler = sub { +my $HANDLE_BLAME_WORKERS_SUB = sub { # don't change $! and $? outside handler local ($!, $?); while ( (my $pid = waitpid(-1, WNOHANG)) > 0 ) { @@ -155,7 +155,6 @@ my $childHandler = sub { delete $childProcesses{$pid}; } }; -# $SIG{CHLD} = $childHandler; ############################################################################## sub StartChildLog($$) { my($operation, $pid) = @_; @@ -220,23 +219,46 @@ sub RunCentralCommitMode($) { $files{$file} = $commitId if not defined $files{$file}; } } + $SIG{CHLD} = $HANDLE_BLAME_WORKERS_SUB; foreach my $file (keys %files) { my($vv, $path, $filename) = File::Spec->splitpath($file); $path = File::Spec->catfile($centralOutputDir, $path); make_path($path, 0750); - my(@blameData); - eval { - @blameData = $gitRepository->run('blame', '-w', '-f', '-n', '-l', @ADDITIONAL_BLAME_OPTS, - $centralCommitId, '--', $file); - }; - my $err = $@; - if (defined $err and $err =~ /fatal.*no\s+such\s+path/) { - # ignore this file; it isn't present anymore in the central commit. - } elsif (defined $err and $err !~ /^\s*$/) { - die "unrecoverable git blame error: $err"; - } else { - my $f = File::Spec->catfile($path, $filename); - GitBlameDataToFile($f, \@blameData); + my $remainingCount = scalar(keys %childProcesses); + while ($remainingCount >= $FORK_LIMIT) { + print STDERR "Sleep a bit while $remainingCount children going for these commits ", + join(", ", sort values %childProcesses), "\n" if $VERBOSE; + sleep 10; + $remainingCount = scalar(keys %childProcesses); + } + my $forkCount = scalar(keys %childProcesses) + 1; + my $pid = fork(); + die "cannot fork: $!" unless defined $pid; + if ($pid == 0) { # The new child process is here + $SIG{CHLD} = 'DEFAULT'; + my $logFH = StartChildLog($filename, $$); + $0 = "$path/$filename git blame subprocess"; + my(@blameData); + print $logFH "running: git", + 'blame', '-w', '-f', '-n', '-l', @ADDITIONAL_BLAME_OPTS, $centralCommitId, '--', $file, "\n"; + eval { + @blameData = $gitRepository->run('blame', '-w', '-f', '-n', '-l', @ADDITIONAL_BLAME_OPTS, + $centralCommitId, '--', $file); + }; + my $err = $@; + if (defined $err and $err =~ /fatal.*no\s+such\s+path/) { + # ignore this file; it isn't present anymore in the central commit. + } elsif (defined $err and $err !~ /^\s*$/) { + print $logFH "unrecoverable git blame error: $err"; + } else { + my $f = File::Spec->catfile($path, $filename); + GitBlameDataToFile($f, \@blameData); + } + EndChildLog($logFH, $filename, $$); + exit 0; + } else { # The parent is here + $childProcesses{$pid} = $file; + print STDERR "Launched $forkCount child to handle $filename\n" if $VERBOSE; } } }