From 2c972f3d70caf99488fff300341450e48be6ebf1 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 9 Jul 2016 03:18:35 +0000 Subject: www: add configurable limiters Currently only for git-http-backend use, this allows limiting the number of spawned processes per-inbox or by group, if there are multiple large inboxes amidst a sea of small ones. For example, a "big" repo limiter could be used for big inboxes: which would be shared between multiple repos: [limiter "big"] max = 4 [publicinbox "git"] address = git@vger.kernel.org mainrepo = /path/to/git.git ; shared limiter with giant: httpbackendmax = big [publicinbox "giant"] address = giant@project.org mainrepo = /path/to/giant.git ; shared limiter with git: httpbackendmax = big ; This is a tiny inbox, use the default limiter with 32 slots: [publicinbox "meta"] address = meta@public-inbox.org mainrepo = /path/to/meta.git --- lib/PublicInbox/Config.pm | 13 ++++++++++++- lib/PublicInbox/GitHTTPBackend.pm | 10 ++++++++-- lib/PublicInbox/Inbox.pm | 25 ++++++++++++++++++++++++- lib/PublicInbox/Qspawn.pm | 7 ++++--- 4 files changed, 48 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm index d34d11ad..d7eaa3e8 100644 --- a/lib/PublicInbox/Config.pm +++ b/lib/PublicInbox/Config.pm @@ -20,6 +20,7 @@ sub new { $self->{-by_addr} ||= {}; $self->{-by_name} ||= {}; $self->{-by_newsgroup} ||= {}; + $self->{-limiters} ||= {}; $self; } @@ -85,6 +86,15 @@ sub lookup_newsgroup { undef; } +sub limiter { + my ($self, $name) = @_; + $self->{-limiters}->{$name} ||= do { + require PublicInbox::Qspawn; + my $key = "limiter.$name.max"; + PublicInbox::Qspawn::Limiter->new($self->{$key}); + }; +} + sub get { my ($self, $inbox, $key) = @_; @@ -131,7 +141,7 @@ sub _fill { my $rv = {}; foreach my $k (qw(mainrepo address filter url newsgroup - watch watchheader)) { + watch watchheader httpbackendmax)) { my $v = $self->{"$pfx.$k"}; $rv->{$k} = $v if defined $v; } @@ -139,6 +149,7 @@ sub _fill { my $name = $pfx; $name =~ s/\Apublicinbox\.//; $rv->{name} = $name; + $rv->{-pi_config} = $self; $rv = PublicInbox::Inbox->new($rv); my $v = $rv->{address}; if (ref($v) eq 'ARRAY') { diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm index ed8fdf00..d4914795 100644 --- a/lib/PublicInbox/GitHTTPBackend.pm +++ b/lib/PublicInbox/GitHTTPBackend.pm @@ -179,7 +179,6 @@ 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) { @@ -197,7 +196,14 @@ sub serve_smart { my $val = $env->{$name}; $env{$name} = $val if defined $val; } - my $git_dir = ref $git ? $git->{git_dir} : $git; + my ($git_dir, $limiter); + if (ref $git) { + $limiter = $git->{-httpbackend_limiter} || $default_limiter; + $git_dir = $git->{git_dir}; + } else { + $limiter = $default_limiter; + $git_dir = $git; + } $env{GIT_HTTP_EXPORT_ALL} = '1'; $env{PATH_TRANSLATED} = "$git_dir/$path"; my %rdr = ( 0 => fileno($in) ); diff --git a/lib/PublicInbox/Inbox.pm b/lib/PublicInbox/Inbox.pm index dc9980b7..23b77213 100644 --- a/lib/PublicInbox/Inbox.pm +++ b/lib/PublicInbox/Inbox.pm @@ -34,6 +34,7 @@ sub new { my $v = $opts->{address} ||= 'public-inbox@example.com'; my $p = $opts->{-primary_address} = ref($v) eq 'ARRAY' ? $v->[0] : $v; $opts->{domain} = ($p =~ /\@(\S+)\z/) ? $1 : 'localhost'; + weaken($opts->{-pi_config}); bless $opts, $class; } @@ -44,11 +45,33 @@ sub _weaken_fields { } } +sub _set_limiter ($$$) { + my ($self, $git, $pfx) = @_; + my $lkey = "-${pfx}_limiter"; + $git->{$lkey} = $self->{$lkey} ||= eval { + my $mkey = $pfx.'max'; + my $val = $self->{$mkey} or return; + my $lim; + if ($val =~ /\A\d+\z/) { + require PublicInbox::Qspawn; + $lim = PublicInbox::Qspawn::Limiter->new($val); + } elsif ($val =~ /\A[a-z][a-z0-9]*\z/) { + $lim = $self->{-pi_config}->limiter($val); + warn "$mkey limiter=$val not found\n" if !$lim; + } else { + warn "$mkey limiter=$val not understood\n"; + } + $lim; + } +} + sub git { my ($self) = @_; $self->{git} ||= eval { _weaken_later($self); - PublicInbox::Git->new($self->{mainrepo}); + my $g = PublicInbox::Git->new($self->{mainrepo}); + _set_limiter($self, $g, 'httpbackend'); + $g; }; } diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm index cc9c340d..697c55a1 100644 --- a/lib/PublicInbox/Qspawn.pm +++ b/lib/PublicInbox/Qspawn.pm @@ -47,7 +47,7 @@ sub start { my ($self, $limiter, $cb) = @_; $self->{limiter} = $limiter; - if ($limiter->{running} < $limiter->{limit}) { + if ($limiter->{running} < $limiter->{max}) { _do_spawn($self, $cb); } else { push @{$limiter->{run_queue}}, [ $self, $cb ]; @@ -59,9 +59,10 @@ use strict; use warnings; sub new { - my ($class, $limit) = @_; + my ($class, $max) = @_; bless { - limit => $limit || 1, + # 32 is same as the git-daemon connection limit + max => $max || 32, running => 0, run_queue => [], }, $class; -- cgit v1.2.3-24-ge0c7