]> Sergey Matveev's repositories - public-inbox.git/commitdiff
inboxidle: avoid needless syscalls on refresh
authorEric Wong <e@80x24.org>
Sat, 26 Dec 2020 09:34:39 +0000 (09:34 +0000)
committerEric Wong <e@80x24.org>
Sat, 26 Dec 2020 20:20:13 +0000 (20:20 +0000)
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"

(cherry picked from commit 10bf54305da8422d9ece6b809996092c1c4b1786)

Note: this seems to fix missed wakeups with many watches,
so it's in the stable branch.

Link: https://public-inbox.org/meta/20201226201115.GA30142@dcvr/
lib/PublicInbox/InboxIdle.pm
t/imapd.t

index 357bd216b5c30642fef65c84bbd343053d53ec25..60948bea72c2a03e21331691bd8db9fe9b465acf 100644 (file)
@@ -30,17 +30,26 @@ sub in2_arm ($$) { # PublicInbox::Config::each_inbox callback
        }
        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 {
index c1c52839f2c1cacec57b949541c4a7c67024d739..a464ad86058d374953a9c3bc943599fd2fa49bde 100644 (file)
--- a/t/imapd.t
+++ b/t/imapd.t
@@ -296,27 +296,11 @@ $pi_config->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