From 19d330703704a3b667b506c4d14c7e8af98866d4 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 29 May 2025 00:20:30 +0000 Subject: [PATCH] xap_helper: mset: ignore non-ultimate exceptions For requests consisting of multiple queries, ignore Xapian exceptions for all but the last query. When sending multiple queries to the `mset' xap_helper command, we only care about the result of the first successful query where success is defined as a non-empty mset response. Thus an exception is considered an empty mset and we can try other queries from the same request. --- lib/PublicInbox/XapHelper.pm | 15 +++++++++------ lib/PublicInbox/xh_mset.h | 23 ++++++++++++++--------- t/xap_helper.t | 16 +++++++++++++++- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/lib/PublicInbox/XapHelper.pm b/lib/PublicInbox/XapHelper.pm index a36acf469..48203de39 100644 --- a/lib/PublicInbox/XapHelper.pm +++ b/lib/PublicInbox/XapHelper.pm @@ -176,12 +176,15 @@ sub cmd_mset { # to be used by WWW + IMAP my @uid_range = @$req{qw(u U)}; $opt->{uid_range} = \@uid_range if grep(defined, @uid_range) == 2; $opt->{threadid} = $req->{T} if defined $req->{T}; - my $mset = $req->{srch}->mset($qry_str, $opt); - my $size = $mset->size; - while ($size == 0 && @rest) { - $mset = $req->{srch}->mset(shift @rest, $opt); - $size = $mset->size; - } + my ($mset, $size); + do { + eval { + $mset = $req->{srch}->mset($qry_str, $opt); + $size = $mset->size; + }; + # swallow exceptions for all but the last query + die if $@ && !@rest; + } while (!$size && (defined($qry_str = shift @rest))); say { $req->{0} } 'mset.size=', $size, ' .get_matches_estimated=', $mset->get_matches_estimated; for my $it ($mset->items) { diff --git a/lib/PublicInbox/xh_mset.h b/lib/PublicInbox/xh_mset.h index 7d0100932..8591bbf4f 100644 --- a/lib/PublicInbox/xh_mset.h +++ b/lib/PublicInbox/xh_mset.h @@ -14,17 +14,22 @@ static bool cmd_mset(struct req *req) { if (optind >= req->argc) ABORT("usage: mset [OPTIONS] WANT QRY_STR"); - const char *qry_str = req->argv[optind]; CLEANUP_FBUF struct fbuf wbuf = {}; - Xapian::MSet mset = req->code_search ? commit_mset(req, qry_str) : + unsigned long long size = 0; + Xapian::MSet mset; + do { + try { + const char *qry_str = req->argv[optind++]; + mset = req->code_search ? commit_mset(req, qry_str) : mail_mset(req, qry_str); - unsigned long long size = mset.size(); - while (size == 0 && ++optind < req->argc) { - qry_str = req->argv[optind]; - mset = req->code_search ? commit_mset(req, qry_str) : - mail_mset(req, qry_str); - size = mset.size(); - } + size = mset.size(); + } catch (const Xapian::Error & e) { + // swallow exceptions for all but the last query + if (optind >= req->argc) + throw; + } + } while (size == 0 && optind < req->argc); + fbuf_init(&wbuf); fprintf(wbuf.fp, "mset.size=%llu .get_matches_estimated=%llu\n", size, (unsigned long long)mset.get_matches_estimated()); diff --git a/t/xap_helper.t b/t/xap_helper.t index 41520866f..86b44dd24 100644 --- a/t/xap_helper.t +++ b/t/xap_helper.t @@ -249,8 +249,11 @@ for my $n (@NO_CXX) { # ensure we can try multiple queries and return the first one # with >0 matches - for my $try ([[], []], [['thisbetternotmatchanything'], ['z:0..']]) { + for my $try ([[], []], [['thisbetternotmatchanything'], ['z:0..']], + [['bogus...range ignored'], []], + [['z:0.. dfn:Search.pm'], ['bogus...range never tried']]) { pipe $r, $w; + diag explain($try); $xhc->mkreq([$w], qw(mset), @ibx_shard_args, @{$try->[0]}, 'dfn:lib/PublicInbox/Search.pm', @{$try->[1]}); @@ -286,6 +289,17 @@ for my $n (@NO_CXX) { like $rank, qr/\A\d+\z/, 'rank is a digit'; is scalar(@rest), 0, 'no extra rows returned'; } + + pipe $r, $w; + pipe $err_r, $err_w; + $xhc->mkreq([$w, $err_w], qw(mset), @ibx_shard_args, 'bogus...range'); + close $w; + close $err_w; + chomp(@res = readline($r)); + is_deeply \@res, [], 'no output on bogus query'; + chomp(@res = readline($err_r)); + ok scalar(@res) && $res[0], 'got error on bogus query'; + my $nr; for my $i (7, 8, 39, 40) { pipe($err_r, $err_w); -- 2.47.3