Ticket #710: 710-remote_server_public_api.diff

File 710-remote_server_public_api.diff, 15.1 KB (added by German M. Bravo, 8 years ago)
  • xapian-core/api/omenquire.cc

    commit 5b062eae0b5fd513b52ad23c95cdc6302c397abb
    Author: German M. Bravo <german.mb@deipi.com>
    Date:   Mon Feb 29 09:54:19 2016 -0600
    
        Remote Server public API for allowing custom protocol implementation.
        
        To be able to implement a Remote Protocol Server with only the xapian
        public API, four changes are needed:
        
        * Add Xapian::Enquire::prepare_mset(): prepares an enquire to get a
          MSet. Xapian::Weight::Internal is filled with the statistics and a
          MultiMatch is initialized.
        
        * Add stats serialisation methods: Xapian::Enquire::serialise_stats()
          and Xapian::Enquire::unserialise_stats(). These are used by
          MSG_QUERY and MSG_GETMSET.
        
        * Add Xapian::MSet::serialise() and Xapian::MSet::unserialise().
          Used by MSG_GETMSET.
        
        * Add Xapian::RSet::serialise() and Xapian::RSet::unserialise().
          Used by MSG_QUERY.
        
        * Use public API to implement remote server.
    
    diff --git a/xapian-core/api/omenquire.cc b/xapian-core/api/omenquire.cc
    index ad04eff..61a756c 100644
    a b  
    4343#include "api/omenquireinternal.h"
    4444#include "str.h"
    4545#include "weight/weightinternal.h"
     46#include "net/serialise.h"
    4647
    4748#include <algorithm>
    4849#include "autoptr.h"
    RSet::Internal::get_description() const  
    133134    return description;
    134135}
    135136
     137std::string
     138RSet::serialise() const
     139{
     140    LOGCALL(API, std::string, "RSet::serialise", NO_ARGS);
     141    RETURN(serialise_rset(*this));
     142}
     143
     144RSet
     145RSet::unserialise(const std::string &s)
     146{
     147    LOGCALL_STATIC(API, RSet, "RSet::unserialise", s);
     148    RETURN(unserialise_rset(s));
     149}
     150
    136151namespace Internal {
    137152
    138153// Methods for Xapian::MSetItem
    MSet::get_description() const  
    321336    return "Xapian::MSet(" + internal->get_description() + ")";
    322337}
    323338
     339std::string
     340MSet::serialise() const
     341{
     342    LOGCALL(API, std::string, "MSet::serialise", NO_ARGS);
     343    RETURN(serialise_mset(*this));
     344}
     345
     346MSet
     347MSet::unserialise(const std::string &s)
     348{
     349    LOGCALL_STATIC(API, MSet, "MSet::unserialise", s);
     350    RETURN(unserialise_mset(s.data(), s.data() + s.size()));
     351}
     352
    324353int
    325354MSet::Internal::convert_to_percent_internal(double wt) const
    326355{
    Enquire::Internal::get_query() const  
    620649    return query;
    621650}
    622651
     652void
     653Enquire::Internal::unserialise_stats(const string& serialised)
     654{
     655    stats.reset(new Xapian::Weight::Internal);
     656    ::unserialise_stats(serialised, *(stats.get()));
     657    stats->set_bounds_from_db(db);
     658}
     659
     660const string
     661Enquire::Internal::serialise_stats() const
     662{
     663    return ::serialise_stats(*(stats.get()));
     664}
     665
     666void
     667Enquire::Internal::prepare_mset(const RSet *rset,
     668                                const MatchDecider *mdecider) const
     669{
     670    LOGCALL(MATCH, MSet, "Enquire::Internal::prepare_mset", rset | mdecider);
     671
     672    if (percent_cutoff && (sort_by == VAL || sort_by == VAL_REL)) {
     673        throw Xapian::UnimplementedError("Use of a percentage cutoff while sorting primary by value isn't currently supported");
     674    }
     675
     676    stats.reset(new Xapian::Weight::Internal);
     677    match.reset(new ::MultiMatch(db, query, qlen, rset,
     678                                 collapse_max, collapse_key,
     679                                 percent_cutoff, weight_cutoff,
     680                                 order, sort_key, sort_by, sort_value_forward,
     681                                 time_limit, *(stats.get()), weight, spies,
     682                                 (sorter.get() != NULL),
     683                                 (mdecider != NULL)));
     684}
     685
    623686MSet
    624687Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    625688                            Xapian::doccount check_at_least, const RSet *rset,
    Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems,  
    644707        check_at_least = max(check_at_least, maxitems);
    645708    }
    646709
    647     AutoPtr<Xapian::Weight::Internal> stats(new Xapian::Weight::Internal);
    648     ::MultiMatch match(db, query, qlen, rset,
    649                        collapse_max, collapse_key,
    650                        percent_cutoff, weight_cutoff,
    651                        order, sort_key, sort_by, sort_value_forward,
    652                        time_limit, *(stats.get()), weight, spies,
    653                        (sorter.get() != NULL),
    654                        (mdecider != NULL));
    655     // Run query and put results into supplied Xapian::MSet object.
    656     MSet retval;
    657     match.get_mset(first, maxitems, check_at_least, retval,
    658                    *(stats.get()), mdecider, sorter.get());
    659     if (first_orig != first && retval.internal.get()) {
    660         retval.internal->firstitem = first_orig;
    661     }
     710    try {
     711        if (!stats || !match) {
     712            prepare_mset(rset, mdecider);
     713        }
    662714
    663     Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
     715        // Run query and put results into supplied Xapian::MSet object.
     716        MSet retval;
     717        match->get_mset(first, maxitems, check_at_least, retval,
     718                    *(stats.get()), mdecider, sorter.get());
     719        if (first_orig != first && retval.internal.get()) {
     720            retval.internal->firstitem = first_orig;
     721        }
    664722
    665     // The Xapian::MSet needs to have a pointer to ourselves, so that it can
    666     // retrieve the documents.  This is set here explicitly to avoid having
    667     // to pass it into the matcher, which gets messy particularly in the
    668     // networked case.
    669     retval.internal->enquire = this;
     723        Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
    670724
    671     if (!retval.internal->stats) {
    672         retval.internal->stats = stats.release();
    673     }
     725        // The Xapian::MSet needs to have a pointer to ourselves, so that it can
     726        // retrieve the documents.  This is set here explicitly to avoid having
     727        // to pass it into the matcher, which gets messy particularly in the
     728        // networked case.
     729        retval.internal->enquire = this;
     730
     731        if (!retval.internal->stats) {
     732            retval.internal->stats = stats.release();
     733        } else {
     734            stats.reset();
     735        }
     736
     737        match.reset();
    674738
    675     RETURN(retval);
     739        RETURN(retval);
     740    } catch(...) {
     741        stats.reset();
     742        match.reset();
     743        throw;
     744    }
    676745}
    677746
    678747ESet
    Enquire::set_time_limit(double time_limit)  
    10061075    internal->time_limit = time_limit;
    10071076}
    10081077
     1078void
     1079Enquire::unserialise_stats(const string& serialised)
     1080{
     1081    internal->unserialise_stats(serialised);
     1082}
     1083
     1084const string
     1085Enquire::serialise_stats() const
     1086{
     1087    RETURN(internal->serialise_stats());
     1088}
     1089
     1090void
     1091Enquire::prepare_mset(const RSet *rset,
     1092                      const MatchDecider *mdecider) const
     1093{
     1094    LOGCALL(API, Xapian::MSet, "Xapian::Enquire::prepare_mset", maxitems | rset | mdecider);
     1095
     1096    internal->prepare_mset(rset, mdecider);
     1097}
     1098
    10091099MSet
    10101100Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    10111101                  Xapian::doccount check_at_least, const RSet *rset,
  • xapian-core/api/omenquireinternal.h

    diff --git a/xapian-core/api/omenquireinternal.h b/xapian-core/api/omenquireinternal.h
    index 4b4c902..f1d7c7e 100644
    a b  
    3737#include <map>
    3838#include <set>
    3939
     40#include "autoptr.h"
    4041#include "weight/weightinternal.h"
    4142
    4243using namespace std;
    class Enquire::Internal : public Xapian::Internal::intrusive_base {  
    151152
    152153        Xapian::Internal::opt_intrusive_ptr<KeyMaker> sorter;
    153154
     155        mutable AutoPtr<Xapian::Weight::Internal> stats;
     156        mutable AutoPtr<::MultiMatch> match;
     157
    154158        double time_limit;
    155159
    156160        /** The weight to use for this query.
    class Enquire::Internal : public Xapian::Internal::intrusive_base {  
    183187
    184188        void set_query(const Query & query_, termcount qlen_);
    185189        const Query & get_query() const;
     190
     191        void unserialise_stats(const string& serialised);
     192        const string serialise_stats() const;
     193
     194        void prepare_mset(const RSet *omrset,
     195                          const MatchDecider *mdecider) const;
     196
    186197        MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    187198                      Xapian::doccount check_at_least,
    188199                      const RSet *omrset,
  • xapian-core/include/xapian/enquire.h

    diff --git a/xapian-core/include/xapian/enquire.h b/xapian-core/include/xapian/enquire.h
    index 09db354..ed7c06b 100644
    a b class XAPIAN_VISIBILITY_DEFAULT RSet {  
    262262
    263263        /// Return a string describing this object.
    264264        std::string get_description() const;
     265
     266        /** Serialise RSet into a string.
     267         *
     268         *  The document representation may change between Xapian releases:
     269         *  even between minor versions.  However, it is guaranteed not to
     270         *  change if the remote database protocol has not changed between
     271         *  releases.
     272         */
     273        std::string serialise() const;
     274
     275        /** Unserialise a document from a string produced by serialise().
     276         */
     277        static RSet unserialise(const std::string &serialised);
     278
    265279};
    266280
    267281/** Base class for matcher decision functor.
    class XAPIAN_VISIBILITY_DEFAULT Enquire {  
    619633         */
    620634        void set_time_limit(double time_limit);
    621635
     636        void unserialise_stats(const std::string& serialised);
     637        const std::string serialise_stats() const;
     638
    622639        /** Get (a portion of) the match set for the current query.
    623640         *
    624641         *  @param first     the first item in the result set to return.
    class XAPIAN_VISIBILITY_DEFAULT Enquire {  
    657674         *
    658675         *  @{
    659676         */
     677        void prepare_mset(const RSet * omrset = 0,
     678                          const MatchDecider * mdecider = 0) const;
    660679        MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    661680                      Xapian::doccount checkatleast = 0,
    662681                      const RSet * omrset = 0,
  • xapian-core/include/xapian/mset.h

    diff --git a/xapian-core/include/xapian/mset.h b/xapian-core/include/xapian/mset.h
    index de6025d..914c535 100644
    a b class XAPIAN_VISIBILITY_DEFAULT MSet {  
    179179    /// Return a string describing this object.
    180180    std::string get_description() const;
    181181
     182    /** Serialise MSet into a string.
     183     *
     184     *  The document representation may change between Xapian releases:
     185     *  even between minor versions.  However, it is guaranteed not to
     186     *  change if the remote database protocol has not changed between
     187     *  releases.
     188     */
     189    std::string serialise() const;
     190
     191    /** Unserialise a document from a string produced by serialise().
     192     */
     193    static MSet unserialise(const std::string &serialised);
     194
    182195    /** @private @internal MSet is what the C++ STL calls a container.
    183196     *
    184197     *  The following typedefs allow the class to be used in templates in the
  • xapian-core/net/remoteserver.cc

    diff --git a/xapian-core/net/remoteserver.cc b/xapian-core/net/remoteserver.cc
    index 9b467b1..9736be8 100644
    a b  
    3636
    3737#include "autoptr.h"
    3838#include "length.h"
    39 #include "matcher/multimatch.h"
     39#include "api/omenquireinternal.h"
    4040#include "noreturn.h"
    4141#include "omassert.h"
    4242#include "realtime.h"
    RemoteServer::msg_update(const string &)  
    393393void
    394394RemoteServer::msg_query(const string &message_in)
    395395{
     396    if (!db)
     397        throw_no_db();
     398
    396399    const char *p = message_in.c_str();
    397400    const char *p_end = p + message_in.size();
    398401
     402    Xapian::Enquire enquire(*db);
     403
    399404    // Unserialise the Query.
    400405    size_t len;
    401406    decode_length_and_check(&p, p_end, len);
    RemoteServer::msg_query(const string &message_in)  
    406411    Xapian::termcount qlen;
    407412    decode_length(&p, p_end, qlen);
    408413
     414    enquire.set_query(query, qlen);
     415
    409416    Xapian::valueno collapse_max;
    410417    decode_length(&p, p_end, collapse_max);
    411418
    RemoteServer::msg_query(const string &message_in)  
    413420    if (collapse_max)
    414421        decode_length(&p, p_end, collapse_key);
    415422
     423    enquire.set_collapse_key(collapse_key, collapse_max);
     424
    416425    if (p_end - p < 4 || *p < '0' || *p > '2') {
    417426        throw Xapian::NetworkError("bad message (docid_order)");
    418427    }
    419428    Xapian::Enquire::docid_order order;
    420429    order = static_cast<Xapian::Enquire::docid_order>(*p++ - '0');
    421430
     431    enquire.set_docid_order(order);
     432
    422433    Xapian::valueno sort_key;
    423434    decode_length(&p, p_end, sort_key);
    424435
    RemoteServer::msg_query(const string &message_in)  
    433444    }
    434445    bool sort_value_forward(*p++ != '0');
    435446
     447    switch(sort_by) {
     448        case Xapian::Enquire::Internal::REL:
     449            enquire.set_sort_by_relevance();
     450            break;
     451        case Xapian::Enquire::Internal::VAL:
     452            enquire.set_sort_by_value(sort_key, sort_value_forward);
     453            break;
     454        case Xapian::Enquire::Internal::VAL_REL:
     455            enquire.set_sort_by_value_then_relevance(sort_key, sort_value_forward);
     456            break;
     457        case Xapian::Enquire::Internal::REL_VAL:
     458            enquire.set_sort_by_relevance_then_value(sort_key, sort_value_forward);
     459            break;
     460    }
     461
    436462    double time_limit = unserialise_double(&p, p_end);
    437463
     464    enquire.set_time_limit(time_limit);
     465
    438466    int percent_cutoff = *p++;
    439467    if (percent_cutoff < 0 || percent_cutoff > 100) {
    440468        throw Xapian::NetworkError("bad message (percent_cutoff)");
    RemoteServer::msg_query(const string &message_in)  
    445473        throw Xapian::NetworkError("bad message (weight_cutoff)");
    446474    }
    447475
     476    enquire.set_cutoff(percent_cutoff, weight_cutoff);
     477
    448478    // Unserialise the Weight object.
    449479    decode_length_and_check(&p, p_end, len);
    450480    string wtname(p, len);
    RemoteServer::msg_query(const string &message_in)  
    461491
    462492    decode_length_and_check(&p, p_end, len);
    463493    AutoPtr<Xapian::Weight> wt(wttype->unserialise(string(p, len)));
     494    enquire.set_weighting_scheme(*wt);
    464495    p += len;
    465496
    466497    // Unserialise the RSet object.
    RemoteServer::msg_query(const string &message_in)  
    469500    p += len;
    470501
    471502    // Unserialise any MatchSpy objects.
    472     vector<Xapian::Internal::opt_intrusive_ptr<Xapian::MatchSpy>> matchspies;
     503    vector<Xapian::MatchSpy*> matchspies;
    473504    while (p != p_end) {
    474505        decode_length_and_check(&p, p_end, len);
    475506        string spytype(p, len);
    RemoteServer::msg_query(const string &message_in)  
    481512        p += len;
    482513
    483514        decode_length_and_check(&p, p_end, len);
    484         matchspies.push_back(spyclass->unserialise(string(p, len), reg)->release());
     515        Xapian::MatchSpy *spy = spyclass->unserialise(string(p, len), reg);
     516        matchspies.push_back(spy);
     517        enquire.add_matchspy(spy->release());
    485518        p += len;
    486519    }
    487520
    488     Xapian::Weight::Internal local_stats;
    489     MultiMatch match(*db, query, qlen, &rset, collapse_max, collapse_key,
    490                      percent_cutoff, weight_cutoff, order,
    491                      sort_key, sort_by, sort_value_forward, time_limit,
    492                      local_stats, wt.get(), matchspies, false, false);
     521    enquire.prepare_mset(&rset, nullptr);
    493522
    494     send_message(REPLY_STATS, serialise_stats(local_stats));
     523    send_message(REPLY_STATS, enquire.serialise_stats());
    495524
    496525    string message;
    497526    get_message(active_timeout, message, MSG_GETMSET);
    RemoteServer::msg_query(const string &message_in)  
    506535    Xapian::termcount check_at_least;
    507536    decode_length(&p, p_end, check_at_least);
    508537
    509     message.erase(0, message.size() - (p_end - p));
    510     AutoPtr<Xapian::Weight::Internal> total_stats(new Xapian::Weight::Internal);
    511     unserialise_stats(message, *(total_stats.get()));
    512     total_stats->set_bounds_from_db(*db);
     538    enquire.unserialise_stats(std::string(p, p_end));
    513539
    514     Xapian::MSet mset;
    515     match.get_mset(first, maxitems, check_at_least, mset, *(total_stats.get()), 0, 0);
    516     mset.internal->stats = total_stats.release();
     540    Xapian::MSet mset = enquire.get_mset(first, maxitems, check_at_least);
    517541
    518542    message.resize(0);
    519543    for (auto i : matchspies) {
    RemoteServer::msg_query(const string &message_in)  
    521545        message += encode_length(spy_results.size());
    522546        message += spy_results;
    523547    }
    524     message += serialise_mset(mset);
     548    message += mset.serialise();
    525549    send_message(REPLY_RESULTS, message);
    526550}
    527551