X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FExtMsg.pm;h=03faf3a142cdc46d65fc4287edcf01191ac4182a;hb=d11feea98718f2abb109af4216a36bdbd21b7191;hp=1d17c2ce673c230ecfe69fbdaf0a0008be7abaa1;hpb=2fc67a18b7ccd75ea6eb945f18203cbf4bcf228f;p=public-inbox.git diff --git a/lib/PublicInbox/ExtMsg.pm b/lib/PublicInbox/ExtMsg.pm index 1d17c2ce..03faf3a1 100644 --- a/lib/PublicInbox/ExtMsg.pm +++ b/lib/PublicInbox/ExtMsg.pm @@ -29,13 +29,10 @@ our @EXT_URL = map { ascii_html($_) } ( sub PARTIAL_MAX () { 100 } -sub mids_from_mset { # Search::retry_reopen callback - [ map { PublicInbox::Smsg::from_mitem($_)->mid } $_[0]->items ]; -} - sub search_partial ($$) { - my ($srch, $mid) = @_; + my ($ibx, $mid) = @_; return if length($mid) < $MIN_PARTIAL_LEN; + my $srch = $ibx->search or return; my $opt = { limit => PARTIAL_MAX, mset => 2 }; my @try = ("m:$mid*"); my $chop = $mid; @@ -68,79 +65,115 @@ sub search_partial ($$) { # has too many results. $@ can be # Search::Xapian::QueryParserError or even: # "something terrible happened at ../Search/Xapian/Enquire.pm" - my $mset = eval { $srch->query($m, $opt) } or next; - my $mids = $srch->retry_reopen(\&mids_from_mset, $mset); - return $mids if scalar(@$mids); + my $mset = eval { $srch->mset($m, $opt) } or next; + my @mids = map { + $_->{mid} + } @{$srch->mset_to_smsg($ibx, $mset)}; + return \@mids if scalar(@mids); } } sub ext_msg_i { - my ($other, $arg) = @_; - my ($cur, $mid, $ibxs, $found) = @$arg; + my ($other, $ctx) = @_; - return if $other->{name} eq $cur->{name} || !$other->base_url; + return if $other->{name} eq $ctx->{-inbox}->{name} || !$other->base_url; my $mm = $other->mm or return; # try to find the URL with Msgmap to avoid forking - my $num = $mm->num_for($mid); + my $num = $mm->num_for($ctx->{mid}); if (defined $num) { - push @$found, $other; + push @{$ctx->{found}}, $other; } else { # no point in trying the fork fallback if we # know Xapian is up-to-date but missing the # message in the current repo - push @$ibxs, $other; + push @{$ctx->{again}}, $other; + } +} + +sub ext_msg_step { + my ($pi_cfg, $section, $ctx) = @_; + if (defined($section)) { + return if $section !~ m!\Apublicinbox\.([^/]+)\z!; + my $ibx = $pi_cfg->lookup_name($1) or return; + ext_msg_i($ibx, $ctx); + } else { # undef == "EOF" + finalize_exact($ctx); } } sub ext_msg { my ($ctx) = @_; - my $cur = $ctx->{-inbox}; - my $mid = $ctx->{mid}; + sub { + $ctx->{-wcb} = $_[0]; # HTTP server write callback + + if ($ctx->{env}->{'pi-httpd.async'}) { + require PublicInbox::ConfigIter; + my $iter = PublicInbox::ConfigIter->new( + $ctx->{www}->{pi_config}, + \&ext_msg_step, $ctx); + $iter->event_step; + } else { + $ctx->{www}->{pi_config}->each_inbox(\&ext_msg_i, $ctx); + finalize_exact($ctx); + } + }; +} - eval { require PublicInbox::Msgmap }; - my $ibxs = []; - my $found = []; - my $arg = [ $cur, $mid, $ibxs, $found ]; +# called via PublicInbox::DS->EventLoop +sub event_step { + my ($ctx, $sync) = @_; + # can't find a partial match in current inbox, try the others: + my $ibx = shift @{$ctx->{again}} or return finalize_partial($ctx); + my $mids = search_partial($ibx, $ctx->{mid}) or + return ($sync ? undef : PublicInbox::DS::requeue($ctx)); + $ctx->{n_partial} += scalar(@$mids); + push @{$ctx->{partial}}, [ $ibx, $mids ]; + $ctx->{n_partial} >= PARTIAL_MAX ? finalize_partial($ctx) + : ($sync ? undef : PublicInbox::DS::requeue($ctx)); +} - $ctx->{www}->{pi_config}->each_inbox(\&ext_msg_i, $arg); +sub finalize_exact { + my ($ctx) = @_; - return exact($ctx, $found, $mid) if @$found; + return $ctx->{-wcb}->(exact($ctx)) if $ctx->{found}; # fall back to partial MID matching - my @partial; - my $n_partial = 0; - my $srch = $cur->search; - my $mids = search_partial($srch, $mid) if $srch; + my $mid = $ctx->{mid}; + my $cur = $ctx->{-inbox}; + my $mids = search_partial($cur, $mid); if ($mids) { - $n_partial = scalar(@$mids); - push @partial, [ $cur, $mids ]; - } - - # can't find a partial match in current inbox, try the others: - if (!$n_partial && length($mid) >= $MIN_PARTIAL_LEN) { - foreach my $ibx (@$ibxs) { - $srch = $ibx->search or next; - $mids = search_partial($srch, $mid) or next; - $n_partial += scalar(@$mids); - push @partial, [ $ibx, $mids]; - last if $n_partial >= PARTIAL_MAX; + $ctx->{n_partial} = scalar(@$mids); + push @{$ctx->{partial}}, [ $cur, $mids ]; + } elsif ($ctx->{again} && length($mid) >= $MIN_PARTIAL_LEN) { + bless $ctx, __PACKAGE__; + if ($ctx->{env}->{'pi-httpd.async'}) { + $ctx->event_step; + return; } + + # synchronous fall-through + $ctx->event_step while @{$ctx->{again}}; } + finalize_partial($ctx); +} +sub finalize_partial { + my ($ctx) = @_; + my $mid = $ctx->{mid}; my $code = 404; my $href = mid_href($mid); my $html = ascii_html($mid); my $title = "<$html> not found"; my $s = "
Message-ID <$html>\nnot found\n";
-	if ($n_partial) {
+	if (my $n_partial = $ctx->{n_partial}) {
 		$code = 300;
 		my $es = $n_partial == 1 ? '' : 'es';
 		$n_partial .= '+' if ($n_partial == PARTIAL_MAX);
 		$s .= "\n$n_partial partial match$es found:\n\n";
-		my $cur_name = $cur->{name};
-		foreach my $pair (@partial) {
+		my $cur_name = $ctx->{-inbox}->{name};
+		foreach my $pair (@{$ctx->{partial}}) {
 			my ($ibx, $res) = @$pair;
 			my $env = $ctx->{env} if $ibx->{name} eq $cur_name;
 			my $u = $ibx->base_url($env) or next;
@@ -159,7 +192,7 @@ sub ext_msg {
 	$ctx->{-html_tip} = $s .= '
'; $ctx->{-title_html} = $title; $ctx->{-upfx} = '../'; - html_oneshot($ctx, $code); + $ctx->{-wcb}->(html_oneshot($ctx, $code)); } sub ext_urls { @@ -181,7 +214,9 @@ sub ext_urls { } sub exact { - my ($ctx, $found, $mid) = @_; + my ($ctx) = @_; + my $mid = $ctx->{mid}; + my $found = $ctx->{found}; my $href = mid_href($mid); my $html = ascii_html($mid); my $title = "<$html> found in ";