about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
authorEric Wong (Contractor, The Linux Foundation) <e@80x24.org>2018-04-04 21:25:00 +0000
committerEric Wong (Contractor, The Linux Foundation) <e@80x24.org>2018-04-04 21:54:46 +0000
commit2431ec2a5db67a9837eab95a9eeaeb4720425e81 (patch)
tree67f4f64b2b933b143d36df40eca4b37861f3e732 /lib/PublicInbox
parent678fb3c2ba03a4a284620c039717c0d94dd6106a (diff)
downloadpublic-inbox-2431ec2a5db67a9837eab95a9eeaeb4720425e81.tar.gz
v2writable: do not modify DBs while iterating for ->remove
Xapian may become unhappy if a DB is modified during iteration:
nntp://news.gmane.org/20180228004400.GU12724@survex.com
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/V2Writable.pm46
1 files changed, 27 insertions, 19 deletions
diff --git a/lib/PublicInbox/V2Writable.pm b/lib/PublicInbox/V2Writable.pm
index 5b4d9c0d..74953d34 100644
--- a/lib/PublicInbox/V2Writable.pm
+++ b/lib/PublicInbox/V2Writable.pm
@@ -256,6 +256,7 @@ sub remove_internal {
         my $mark;
 
         foreach my $mid (@$mids) {
+                my %gone;
                 $srch->reopen->each_smsg_by_mid($mid, sub {
                         my ($smsg) = @_;
                         $smsg->load_expand;
@@ -267,28 +268,35 @@ sub remove_internal {
                         my $orig = $$msg;
                         my $cur = PublicInbox::MIME->new($msg);
                         if (content_id($cur) eq $cid) {
-                                $mm->num_delete($smsg->num);
-                                # $removed should only be set once assuming
-                                # no bugs in our deduplication code:
-                                $removed = $smsg;
-                                $removed->{mime} = $cur;
-                                my $oid = $smsg->{blob};
-                                if ($purge) {
-                                        $purge->{$oid} = 1;
-                                } else {
-                                        ($mark, undef) =
-                                                $im->remove(\$orig, $cmt_msg);
-                                }
-                                $orig = undef;
-                                $removed->num; # memoize this for callers
-
-                                foreach my $idx (@$parts) {
-                                        $idx->remote_remove($oid, $mid);
-                                }
-                                $self->{over}->remove_oid($oid, $mid);
+                                $smsg->{mime} = $cur;
+                                $gone{$smsg->num} = [ $smsg, \$orig ];
                         }
                         1; # continue
                 });
+                my $n = scalar keys %gone;
+                next unless $n;
+                if ($n > 1) {
+                        warn "BUG: multiple articles linked to <$mid>\n",
+                                join(',', sort keys %gone), "\n";
+                }
+                foreach my $num (keys %gone) {
+                        my ($smsg, $orig) = @{$gone{$num}};
+                        $mm->num_delete($num);
+                        # $removed should only be set once assuming
+                        # no bugs in our deduplication code:
+                        $removed = $smsg;
+                        my $oid = $smsg->{blob};
+                        if ($purge) {
+                                $purge->{$oid} = 1;
+                        } else {
+                                ($mark, undef) = $im->remove($orig, $cmt_msg);
+                        }
+                        $orig = undef;
+                        foreach my $idx (@$parts) {
+                                $idx->remote_remove($oid, $mid);
+                        }
+                        $self->{over}->remove_oid($oid, $mid);
+                }
                 $self->barrier;
         }