DBIx-QuickDB
view release on metacpan or search on metacpan
lib/DBIx/QuickDB/Watcher.pm view on Meta::CPAN
if ($pid) {
close($wh);
waitpid($pid, 0);
chomp($self->{+WATCHER_PID} = <$rh>);
chomp($self->{+SERVER_PID} = <$rh>);
close($rh);
die "Did not get watcher pid!" unless $self->{+WATCHER_PID};
die "Did not get server pid!" unless $self->{+SERVER_PID};
return;
}
close($rh);
POSIX::setsid();
setpgrp(0, 0);
$pid = fork;
die "Could not fork: $!" unless defined $pid;
POSIX::_exit(0) if $pid;
$wh->autoflush(1);
print $wh "$$\n";
# In watcher now
eval { $self->watch($wh); 1 } or POSIX::_exit(1);
POSIX::_exit(0);
}
sub watch {
my $self = shift;
my ($wh) = @_;
$0 = 'db-quick-watcher';
my $kill = '';
my $hup = 0;
local $SIG{TERM} = sub { $kill = 'TERM' };
local $SIG{INT} = sub { $kill = 'INT' };
local $SIG{USR1} = sub { $kill = 'FAST_TERM' };
local $SIG{HUP} = sub { $hup = 1 };
my $start_pid = $$;
my $pid = $self->spawn();
print $wh "$pid\n";
close($wh);
my $mpid = $self->{+MASTER_PID};
my $spid = $self->{+SERVER_PID} or die "No server pid";
my $ddir = $self->{+DB}->dir;
my $ssig = $self->{+DB}->stop_sig // 'TERM';
my $fsig = $self->{+DB}->fast_stop_sig // 'KILL';
# Ignore SIGTERM/SIGINT before exec so the watcher cannot be killed
# during startup before _do_watch installs its signal handlers.
# SIG_IGN persists across exec, and any pending signal will be held
# until _do_watch replaces these with proper handlers.
$SIG{TERM} = 'IGNORE';
$SIG{INT} = 'IGNORE';
# Block (rather than ignore) the fast-eliminate signal across the exec. A
# blocked signal stays *pending* instead of being discarded, so a
# fast_eliminate() that races server startup -- arriving after the socket is
# up (so the caller's start() has returned) but before _do_watch has
# installed its handler -- is not lost: _do_watch unblocks it once the
# handler is in place and it fires immediately. SIG_IGN would silently drop
# it, leaving the caller's wait() to block for the full stop-grace timeout.
POSIX::sigprocmask(POSIX::SIG_BLOCK(), POSIX::SigSet->new(POSIX::SIGUSR1()));
exec(
$^X, '-Ilib',
'-e' => "require DBIx::QuickDB::Watcher; DBIx::QuickDB::Watcher->_do_watch()",
master_pid => $mpid,
data_dir => $ddir,
server_pid => $spid,
signal => $ssig,
fast_signal => $fsig,
kill => $kill,
hup => $hup,
);
}
sub _do_watch {
my $class = shift;
$0 = 'db-quick-watcher';
my %params = @ARGV;
my $kill = $params{kill} // '';
my $hup = $params{hup} // 0;
local $SIG{TERM} = sub { $kill = 'TERM' };
local $SIG{INT} = sub { $kill = 'INT' };
local $SIG{USR1} = sub { $kill = 'FAST_TERM' };
local $SIG{HUP} = sub { $hup = 1 };
# watch() blocked SIGUSR1 before exec so a fast_eliminate() racing startup
# would stay pending rather than be discarded. Now that the handler above is
# installed, unblock it -- any pending fast-eliminate fires here and sets
# $kill before we enter the watch loop.
POSIX::sigprocmask(POSIX::SIG_UNBLOCK(), POSIX::SigSet->new(POSIX::SIGUSR1()));
my $blah;
close(STDIN);
open(STDIN, '<', \$blah) or warn "$!";
my $master_pid = $params{master_pid} or die "No master pid provided";
my $server_pid = $params{server_pid} or die "No server pid provided";
my $data_dir = $params{data_dir} or die "No data dir provided";
my $signal = $params{signal} // 'TERM';
my $fast_signal = $params{fast_signal} // 'KILL';
my $hupped = 0;
while (!$kill) {
if ($hup && !$hupped) {
close(STDOUT);
open(STDOUT, '>', \$blah) or warn "$!";
close(STDERR);
open(STDERR, '>', \$blah) or warn "$!";
}
sleep 0.1;
next if kill(0, $master_pid);
$kill = 'TERM';
}
unless (eval { $class->_watcher_terminate(send_sig => $signal, fast_sig => $fast_signal, got_sig => $kill, pid => $server_pid, dir => $data_dir); 1 }) {
my $err = $@;
eval { warn $@ };
POSIX::_exit(1);
}
POSIX::_exit(0);
}
sub spawn {
my $self = shift;
croak "Extra spawn" if $self->{+SERVER_PID};
my $db = $self->{+DB};
my $args = $self->{+ARGS} || [];
my $init_pid = $$;
my ($pid, $log_file) = $db->run_command([$db->start_command, @$args], {no_wait => 1, log_file => $self->{+LOG_FILE}});
$self->{+SERVER_PID} = $pid;
$self->{+LOG_FILE} = $log_file;
return $pid;
}
sub _watcher_terminate {
my $class = shift;
my %params = @_;
my $pid = $params{pid} or die "No pid";
( run in 0.908 second using v1.01-cache-2.11-cpan-bbe5e583499 )