# Copyright (C) 2015-2020 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
-# based on notmuch, but with no concept of folders, files or flags
+# based on notmuch, but with no concept of folders, files
#
# Indexes mail with Xapian and our (SQLite-based) ::Msgmap for use
# with the web and NNTP interfaces. This index maintains thread
index_headers($self, $smsg);
if (defined(my $eidx_key = $smsg->{eidx_key})) {
- $doc->add_boolean_term('O'.$eidx_key);
+ $doc->add_boolean_term('O'.$eidx_key) if $eidx_key ne '.';
}
msg_iter($eml, \&index_xapian, [ $self, $doc ]);
index_ids($self, $doc, $eml, $mids);
begin_txn_lazy($self);
my $doc = _get_doc($self, $docid) or return;
term_generator($self)->set_document($doc);
- $doc->add_boolean_term('O'.$eidx_key);
+ $doc->add_boolean_term('O'.$eidx_key) if $eidx_key ne '.';
index_list_id($self, $doc, $eml);
$self->{xdb}->replace_document($docid, $doc);
}
$self->{xdb}->replace_document($docid, $doc);
}
+sub set_keywords {
+ my ($self, $docid, @kw) = @_;
+ begin_txn_lazy($self);
+ my $doc = _get_doc($self, $docid) or return;
+ my %keep = map { $_ => 1 } @kw;
+ my %add = %keep;
+ my @rm;
+ my $end = $doc->termlist_end;
+ for (my $cur = $doc->termlist_begin; $cur != $end; $cur++) {
+ $cur->skip_to('K');
+ last if $cur == $end;
+ my $kw = $cur->get_termname;
+ $kw =~ s/\AK//s or next;
+ $keep{$kw} ? delete($add{$kw}) : push(@rm, $kw);
+ }
+ return unless (scalar(@rm) + scalar(keys %add));
+ $doc->remove_term('K'.$_) for @rm;
+ $doc->add_boolean_term('K'.$_) for (keys %add);
+ $self->{xdb}->replace_document($docid, $doc);
+}
+
+sub add_keywords {
+ my ($self, $docid, @kw) = @_;
+ begin_txn_lazy($self);
+ my $doc = _get_doc($self, $docid) or return;
+ $doc->add_boolean_term('K'.$_) for @kw;
+ $self->{xdb}->replace_document($docid, $doc);
+}
+
+sub remove_keywords {
+ my ($self, $docid, @kw) = @_;
+ begin_txn_lazy($self);
+ my $doc = _get_doc($self, $docid) or return;
+ my $replace;
+ eval {
+ $doc->remove_term('K'.$_);
+ $replace = 1
+ } for @kw;
+ $self->{xdb}->replace_document($docid, $doc) if $replace;
+}
+
sub get_val ($$) {
my ($doc, $col) = @_;
sortable_unserialise($doc->get_value($col));
$size += crlf_adjust($$bref);
my $smsg = bless { bytes => $size, blob => $oid }, 'PublicInbox::Smsg';
my $self = $sync->{sidx};
+ local $self->{current_info} = "$self->{current_info}: $oid";
my $eml = PublicInbox::Eml->new($bref);
$smsg->{num} = index_mm($self, $eml, $oid, $sync) or
die "E: could not generate NNTP article number for $oid";
sub unindex_both { # git->cat_async callback
my ($bref, $oid, $type, $size, $sync) = @_;
return if is_bad_blob($oid, $type, $size, $sync->{oid});
- unindex_eml($sync->{sidx}, $oid, PublicInbox::Eml->new($bref));
+ my $self = $sync->{sidx};
+ local $self->{current_info} = "$self->{current_info}: $oid";
+ unindex_eml($self, $oid, PublicInbox::Eml->new($bref));
# may be undef if leftover
if (defined(my $cur_cmt = $sync->{cur_cmt})) {
${$sync->{latest_cmt}} = $cur_cmt;
my ($self, $opt) = @_;
my $tip = $opt->{ref} || 'HEAD';
my $ibx = $self->{ibx};
+ local $self->{current_info} = "$ibx->{inboxdir}";
$self->{batch_bytes} = $opt->{batch_size} // $BATCH_BYTES;
$ibx->git->batch_prepare;
my $pr = $opt->{-progress};
}
}
-sub reindex_xap { # git->cat_async callback
- my ($bref, $oid, $type, $size, $ary) = @_;
- my ($ibx_id, $oidhex, $req, $more) = @$ary;
- my $self = $req->{self} // die 'BUG: {self} missing';
- my $eidx = $self->{eidx} // die 'BUG: {eidx} missing';
- my $eidx_key = $self->{-eidx_key_for}->{$ibx_id} //
- die "BUG: bad ibx_id=$ibx_id ($oid)";
-
- my $docid = $req->{docid};
- local $eidx->{current_info} = "#$docid $oid";
- return if is_bad_blob($oid, $type, $size, $oidhex);
- if (my $doc = $req->{doc}) { # modify existing doc
- $req->{tg_isset} //= do { # for existing documents in {xdb}
- term_generator($self)->set_document($doc);
- 1;
- };
- $doc->add_boolean_term('O'.$eidx_key);
- index_list_id($self, $doc, PublicInbox::Eml->new($bref));
- } else { # first time seeing this doc
- my $smsg = $self->{eidx}->over->get_art($docid) //
- die "BUG: #$docid ($oid) not in over";
- $smsg->{bytes} = $size + crlf_adjust($$bref);
- $smsg->{eidx_key} = $eidx_key;
- my $eml = PublicInbox::Eml->new($bref);
- $req->{doc} = eml2doc($self, $eml, $smsg);
- $req->{tg_isset} = 1; # eml2doc calls $tg->set_document
- }
- return if $more;
- my $doc = delete($req->{doc}) or return; # all bad blobs!
- $eidx->{transact_bytes} += $size;
- $self->{xdb}->replace_document($req->{docid}, $doc);
-}
-
-sub reindex_docid {
- my ($self, $docid) = @_;
- my $eidx = $self->{eidx} // die 'BUG: {eidx} missing';
- my $eidx_key_for = $self->{-eidx_key_for} //= do {
- my %eidx_key_for = map {
- $_->[0] => $_->[1];
- } @{$eidx->over->dbh->selectall_arrayref(<<'')};
-SELECT ibx_id,eidx_key FROM inboxes
-
- \%eidx_key_for;
- };
-
- begin_txn_lazy($self);
- my $doc = eval { $self->{xdb}->get_document($docid) };
- my $req = { doc => $doc, self => $self, docid => $docid };
- my $sth = $eidx->over->dbh->prepare_cached(<<'', undef, 1);
-SELECT ibx_id,oidbin FROM xref3 WHERE docid = ? ORDER BY ibx_id ASC
-
- $sth->execute($docid);
- my $rows = $sth->fetchall_arrayref;
- while (my $row = shift(@$rows)) {
- my ($ibx_id, $oidbin) = @$row;
- my $oidhex = unpack('H*', $oidbin);
- $eidx->git->cat_async($oidhex, \&reindex_xap,
- [ $ibx_id, $oidhex, $req, scalar(@$rows) ]);
- }
- if ($eidx->{transact_bytes} >= $eidx->{batch_bytes}) {
- commit_txn_lazy($self);
- }
-}
-
1;