diff options
author | Eric Wong <e@80x24.org> | 2021-10-21 21:10:32 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2021-10-22 00:54:51 +0000 |
commit | 4cd7a78f3b8c03670e2d77675229472506eee1eb (patch) | |
tree | 2a0e89de3e77b70962e509d41883518fb6574dde /lib/PublicInbox/LeiExportKw.pm | |
parent | 2c354e17694da744c6dc1ab19c14af3d456b28bb (diff) | |
download | public-inbox-4cd7a78f3b8c03670e2d77675229472506eee1eb.tar.gz |
One syscall is better than two for atomicity in Maildirs. This means there's no window where another process can see both the old and new file at the same time (link && unlink), nor a window where we might inadvertantly clobber an existing file if we were to do `stat && rename'.
Diffstat (limited to 'lib/PublicInbox/LeiExportKw.pm')
-rw-r--r-- | lib/PublicInbox/LeiExportKw.pm | 19 |
1 files changed, 6 insertions, 13 deletions
diff --git a/lib/PublicInbox/LeiExportKw.pm b/lib/PublicInbox/LeiExportKw.pm index 0b65c276..ceeef7f2 100644 --- a/lib/PublicInbox/LeiExportKw.pm +++ b/lib/PublicInbox/LeiExportKw.pm @@ -7,6 +7,7 @@ use strict; use v5.10.1; use parent qw(PublicInbox::IPC PublicInbox::LeiInput); use Errno qw(EEXIST ENOENT); +use PublicInbox::Syscall qw(rename_noreplace); sub export_kw_md { # LeiMailSync->each_src callback my ($oidbin, $id, $self, $mdir) = @_; @@ -30,30 +31,22 @@ sub export_kw_md { # LeiMailSync->each_src callback my $lei = $self->{lei}; for my $d (@try) { my $src = "$mdir/$d/$$id"; - - # we use link(2) + unlink(2) since rename(2) may - # inadvertently clobber if the "uniquefilename" part wasn't - # actually unique. - if (link($src, $dst)) { # success - # unlink(2) may ENOENT from parallel invocation, - # ignore it, but not other serious errors - if (!unlink($src) and $! != ENOENT) { - $lei->child_error(1, "E: unlink($src): $!"); - } + if (rename_noreplace($src, $dst)) { # success $self->{lms}->mv_src("maildir:$mdir", $oidbin, $id, $bn); - return; # success anyways if link(2) worked + return; # success } elsif ($! == EEXIST) { # lost race with lei/store? return; } elsif ($! != ENOENT) { - $lei->child_error(1, "E: link($src -> $dst): $!"); + $lei->child_error(1, + "E: rename_noreplace($src -> $dst): $!"); } # else loop @try } my $e = $!; # both tries failed my $oidhex = unpack('H*', $oidbin); my $src = "$mdir/{".join(',', @try)."}/$$id"; - $lei->child_error(1, "link($src -> $dst) ($oidhex): $e"); + $lei->child_error(1, "rename_noreplace($src -> $dst) ($oidhex): $e"); for (@try) { return if -e "$mdir/$_/$$id" } $self->{lms}->clear_src("maildir:$mdir", $id); } |