diff options
author | Eric Wong <e@80x24.org> | 2016-03-07 08:10:59 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2016-04-05 18:58:27 +0000 |
commit | 2e8db833263abea68546813d73fb6a0ac6d8db3d (patch) | |
tree | a254810e7953248c722791e285ea8d3d2e702228 /lib/PublicInbox/RepobrowseGitPatch.pm | |
parent | 2d3debbcf3fa4a4f0705624a897cf43547e5bf32 (diff) | |
download | public-inbox-2e8db833263abea68546813d73fb6a0ac6d8db3d.tar.gz |
This should allow better concurrency in case git-format-patch needs to take a long time for merge commits.
Diffstat (limited to 'lib/PublicInbox/RepobrowseGitPatch.pm')
-rw-r--r-- | lib/PublicInbox/RepobrowseGitPatch.pm | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/lib/PublicInbox/RepobrowseGitPatch.pm b/lib/PublicInbox/RepobrowseGitPatch.pm index b67fb86f..b3cf17fe 100644 --- a/lib/PublicInbox/RepobrowseGitPatch.pm +++ b/lib/PublicInbox/RepobrowseGitPatch.pm @@ -26,22 +26,54 @@ sub call_git_patch { if (defined(my $expath = $req->{expath})) { push @cmd, $expath; } - my $fp = $git->popen(@cmd); - my ($buf, $n); + my $rpipe = $git->popen(@cmd); + my $env = $req->{cgi}->env; + my $err = $env->{'psgi.errors'}; + my ($buf, $n, $res, $vin, $fh); + my $end = sub { + if ($fh) { + $fh->close; + $fh = undef; + } elsif ($res) { + $res->($self->r(500)); + } + if ($rpipe) { + $rpipe->close; # _may_ be Danga::Socket::close + $rpipe = undef; + } + }; + my $fail = sub { + if ($!{EAGAIN} || $!{EINTR}) { + select($vin, undef, undef, undef) if defined $vin; + # $vin is undef on async, so this is a noop on EAGAIN + return; + } + my $e = $!; + $end->(); + $err->print("git format-patch ($git->{git_dir}): $e\n"); + }; + my $cb = sub { + $n = $rpipe->sysread($buf, 8192); + return $fail->() unless defined $n; + return $end->() if $n == 0; + if ($res) { + my $h = ['Content-Type', 'text/plain; charset=UTF-8']; + $fh = $res->([200, $h]); + $res = undef; + } + $fh->write($buf) if $fh; + }; - $n = read($fp, $buf, 8192); - return unless (defined $n && $n > 0); - sub { - my ($res) = @_; # Plack callback - my $fh = $res->([200, [ - 'Content-Type' => 'text/plain; charset=UTF-8']]); - $fh->write($buf); - while (1) { - $n = read($fp, $buf, 8192); - last unless (defined $n && $n > 0); - $fh->write($buf); + if (my $async = $env->{'pi-httpd.async'}) { + $rpipe = $async->($rpipe, $cb); + sub { ($res) = @_ } # let Danga::Socket handle the rest. + } else { # synchronous loop for other PSGI servers + $vin = ''; + vec($vin, fileno($rpipe), 1) = 1; + sub { + ($res) = @_; + while ($rpipe) { $cb->() } } - $fh->close; } } |