user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [PATCH 09/11] watch: use EOFpipe to reduce dwaitpid wakeups
  2020-08-31  4:41  7% [PATCH 00/11] watch: fix contention w/ Maildir & NNTP Eric Wong
@ 2020-08-31  4:41  6% ` Eric Wong
  0 siblings, 0 replies; 2+ results
From: Eric Wong @ 2020-08-31  4:41 UTC (permalink / raw)
  To: meta

It's a bit inefficient to use a pipe, here.  However, using
dwaitpid() on a process that's not expected to exit soon is
also inefficient as it causes excessive wakeups as most of
our inbox-writing code expects synchronous waitpid().

This only affects -watch instances configured for NNTP and IMAP
clients.
---
 MANIFEST                   |  1 +
 lib/PublicInbox/EOFpipe.pm | 24 ++++++++++++++++++++++++
 lib/PublicInbox/Watch.pm   | 25 +++++++++++++++++++++----
 3 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 lib/PublicInbox/EOFpipe.pm

diff --git a/MANIFEST b/MANIFEST
index f090175e..0b3835d8 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -114,6 +114,7 @@ lib/PublicInbox/DSPoll.pm
 lib/PublicInbox/Daemon.pm
 lib/PublicInbox/DirIdle.pm
 lib/PublicInbox/DummyInbox.pm
+lib/PublicInbox/EOFpipe.pm
 lib/PublicInbox/Emergency.pm
 lib/PublicInbox/Eml.pm
 lib/PublicInbox/EmlContentFoo.pm
diff --git a/lib/PublicInbox/EOFpipe.pm b/lib/PublicInbox/EOFpipe.pm
new file mode 100644
index 00000000..489caf82
--- /dev/null
+++ b/lib/PublicInbox/EOFpipe.pm
@@ -0,0 +1,24 @@
+# Copyright (C) 2020 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+package PublicInbox::EOFpipe;
+use strict;
+use parent qw(PublicInbox::DS);
+use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT);
+
+sub new {
+	my (undef, $rd, $cb, $arg) = @_;
+	my $self = bless {  cb => $cb, arg => $arg }, __PACKAGE__;
+	# 1031: F_SETPIPE_SZ, 4096: page size
+	fcntl($rd, 1031, 4096) if $^O eq 'linux';
+	$self->SUPER::new($rd, EPOLLIN|EPOLLONESHOT);
+}
+
+sub event_step {
+	my ($self) = @_;
+	if ($self->do_read(my $buf, 1) == 0) { # auto-closed
+		$self->{cb}->($self->{arg});
+	}
+}
+
+1;
diff --git a/lib/PublicInbox/Watch.pm b/lib/PublicInbox/Watch.pm
index db8d0396..17786377 100644
--- a/lib/PublicInbox/Watch.pm
+++ b/lib/PublicInbox/Watch.pm
@@ -14,7 +14,8 @@ use PublicInbox::Sigfd;
 use PublicInbox::DS qw(now);
 use PublicInbox::MID qw(mids);
 use PublicInbox::ContentHash qw(content_hash);
-use POSIX qw(_exit);
+use PublicInbox::EOFpipe;
+use POSIX qw(_exit WNOHANG);
 
 sub compile_watchheaders ($) {
 	my ($ibx) = @_;
@@ -611,17 +612,30 @@ sub imap_idle_reap { # PublicInbox::DS::dwaitpid callback
 				\&imap_idle_requeue, [ $self, $url_intvl ]);
 }
 
+sub reap { # callback for EOFpipe
+	my ($pid, $cb, $self) = @{$_[0]};
+	my $ret = waitpid($pid, 0);
+	if ($ret == $pid) {
+		$cb->($self, $pid); # poll_fetch_reap || imap_idle_reap
+	} else {
+		warn "W: waitpid($pid) => ", $ret // "($!)", "\n";
+	}
+}
+
 sub imap_idle_fork ($$) {
 	my ($self, $url_intvl) = @_;
 	my ($url, $intvl) = @$url_intvl;
+	pipe(my ($r, $w)) or die "pipe: $!";
 	defined(my $pid = fork) or die "fork: $!";
 	if ($pid == 0) {
+		close $r;
 		watch_atfork_child($self);
 		watch_imap_idle_1($self, $url, $intvl);
+		close $w;
 		_exit(0);
 	}
 	$self->{idle_pids}->{$pid} = $url_intvl;
-	PublicInbox::DS::dwaitpid($pid, \&imap_idle_reap, $self);
+	PublicInbox::EOFpipe->new($r, \&reap, [$pid, \&imap_idle_reap, $self]);
 }
 
 sub event_step {
@@ -689,24 +703,27 @@ sub watch_nntp_fetch_all ($$) {
 sub poll_fetch_fork ($) { # DS::add_timer callback
 	my ($self, $intvl, $urls) = @{$_[0]};
 	return if $self->{quit};
+	pipe(my ($r, $w)) or die "pipe: $!";
 	my $oldset = watch_atfork_parent($self);
 	my $pid = fork;
 	if (defined($pid) && $pid == 0) {
+		close $r;
 		watch_atfork_child($self);
 		if ($urls->[0] =~ m!\Aimaps?://!i) {
 			watch_imap_fetch_all($self, $urls);
 		} else {
 			watch_nntp_fetch_all($self, $urls);
 		}
+		close $w;
 		_exit(0);
 	}
 	PublicInbox::Sigfd::sig_setmask($oldset);
 	die "fork: $!"  unless defined $pid;
 	$self->{poll_pids}->{$pid} = [ $intvl, $urls ];
-	PublicInbox::DS::dwaitpid($pid, \&poll_fetch_reap, $self);
+	PublicInbox::EOFpipe->new($r, \&reap, [$pid, \&poll_fetch_reap, $self]);
 }
 
-sub poll_fetch_reap { # PublicInbox::DS::dwaitpid callback
+sub poll_fetch_reap {
 	my ($self, $pid) = @_;
 	my $intvl_urls = delete $self->{poll_pids}->{$pid} or
 		die "BUG: PID=$pid (unknown) reaped: \$?=$?\n";

^ permalink raw reply related	[relevance 6%]

* [PATCH 00/11] watch: fix contention w/ Maildir & NNTP
@ 2020-08-31  4:41  7% Eric Wong
  2020-08-31  4:41  6% ` [PATCH 09/11] watch: use EOFpipe to reduce dwaitpid wakeups Eric Wong
  0 siblings, 1 reply; 2+ results
From: Eric Wong @ 2020-08-31  4:41 UTC (permalink / raw)
  To: meta

Here's a bunch of fixes to improve watch performance when
both Maildirs and NNTP are being watched (possibly on the same
inbox, or if `watchspam' is configured for spam removals).

Wakeups are reduced, and inbox.lock contention is minimized by
using read-only ->over to check for `watchspam' removals.

These affect IMAP, too; but I've been mainly using NNTP.

Eric Wong (11):
  watch: limit batch size of NNTP and IMAP workers, too
  watchmaildir: use v5.10.1, drop warnings
  rename WatchMaildir => Watch
  watch: log signal activities to STDERR
  watch: avoid unnecessary spawning on spam removals
  watch: block signals before fork on non-signalfd/kevent systems
  watch: comments and tiny cleanups
  ds: avoid excessive queueing when reaping PIDs
  watch: use EOFpipe to reduce dwaitpid wakeups
  ds: avoid unnecessary timer for waitpid
  replace ParentPipe with EOFpipe

 MANIFEST                                      |   4 +-
 lib/PublicInbox/DS.pm                         |  38 +++---
 lib/PublicInbox/Daemon.pm                     |   6 +-
 lib/PublicInbox/EOFpipe.pm                    |  24 ++++
 lib/PublicInbox/Import.pm                     |   3 +
 lib/PublicInbox/ParentPipe.pm                 |  23 ----
 lib/PublicInbox/V2Writable.pm                 |   3 +
 lib/PublicInbox/{WatchMaildir.pm => Watch.pm} | 111 +++++++++++++-----
 script/public-inbox-watch                     |  34 ++++--
 t/imapd.t                                     |   2 +-
 t/nntpd.t                                     |   2 +-
 t/watch_filter_rubylang.t                     |   4 +-
 t/watch_imap.t                                |   4 +-
 t/watch_maildir.t                             |  18 +--
 t/watch_maildir_v2.t                          |  22 ++--
 t/watch_multiple_headers.t                    |   4 +-
 t/watch_nntp.t                                |   4 +-
 17 files changed, 190 insertions(+), 116 deletions(-)
 create mode 100644 lib/PublicInbox/EOFpipe.pm
 delete mode 100644 lib/PublicInbox/ParentPipe.pm
 rename lib/PublicInbox/{WatchMaildir.pm => Watch.pm} (92%)

^ permalink raw reply	[relevance 7%]

Results 1-2 of 2 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2020-08-31  4:41  7% [PATCH 00/11] watch: fix contention w/ Maildir & NNTP Eric Wong
2020-08-31  4:41  6% ` [PATCH 09/11] watch: use EOFpipe to reduce dwaitpid wakeups Eric Wong

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).