+sub _docids_and_maybe_kw ($$) {
+ my ($self, $docids) = @_;
+ return $docids unless wantarray;
+ my $kw = {};
+ for my $num (@$docids) { # likely only 1, unless ContentHash changes
+ # can't use ->search->msg_keywords on uncommitted docs
+ my $idx = $self->{priv_eidx}->idx_shard($num);
+ my $tmp = eval { $idx->ipc_do('get_terms', 'K', $num) };
+ if ($@) { warn "#$num get_terms: $@" }
+ else { @$kw{keys %$tmp} = values(%$tmp) };
+ }
+ ($docids, [ sort keys %$kw ]);
+}
+
+sub _reindex_1 { # git->cat_async callback
+ my ($bref, $hex, $type, $size, $smsg) = @_;
+ my $self = delete $smsg->{-sto};
+ my ($eidx, $tl) = eidx_init($self);
+ $bref //= _lms_rw($self)->local_blob($hex, 1);
+ if ($bref) {
+ my $eml = PublicInbox::Eml->new($bref);
+ $smsg->{-merge_vmd} = 1; # preserve existing keywords
+ $eidx->idx_shard($smsg->{num})->index_eml($eml, $smsg);
+ } elsif ($type eq 'missing') {
+ # pre-release/buggy lei may've indexed external-only msgs,
+ # try to correct that, here
+ warn("E: missing $hex, culling (ancient lei artifact?)\n");
+ $smsg->{to} = $smsg->{cc} = $smsg->{from} = '';
+ $smsg->{bytes} = 0;
+ $eidx->{oidx}->update_blob($smsg, '');
+ my $eml = PublicInbox::Eml->new("\r\n\r\n");
+ $eidx->idx_shard($smsg->{num})->index_eml($eml, $smsg);
+ } else {
+ warn("E: $type $hex\n");
+ }
+}
+
+sub reindex_art {
+ my ($self, $art) = @_;
+ my ($eidx, $tl) = eidx_init($self);
+ my $smsg = $eidx->{oidx}->get_art($art) // return;
+ return if $smsg->{bytes} == 0; # external-only message
+ $smsg->{-sto} = $self;
+ $eidx->git->cat_async($smsg->{blob} // die("no blob (#$art)"),
+ \&_reindex_1, $smsg);
+}
+
+sub reindex_done {
+ my ($self) = @_;
+ my ($eidx, $tl) = eidx_init($self);
+ $eidx->git->async_wait_all;
+ # ->done to be called via sto_done_request
+}
+