]> Sergey Matveev's repositories - public-inbox.git/commitdiff
lei: prefer IO::FDPass over our Inline::C recv_3fds
authorEric Wong <e@80x24.org>
Sun, 3 Jan 2021 20:58:29 +0000 (20:58 +0000)
committerEric Wong <e@80x24.org>
Mon, 4 Jan 2021 04:02:54 +0000 (04:02 +0000)
While our recv_3fds() implementation is more efficient
syscall-wise, loading Inline takes nearly 50ms on my machine
even after Inline::C memoizes the build.  The current ~20ms in
the fast path is barely acceptable to me, and 50ms would be
unusable.

Eventually, script/lei may invoke tcc(1) or cc(1) directly in
the fast path, but it needs @INC for the slow path, at least.

We'll encode the number of FDs into the socket name allow
parallel installations, for now.

lib/PublicInbox/LEI.pm
lib/PublicInbox/Spawn.pm
script/lei
t/lei.t

index 6f21da352a257b4e8cb6a1b97fb8105cd69eebaf..f41f63ed126870683e4f93fd499e50c345605053 100644 (file)
@@ -660,7 +660,7 @@ sub noop {}
 
 # lei(1) calls this when it can't connect
 sub lazy_start {
-       my ($path, $errno) = @_;
+       my ($path, $errno, $nfd) = @_;
        if ($errno == ECONNREFUSED) {
                unlink($path) or die "unlink($path): $!";
        } elsif ($errno != ENOENT) {
@@ -675,8 +675,14 @@ sub lazy_start {
        my $dev_ino_expect = pack('dd', $st[0], $st[1]); # dev+ino
        pipe(my ($eof_r, $eof_w)) or die "pipe: $!";
        my $oldset = PublicInbox::Sigfd::block_signals();
-       $recv_3fds = PublicInbox::Spawn->can('recv_3fds') or die
-               "Inline::C not installed/configured or IO::FDPass missing\n";
+       if ($nfd == 1) {
+               require IO::FDPass;
+               $recv_3fds = sub { map { IO::FDPass::recv($_[0]) } (0..2) };
+       } elsif ($nfd == 3) {
+               $recv_3fds = PublicInbox::Spawn->can('recv_3fds');
+       }
+       $recv_3fds or die
+               "IO::FDPass missing or Inline::C not installed/configured\n";
        require PublicInbox::Listener;
        require PublicInbox::EOFpipe;
        (-p STDOUT) or die "E: stdout must be a pipe\n";
index 61e954338ef2f285056feee6c917401630ce9760..cd94ba9623bce0267c7255d4c38cb474dd34500b 100644 (file)
@@ -315,17 +315,6 @@ unless ($set_nodatacow) {
        *nodatacow_fd = \&PublicInbox::NDC_PP::nodatacow_fd;
        *nodatacow_dir = \&PublicInbox::NDC_PP::nodatacow_dir;
 }
-unless (__PACKAGE__->can('recv_3fds')) {
-       eval { # try the XS IO::FDPass package
-               require IO::FDPass;
-               no warnings 'once';
-               *recv_3fds = sub { map { IO::FDPass::recv($_[0]) } (0..2) };
-               *send_3fds = sub ($$$$) {
-                       my $sockfd = shift;
-                       IO::FDPass::send($sockfd, shift) for (0..2);
-               };
-       };
-}
 
 undef $set_nodatacow;
 undef $vfork_spawn;
index 029881f8a70d1cdcda66b4c17c55cfb1a9e47590..2ea98da4d0ac4ec586d9ecb82bb7c69da89c3247 100755 (executable)
@@ -4,11 +4,17 @@
 use strict;
 use v5.10.1;
 use Socket qw(AF_UNIX SOCK_STREAM pack_sockaddr_un);
-my $send_3fds;
+my ($send_3fds, $nfd);
 if (my ($sock, $pwd) = eval {
-       require PublicInbox::Spawn;
-       $send_3fds = PublicInbox::Spawn->can('send_3fds') or die
-               "Inline::C not installed/configured or IO::FDPass missing\n";
+       $send_3fds = eval {
+               require IO::FDPass;
+               $nfd = 1; # 1 FD per-sendmsg
+               sub { IO::FDPass::send($_[0], $_[$_]) for (1..3) }
+       } // do {
+               require PublicInbox::Spawn; # takes ~50ms even if built *sigh*
+               $nfd = 3; # 3 FDs per-sendmsg(2)
+               PublicInbox::Spawn->can('send_3fds');
+       } // die "IO::FDPass missing or Inline::C not installed/configured\n";
        my $path = do {
                my $runtime_dir = ($ENV{XDG_RUNTIME_DIR} // '') . '/lei';
                if ($runtime_dir eq '/lei') {
@@ -19,7 +25,7 @@ if (my ($sock, $pwd) = eval {
                        require File::Path;
                        File::Path::mkpath($runtime_dir, 0, 0700);
                }
-               "$runtime_dir/sock";
+               "$runtime_dir/$nfd.sock";
        };
        my $addr = pack_sockaddr_un($path);
        socket(my $sock, AF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
@@ -27,7 +33,7 @@ if (my ($sock, $pwd) = eval {
                local $ENV{PERL5LIB} = join(':', @INC);
                open(my $daemon, '-|', $^X, qw[-MPublicInbox::LEI
                        -E PublicInbox::LEI::lazy_start(@ARGV)],
-                       $path, $! + 0) or die "popen: $!";
+                       $path, $! + 0, $nfd) or die "popen: $!";
                while (<$daemon>) { warn $_ } # EOF when STDERR is redirected
                close($daemon) or warn <<"";
 lei-daemon could not start, exited with \$?=$?
diff --git a/t/lei.t b/t/lei.t
index 42c0eb8ff22b790e9213acc43c9dba5ec712dc13..5afb83511d11053be785c2db6f650a0a74415ff1 100644 (file)
--- a/t/lei.t
+++ b/t/lei.t
@@ -193,12 +193,14 @@ if ($ENV{TEST_LEI_ONESHOT}) {
 
 SKIP: { # real socket
        require_mods(qw(Cwd), my $nr = 46);
-       require PublicInbox::Spawn;
-       skip "Inline::C not installed/configured or IO::FDPass missing", $nr
-               unless PublicInbox::Spawn->can('send_3fds');
+       my $nfd = eval { require IO::FDPass; 1 } // do {
+               require PublicInbox::Spawn;
+               PublicInbox::Spawn->can('send_3fds') ? 3 : undef;
+       } //
+       skip 'IO::FDPass missing or Inline::C not installed/configured', $nr;
 
        local $ENV{XDG_RUNTIME_DIR} = "$home/xdg_run";
-       my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/sock";
+       my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/$nfd.sock";
 
        ok($lei->('daemon-pid'), 'daemon-pid');
        is($err, '', 'no error from daemon-pid');