]> Sergey Matveev's repositories - public-inbox.git/commitdiff
lei_mail_sync: mv_src: use transaction, check UNIQUE
authorEric Wong <e@80x24.org>
Thu, 21 Oct 2021 21:10:31 +0000 (21:10 +0000)
committerEric Wong <e@80x24.org>
Fri, 22 Oct 2021 00:54:50 +0000 (00:54 +0000)
We need a transaction across two SQL statements so readers
(which don't use flock) will see the result as atomic.

This may help against some occasional test failures I'm seeing
from t/lei-auto-watch.t and t/lei-watch.t, or make the problem
more apparent.

lib/PublicInbox/LeiMailSync.pm

index e70cb5de2b6b5046736ba72feeeb51a05a6bdf7b..124eb96948c5421c1f1bd66478de7ca6bc0021ad 100644 (file)
@@ -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