X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FXapcmd.pm;h=106856369c689007470b7ec364796e29079821f6;hb=23af251dd607c4e75ab1e68063f2c885c48cc035;hp=588e7b9408617e1fb92adef2a7b91dde3014820d;hpb=4c6f9a39621fdae852e0655b7db3d61f03c716c5;p=public-inbox.git diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm index 588e7b94..10685636 100644 --- a/lib/PublicInbox/Xapcmd.pm +++ b/lib/PublicInbox/Xapcmd.pm @@ -1,8 +1,9 @@ -# 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; @@ -20,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): $!"; } @@ -46,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 @@ -149,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)) { @@ -203,7 +212,7 @@ sub prepare_run { 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"; @@ -234,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 @@ -285,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); } @@ -343,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>) { @@ -428,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) = ($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; }