-# Copyright (C) 2018-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>
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;
my $reshard = $opt->{reshard};
$SIG{INT} or die 'BUG: $SIG{INT} not handled';
- my @old_shard;
- my $over_chg;
- my $mode;
-
- 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
- $mode //= do {
- my ($dname) = ($old =~ m!(.*/)[^/]+/*\z!);
- (stat($dname))[2];
- };
+ my $newdir = $tmp->{$old};
my $have_old = -e $old;
if (!$have_old && !defined($opt->{reshard})) {
die "failed to stat($old): $!";
die "rename $old => $new/old: $!\n";
}
rename($new, $old) or die "rename $new => $old: $!\n";
- if ($have_old) {
- 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
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";
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
$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;
}