about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2021-10-21 21:10:31 +0000
committerEric Wong <e@80x24.org>2021-10-22 00:54:50 +0000
commit2c354e17694da744c6dc1ab19c14af3d456b28bb (patch)
tree192dab7aba9eff77833050cb9b3d7957cb9690dd /lib/PublicInbox
parent17a178cd376fc132370ec4a172ce9dc5f71d8622 (diff)
downloadpublic-inbox-2c354e17694da744c6dc1ab19c14af3d456b28bb.tar.gz
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.
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/LeiMailSync.pm8
1 files changed, 6 insertions, 2 deletions
diff --git a/lib/PublicInbox/LeiMailSync.pm b/lib/PublicInbox/LeiMailSync.pm
index e70cb5de..124eb969 100644
--- a/lib/PublicInbox/LeiMailSync.pm
+++ b/lib/PublicInbox/LeiMailSync.pm
@@ -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