diff options
Diffstat (limited to 'lib/PublicInbox/Gcf2Client.pm')
-rw-r--r-- | lib/PublicInbox/Gcf2Client.pm | 72 |
1 files changed, 23 insertions, 49 deletions
diff --git a/lib/PublicInbox/Gcf2Client.pm b/lib/PublicInbox/Gcf2Client.pm index 09c3aa06..07ff7dcb 100644 --- a/lib/PublicInbox/Gcf2Client.pm +++ b/lib/PublicInbox/Gcf2Client.pm @@ -1,15 +1,18 @@ -# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org> +# Copyright (C) all contributors <meta@public-inbox.org> # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> # connects public-inbox processes to PublicInbox::Gcf2::loop() package PublicInbox::Gcf2Client; -use strict; +use v5.12; use parent qw(PublicInbox::DS); use PublicInbox::Git; use PublicInbox::Gcf2; # fails if Inline::C or libgit2-dev isn't available use PublicInbox::Spawn qw(spawn); use Socket qw(AF_UNIX SOCK_STREAM); -use PublicInbox::Syscall qw(EPOLLIN EPOLLET); +use PublicInbox::Syscall qw(EPOLLIN); +use PublicInbox::IO; +use autodie qw(socketpair); + # fields: # sock => socket to Gcf2::loop # The rest of these fields are compatible with what PublicInbox::Git @@ -18,68 +21,39 @@ use PublicInbox::Syscall qw(EPOLLIN EPOLLET); # pid.owner => process which spawned {pid} # in => same as {sock}, for compatibility with PublicInbox::Git # inflight => array (see PublicInbox::Git) -# rbuf => scalarref, may be non-existent or empty sub new { - my ($rdr) = @_; + my ($opt) = @_; my $self = bless {}, __PACKAGE__; # ensure the child process has the same @INC we do: my $env = { PERL5LIB => join(':', @INC) }; - my ($s1, $s2); - socketpair($s1, $s2, AF_UNIX, SOCK_STREAM, 0) or die "socketpair $!"; - $rdr //= {}; - $rdr->{0} = $rdr->{1} = $s2; - my $cmd = [$^X, qw[-MPublicInbox::Gcf2 -e PublicInbox::Gcf2::loop]]; - $self->{'pid.owner'} = $$; - $self->{pid} = spawn($cmd, $env, $rdr); + socketpair(my $s1, my $s2, AF_UNIX, SOCK_STREAM, 0); $s1->blocking(0); + $opt->{0} = $opt->{1} = $s2; + my $cmd = [$^X, $^W ? ('-w') : (), + qw[-MPublicInbox::Gcf2 -e PublicInbox::Gcf2::loop]]; $self->{inflight} = []; - $self->{in} = $s1; - $self->SUPER::new($s1, EPOLLIN|EPOLLET); -} - -sub fail { - my $self = shift; - $self->close; # PublicInbox::DS::close - PublicInbox::Git::fail($self, @_); + PublicInbox::IO::attach_pid($s1, spawn($cmd, $env, $opt), + \&PublicInbox::Git::gcf_drain, $self->{inflight}); + $self->{epwatch} = \undef; # for Git->cleanup + $self->SUPER::new($s1, EPOLLIN); } sub gcf2_async ($$$;$) { my ($self, $req, $cb, $arg) = @_; - my $inflight = $self->{inflight} or return $self->close; - - # {wbuf} is rare, I hope: - cat_async_step($self, $inflight) if $self->{wbuf}; - - $self->fail("gcf2c write: $!") if !$self->write($req) && !$self->{sock}; - push @$inflight, $req, $cb, $arg; + my $inflight = $self->gcf_inflight or return; + PublicInbox::Git::write_all($self, $req, \&cat_async_step, $inflight); + push @$inflight, \$req, $cb, $arg; # ref prevents Git.pm retries } # ensure PublicInbox::Git::cat_async_step never calls cat_async_retry sub alternates_changed {} -# DS::event_loop will call this -sub event_step { - my ($self) = @_; - $self->flush_write; - $self->close if !$self->{in} || !$self->{sock}; # process died - my $inflight = $self->{inflight}; - if ($inflight && @$inflight) { - cat_async_step($self, $inflight); - return $self->close unless $self->{in}; # process died - - # ok, more to do, requeue for fairness - $self->requeue if @$inflight || exists($self->{rbuf}); - } -} - -sub DESTROY { - my ($self) = @_; - delete $self->{sock}; # if outside event_loop - PublicInbox::Git::DESTROY($self); -} - no warnings 'once'; -*cat_async_step = \&PublicInbox::Git::cat_async_step; +*gcf_inflight = \&PublicInbox::Git::gcf_inflight; # for event_step +*cat_async_step = \&PublicInbox::Git::cat_async_step; # for event_step +*event_step = \&PublicInbox::Git::event_step; +*fail = \&PublicInbox::Git::fail; +*DESTROY = \&PublicInbox::Git::DESTROY; 1; |