From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-3.8 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 5BA6E1F4B4 for ; Sat, 26 Dec 2020 09:36:31 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH] inboxidle: avoid needless syscalls on refresh Date: Sat, 26 Dec 2020 09:36:31 +0000 Message-Id: <20201226093631.14313-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: We don't have to replace a bunch of existing watches with identical new ones. On Linux with Linux::Inotify2 installed, this avoids a storm of inotify_add_watch(2) and inotify_rm_watch(2) syscalls on SIGHUP with -imapd and "-extindex --watch" --- lib/PublicInbox/InboxIdle.pm | 15 ++++++++++++--- t/imapd.t | 26 +++++--------------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/lib/PublicInbox/InboxIdle.pm b/lib/PublicInbox/InboxIdle.pm index 69da5f4f..35aed696 100644 --- a/lib/PublicInbox/InboxIdle.pm +++ b/lib/PublicInbox/InboxIdle.pm @@ -24,17 +24,26 @@ sub in2_arm ($$) { # PublicInbox::Config::each_inbox callback my $dir = $ibx->{inboxdir}; my $inot = $self->{inot}; my $cur = $self->{pathmap}->{$dir} //= []; + my $lock = "$dir/".($ibx->version >= 2 ? 'inbox.lock' : 'ssoma.lock'); # transfer old subscriptions to the current inbox, cancel the old watch - if (my $old_ibx = $cur->[0]) { + my $old_ibx = $cur->[0]; + $cur->[0] = $ibx; + if ($old_ibx) { $ibx->{unlock_subs} and die "BUG: $dir->{unlock_subs} should not exist"; $ibx->{unlock_subs} = $old_ibx->{unlock_subs}; + + # Linux::Inotify2::Watch::name matches if watches are the + # same, no point in replacing a watch of the same name + if ($cur->[1]->name eq $lock) { + $self->{on_unlock}->{$lock} = $ibx; + return; + } + # rare, name changed (v1 inbox converted to v2) $cur->[1]->cancel; # Linux::Inotify2::Watch::cancel } - $cur->[0] = $ibx; - my $lock = "$dir/".($ibx->version >= 2 ? 'inbox.lock' : 'ssoma.lock'); if (my $w = $cur->[1] = $inot->watch($lock, $IN_MODIFY)) { $self->{on_unlock}->{$w->name} = $ibx; } else { diff --git a/t/imapd.t b/t/imapd.t index 43ec200c..63a86e71 100644 --- a/t/imapd.t +++ b/t/imapd.t @@ -296,27 +296,11 @@ $pi_cfg->each_inbox(sub { # ensure IDLE persists across HUP, w/o extra watches or FDs $td->kill('HUP') or BAIL_OUT "failed to kill -imapd: $!"; - SKIP: { - skip 'no inotify fdinfo (or support)', 2 if !@ino_info; - my (@tmp, %prev); - local $/ = "\n"; - my $end = time + 5; - until (time > $end) { - select undef, undef, undef, 0.01; - open my $fh, '<', $ino_fdinfo or - BAIL_OUT "$ino_fdinfo: $!"; - %prev = map { $_ => 1 } @ino_info; - @tmp = grep(/^inotify wd:/, <$fh>); - if (scalar(@tmp) == scalar(@ino_info)) { - delete @prev{@tmp}; - last if scalar(keys(%prev)) == @ino_info; - } - } - is(scalar @tmp, scalar @ino_info, - 'old inotify watches replaced'); - is(scalar keys %prev, scalar @ino_info, - 'no previous watches overlap'); - }; + for my $n (1..2) { # kick the event loop so we know HUP is done + my $m = $imap_client->new(%mic_opt); + ok($m->login && $m->IsAuthenticated && $m->logout, + "connection $n works after HUP"); + } open($fh, '<', 't/data/0001.patch') or BAIL_OUT("open: $!"); run_script(['-mda', '--no-precheck'], $env, { 0 => $fh }) or