use Search::Xapian qw/:standard/;
use PublicInbox::SearchMsg;
use PublicInbox::MIME;
-use PublicInbox::MID qw/mid_clean id_compress/;
+use PublicInbox::MID qw/id_compress/;
# This is English-only, everything else is non-standard and may be confused as
# a prefix common in patch emails
sub get_thread {
my ($self, $mid, $opts) = @_;
- my $smsg = retry_reopen($self, sub { lookup_skeleton($self, $mid) });
-
- return { total => 0, msgs => [] } unless $smsg;
+ my $smsg = first_smsg_by_mid($self, $mid) or
+ return { total => 0, msgs => [] };
my $qtid = Search::Xapian::Query->new('G' . $smsg->thread_id);
my $path = $smsg->path;
if (defined $path && $path ne '') {
sub retry_reopen {
my ($self, $cb) = @_;
my $ret;
- for (1..10) {
+ for my $i (1..10) {
eval { $ret = $cb->() };
return $ret unless $@;
# Exception: The revision being read has been discarded -
# you should call Xapian::Database::reopen()
if (ref($@) eq 'Search::Xapian::DatabaseModifiedError') {
+ warn "reopen try #$i on $@\n";
reopen($self);
} else {
warn "ref: ", ref($@), "\n";
die;
}
}
+ die "Too many Xapian database modifications in progress\n";
}
sub _do_enquire {
_do_enquire($self, $query, $opts);
}
-sub lookup_skeleton {
- my ($self, $mid) = @_;
- my $skel = $self->{skel} or return lookup_message($self, $mid);
- $mid = mid_clean($mid);
- my $term = 'Q' . $mid;
- my $smsg;
- my $beg = $skel->postlist_begin($term);
- if ($beg != $skel->postlist_end($term)) {
- my $doc_id = $beg->get_docid;
- if (defined $doc_id) {
- # raises on error:
- my $doc = $skel->get_document($doc_id);
- $smsg = PublicInbox::SearchMsg->wrap($doc, $mid);
- $smsg->{doc_id} = $doc_id;
- }
- }
- $smsg;
-}
-
-sub lookup_message {
+sub first_smsg_by_mid {
my ($self, $mid) = @_;
- $mid = mid_clean($mid);
-
- my $doc_id = $self->find_first_doc_id('Q' . $mid);
my $smsg;
- if (defined $doc_id) {
- # raises on error:
- my $doc = $self->{xdb}->get_document($doc_id);
- $smsg = PublicInbox::SearchMsg->wrap($doc, $mid);
- $smsg->{doc_id} = $doc_id;
- }
- $smsg;
-}
-
-sub lookup_mail { # no ghosts!
- my ($self, $mid) = @_;
retry_reopen($self, sub {
- my $smsg = lookup_skeleton($self, $mid) or return;
- $smsg->load_expand;
+ each_smsg_by_mid($self, $mid, sub { $smsg = $_[0]; undef });
});
+ $smsg;
}
sub lookup_article {
my ($self, $num) = @_;
my $term = 'XNUM'.$num;
- my $smsg;
- eval {
- retry_reopen($self, sub {
- my $db = $self->{skel} || $self->{xdb};
- my $head = $db->postlist_begin($term);
- return if $head == $db->postlist_end($term);
- my $doc_id = $head->get_docid;
- return unless defined $doc_id;
- # raises on error:
- my $doc = $db->get_document($doc_id);
- $smsg = PublicInbox::SearchMsg->wrap($doc);
- $smsg->load_expand;
- $smsg->{doc_id} = $doc_id;
- });
- };
- $smsg;
+ my $db = $self->{skel} || $self->{xdb};
+ retry_reopen($self, sub {
+ my $head = $db->postlist_begin($term);
+ my $tail = $db->postlist_end($term);
+ return if $head->equal($tail);
+ my $doc_id = $head->get_docid;
+ return unless defined $doc_id;
+ $head->inc;
+ if ($head->nequal($tail)) {
+ my $loc= $self->{mainrepo} .
+ ($self->{skel} ? 'skel' : 'xdb');
+ warn "article #$num is not unique in $loc\n";
+ }
+ # raises on error:
+ my $doc = $db->get_document($doc_id);
+ my $smsg = PublicInbox::SearchMsg->wrap($doc);
+ $smsg->{doc_id} = $doc_id;
+ $smsg->load_expand;
+ });
}
sub each_smsg_by_mid {
my $term = 'Q' . $mid;
my $head = $db->postlist_begin($term);
my $tail = $db->postlist_end($term);
+ if ($head == $tail) {
+ $db->reopen;
+ $head = $db->postlist_begin($term);
+ $tail = $db->postlist_end($term);
+ }
return ($head, $tail, $db) if wantarray;
for (; $head->nequal($tail); $head->inc) {
my $doc_id = $head->get_docid;
}
}
-sub find_unique_doc_id {
- my ($self, $termval) = @_;
-
- my ($begin, $end) = $self->find_doc_ids($termval);
-
- return undef if $begin->equal($end); # not found
-
- my $rv = $begin->get_docid;
-
- # sanity check
- $begin->inc;
- $begin->equal($end) or die "Term '$termval' is not unique\n";
- $rv;
-}
-
-# returns begin and end PostingIterator
-sub find_doc_ids {
- my ($self, $termval) = @_;
- my $db = $self->{xdb};
-
- ($db->postlist_begin($termval), $db->postlist_end($termval));
-}
-
-sub find_first_doc_id {
- my ($self, $termval) = @_;
-
- my ($begin, $end) = $self->find_doc_ids($termval);
-
- return undef if $begin->equal($end); # not found
-
- $begin->get_docid;
-}
-
# normalize subjects so they are suitable as pathnames for URLs
# XXX: consider for removal
sub subject_path {