Ticket #710: 710-remote_server_public_api.diff
File 710-remote_server_public_api.diff, 15.1 KB (added by , 9 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 43 43 #include "api/omenquireinternal.h" 44 44 #include "str.h" 45 45 #include "weight/weightinternal.h" 46 #include "net/serialise.h" 46 47 47 48 #include <algorithm> 48 49 #include "autoptr.h" … … RSet::Internal::get_description() const 133 134 return description; 134 135 } 135 136 137 std::string 138 RSet::serialise() const 139 { 140 LOGCALL(API, std::string, "RSet::serialise", NO_ARGS); 141 RETURN(serialise_rset(*this)); 142 } 143 144 RSet 145 RSet::unserialise(const std::string &s) 146 { 147 LOGCALL_STATIC(API, RSet, "RSet::unserialise", s); 148 RETURN(unserialise_rset(s)); 149 } 150 136 151 namespace Internal { 137 152 138 153 // Methods for Xapian::MSetItem … … MSet::get_description() const 321 336 return "Xapian::MSet(" + internal->get_description() + ")"; 322 337 } 323 338 339 std::string 340 MSet::serialise() const 341 { 342 LOGCALL(API, std::string, "MSet::serialise", NO_ARGS); 343 RETURN(serialise_mset(*this)); 344 } 345 346 MSet 347 MSet::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 324 353 int 325 354 MSet::Internal::convert_to_percent_internal(double wt) const 326 355 { … … Enquire::Internal::get_query() const 620 649 return query; 621 650 } 622 651 652 void 653 Enquire::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 660 const string 661 Enquire::Internal::serialise_stats() const 662 { 663 return ::serialise_stats(*(stats.get())); 664 } 665 666 void 667 Enquire::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 623 686 MSet 624 687 Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems, 625 688 Xapian::doccount check_at_least, const RSet *rset, … … Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems, 644 707 check_at_least = max(check_at_least, maxitems); 645 708 } 646 709 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 } 662 714 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 } 664 722 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); 670 724 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(); 674 738 675 RETURN(retval); 739 RETURN(retval); 740 } catch(...) { 741 stats.reset(); 742 match.reset(); 743 throw; 744 } 676 745 } 677 746 678 747 ESet … … Enquire::set_time_limit(double time_limit) 1006 1075 internal->time_limit = time_limit; 1007 1076 } 1008 1077 1078 void 1079 Enquire::unserialise_stats(const string& serialised) 1080 { 1081 internal->unserialise_stats(serialised); 1082 } 1083 1084 const string 1085 Enquire::serialise_stats() const 1086 { 1087 RETURN(internal->serialise_stats()); 1088 } 1089 1090 void 1091 Enquire::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 1009 1099 MSet 1010 1100 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems, 1011 1101 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 37 37 #include <map> 38 38 #include <set> 39 39 40 #include "autoptr.h" 40 41 #include "weight/weightinternal.h" 41 42 42 43 using namespace std; … … class Enquire::Internal : public Xapian::Internal::intrusive_base { 151 152 152 153 Xapian::Internal::opt_intrusive_ptr<KeyMaker> sorter; 153 154 155 mutable AutoPtr<Xapian::Weight::Internal> stats; 156 mutable AutoPtr<::MultiMatch> match; 157 154 158 double time_limit; 155 159 156 160 /** The weight to use for this query. … … class Enquire::Internal : public Xapian::Internal::intrusive_base { 183 187 184 188 void set_query(const Query & query_, termcount qlen_); 185 189 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 186 197 MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems, 187 198 Xapian::doccount check_at_least, 188 199 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 { 262 262 263 263 /// Return a string describing this object. 264 264 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 265 279 }; 266 280 267 281 /** Base class for matcher decision functor. … … class XAPIAN_VISIBILITY_DEFAULT Enquire { 619 633 */ 620 634 void set_time_limit(double time_limit); 621 635 636 void unserialise_stats(const std::string& serialised); 637 const std::string serialise_stats() const; 638 622 639 /** Get (a portion of) the match set for the current query. 623 640 * 624 641 * @param first the first item in the result set to return. … … class XAPIAN_VISIBILITY_DEFAULT Enquire { 657 674 * 658 675 * @{ 659 676 */ 677 void prepare_mset(const RSet * omrset = 0, 678 const MatchDecider * mdecider = 0) const; 660 679 MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems, 661 680 Xapian::doccount checkatleast = 0, 662 681 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 { 179 179 /// Return a string describing this object. 180 180 std::string get_description() const; 181 181 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 182 195 /** @private @internal MSet is what the C++ STL calls a container. 183 196 * 184 197 * 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 36 36 37 37 #include "autoptr.h" 38 38 #include "length.h" 39 #include " matcher/multimatch.h"39 #include "api/omenquireinternal.h" 40 40 #include "noreturn.h" 41 41 #include "omassert.h" 42 42 #include "realtime.h" … … RemoteServer::msg_update(const string &) 393 393 void 394 394 RemoteServer::msg_query(const string &message_in) 395 395 { 396 if (!db) 397 throw_no_db(); 398 396 399 const char *p = message_in.c_str(); 397 400 const char *p_end = p + message_in.size(); 398 401 402 Xapian::Enquire enquire(*db); 403 399 404 // Unserialise the Query. 400 405 size_t len; 401 406 decode_length_and_check(&p, p_end, len); … … RemoteServer::msg_query(const string &message_in) 406 411 Xapian::termcount qlen; 407 412 decode_length(&p, p_end, qlen); 408 413 414 enquire.set_query(query, qlen); 415 409 416 Xapian::valueno collapse_max; 410 417 decode_length(&p, p_end, collapse_max); 411 418 … … RemoteServer::msg_query(const string &message_in) 413 420 if (collapse_max) 414 421 decode_length(&p, p_end, collapse_key); 415 422 423 enquire.set_collapse_key(collapse_key, collapse_max); 424 416 425 if (p_end - p < 4 || *p < '0' || *p > '2') { 417 426 throw Xapian::NetworkError("bad message (docid_order)"); 418 427 } 419 428 Xapian::Enquire::docid_order order; 420 429 order = static_cast<Xapian::Enquire::docid_order>(*p++ - '0'); 421 430 431 enquire.set_docid_order(order); 432 422 433 Xapian::valueno sort_key; 423 434 decode_length(&p, p_end, sort_key); 424 435 … … RemoteServer::msg_query(const string &message_in) 433 444 } 434 445 bool sort_value_forward(*p++ != '0'); 435 446 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 436 462 double time_limit = unserialise_double(&p, p_end); 437 463 464 enquire.set_time_limit(time_limit); 465 438 466 int percent_cutoff = *p++; 439 467 if (percent_cutoff < 0 || percent_cutoff > 100) { 440 468 throw Xapian::NetworkError("bad message (percent_cutoff)"); … … RemoteServer::msg_query(const string &message_in) 445 473 throw Xapian::NetworkError("bad message (weight_cutoff)"); 446 474 } 447 475 476 enquire.set_cutoff(percent_cutoff, weight_cutoff); 477 448 478 // Unserialise the Weight object. 449 479 decode_length_and_check(&p, p_end, len); 450 480 string wtname(p, len); … … RemoteServer::msg_query(const string &message_in) 461 491 462 492 decode_length_and_check(&p, p_end, len); 463 493 AutoPtr<Xapian::Weight> wt(wttype->unserialise(string(p, len))); 494 enquire.set_weighting_scheme(*wt); 464 495 p += len; 465 496 466 497 // Unserialise the RSet object. … … RemoteServer::msg_query(const string &message_in) 469 500 p += len; 470 501 471 502 // Unserialise any MatchSpy objects. 472 vector<Xapian:: Internal::opt_intrusive_ptr<Xapian::MatchSpy>> matchspies;503 vector<Xapian::MatchSpy*> matchspies; 473 504 while (p != p_end) { 474 505 decode_length_and_check(&p, p_end, len); 475 506 string spytype(p, len); … … RemoteServer::msg_query(const string &message_in) 481 512 p += len; 482 513 483 514 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()); 485 518 p += len; 486 519 } 487 520 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); 493 522 494 send_message(REPLY_STATS, serialise_stats(local_stats));523 send_message(REPLY_STATS, enquire.serialise_stats()); 495 524 496 525 string message; 497 526 get_message(active_timeout, message, MSG_GETMSET); … … RemoteServer::msg_query(const string &message_in) 506 535 Xapian::termcount check_at_least; 507 536 decode_length(&p, p_end, check_at_least); 508 537 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)); 513 539 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); 517 541 518 542 message.resize(0); 519 543 for (auto i : matchspies) { … … RemoteServer::msg_query(const string &message_in) 521 545 message += encode_length(spy_results.size()); 522 546 message += spy_results; 523 547 } 524 message += serialise_mset(mset);548 message += mset.serialise(); 525 549 send_message(REPLY_RESULTS, message); 526 550 } 527 551