X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FXapcmd.pm;h=106856369c689007470b7ec364796e29079821f6;hb=23af251dd607c4e75ab1e68063f2c885c48cc035;hp=e37eece5937f52bead48cb24aa8cd18737eea40c;hpb=dd80dcaa1e46543893de533938a1651639f91f10;p=public-inbox.git
diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm
index e37eece5..10685636 100644
--- a/lib/PublicInbox/Xapcmd.pm
+++ b/lib/PublicInbox/Xapcmd.pm
@@ -1,14 +1,14 @@
-# Copyright (C) 2018-2021 all contributors
+# Copyright (C) all contributors
# License: AGPL-3.0+
package PublicInbox::Xapcmd;
use strict;
-use PublicInbox::Spawn qw(which popen_rd nodatacow_dir);
+use PublicInbox::Spawn qw(which popen_rd);
+use PublicInbox::Syscall;
use PublicInbox::Admin qw(setup_signals);
use PublicInbox::Over;
use PublicInbox::SearchIdx;
use File::Temp 0.19 (); # ->newdir
use File::Path qw(remove_tree);
-use File::Basename qw(dirname);
use POSIX qw(WNOHANG _exit);
# support testing with dev versions of Xapian which installs
@@ -21,13 +21,25 @@ sub commit_changes ($$$$) {
my $reshard = $opt->{reshard};
$SIG{INT} or die 'BUG: $SIG{INT} not handled';
- my @old_shard;
- my $over_chg;
-
- while (my ($old, $newdir) = each %$tmp) {
+ my (@old_shard, $over_chg);
+
+ # Sort shards highest-to-lowest, since ->xdb_shards_flat
+ # determines the number of shards to load based on the max;
+ # and we'd rather xdb_shards_flat to momentarily fail rather
+ # than load out-of-date shards
+ my @order = sort {
+ my ($x) = ($a =~ m!/([0-9]+)/*\z!);
+ my ($y) = ($b =~ m!/([0-9]+)/*\z!);
+ ($y // -1) <=> ($x // -1) # we may have non-shards
+ } keys %$tmp;
+
+ my ($dname) = ($order[0] =~ m!(.*/)[^/]+/*\z!);
+ my $mode = (stat($dname))[2];
+ for my $old (@order) {
next if $old eq ''; # no invalid paths
- my @st = stat($old);
- if (!@st && !defined($opt->{reshard})) {
+ my $newdir = $tmp->{$old};
+ my $have_old = -e $old;
+ if (!$have_old && !defined($opt->{reshard})) {
die "failed to stat($old): $!";
}
@@ -47,17 +59,13 @@ sub commit_changes ($$$$) {
next;
}
- if (@st) {
- chmod($st[2] & 07777, $new) or die "chmod $old: $!\n";
+ chmod($mode & 07777, $new) or die "chmod($new): $!\n";
+ if ($have_old) {
rename($old, "$new/old") or
die "rename $old => $new/old: $!\n";
}
rename($new, $old) or die "rename $new => $old: $!\n";
- if (@st) {
- my $prev = "$old/old";
- remove_tree($prev) or
- die "failed to remove $prev: $!\n";
- }
+ push @old_shard, "$old/old" if $have_old;
}
# trigger ->check_inodes in read-only daemons
@@ -150,7 +158,7 @@ sub process_queue {
# run in parallel:
my %pids;
- local %SIG = %SIG;
+ local @SIG{keys %SIG} = values %SIG;
setup_signals(\&kill_pids, \%pids);
while (@$queue) {
while (scalar(keys(%pids)) < $max && scalar(@$queue)) {
@@ -199,12 +207,12 @@ sub prepare_run {
warn
"--reshard=$reshard ignored for v1 $ibx->{inboxdir}\n";
}
- my $dir = dirname($old);
+ my ($dir) = ($old =~ m!(.*?/)[^/]+/*\z!);
same_fs_or_die($dir, $old);
my $v = PublicInbox::Search::SCHEMA_VERSION();
my $wip = File::Temp->newdir("xapian$v-XXXX", DIR => $dir);
$tmp->{$old} = $wip;
- nodatacow_dir($wip->dirname);
+ PublicInbox::Syscall::nodatacow_dir($wip->dirname);
push @queue, [ $old, $wip ];
} elsif (defined $old) {
opendir my $dh, $old or die "Failed to opendir $old: $!\n";
@@ -235,7 +243,7 @@ sub prepare_run {
same_fs_or_die($old, $wip->dirname);
my $cur = "$old/$dn";
push @queue, [ $src // $cur , $wip ];
- nodatacow_dir($wip->dirname);
+ PublicInbox::Syscall::nodatacow_dir($wip->dirname);
$tmp->{$cur} = $wip;
}
# mark old shards to be unlinked
@@ -286,7 +294,7 @@ sub run {
PublicInbox::SearchIdx::load_xapian_writable();
}
- local %SIG = %SIG;
+ local @SIG{keys %SIG} = values %SIG;
setup_signals();
$ibx->with_umask(\&_run, $ibx, $cb, $opt);
}
@@ -344,7 +352,7 @@ sub compact ($$) { # cb_spawn callback
$pr->("$pfx `".join(' ', @$cmd)."'\n") if $pr;
push @$cmd, $src, $dst;
my ($rd, $pid);
- local %SIG = %SIG;
+ local @SIG{keys %SIG} = values %SIG;
setup_signals(\&kill_compact, \$pid);
($rd, $pid) = popen_rd($cmd, undef, $rdr);
while (<$rd>) {
@@ -406,7 +414,7 @@ sub cpdb ($$) { # cb_spawn callback
my $new = $newdir->dirname;
my ($src, $cur_shard);
my $reshard;
- PublicInbox::SearchIdx::load_xapian_writable() or die;
+ PublicInbox::SearchIdx::load_xapian_writable();
my $XapianDatabase = $PublicInbox::Search::X{Database};
if (ref($old) eq 'ARRAY') {
($cur_shard) = ($new =~ m!(?:xap|ei)[0-9]+/([0-9]+)\b!);
@@ -429,14 +437,14 @@ sub cpdb ($$) { # cb_spawn callback
}
my ($tmp, $ft);
- local %SIG = %SIG;
+ local @SIG{keys %SIG} = values %SIG;
if ($opt->{compact}) {
- my $dir = dirname($new);
+ my ($dir) = ($new =~ m!(.*?/)[^/]+/*\z!);
same_fs_or_die($dir, $new);
$ft = File::Temp->newdir("$new.compact-XXXX", DIR => $dir);
setup_signals();
$tmp = $ft->dirname;
- nodatacow_dir($tmp);
+ PublicInbox::Syscall::nodatacow_dir($tmp);
} else {
$tmp = $new;
}