From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH] listener: support publicinboxdaemon.multiaccept in config
Date: Mon, 13 May 2019 02:56:10 +0000 [thread overview]
Message-ID: <20190513025610.30378-1-e@80x24.org> (raw)
Similar to the nginx "multi_accept" parameter, this allows
single-worker deployments to accept() multiple clients whenever
the listen socket reports readiness via epoll_wait/poll/kevent.
Unlike nginx, we also parse an integer parameter to determine
how many times in a row we call accept().
Single-process deployments with no shared sockets can safely set
"true", here; meaning accept() will be retried indefinitely as
long as there are clients connecting.
Multi-process deployments with many workers should leave this at
the default ("false", or "0") or try a small positive integer.
Using large values with many workers can lead to imbalanced
connections between workers.
We also can't reliably detect whether a listen socket is shared
between multiple processes. Sockets can be shared via socket
activation in systemd (or similar) and TTIN/TTOU signals can
adjust worker count of our daemons.
---
lib/PublicInbox/Config.pm | 29 +++++++++++++++++++++++++++--
lib/PublicInbox/Listener.pm | 14 +++++++-------
2 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index 09f9179..938685a 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -13,6 +13,9 @@ use warnings;
require PublicInbox::Inbox;
use PublicInbox::Spawn qw(popen_rd);
+my $FALSE_RE = qr/\A(?:false|no|off|0)\z/;
+my $TRUE_RE = qr/\A(?:true|yes|on|1)\z/;
+
sub _array ($) { ref($_[0]) eq 'ARRAY' ? $_[0] : [ $_[0] ] }
# returns key-value pairs of config directives in a hash
@@ -54,6 +57,28 @@ sub new {
$self->{css} = _array($css);
}
+ if (defined(my $ma = $self->{'publicinboxdaemon.multiaccept'})) {
+ # multiaccept=0 accept once (default)
+ # multiaccept=(1..X) accept an extra X times (or EAGAIN)
+ # multiaccept=true accept until EAGAIN
+ if ($ma =~ $TRUE_RE) {
+ $ma = -1 if $ma ne '1';
+ } elsif ($ma =~ $FALSE_RE) {
+ $ma = 0;
+ } elsif ($ma =~ /\A(\d+)\z/) {
+ # positive integer value, leave as-is
+ } else {
+ warn
+"publicinboxdaemon.multiaccept=$ma not understood\n";
+ $ma = undef;
+ }
+
+ defined($ma) and eval {
+ no warnings 'once';
+ $PublicInbox::Listener::multi_accept = $ma;
+ };
+ }
+
$self;
}
@@ -379,9 +404,9 @@ sub _fill {
foreach my $k (qw(obfuscate)) {
my $v = $self->{"$pfx.$k"};
defined $v or next;
- if ($v =~ /\A(?:false|no|off|0)\z/) {
+ if ($v =~ $FALSE_RE) {
$ibx->{$k} = 0;
- } elsif ($v =~ /\A(?:true|yes|on|1)\z/) {
+ } elsif ($v =~ $TRUE_RE) {
$ibx->{$k} = 1;
} else {
warn "Ignoring $pfx.$k=$v in config, not boolean\n";
diff --git a/lib/PublicInbox/Listener.pm b/lib/PublicInbox/Listener.pm
index a75a6fd..c4d1a55 100644
--- a/lib/PublicInbox/Listener.pm
+++ b/lib/PublicInbox/Listener.pm
@@ -10,6 +10,8 @@ use Socket qw(SOL_SOCKET SO_KEEPALIVE IPPROTO_TCP TCP_NODELAY);
use fields qw(post_accept);
require IO::Handle;
+our $multi_accept = 0;
+
sub new ($$$) {
my ($class, $s, $cb) = @_;
setsockopt($s, SOL_SOCKET, SO_KEEPALIVE, 1);
@@ -26,16 +28,14 @@ sub new ($$$) {
sub event_read {
my ($self) = @_;
my $sock = $self->{sock};
+ my $n = $multi_accept;
+ my ($addr, $c);
- # no loop here, we want to fairly distribute clients
- # between multiple processes sharing the same socket
- # XXX our event loop needs better granularity for
- # a single accept() here to be, umm..., acceptable
- # on high-traffic sites.
- if (my $addr = accept(my $c, $sock)) {
+ do {
+ $addr = accept($c, $sock) or return;
IO::Handle::blocking($c, 0); # no accept4 :<
$self->{post_accept}->($c, $addr, $sock);
- }
+ } while ($n--);
}
1;
--
EW
next reply other threads:[~2019-05-13 2:56 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-13 2:56 Eric Wong [this message]
2019-06-25 6:41 ` [PATCH] listener: support publicinboxdaemon.multiaccept in config Eric Wong
2023-04-12 10:17 ` [PATCH v2] listener: support multi-accept like nginx Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://public-inbox.org/README
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190513025610.30378-1-e@80x24.org \
--to=e@80x24.org \
--cc=meta@public-inbox.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/public-inbox.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).