X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FGit.pm;h=96627daa19735106f31308be686d8c37961661b4;hb=44fbd4169f7434442dbf57851232edafa6fd0e46;hp=395add1fecee08305e6748b989a341b89b0b526d;hpb=6dec9bf8c0e1b859703d7a5dfb87052cf4e87846;p=public-inbox.git diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm index 395add1f..96627daa 100644 --- a/lib/PublicInbox/Git.pm +++ b/lib/PublicInbox/Git.pm @@ -28,8 +28,10 @@ our $in_cleanup; our $RDTIMEO = 60_000; # milliseconds our $async_warn; # true in read-only daemons -use constant MAX_INFLIGHT => (POSIX::PIPE_BUF * 3) / - 65; # SHA-256 hex size + "\n" in preparation for git using non-SHA1 +# 512: POSIX PIPE_BUF minimum (see pipe(7)) +# 3: @$inflight is flattened [ $OID, $cb, $arg ] +# 65: SHA-256 hex size + "\n" in preparation for git using non-SHA1 +use constant MAX_INFLIGHT => 512 * 3 / 65; my %GIT_ESC = ( a => "\a", @@ -143,6 +145,7 @@ sub _bidi_pipe { fcntl($out_w, 1031, 4096); fcntl($in_r, 1031, 4096) if $batch eq '--batch-check'; } + $out_w->blocking(0); $self->{$out} = $out_w; $self->{$in} = $in_r; } @@ -201,7 +204,9 @@ sub cat_async_retry ($$) { for (my $i = 0; $i < @$inflight; $i += 3) { $buf .= "$inflight->[$i]\n"; } + $self->{out}->blocking(1); # brand new pipe, should never block print { $self->{out} } $buf or $self->fail("write error: $!"); + $self->{out}->blocking(0); my $req = shift @$inflight; unshift(@$inflight, \$req); # \$ref to indicate retried @@ -303,13 +308,26 @@ sub check_async_begin ($) { $self->{inflight_c} = []; } +sub write_all { + my ($self, $out, $buf, $read_step, $inflight) = @_; + $read_step->($self, $inflight) while @$inflight >= MAX_INFLIGHT; + do { + my $w = syswrite($out, $buf); + if (defined $w) { + return if $w == length($buf); + substr($buf, 0, $w, ''); # sv_chop + } elsif ($! != EAGAIN) { + $self->fail("write: $!"); + } + $read_step->($self, $inflight); + } while (1); +} + sub check_async ($$$$) { my ($self, $oid, $cb, $arg) = @_; my $inflight_c = $self->{inflight_c} // check_async_begin($self); - while (scalar(@$inflight_c) >= MAX_INFLIGHT) { - check_async_step($self, $inflight_c); - } - print { $self->{out_c} } $oid, "\n" or $self->fail("write error: $!"); + write_all($self, $self->{out_c}, $oid."\n", + \&check_async_step, $inflight_c); push(@$inflight_c, $oid, $cb, $arg); } @@ -426,6 +444,7 @@ sub cleanup { scalar(@{$self->{inflight} // []})); local $in_cleanup = 1; delete $self->{async_cat}; + delete $self->{async_chk}; async_wait_all($self); delete $self->{inflight}; delete $self->{inflight_c}; @@ -451,24 +470,26 @@ sub DESTROY { cleanup(@_) } sub local_nick ($) { # don't show full FS path, basename should be OK: - $_[0]->{git_dir} =~ m!/([^/]+?)(?:/*\.git/*)?\z! ? "$1.git" : '???'; + $_[0]->{nick} // ($_[0]->{git_dir} =~ m!/([^/]+?)(?:/*\.git/*)?\z! ? + "$1.git" : undef); } sub host_prefix_url ($$) { my ($env, $url) = @_; return $url if index($url, '//') >= 0; - my $scheme = $env->{'psgi.url_scheme'}; my $host_port = $env->{HTTP_HOST} // "$env->{SERVER_NAME}:$env->{SERVER_PORT}"; - "$scheme://$host_port". ($env->{SCRIPT_NAME} || '/') . $url; + my $sn = $env->{SCRIPT_NAME} // ''; + "$env->{'psgi.url_scheme'}://$host_port$sn/$url"; } sub base_url { # for coderepos, PSGI-only my ($self, $env) = @_; # env - PSGI env + my $nick = $self->{nick} // return undef; my $url = host_prefix_url($env, ''); # for mount in Plack::Builder $url .= '/' if substr($url, -1, 1) ne '/'; - $url . $self->{nick} . '/'; + $url . $nick . '/'; } sub isrch {} # TODO @@ -476,9 +497,10 @@ sub isrch {} # TODO sub pub_urls { my ($self, $env) = @_; if (my $urls = $self->{cgit_url}) { - return map { host_prefix_url($env, $_) } @$urls; + map { host_prefix_url($env, $_) } @$urls; + } else { + (base_url($self, $env) // '???'); } - (local_nick($self)); } sub cat_async_begin { @@ -492,10 +514,7 @@ sub cat_async_begin { sub cat_async ($$$;$) { my ($self, $oid, $cb, $arg) = @_; my $inflight = $self->{inflight} // cat_async_begin($self); - while (scalar(@$inflight) >= MAX_INFLIGHT) { - cat_async_step($self, $inflight); - } - print { $self->{out} } $oid, "\n" or $self->fail("write error: $!"); + write_all($self, $self->{out}, $oid."\n", \&cat_async_step, $inflight); push(@$inflight, $oid, $cb, $arg); }