about summary refs log tree commit homepage
path: root/lib/PublicInbox/Search.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/Search.pm')
-rw-r--r--lib/PublicInbox/Search.pm86
1 files changed, 82 insertions, 4 deletions
diff --git a/lib/PublicInbox/Search.pm b/lib/PublicInbox/Search.pm
index 678c8c5d..25ef49c5 100644
--- a/lib/PublicInbox/Search.pm
+++ b/lib/PublicInbox/Search.pm
@@ -11,6 +11,7 @@ our @EXPORT_OK = qw(retry_reopen int_val get_pct xap_terms);
 use List::Util qw(max);
 use POSIX qw(strftime);
 use Carp ();
+our $XHC = 0; # defined but false
 
 # values for searching, changing the numeric value breaks
 # compatibility with old indices (so don't change them it)
@@ -53,10 +54,13 @@ use constant {
         #
         #      v1.6.0 adds BYTES, UID and THREADID values
         SCHEMA_VERSION => 15,
+
+        # we may have up to 8 FDs per shard (depends on Xapian *shrug*)
+        SHARD_COST => 8,
 };
 
 use PublicInbox::Smsg;
-use PublicInbox::Over;
+eval { require PublicInbox::Over };
 our $QP_FLAGS;
 our %X = map { $_ => 0 } qw(BoolWeight Database Enquire QueryParser Stem Query);
 our $Xap; # 'Xapian' or 'Search::Xapian'
@@ -85,14 +89,13 @@ our @XH_SPEC = (
         'k=i', # sort column (like sort(1))
         'm=i', # maximum number of results
         'o=i', # offset
-        'p', # show percent
         'r', # 1=relevance then column
         't', # collapse threads
         'A=s@', # prefixes
-        'D', # emit docdata
         'K=i', # timeout kill after i seconds
         'O=s', # eidx_key
         'T=i', # threadid
+        'Q=s@', # query prefixes "$user_prefix[:=]$XPREFIX"
 );
 
 sub load_xapian () {
@@ -429,6 +432,68 @@ sub mset {
         do_enquire($self, $qry, $opt, TS);
 }
 
+sub xhc_start_maybe (@) {
+        require PublicInbox::XapClient;
+        my $xhc = PublicInbox::XapClient::start_helper(@_);
+        require PublicInbox::XhcMset if $xhc;
+        $xhc;
+}
+
+sub xh_opt ($$) {
+        my ($self, $opt) = @_;
+        my $lim = $opt->{limit} || 50;
+        my @ret;
+        push @ret, '-o', $opt->{offset} if $opt->{offset};
+        push @ret, '-m', $lim;
+        my $rel = $opt->{relevance} // 0;
+        if ($rel == -2) { # ORDER BY docid/UID (highest first)
+                push @ret, '-k', '-1';
+        } elsif ($rel == -1) { # ORDER BY docid/UID (lowest first)
+                push @ret, '-k', '-1';
+                push @ret, '-a';
+        } elsif ($rel == 0) {
+                push @ret, '-k', $opt->{sort_col} // TS;
+                push @ret, '-a' if $opt->{asc};
+        } else { # rel > 0
+                push @ret, '-r';
+                push @ret, '-k', $opt->{sort_col} // TS;
+                push @ret, '-a' if $opt->{asc};
+        }
+        push @ret, '-t' if $opt->{threads};
+        push @ret, '-T', $opt->{threadid} if defined $opt->{threadid};
+        push @ret, '-O', $opt->{eidx_key} if defined $opt->{eidx_key};
+        my $apfx = $self->{-alt_pfx} //= do {
+                my @tmp;
+                for (grep /\Aserial:/, @{$self->{altid} // []}) {
+                        my (undef, $pfx) = split /:/, $_;
+                        push @tmp, '-Q', "$pfx=X\U$pfx";
+                }
+                # TODO: arbitrary header indexing goes here
+                \@tmp;
+        };
+        (@ret, @$apfx);
+}
+
+# returns a true value if actually handled asynchronously,
+# and a falsy value if handled synchronously
+sub async_mset {
+        my ($self, $qry_str, $opt, $cb, @args) = @_;
+        if ($XHC) { # unconditionally retrieving pct + rank for now
+                xdb($self); # populate {nshards}
+                my @margs = ($self->xh_args, xh_opt($self, $opt));
+                my $ret = eval {
+                        my $rd = $XHC->mkreq(undef, 'mset', @margs, $qry_str);
+                        PublicInbox::XhcMset->maybe_new($rd, $self, $cb, @args);
+                };
+                $cb->(@args, undef, $@) if $@;
+                $ret;
+        } else { # synchronous
+                my $mset = $self->mset($qry_str, $opt);
+                $cb->(@args, $mset);
+                undef;
+        }
+}
+
 sub do_enquire { # shared with CodeSearch
         my ($self, $qry, $opt, $col) = @_;
         my $enq = $X{Enquire}->new(xdb($self));
@@ -578,7 +643,7 @@ EOM
                         $ret .= qq{\tqp->add_boolean_prefix("$name", "$_");\n}
                 }
         }
-        # TODO: altid support
+        # altid support is handled in xh_opt and srch_init_extra in XH
         for my $name (sort keys %prob_prefix) {
                 for (split(/ /, $prob_prefix{$name})) {
                         $ret .= qq{\tqp->add_prefix("$name", "$_");\n}
@@ -667,4 +732,17 @@ sub get_doc ($$) {
         }
 }
 
+# not sure where best to put this...
+sub ulimit_n () {
+        my $n;
+        if (eval { require BSD::Resource; 1 }) {
+                my $NOFILE = BSD::Resource::RLIMIT_NOFILE();
+                ($n, undef) = BSD::Resource::getrlimit($NOFILE);
+        } else {
+                require PublicInbox::Spawn;
+                $n = PublicInbox::Spawn::run_qx([qw(/bin/sh -c), 'ulimit -n']);
+        }
+        $n;
+}
+
 1;