]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiMailSync.pm
rewrite Linux nodatacow use in pure Perl w/o system
[public-inbox.git] / lib / PublicInbox / LeiMailSync.pm
index f2f1e3ed265838e384ad303b8e084c9575719e03..182b0c222412d35ef740353ffb1fd5629d0738aa 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 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>
 
 # for maintaining synchronization between lei/store <=> Maildir|MH|IMAP|JMAP
@@ -15,9 +15,9 @@ sub dbh_new {
        my $f = $self->{filename};
        my $creat = $rw && !-s $f;
        if ($creat) {
-               require PublicInbox::Spawn;
+               require PublicInbox::Syscall;
                open my $fh, '+>>', $f or Carp::croak "open($f): $!";
-               PublicInbox::Spawn::nodatacow_fd(fileno($fh));
+               PublicInbox::Syscall::nodatacow_fh($fh);
        }
        my $dbh = DBI->connect("dbi:SQLite:dbname=$f",'','', {
                AutoCommit => 1,
@@ -182,16 +182,20 @@ sub mv_src {
        my ($self, $folder, $oidbin, $id, $newbn) = @_;
        my $lk = $self->lock_for_scope;
        my $fid = $self->{fmap}->{$folder} //= fid_for($self, $folder, 1);
+       $self->{dbh}->begin_work;
        my $sth = $self->{dbh}->prepare_cached(<<'');
 UPDATE blob2name SET name = ? WHERE fid = ? AND oidbin = ? AND name = ?
 
-       my $nr = $sth->execute($newbn, $fid, $oidbin, $$id);
-       if ($nr == 0) { # may race with a clear_src, ensure new value exists
+       # eval since unique constraint may fail due to race
+       my $nr = eval { $sth->execute($newbn, $fid, $oidbin, $$id) };
+       if (!defined($nr) || $nr == 0) { # $nr may be `0E0'
+               # may race with a clear_src, ensure new value exists
                $sth = $self->{dbh}->prepare_cached(<<'');
 INSERT OR IGNORE INTO blob2name (oidbin, fid, name) VALUES (?, ?, ?)
 
                $sth->execute($oidbin, $fid, $newbn);
        }
+       $self->{dbh}->commit;
 }
 
 # read-only, iterates every oidbin + UID or name for a given folder
@@ -339,9 +343,12 @@ WHERE b.oidbin = ?
                        next unless -s $fh;
                        local $/;
                        my $raw = <$fh>;
-                       if ($vrfy && git_sha(1, \$raw)->hexdigest ne $oidhex) {
-                               warn "$f changed $oidhex\n";
-                               next;
+                       if ($vrfy) {
+                               my $got = git_sha(1, \$raw)->hexdigest;
+                               if ($got ne $oidhex) {
+                                       warn "$f changed $oidhex => $got\n";
+                                       next;
+                               }
                        }
                        return \$raw;
                }