]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Git.pm
git: pub_urls shows base_url default
[public-inbox.git] / lib / PublicInbox / Git.pm
index 882a9a4ac28815f3dbc920e3344b78781edb9a7d..96627daa19735106f31308be686d8c37961661b4 100644 (file)
@@ -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);
 }
 
@@ -459,18 +477,19 @@ sub local_nick ($) {
 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
@@ -478,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 {
@@ -494,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);
 }