]> Sergey Matveev's repositories - public-inbox.git/commitdiff
xcpdb: remove temporary directories on aborts
authorEric Wong <e@80x24.org>
Thu, 23 May 2019 09:36:59 +0000 (09:36 +0000)
committerEric Wong <e@80x24.org>
Thu, 23 May 2019 17:43:50 +0000 (17:43 +0000)
Cleanup temporary directories on common termination signals
(INT, HUP, PIPE, TERM), but only if it's not in the process
of being committed via rename() sequence.

lib/PublicInbox/Xapcmd.pm

index 0e4480473b86ddfb9047d69d0d4ff273b49c2a1d..06389dd0fdef53fa8b03613d8538b3e0e5950fd8 100644 (file)
@@ -31,13 +31,15 @@ sub commit_changes ($$$) {
                        $over->connect->sqlite_backup_to_file($tmp_over);
                        $over = undef;
                }
+               chmod($st[2] & 07777, $new) or die "chmod $old: $!\n";
 
+               # Xtmpdir->DESTROY won't remove $new after this:
                rename($old, "$new/old") or die "rename $old => $new/old: $!\n";
-               chmod($st[2] & 07777, $new) or die "chmod $old: $!\n";
                rename($new, $old) or die "rename $new => $old: $!\n";
                my $prev = "$old/old";
                remove_tree($prev) or die "failed to remove $prev: $!\n";
        }
+       $tmp->done;
        if ($reindex) {
                $opt->{-skip_lock} = 1;
                PublicInbox::Admin::index_inbox($ibx, $opt);
@@ -126,7 +128,7 @@ sub run {
        my $old = $ibx->search->xdir(1);
        -d $old or die "$old does not exist\n";
 
-       my $tmp = {}; # old partition => new (tmp) partition
+       my $tmp = PublicInbox::Xtmpdirs->new;
        my $v = $ibx->{version} ||= 1;
        my @cmds;
 
@@ -286,4 +288,37 @@ sub cpdb {
        remove_tree($tmp) or die "failed to remove $tmp: $!\n";
 }
 
+# slightly easier-to-manage manage than END{} blocks
+package PublicInbox::Xtmpdirs;
+use strict;
+use warnings;
+use File::Path qw(remove_tree);
+my %owner;
+
+sub new {
+       # http://www.tldp.org/LDP/abs/html/exitcodes.html
+       $SIG{INT} = sub { exit(130) };
+       $SIG{HUP} = $SIG{PIPE} = $SIG{TERM} = sub { exit(1) };
+       my $self = bless {}, $_[0]; # old partition => new (tmp) partition
+       $owner{"$self"} = $$;
+       $self;
+}
+
+sub done {
+       my ($self) = @_;
+       delete $owner{"$self"};
+       $SIG{INT} = $SIG{HUP} = $SIG{PIPE} = $SIG{TERM} = 'DEFAULT';
+       %$self = ();
+}
+
+sub DESTROY {
+       my ($self) = @_;
+       my $owner_pid = delete $owner{"$self"} or return;
+       return if $owner_pid != $$;
+       foreach my $new (values %$self) {
+               remove_tree($new) unless -d "$new/old";
+       }
+       $SIG{INT} = $SIG{HUP} = $SIG{PIPE} = $SIG{TERM} = 'DEFAULT';
+}
+
 1;