# Unstable internal API
package PublicInbox::Admin;
use strict;
-use warnings;
-use Cwd 'abs_path';
-use base qw(Exporter);
-our @EXPORT_OK = qw(resolve_repo_dir);
+use parent qw(Exporter);
+use Cwd qw(abs_path);
+use POSIX ();
+our @EXPORT_OK = qw(resolve_repo_dir setup_signals);
use PublicInbox::Config;
use PublicInbox::Inbox;
use PublicInbox::Spawn qw(popen_rd);
+sub setup_signals {
+ my ($cb, $arg) = @_; # optional
+
+ # we call exit() here instead of _exit() so DESTROY methods
+ # get called (e.g. File::Temp::Dir and PublicInbox::Msgmap)
+ $SIG{INT} = $SIG{HUP} = $SIG{PIPE} = $SIG{TERM} = sub {
+ my ($sig) = @_;
+ # https://www.tldp.org/LDP/abs/html/exitcodes.html
+ eval { $cb->($sig, $arg) } if $cb;
+ $sig = 'SIG'.$sig;
+ exit(128 + POSIX->$sig);
+ };
+}
+
sub resolve_repo_dir {
my ($cd, $ver) = @_;
my $prefix = defined $cd ? $cd : './';
die missing_mod_msg($err) ." required for indexlevel=$indexlevel\n";
}
+sub index_terminate {
+ my (undef, $ibx) = @_; # $_[0] = signal name
+ $ibx->git->cleanup;
+}
+
sub index_inbox {
my ($ibx, $im, $opt) = @_;
my $jobs = delete $opt->{jobs} if $opt;
+ local %SIG = %SIG;
+ setup_signals(\&index_terminate, $ibx);
if (ref($ibx) && $ibx->version == 2) {
eval { require PublicInbox::V2Writable };
die "v2 requirements not met: $@\n" if $@;
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
package PublicInbox::Xapcmd;
use strict;
-use warnings;
use PublicInbox::Spawn qw(which popen_rd nodatacow_dir);
+use PublicInbox::Admin qw(setup_signals);
use PublicInbox::Over;
use PublicInbox::SearchIdx;
use File::Temp 0.19 (); # ->newdir
die "$x and $y reside on different filesystems\n";
}
+sub kill_pids {
+ my ($sig, $pids) = @_;
+ kill($sig, keys %$pids); # pids may be empty
+}
+
sub process_queue {
my ($queue, $cb, $opt) = @_;
my $max = $opt->{jobs} // scalar(@$queue);
# run in parallel:
my %pids;
+ local %SIG = %SIG;
+ setup_signals(\&kill_pids, \%pids);
while (@$queue) {
while (scalar(keys(%pids)) < $max && scalar(@$queue)) {
my $args = shift @$queue;
}
}
-sub setup_signals () {
- # http://www.tldp.org/LDP/abs/html/exitcodes.html
- $SIG{INT} = sub { exit(130) };
- $SIG{HUP} = $SIG{PIPE} = $SIG{TERM} = sub { exit(1) };
-}
-
sub prepare_run {
my ($ibx, $opt) = @_;
my $tmp = {}; # old shard dir => File::Temp->newdir object or undef
($p[-1] =~ /\A([0-9]+)/) ? "$p[-2]/$1" : $p[-1];
}
+sub kill_compact { # setup_signals callback
+ my ($sig, $pidref) = @_;
+ kill($sig, $$pidref) if defined($$pidref);
+}
+
# xapian-compact wrapper
sub compact ($$) {
my ($args, $opt) = @_;
}
$pr->("$pfx `".join(' ', @$cmd)."'\n") if $pr;
push @$cmd, $src, $dst;
- my $rd = popen_rd($cmd, undef, $rdr);
+ my ($rd, $pid);
+ local %SIG = %SIG;
+ setup_signals(\&kill_compact, \$pid);
+ ($rd, $pid) = popen_rd($cmd, undef, $rdr);
while (<$rd>) {
if ($pr) {
s/\r/\r$pfx /g;
$pr->("$pfx $_");
}
}
- close $rd or die join(' ', @$cmd)." failed: $?n";
+ waitpid($pid, 0);
+ die "@$cmd failed: \$?=$?\n" if $?;
}
sub cpdb_loop ($$$;$$) {