]> Sergey Matveev's repositories - public-inbox.git/commitdiff
search: retry document loading from Xapian
authorEric Wong <e@80x24.org>
Sat, 10 Dec 2016 23:35:43 +0000 (23:35 +0000)
committerEric Wong <e@80x24.org>
Sat, 10 Dec 2016 23:44:10 +0000 (23:44 +0000)
In addition to needing to retry enquire queries, we also need
to protect document loading from the Xapian DB and retry on
modification, as it seems to throw the same errors.

Checking the $@ ref for Search::Xapian::DatabaseModifiedError
is actually in the test suite for both the XS and SWIG Xapian
bindings, so we should be good as far as forward/backwards
compatibility.

lib/PublicInbox/Search.pm
lib/PublicInbox/SearchView.pm
lib/PublicInbox/View.pm

index 5e6bfc68bdb3d20985ffc177660b270c6ed3cd09..24cb26670754b2f4a21b62e7d22c3cdc76098a5a 100644 (file)
@@ -166,22 +166,27 @@ sub get_thread {
        _do_enquire($self, $qtid, $opts);
 }
 
-sub _do_enquire {
-       my ($self, $query, $opts) = @_;
+sub retry_reopen {
+       my ($self, $cb) = @_;
        my $ret;
        for (1..10) {
-               eval { $ret = _enquire_once($self, $query, $opts) };
+               eval { $ret = $cb->() };
                return $ret unless $@;
                # Exception: The revision being read has been discarded -
                # you should call Xapian::Database::reopen()
-               if (index($@, 'Xapian::Database::reopen') >= 0) {
+               if (ref($@) eq 'Search::Xapian::DatabaseModifiedError') {
                        reopen($self);
                } else {
-                       die $@;
+                       die;
                }
        }
 }
 
+sub _do_enquire {
+       my ($self, $query, $opts) = @_;
+       retry_reopen($self, sub { _enquire_once($self, $query, $opts) });
+}
+
 sub _enquire_once {
        my ($self, $query, $opts) = @_;
        my $enquire = $self->enquire;
index 6af151a4b82fc360779046899dbd1ad7647aea3c..50a2c01c4749f05ab54dc73a5d05ee04747d4884 100644 (file)
@@ -59,6 +59,17 @@ sub sres_top_html {
        PublicInbox::WwwStream->response($ctx, $code, $cb);
 }
 
+# allow undef for individual doc loads...
+sub load_doc_retry {
+       my ($srch, $mitem) = @_;
+
+       eval {
+               $srch->retry_reopen(sub {
+                       PublicInbox::SearchMsg->load_doc($mitem->get_document)
+               });
+       }
+}
+
 # display non-threaded search results similar to what users expect from
 # regular WWW search engines:
 sub mset_summary {
@@ -68,10 +79,18 @@ sub mset_summary {
        my $pad = length("$total");
        my $pfx = ' ' x $pad;
        my $res = \($ctx->{-html_tip});
+       my $srch = $ctx->{srch};
        foreach my $m ($mset->items) {
                my $rank = sprintf("%${pad}d", $m->get_rank + 1);
                my $pct = $m->get_percent;
-               my $smsg = PublicInbox::SearchMsg->load_doc($m->get_document);
+               my $smsg = load_doc_retry($srch, $m);
+               unless ($smsg) {
+                       eval {
+                               $m = "$m ".$m->get_docid . " expired\n";
+                               $ctx->{env}->{'psgi.errors'}->print($m);
+                       };
+                       next;
+               }
                my $s = ascii_html($smsg->subject);
                my $f = ascii_html($smsg->from_name);
                my $ts = PublicInbox::View::fmt_ts($smsg->ts);
@@ -145,14 +164,14 @@ sub search_nav_bot {
 sub mset_thread {
        my ($ctx, $mset, $q) = @_;
        my %pct;
-       my @m = map {
+       my $msgs = $ctx->{srch}->retry_reopen(sub { [ map {
                my $i = $_;
-               my $m = PublicInbox::SearchMsg->load_doc($i->get_document);
-               $pct{$m->mid} = $i->get_percent;
-               $m;
-       } ($mset->items);
+               my $smsg = PublicInbox::SearchMsg->load_doc($i->get_document);
+               $pct{$smsg->mid} = $i->get_percent;
+               $smsg;
+       } ($mset->items) ]});
 
-       my $th = PublicInbox::SearchThread->new(\@m);
+       my $th = PublicInbox::SearchThread->new($msgs);
        $th->thread;
        if ($q->{r}) { # order by relevance
                $th->order(sub {
@@ -175,12 +194,11 @@ sub mset_thread {
        $ctx->{prev_attr} = '';
        $ctx->{prev_level} = 0;
        $ctx->{seen} = {};
-       $ctx->{s_nr} = scalar(@m).'+ results';
+       $ctx->{s_nr} = scalar(@$msgs).'+ results';
 
        PublicInbox::View::walk_thread($th, $ctx,
                *PublicInbox::View::pre_thread);
 
-       my $msgs = \@m;
        my $mime;
        sub {
                return unless $msgs;
@@ -217,9 +235,10 @@ sub adump {
        my $ibx = $ctx->{-inbox};
        my @items = $mset->items;
        $ctx->{search_query} = $q;
+       my $srch = $ctx->{srch};
        PublicInbox::WwwAtomStream->response($ctx, 200, sub {
                while (my $x = shift @items) {
-                       $x = PublicInbox::SearchMsg->load_doc($x->get_document);
+                       $x = load_doc_retry($srch, $x);
                        $x = $ibx->msg_by_smsg($x) and
                                        return Email::MIME->new($x);
                }
index ec5f7e0f162b57359714ac90bd6590fb43728420..fa47a16a3d3d40087a0390e8d03ed937c18f88db 100644 (file)
@@ -327,8 +327,9 @@ sub stream_thread ($$) {
 sub thread_html {
        my ($ctx) = @_;
        my $mid = $ctx->{mid};
-       my $sres = $ctx->{srch}->get_thread($mid);
-       my $msgs = load_results($sres);
+       my $srch = $ctx->{srch};
+       my $sres = $srch->get_thread($mid);
+       my $msgs = load_results($srch, $sres);
        my $nr = $sres->{total};
        return missing_thread($ctx) if $nr == 0;
        my $skel = '<hr><pre>';
@@ -574,7 +575,8 @@ sub thread_skel {
        $ctx->{prev_attr} = '';
        $ctx->{prev_level} = 0;
        $ctx->{dst} = $dst;
-       walk_thread(thread_results(load_results($sres)), $ctx, *skel_dump);
+       $sres = load_results($srch, $sres);
+       walk_thread(thread_results($sres), $ctx, *skel_dump);
        $ctx->{parent_msg} = $parent;
 }
 
@@ -733,9 +735,9 @@ sub indent_for {
 }
 
 sub load_results {
-       my ($sres) = @_;
-
-       [ map { $_->ensure_metadata; $_ } @{delete $sres->{msgs}} ];
+       my ($srch, $sres) = @_;
+       my $msgs = delete $sres->{msgs};
+       $srch->retry_reopen(sub { [ map { $_->ensure_metadata; $_ } @$msgs ] });
 }
 
 sub msg_timestamp {
@@ -975,10 +977,11 @@ sub index_topics {
        my $opts = { offset => $off, limit => 200 };
 
        $ctx->{order} = [];
-       my $sres = $ctx->{srch}->query('', $opts);
+       my $srch = $ctx->{srch};
+       my $sres = $srch->query('', $opts);
        my $nr = scalar @{$sres->{msgs}};
        if ($nr) {
-               $sres = load_results($sres);
+               $sres = load_results($srch, $sres);
                walk_thread(thread_results($sres), $ctx, *acc_topic);
        }
        $ctx->{-next_o} = $off+ $nr;