xapian-core  2.1.0
remote-database.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006-2024 Olly Betts
5  * Copyright (C) 2007,2009,2010 Lemur Consulting Ltd
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include "remote-database.h"
25 
26 #include <signal.h>
27 
28 #include "api/msetinternal.h"
29 #include "api/smallvector.h"
32 #include "net_postlist.h"
33 #include "remote-document.h"
34 #include "omassert.h"
35 #include "realtime.h"
36 #include "net/serialise.h"
37 #include "net/serialise-error.h"
38 #include "pack.h"
39 #include "remote_alltermslist.h"
40 #include "remote_keylist.h"
41 #include "remote_termlist.h"
42 #include "serialise-double.h"
43 #include "str.h"
44 #include "stringutils.h" // For STRINGIZE().
45 #include "weight/weightinternal.h"
46 
47 #include <cerrno>
48 #include <memory>
49 #include <string>
50 #include <string_view>
51 #include <vector>
52 
53 #include "xapian/constants.h"
54 #include "xapian/error.h"
55 #include "xapian/matchspy.h"
56 
57 using namespace std;
59 
61 static inline bool
62 is_intermediate_reply(int reply_code)
63 {
64  return reply_code == REPLY_DOCDATA ||
65  reply_code == REPLY_VALUE ||
66  reply_code == REPLY_TERMLISTHEADER ||
67  reply_code == REPLY_POSTLISTHEADER;
68 }
69 
70 [[noreturn]]
71 static void
72 throw_invalid_operation(const char* message)
73 {
74  throw Xapian::InvalidOperationError(message);
75 }
76 
77 [[noreturn]]
78 static void
79 throw_handshake_failed(const string & context)
80 {
81  throw Xapian::NetworkError("Handshake failed - is this a Xapian server?",
82  context);
83 }
84 
85 [[noreturn]]
86 static void
88 {
89  throw Xapian::NetworkError("Connection closed unexpectedly");
90 }
91 
92 RemoteDatabase::RemoteDatabase(pair<int, string> fd_and_context,
93  double timeout_,
94  bool writable,
95  int flags)
96  : Xapian::Database::Internal(writable ?
97  TRANSACTION_NONE :
98  TRANSACTION_READONLY),
99  link(fd_and_context.first, fd_and_context.first, fd_and_context.second),
100  cached_stats_valid(),
101  mru_valstats(),
102  mru_slot(Xapian::BAD_VALUENO),
103  timeout(timeout_)
104 {
105  update_stats(MSG_MAX);
106 
107  if (writable) {
108  if (flags & Xapian::DB_RETRY_LOCK) {
109  string message;
110  pack_uint_last(message, unsigned(flags & Xapian::DB_RETRY_LOCK));
111  update_stats(MSG_WRITEACCESS, message);
112  } else {
113  update_stats(MSG_WRITEACCESS);
114  }
115  }
116 }
117 
120  std::string_view term) const
121 {
123  return 0;
124 
125  string message;
126  pack_uint(message, did);
127  message += term;
129 
131  const char * p = message.data();
132  const char * p_end = p + message.size();
133  Xapian::termcount count;
134  if (!unpack_uint_last(&p, p_end, &count)) {
135  throw Xapian::NetworkError("Bad REPLY_POSITIONLISTCOUNT",
136  link.get_context());
137  }
138  return count;
139 }
140 
141 void
143 {
145  string message;
146  get_message(message, REPLY_DONE);
147 }
148 
149 TermList*
150 RemoteDatabase::open_metadata_keylist(std::string_view prefix) const
151 {
153  string message;
155  return new RemoteKeyList(prefix, std::move(message));
156 }
157 
158 TermList *
160 {
161  Assert(did);
162 
163  // Ensure that total_length and doccount are up-to-date.
165 
166  string message;
167  pack_uint_last(message, did);
168  send_message(MSG_TERMLIST, message);
169 
171  const char * p = message.c_str();
172  const char * p_end = p + message.size();
173  Xapian::termcount doclen;
174  Xapian::termcount num_entries;
175  if (!unpack_uint(&p, p_end, &doclen) ||
176  !unpack_uint_last(&p, p_end, &num_entries)) {
177  throw Xapian::NetworkError("Bad REPLY_TERMLISTHEADER",
178  link.get_context());
179  }
180  get_message(message, REPLY_TERMLIST);
181  return new RemoteTermList(num_entries, doclen, doccount, this, did,
182  std::move(message));
183 }
184 
185 TermList *
187 {
188  return RemoteDatabase::open_term_list(did);
189 }
190 
191 TermList*
192 RemoteDatabase::open_allterms(string_view prefix) const
193 {
194  send_message(MSG_ALLTERMS, prefix);
195  string message;
196  get_message(message, REPLY_ALLTERMS);
197  return new RemoteAllTermsList(prefix, std::move(message));
198 }
199 
200 PostList*
202 {
203  if (term.empty()) {
205  if (rare(doccount == 0))
206  return nullptr;
207  if (doccount == lastdocid) {
208  // The used docid range is exactly 1 to doccount inclusive.
210  }
211  }
212 
214 
215  string message;
217 
218  const char * p = message.data();
219  const char * p_end = p + message.size();
220  Xapian::doccount termfreq;
221  if (!unpack_uint_last(&p, p_end, &termfreq)) {
223  }
224 
225  get_message(message, REPLY_POSTLIST);
226 
228  term,
229  termfreq,
230  std::move(message));
231 }
232 
234 RemoteDatabase::open_leaf_post_list(string_view, bool) const
235 {
236  // This method is only called during the match, and remote shards are
237  // handled by running the match on the remote.
238  Assert(false);
239  return nullptr;
240 }
241 
244 {
245  string message;
246  pack_uint(message, did);
247  message += term;
248  send_message(MSG_POSITIONLIST, message);
249 
251  if (message.empty())
252  return nullptr;
253 
255  Xapian::termpos lastpos = static_cast<Xapian::termpos>(-1);
256  const char* p = message.data();
257  const char* p_end = p + message.size();
258  while (p != p_end) {
259  Xapian::termpos inc;
260  if (!unpack_uint(&p, p_end, &inc)) {
262  }
263  UNSIGNED_OVERFLOW_OK(lastpos += inc + 1);
264  positions.push_back(lastpos);
265  }
266 
267  return new InMemoryPositionList(std::move(positions));
268 }
269 
270 bool
272 {
274  return has_positional_info;
275 }
276 
277 bool
279 {
281  return update_stats(MSG_REOPEN);
282 }
283 
284 void
286 {
287  do_close();
288 }
289 
290 // Currently lazy is used:
291 //
292 // * To implement API flag Xapian::DOC_ASSUME_VALID which can be specified when
293 // calling method Database::get_document()
294 //
295 // * To read values for backends without streamed values in SlowValueList
296 //
297 // * If you call get_data(), values_begin() or values_count() on a Document
298 // object passed to a KeyMaker, MatchDecider, MatchSpy during the match
299 //
300 // The first is relevant to the remote backend, but doesn't happen during
301 // the match.
302 //
303 // SlowValueList is used with the remote backend, but not to read values
304 // during the match.
305 //
306 // KeyMaker and MatchSpy happens on the server with the remote backend, so
307 // they aren't relevant here.
308 //
309 // So the cases which are relevant to the remote backend don't matter during
310 // the match, and so we can ignore the lazy flag here without affecting matcher
311 // performance.
314 {
315  Assert(did);
316 
317  string message;
318  pack_uint_last(message, did);
319  send_message(MSG_DOCUMENT, message);
320 
321  string doc_data;
322  get_message(doc_data, REPLY_DOCDATA);
323 
324  map<Xapian::valueno, string> values;
325  while (get_message_or_done(message, REPLY_VALUE)) {
326  const char * p = message.data();
327  const char * p_end = p + message.size();
328  Xapian::valueno slot;
329  if (!unpack_uint(&p, p_end, &slot)) {
331  }
332  values.insert(make_pair(slot, string(p, p_end)));
333  }
334 
335  return new RemoteDocument(this, did, std::move(doc_data),
336  std::move(values));
337 }
338 
339 bool
340 RemoteDatabase::update_stats(message_type msg_code, const string & body) const
341 {
342  // MSG_MAX signals that we're handling the opening greeting, which isn't in
343  // response to an explicit message.
344  if (msg_code != MSG_MAX)
345  send_message(msg_code, body);
346 
347  string message;
348  if (!get_message_or_done(message, REPLY_UPDATE)) {
349  // The database was already open at the latest revision.
350  return false;
351  }
352 
353  if (message.size() < 3) {
355  }
356  const char *p = message.c_str();
357  const char *p_end = p + message.size();
358 
359  // The protocol major versions must match. The protocol minor version of
360  // the server must be >= that of the client.
361  int protocol_major = static_cast<unsigned char>(*p++);
362  int protocol_minor = static_cast<unsigned char>(*p++);
363  if (protocol_major != XAPIAN_REMOTE_PROTOCOL_MAJOR_VERSION ||
364  protocol_minor < XAPIAN_REMOTE_PROTOCOL_MINOR_VERSION) {
365  string errmsg("Server supports protocol version");
366  if (protocol_minor) {
367  errmsg += "s ";
368  errmsg += str(protocol_major);
369  errmsg += ".0 to ";
370  } else {
371  errmsg += ' ';
372  }
373  errmsg += str(protocol_major);
374  errmsg += '.';
375  errmsg += str(protocol_minor);
376  errmsg +=
377  " - client is using "
379  "."
381  throw Xapian::NetworkError(errmsg, link.get_context());
382  }
383 
384  if (!unpack_uint(&p, p_end, &doccount) ||
385  !unpack_uint(&p, p_end, &lastdocid) ||
386  !unpack_uint(&p, p_end, &doclen_lbound) ||
387  !unpack_uint(&p, p_end, &doclen_ubound) ||
388  !unpack_bool(&p, p_end, &has_positional_info) ||
389  !unpack_uint(&p, p_end, &total_length)) {
390  throw Xapian::NetworkError("Bad stats update message received",
391  link.get_context());
392  }
393  lastdocid += doccount;
395  uuid.assign(p, p_end);
396  cached_stats_valid = true;
397  return true;
398 }
399 
402 {
404  return doccount;
405 }
406 
409 {
411  return lastdocid;
412 }
413 
416 {
418  return total_length;
419 }
420 
421 bool
423 {
424  if (term.empty()) {
425  return get_doccount() != 0;
426  }
428  string message;
429  reply_type type = get_message(message,
432  return (type == REPLY_TERMEXISTS);
433 }
434 
435 void
437  Xapian::doccount* termfreq_ptr,
438  Xapian::termcount* collfreq_ptr) const
439 {
440  Assert(!term.empty());
441  string message;
442  if (termfreq_ptr && collfreq_ptr) {
444  get_message(message, REPLY_FREQS);
445  const char* p = message.data();
446  const char* p_end = p + message.size();
447  if (unpack_uint(&p, p_end, termfreq_ptr) &&
448  unpack_uint_last(&p, p_end, collfreq_ptr)) {
449  return;
450  }
451  } else if (termfreq_ptr) {
453  get_message(message, REPLY_TERMFREQ);
454  const char* p = message.data();
455  const char* p_end = p + message.size();
456  if (unpack_uint_last(&p, p_end, termfreq_ptr)) {
457  return;
458  }
459  } else if (collfreq_ptr) {
461  get_message(message, REPLY_COLLFREQ);
462  const char* p = message.data();
463  const char* p_end = p + message.size();
464  if (unpack_uint_last(&p, p_end, collfreq_ptr)) {
465  return;
466  }
467  } else {
468  Assert(false);
469  return;
470  }
471  throw Xapian::NetworkError("Bad REPLY_FREQS/REPLY_TERMFREQ/REPLY_COLLFREQ",
472  link.get_context());
473 }
474 
475 void
477 {
478  if (mru_slot == slot)
479  return;
480 
481  string message;
482  pack_uint_last(message, slot);
483  send_message(MSG_VALUESTATS, message);
484 
485  get_message(message, REPLY_VALUESTATS);
486  const char* p = message.data();
487  const char* p_end = p + message.size();
488  mru_slot = slot;
489  if (!unpack_uint(&p, p_end, &mru_valstats.freq) ||
491  throw Xapian::NetworkError("Bad REPLY_VALUESTATS", link.get_context());
492  }
493  mru_valstats.upper_bound.assign(p, p_end);
494 }
495 
498 {
499  read_value_stats(slot);
500  return mru_valstats.freq;
501 }
502 
503 std::string
505 {
506  read_value_stats(slot);
507  return mru_valstats.lower_bound;
508 }
509 
510 std::string
512 {
513  read_value_stats(slot);
514  return mru_valstats.upper_bound;
515 }
516 
519 {
520  return doclen_lbound;
521 }
522 
525 {
526  return doclen_ubound;
527 }
528 
531 {
532  // The default implementation returns get_collection_freq(), but we
533  // don't want the overhead of a remote message and reply per query
534  // term, and we can get called in the middle of a remote exchange
535  // too. FIXME: handle this bound in the stats local/remote code...
536  return doclen_ubound;
537 }
538 
541 {
542  Assert(did != 0);
543  string message;
544  pack_uint_last(message, did);
545  send_message(MSG_DOCLENGTH, message);
546 
547  get_message(message, REPLY_DOCLENGTH);
548  const char* p = message.c_str();
549  const char* p_end = p + message.size();
550  Xapian::termcount doclen;
551  if (!unpack_uint_last(&p, p_end, &doclen)) {
552  throw Xapian::NetworkError("Bad REPLY_DOCLENGTH", link.get_context());
553  }
554  return doclen;
555 }
556 
559 {
560  Assert(did != 0);
561  string message;
562  pack_uint_last(message, did);
563  send_message(MSG_UNIQUETERMS, message);
564 
565  get_message(message, REPLY_UNIQUETERMS);
566  const char* p = message.c_str();
567  const char* p_end = p + message.size();
568  Xapian::termcount doclen;
569  if (!unpack_uint_last(&p, p_end, &doclen)) {
570  throw Xapian::NetworkError("Bad REPLY_DOCLENGTH", link.get_context());
571  }
572  return doclen;
573 }
574 
577 {
578  Assert(did != 0);
579  string message;
580  pack_uint_last(message, did);
581  send_message(MSG_WDFDOCMAX, message);
582 
583  get_message(message, REPLY_WDFDOCMAX);
584  const char* p = message.c_str();
585  const char* p_end = p + message.size();
586  Xapian::termcount wdfdocmax;
587  if (!unpack_uint_last(&p, p_end, &wdfdocmax)) {
588  throw Xapian::NetworkError("Bad REPLY_WDFDOCMAX", link.get_context());
589  }
590  return wdfdocmax;
591 }
592 
595  reply_type required_type,
596  reply_type required_type2) const
597 {
599  int type = link.get_message(result, end_time);
600  if (pending_reply && !is_intermediate_reply(type)) {
601  pending_reply = false;
602  }
603  if (type < 0)
605  if (rare(type) >= REPLY_MAX) {
606  if (required_type == REPLY_UPDATE)
608  string errmsg("Invalid reply type ");
609  errmsg += str(type);
610  throw Xapian::NetworkError(errmsg);
611  }
612  if (type == REPLY_EXCEPTION) {
613  unserialise_error(result, "REMOTE:", link.get_context());
614  }
615  if (type != required_type && type != required_type2) {
616  string errmsg("Expecting reply type ");
617  errmsg += str(int(required_type));
618  if (required_type2 != required_type) {
619  errmsg += " or ";
620  errmsg += str(int(required_type2));
621  }
622  errmsg += ", got ";
623  errmsg += str(type);
624  throw Xapian::NetworkError(errmsg);
625  }
626 
627  return static_cast<reply_type>(type);
628 }
629 
630 void
631 RemoteDatabase::send_message(message_type type, string_view message) const
632 {
634  while (pending_reply) {
635  string dummy;
636  int reply_code = link.get_message(dummy, end_time);
637  if (reply_code < 0)
639  if (!is_intermediate_reply(reply_code)) {
640  pending_reply = false;
641  }
642  }
643  link.send_message(static_cast<unsigned char>(type), message, end_time);
644  pending_reply = true;
645 }
646 
647 void
649 {
650  if (!is_read_only()) {
651  try {
652  if (transaction_active()) {
653  end_transaction(false);
654  } else {
655  commit();
656  }
657  } catch (...) {
658  try {
659  link.do_close();
660  } catch (...) {
661  }
662  throw;
663  }
664 
665  // If we're writable, send a shutdown message to the server and wait
666  // for it to close its end of the connection so we know that changes
667  // have been written and flushed, and the database write lock released.
668  // For the non-writable case, there's no need to wait - it would just
669  // slow down searching needlessly.
670  link.shutdown();
671  }
672  link.do_close();
673 }
674 
675 void
677  Xapian::termcount qlen,
678  Xapian::valueno collapse_key,
679  Xapian::doccount collapse_max,
681  Xapian::valueno sort_key,
683  bool sort_value_forward,
684  double time_limit,
685  int percent_threshold, double weight_threshold,
686  const Xapian::Weight& wtscheme,
687  const Xapian::RSet &omrset,
688  const vector<opt_ptr_spy>& matchspies) const
689 {
690  string message;
691  pack_string(message, query.serialise());
692 
693  // Serialise assorted Enquire settings.
694  pack_uint(message, qlen);
695  pack_uint(message, collapse_max);
696  if (collapse_max) pack_uint(message, collapse_key);
697  message += char(order);
698  message += char(sort_by);
699  if (sort_by != Xapian::Enquire::Internal::REL) {
700  pack_uint(message, sort_key);
701  }
702  pack_bool(message, sort_value_forward);
703  message += serialise_double(time_limit);
704  message += char(percent_threshold);
705  message += serialise_double(weight_threshold);
706 
707  pack_string(message, wtscheme.name());
708 
709  pack_string(message, wtscheme.serialise());
710 
711  pack_string(message, serialise_rset(omrset));
712 
713  for (auto i : matchspies) {
714  const string& name = i->name();
715  if (name.empty()) {
716  throw Xapian::UnimplementedError("MatchSpy subclass not suitable for use with remote searches - name() method returned empty string");
717  }
718  pack_string(message, name);
719  pack_string(message, i->serialise());
720  }
721 
722  send_message(MSG_QUERY, message);
723 }
724 
725 void
727 {
728  string message;
729  get_message(message, REPLY_STATS);
730  const char* p = message.data();
731  Xapian::Weight::Internal remote_stats;
732  unserialise_stats(p, p + message.size(), remote_stats);
733  total += remote_stats;
734 }
735 
736 void
738  Xapian::doccount maxitems,
739  Xapian::doccount check_at_least,
740  const Xapian::KeyMaker* sorter,
741  const Xapian::Weight::Internal &stats) const
742 {
743  string message;
744  pack_uint(message, first);
745  pack_uint(message, maxitems);
746  pack_uint(message, check_at_least);
747  if (!sorter) {
748  pack_string_empty(message);
749  } else {
750  const string& name = sorter->name();
751  if (name.empty()) {
752  throw_invalid_operation("sorter reported empty name");
753  }
754  pack_string(message, name);
755  pack_string(message, sorter->serialise());
756  }
757  message += serialise_stats(stats);
758  send_message(MSG_GETMSET, message);
759 }
760 
762 RemoteDatabase::get_mset(const vector<opt_ptr_spy>& matchspies) const
763 {
764  string message;
765  get_message(message, REPLY_RESULTS);
766  const char * p = message.data();
767  const char * p_end = p + message.size();
768 
769  string spyresults;
770  for (auto i : matchspies) {
771  if (!unpack_string(&p, p_end, spyresults)) {
772  throw Xapian::NetworkError("Expected serialised matchspy");
773  }
774  i->merge_results(spyresults);
775  }
776  Xapian::MSet mset;
777  mset.internal->unserialise(p, p_end);
778  return mset;
779 }
780 
781 void
783 {
784  if (!uncommitted_changes) return;
785 
787 
788  // We need to wait for a response to ensure documents have been committed.
789  string message;
790  get_message(message, REPLY_DONE);
791 
792  uncommitted_changes = false;
793 }
794 
795 void
797 {
798  if (!uncommitted_changes) return;
799 
800  cached_stats_valid = false;
802 
804  string dummy;
806 
807  uncommitted_changes = false;
808 }
809 
812 {
813  cached_stats_valid = false;
815  uncommitted_changes = true;
816 
818 
819  string message;
820  get_message(message, REPLY_ADDDOCUMENT);
821 
822  const char* p = message.data();
823  const char* p_end = p + message.size();
824  Xapian::docid did;
825  if (!unpack_uint_last(&p, p_end, &did)) {
827  }
828  return did;
829 }
830 
831 void
833 {
834  cached_stats_valid = false;
836  uncommitted_changes = true;
837 
838  string message;
839  pack_uint_last(message, did);
841 
842  get_message(message, REPLY_DONE);
843 }
844 
845 void
846 RemoteDatabase::delete_document(std::string_view unique_term)
847 {
848  cached_stats_valid = false;
850  uncommitted_changes = true;
851 
852  send_message(MSG_DELETEDOCUMENTTERM, unique_term);
853  string dummy;
855 }
856 
857 void
859  const Xapian::Document & doc)
860 {
861  cached_stats_valid = false;
863  uncommitted_changes = true;
864 
865  string message;
866  pack_uint(message, did);
867  message += serialise_document(doc);
868 
870 
871  get_message(message, REPLY_DONE);
872 }
873 
875 RemoteDatabase::replace_document(std::string_view unique_term,
876  const Xapian::Document & doc)
877 {
878  cached_stats_valid = false;
880  uncommitted_changes = true;
881 
882  string message;
883  pack_string(message, unique_term);
884  message += serialise_document(doc);
885 
887 
888  get_message(message, REPLY_ADDDOCUMENT);
889 
890  const char* p = message.data();
891  const char* p_end = p + message.size();
892  Xapian::docid did;
893  if (!unpack_uint_last(&p, p_end, &did)) {
895  }
896  return did;
897 }
898 
899 string
901 {
902  return uuid;
903 }
904 
905 string
906 RemoteDatabase::get_metadata(string_view key) const
907 {
909  string metadata;
910  get_message(metadata, REPLY_METADATA);
911  return metadata;
912 }
913 
914 void
915 RemoteDatabase::set_metadata(string_view key, string_view value)
916 {
917  uncommitted_changes = true;
918 
919  string message;
920  pack_string(message, key);
921  message += value;
922  send_message(MSG_SETMETADATA, message);
923 
924  get_message(message, REPLY_DONE);
925 }
926 
927 void
929 {
930  string message;
931  pack_uint(message, did);
933 
934  get_message(message, REPLY_DONE);
935 }
936 
937 void
939  Xapian::termcount freqinc) const
940 {
941  uncommitted_changes = true;
942 
943  string message;
944  pack_uint(message, freqinc);
945  message += word;
946  send_message(MSG_ADDSPELLING, message);
947 
948  get_message(message, REPLY_DONE);
949 }
950 
953  Xapian::termcount freqdec) const
954 {
955  uncommitted_changes = true;
956 
957  string message;
958  pack_uint(message, freqdec);
959  message += word;
961 
963  const char * p = message.data();
964  const char * p_end = p + message.size();
965  Xapian::termcount result;
966  if (!unpack_uint_last(&p, p_end, &result)) {
967  throw Xapian::NetworkError("Bad REPLY_REMOVESPELLING",
968  link.get_context());
969  }
970  return result;
971 }
972 
973 TermList*
975 {
976  string message;
979  return new RemoteKeyList({}, std::move(message));
980 }
981 
982 TermList*
983 RemoteDatabase::open_synonym_keylist(string_view prefix) const
984 {
985  string message;
988  return new RemoteKeyList({}, std::move(message));
989 }
990 
991 void
992 RemoteDatabase::add_synonym(string_view word, string_view synonym) const
993 {
994  uncommitted_changes = true;
995 
996  string message;
997  pack_string(message, word);
998  message += synonym;
999  send_message(MSG_ADDSYNONYM, message);
1000  get_message(message, REPLY_DONE);
1001 }
1002 
1003 void
1004 RemoteDatabase::remove_synonym(string_view word, string_view synonym) const
1005 {
1006  uncommitted_changes = true;
1007 
1008  string message;
1009  pack_string(message, word);
1010  message += synonym;
1011  send_message(MSG_REMOVESYNONYM, message);
1012  get_message(message, REPLY_DONE);
1013 }
1014 
1015 void
1016 RemoteDatabase::clear_synonyms(string_view word) const
1017 {
1018  uncommitted_changes = true;
1019 
1020  string message;
1022  get_message(message, REPLY_DONE);
1023 }
1024 
1025 bool
1027 {
1028  throw Xapian::UnimplementedError("Database::locked() not implemented for remote backend");
1029 }
1030 
1031 string
1033  size_t length,
1034  string_view prefix,
1035  Xapian::termpos start_pos,
1036  Xapian::termpos end_pos) const
1037 {
1038  string message;
1039  pack_uint(message, did);
1040  pack_uint(message, length);
1041  pack_uint(message, start_pos);
1042  pack_uint(message, end_pos);
1043  message += prefix;
1045 
1047  return message;
1048 }
1049 
1050 string
1052 {
1053  string desc = "Remote(context=";
1054  desc += link.get_context();
1055  desc += ')';
1056  return desc;
1057 }
static Xapian::Query query(Xapian::Query::op op, const string &t1=string(), const string &t2=string(), const string &t3=string(), const string &t4=string(), const string &t5=string(), const string &t6=string(), const string &t7=string(), const string &t8=string(), const string &t9=string(), const string &t10=string())
Definition: api_anydb.cc:62
A PostList iterating all docids when they form a contiguous range.
PositionList from an InMemory DB or a Document object.
Abstract base class for leaf postlists.
Definition: leafpostlist.h:40
A postlist in a remote database.
Definition: net_postlist.h:35
Iterate all terms in a remote database.
void send_message(char type, std::string_view s, double end_time)
Send a message.
const std::string & get_context() const
Return the context to report with errors.
void do_close()
Close the connection.
int get_message(std::string &result, double end_time)
Read one message from fdin.
void shutdown()
Shutdown the connection.
bool get_message_or_done(std::string &message, reply_type required_type) const
Xapian::doccount doccount
The remote document count, given at open.
void set_metadata(std::string_view key, std::string_view value)
Set the metadata associated with a given key.
bool locked() const
Return true if the database is open for writing.
LeafPostList * open_leaf_post_list(std::string_view term, bool) const
Create a LeafPostList for use during a match.
void set_query(const Xapian::Query &query, Xapian::termcount qlen, Xapian::valueno collapse_key, Xapian::doccount collapse_max, Xapian::Enquire::docid_order order, Xapian::valueno sort_key, Xapian::Enquire::Internal::sort_setting sort_by, bool sort_value_forward, double time_limit, int percent_threshold, double weight_threshold, const Xapian::Weight &wtscheme, const Xapian::RSet &omrset, const std::vector< opt_ptr_spy > &matchspies) const
Set the query.
TermList * open_synonym_keylist(std::string_view prefix) const
Open a termlist returning each term which has synonyms.
RemoteDatabase(const RemoteDatabase &)
Don't allow copying.
bool update_stats(message_type msg_code=MSG_UPDATE, const std::string &body=std::string()) const
TermList * open_allterms(std::string_view prefix) const
Iterate all terms.
Xapian::termcount get_unique_terms(Xapian::docid did) const
Get the number of unique terms in document.
bool has_positional_info
Has positional information?
void clear_synonyms(std::string_view word) const
Clear all synonyms for a term.
std::string uuid
The UUID of the remote database.
void do_close()
Close the socket.
void send_global_stats(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount check_at_least, const Xapian::KeyMaker *sorter, const Xapian::Weight::Internal &stats) const
Send the global stats to the remote server.
void cancel()
Cancel pending modifications to the database.
std::string get_value_upper_bound(Xapian::valueno slot) const
Get an upper bound on the values stored in the given value slot.
TermList * open_synonym_termlist(std::string_view term) const
Open a termlist returning synonyms for a term.
TermList * open_term_list(Xapian::docid did) const
Get remote termlist.
Xapian::termcount doclen_lbound
A lower bound on the smallest document length in this database.
Xapian::termcount get_doclength(Xapian::docid did) const
TermList * open_metadata_keylist(std::string_view prefix) const
Get remote metadata key list.
void delete_document(Xapian::docid did)
bool pending_reply
Are we currently expecting a reply?
std::string get_metadata(std::string_view key) const
Get the metadata associated with a given key.
void request_document(Xapian::docid did) const
Request a document.
bool has_positions() const
Check whether this database contains any positional information.
Xapian::Document::Internal * open_document(Xapian::docid did, bool lazy) const
Get a remote document.
bool uncommitted_changes
True if there are (or may be) uncommitted changes.
Xapian::valueno mru_slot
The value slot for the most recently used value statistics.
Xapian::termcount get_doclength_upper_bound() const
Get an upper bound on the length of a document in this DB.
bool term_exists(std::string_view term) const
Check if term exists.
Xapian::termcount get_wdf_upper_bound(std::string_view term) const
Get an upper bound on the wdf of term term.
bool reopen()
Reopen the database to the latest available revision.
void remove_synonym(std::string_view word, std::string_view synonym) const
Remove a synonym for a term.
void add_synonym(std::string_view word, std::string_view synonym) const
Add a synonym for a term.
double timeout
The timeout value used in network communications, in seconds.
OwnedRemoteConnection link
The object which does the I/O.
TermList * open_term_list_direct(Xapian::docid did) const
Like open_term_list() but without MultiTermList wrapper.
void keep_alive()
Send a keep-alive message.
Xapian::doccount get_value_freq(Xapian::valueno slot) const
Return the frequency of a given value slot.
ValueStats mru_valstats
The most recently used value statistics.
void get_freqs(std::string_view term, Xapian::doccount *termfreq_ptr, Xapian::termcount *collfreq_ptr) const
Returns frequencies for a term.
void add_spelling(std::string_view word, Xapian::termcount freqinc) const
Add a word to the spelling dictionary.
Xapian::totallength get_total_length() const
Return the total length of all documents in this database.
Xapian::docid add_document(const Xapian::Document &doc)
reply_type get_message(std::string &message, reply_type required_type, reply_type required_type2) const
Receive a message from the server.
void read_value_stats(Xapian::valueno slot) const
Read the value statistics for a value from a remote database.
std::string get_uuid() const
Get a UUID for the database.
Xapian::docid get_lastdocid() const
Get the last used docid.
std::string reconstruct_text(Xapian::docid did, size_t length, std::string_view prefix, Xapian::termpos start_pos, Xapian::termpos end_pos) const
void commit()
Commit pending modifications to the database.
void replace_document(Xapian::docid did, const Xapian::Document &doc)
std::string get_description() const
Return a string describing this object.
Xapian::termcount remove_spelling(std::string_view word, Xapian::termcount freqdec) const
Remove a word from the spelling dictionary.
PostList * open_post_list(std::string_view term) const
Return a PostList suitable for use in a PostingIterator.
Xapian::termcount get_doclength_lower_bound() const
Get a lower bound on the length of a document in this DB.
Xapian::MSet get_mset(const std::vector< opt_ptr_spy > &matchspies) const
Get the MSet from the remote server.
void send_message(message_type type, std::string_view data) const
Send a message to the server.
Xapian::totallength total_length
The total length of all documents in this database.
std::string get_value_lower_bound(Xapian::valueno slot) const
Get a lower bound on the values stored in the given value slot.
Xapian::termcount get_wdfdocmax(Xapian::docid did) const
Get the max wdf in document.
Xapian::doccount get_doccount() const
Get the document count.
Xapian::docid lastdocid
The remote last docid, given at open.
Xapian::termcount positionlist_count(Xapian::docid did, std::string_view term) const
Get the length of the position list.
void close()
Close the database.
Xapian::termcount doclen_ubound
An upper bound on the greatest document length in this database.
PositionList * open_position_list(Xapian::docid did, std::string_view term) const
void accumulate_remote_stats(Xapian::Weight::Internal &total) const
Accumulate stats from the remote server.
A document read from a RemoteDatabase.
Iterate keys in a remote database.
Iterate terms in a remote document.
bool is_read_only() const
Test if this shard is read-only.
bool transaction_active() const
Test if a transaction is currently active.
virtual void end_transaction(bool do_commit)
End transaction.
Abstract base class for a document.
Class representing a document.
Definition: document.h:64
docid_order
Ordering of docids.
Definition: enquire.h:130
Abstract base class for postlists.
Definition: postlist.h:40
A smart pointer that uses intrusive reference counting.
Definition: intrusive_ptr.h:83
InvalidOperationError indicates the API was used in an invalid way.
Definition: error.h:271
Virtual base class for key making functors.
Definition: keymaker.h:44
virtual std::string serialise() const
Return this object's parameters serialised as a single string.
Definition: keymaker.cc:55
virtual std::string name() const
Return the name of this KeyMaker.
Definition: keymaker.cc:48
Class representing a list of search results.
Definition: mset.h:46
Xapian::Internal::intrusive_ptr_nonnull< Internal > internal
Definition: mset.h:78
Indicates a problem communicating with a remote database.
Definition: error.h:791
Abstract base class for iterating term positions in a document.
Definition: positionlist.h:32
Class representing a query.
Definition: query.h:45
std::string serialise() const
Serialise this object into a string.
Definition: query.cc:256
Class representing a set of documents judged as relevant.
Definition: rset.h:39
Abstract base class for termlists.
Definition: termlist.h:42
UnimplementedError indicates an attempt to use an unimplemented feature.
Definition: error.h:313
Suitable for "simple" type T.
Definition: smallvector.h:62
void push_back(T elt)
Definition: smallvector.h:190
Class to hold statistics for a given collection.
Abstract base class for weighting schemes.
Definition: weight.h:38
virtual std::string name() const
Return the name of this weighting scheme, e.g.
Definition: weight.cc:186
virtual std::string serialise() const
Return this object's parameters serialised as a single string.
Definition: weight.cc:192
#define UNSIGNED_OVERFLOW_OK(X)
Definition: config.h:635
#define rare(COND)
Definition: config.h:616
Constants in the Xapian namespace.
Iterate all document ids when they form a contiguous range.
string term
PositionList * p
Hierarchy of classes which Xapian can throw as exceptions.
PositionList from an InMemory DB or a Document object.
MatchSpy implementation.
Xapian::MSet internals.
double end_time(double timeout)
Return the end time for a timeout in timeout seconds.
Definition: realtime.h:95
string str(int value)
Convert int to std::string.
Definition: str.cc:91
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:82
const valueno BAD_VALUENO
Reserved value to indicate "no valueno".
Definition: types.h:100
const int DB_RETRY_LOCK
If the database is already locked, retry the lock.
Definition: constants.h:144
unsigned XAPIAN_TERMCOUNT_BASE_TYPE termcount
A counts of terms.
Definition: types.h:64
unsigned valueno
The number for a value slot in a document.
Definition: types.h:90
unsigned XAPIAN_DOCID_BASE_TYPE doccount
A count of documents.
Definition: types.h:37
unsigned XAPIAN_DOCID_BASE_TYPE docid
A unique identifier for a document.
Definition: types.h:51
unsigned XAPIAN_TERMPOS_BASE_TYPE termpos
A term position within a document or query.
Definition: types.h:75
XAPIAN_TOTALLENGTH_TYPE totallength
The total length of all documents in a database.
Definition: types.h:112
Postlists for remote databases.
Various assertion macros.
#define Assert(COND)
Definition: omassert.h:122
void unpack_throw_serialisation_error(const char *p)
Throw appropriate SerialisationError.
Definition: pack.cc:29
Pack types into strings and unpack them again.
bool unpack_uint_last(const char **p, const char *end, U *result)
Decode an unsigned integer as the last item in a string.
Definition: pack.h:118
bool unpack_string(const char **p, const char *end, std::string &result)
Decode a std::string from a string.
Definition: pack.h:468
void pack_uint_last(std::string &s, U value)
Append an encoded unsigned integer to a string as the last item.
Definition: pack.h:100
bool unpack_bool(const char **p, const char *end, bool *result)
Decode a bool from a string.
Definition: pack.h:76
void pack_bool(std::string &s, bool value)
Append an encoded bool to a string.
Definition: pack.h:64
bool unpack_uint(const char **p, const char *end, U *result)
Decode an unsigned integer from a string.
Definition: pack.h:346
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
Definition: pack.h:315
void pack_string(std::string &s, std::string_view value)
Append an encoded std::string to a string.
Definition: pack.h:442
void pack_string_empty(std::string &s)
Append an empty encoded std::string to a string.
Definition: pack.h:456
Functions for handling a time or time interval in a double.
static void throw_handshake_failed(const string &context)
static void throw_invalid_operation(const char *message)
static void throw_connection_closed_unexpectedly()
static bool is_intermediate_reply(int reply_code)
Return true if further replies should be expected.
RemoteDatabase is the baseclass for remote database implementations.
A document read from a RemoteDatabase.
Iterate all terms in a remote database.
Iterate keys in a remote database.
Iterate terms in a remote document.
#define XAPIAN_REMOTE_PROTOCOL_MAJOR_VERSION
message_type
Message types (client -> server).
@ MSG_WDFDOCMAX
@ MSG_GETMSET
@ MSG_REOPEN
@ MSG_CANCEL
@ MSG_CLEARSYNONYMS
@ MSG_KEEPALIVE
@ MSG_REMOVESYNONYM
@ MSG_POSITIONLISTCOUNT
@ MSG_DELETEDOCUMENT
@ MSG_QUERY
@ MSG_WRITEACCESS
@ MSG_RECONSTRUCTTEXT
@ MSG_POSITIONLIST
@ MSG_DOCLENGTH
@ MSG_VALUESTATS
@ MSG_SETMETADATA
@ MSG_TERMFREQ
@ MSG_COMMIT
@ MSG_ADDDOCUMENT
@ MSG_COLLFREQ
@ MSG_REQUESTDOCUMENT
@ MSG_FREQS
@ MSG_REPLACEDOCUMENTTERM
@ MSG_REMOVESPELLING
@ MSG_SYNONYMTERMLIST
@ MSG_GETMETADATA
@ MSG_METADATAKEYLIST
@ MSG_ALLTERMS
@ MSG_DELETEDOCUMENTTERM
@ MSG_POSTLIST
@ MSG_DOCUMENT
@ MSG_REPLACEDOCUMENT
@ MSG_TERMLIST
@ MSG_ADDSYNONYM
@ MSG_UNIQUETERMS
@ MSG_TERMEXISTS
@ MSG_SYNONYMKEYLIST
@ MSG_ADDSPELLING
@ MSG_MAX
reply_type
Reply types (server -> client).
@ REPLY_VALUE
@ REPLY_DOCDATA
@ REPLY_EXCEPTION
@ REPLY_RESULTS
@ REPLY_METADATAKEYLIST
@ REPLY_WDFDOCMAX
@ REPLY_POSITIONLISTCOUNT
@ REPLY_DONE
@ REPLY_REMOVESPELLING
@ REPLY_UNIQUETERMS
@ REPLY_SYNONYMKEYLIST
@ REPLY_POSTLIST
@ REPLY_ADDDOCUMENT
@ REPLY_TERMFREQ
@ REPLY_MAX
@ REPLY_TERMEXISTS
@ REPLY_STATS
@ REPLY_COLLFREQ
@ REPLY_TERMLIST
@ REPLY_TERMDOESNTEXIST
@ REPLY_SYNONYMTERMLIST
@ REPLY_RECONSTRUCTTEXT
@ REPLY_DOCLENGTH
@ REPLY_POSTLISTHEADER
@ REPLY_POSITIONLIST
@ REPLY_TERMLISTHEADER
@ REPLY_FREQS
@ REPLY_UPDATE
@ REPLY_METADATA
@ REPLY_ALLTERMS
@ REPLY_VALUESTATS
#define XAPIAN_REMOTE_PROTOCOL_MINOR_VERSION
string serialise_double(double v)
Serialise a double to a string.
functions to serialise and unserialise a double
void unserialise_error(const string &serialised_error, const string &prefix, const string &new_context)
Unserialise a Xapian::Error object and throw it.
functions to convert classes to strings and back
string serialise_document(const Xapian::Document &doc)
Serialise a Xapian::Document object.
Definition: serialise.cc:183
string serialise_stats(const Xapian::Weight::Internal &stats)
Serialise a stats object.
Definition: serialise.cc:42
void unserialise_stats(const char *p, const char *p_end, Xapian::Weight::Internal &stat)
Unserialise a serialised stats object.
Definition: serialise.cc:92
string serialise_rset(const Xapian::RSet &rset)
Serialise a Xapian::RSet object.
Definition: serialise.cc:148
functions to convert classes to strings and back
Custom vector implementations using small vector optimisation.
Convert types to std::string.
Various handy string-related helpers.
#define STRINGIZE(X)
The STRINGIZE macro converts its parameter into a string constant.
Definition: stringutils.h:41
std::string lower_bound
A lower bound on the values stored in the given value slot.
Definition: valuestats.h:36
std::string upper_bound
An upper bound on the values stored in the given value slot.
Definition: valuestats.h:40
Xapian::doccount freq
The number of documents which have a (non-empty) value stored in the slot.
Definition: valuestats.h:32
Definition: header.h:242
const char * dummy[]
Definition: version_h.cc:7
Xapian::Weight::Internal class, holding database and term statistics.