about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-07-09 03:18:34 +0000
committerEric Wong <e@80x24.org>2016-07-09 03:20:24 +0000
commitf89bd1444a595b569606679293d2d01b0b7a049e (patch)
treefbb8007c319f0655adbc1245dfff48bd441c720f /lib/PublicInbox
parent239514fd687eb88d023b67de1daccaf2e440e884 (diff)
downloadpublic-inbox-f89bd1444a595b569606679293d2d01b0b7a049e.tar.gz
And bump the default limit to 32 so we match git-daemon
behavior.  This shall allow us to configure different levels
of concurrency for different repositories and prevent clones
of giant repos from stalling service to small repos.
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/GitHTTPBackend.pm6
-rw-r--r--lib/PublicInbox/Qspawn.pm38
2 files changed, 33 insertions, 11 deletions
diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm
index ebb0850a..ed8fdf00 100644
--- a/lib/PublicInbox/GitHTTPBackend.pm
+++ b/lib/PublicInbox/GitHTTPBackend.pm
@@ -13,6 +13,9 @@ use HTTP::Status qw(status_message);
 use Plack::Util;
 use PublicInbox::Qspawn;
 
+# 32 is same as the git-daemon connection limit
+my $default_limiter = PublicInbox::Qspawn::Limiter->new(32);
+
 # n.b. serving "description" and "cloneurl" should be innocuous enough to
 # not cause problems.  serving "config" might...
 my @text = qw[HEAD info/refs
@@ -176,6 +179,7 @@ sub prepare_range {
 # returns undef if 403 so it falls back to dumb HTTP
 sub serve_smart {
         my ($env, $git, $path) = @_;
+        my $limiter = $default_limiter;
         my $in = $env->{'psgi.input'};
         my $fd = eval { fileno($in) };
         unless (defined $fd && $fd >= 0) {
@@ -248,7 +252,7 @@ sub serve_smart {
                 # holding the input here is a waste of FDs and memory
                 $env->{'psgi.input'} = undef;
 
-                $x->start(sub { # may run later, much later...
+                $x->start($limiter, sub { # may run later, much later...
                         ($rpipe) = @_;
                         $in = undef;
                         if ($async) {
diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm
index 9299096a..cc9c340d 100644
--- a/lib/PublicInbox/Qspawn.pm
+++ b/lib/PublicInbox/Qspawn.pm
@@ -1,12 +1,14 @@
 # Copyright (C) 2016 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# Limits the number of processes spawned
+# This does not depend on Danga::Socket or any other external
+# scheduling mechanism, you just need to call start and finish
+# appropriately
 package PublicInbox::Qspawn;
 use strict;
 use warnings;
 use PublicInbox::Spawn qw(popen_rd);
-our $LIMIT = 1;
-my $running = 0;
-my @run_queue;
 
 sub new ($$$;) {
         my ($class, $cmd, $env, $opt) = @_;
@@ -16,9 +18,10 @@ sub new ($$$;) {
 sub _do_spawn {
         my ($self, $cb) = @_;
         my $err;
+
         ($self->{rpipe}, $self->{pid}) = popen_rd(@{$self->{args}});
         if (defined $self->{pid}) {
-                $running++;
+                $self->{limiter}->{running}++;
         } else {
                 $self->{err} = $!;
         }
@@ -27,26 +30,41 @@ sub _do_spawn {
 
 sub finish ($) {
         my ($self) = @_;
+        my $limiter = $self->{limiter};
         if (delete $self->{rpipe}) {
                 my $pid = delete $self->{pid};
                 $self->{err} = $pid == waitpid($pid, 0) ? $? :
                                 "PID:$pid still running?";
-                $running--;
+                $limiter->{running}--;
         }
-        if (my $next = shift @run_queue) {
+        if (my $next = shift @{$limiter->{run_queue}}) {
                 _do_spawn(@$next);
         }
         $self->{err};
 }
 
-sub start ($$) {
-        my ($self, $cb) = @_;
+sub start {
+        my ($self, $limiter, $cb) = @_;
+        $self->{limiter} = $limiter;
 
-        if ($running < $LIMIT) {
+        if ($limiter->{running} < $limiter->{limit}) {
                 _do_spawn($self, $cb);
         } else {
-                push @run_queue, [ $self, $cb ];
+                push @{$limiter->{run_queue}}, [ $self, $cb ];
         }
 }
 
+package PublicInbox::Qspawn::Limiter;
+use strict;
+use warnings;
+
+sub new {
+        my ($class, $limit) = @_;
+        bless {
+                limit => $limit || 1,
+                running => 0,
+                run_queue => [],
+        }, $class;
+}
+
 1;