xapian-core  2.1.0
remoteserver.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006-2026 Olly Betts
5  * Copyright (C) 2006,2007,2009,2010 Lemur Consulting Ltd
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (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 #include "remoteserver.h"
24 
25 #include "xapian/constants.h"
26 #include "xapian/database.h"
27 #include "xapian/enquire.h"
28 #include "xapian/error.h"
29 #include "xapian/matchspy.h"
30 #include "xapian/query.h"
31 #include "xapian/rset.h"
32 #include "xapian/valueiterator.h"
33 
34 #include <signal.h>
35 #include <cerrno>
36 #include <cstdlib>
37 #include <memory>
38 
39 #include "api/msetinternal.h"
40 #include "api/termlist.h"
41 #include "matcher/matcher.h"
42 #include "omassert.h"
43 #include "pack.h"
44 #include "realtime.h"
45 #include "serialise.h"
46 #include "serialise-double.h"
47 #include "serialise-error.h"
48 #include "str.h"
49 #include "stringutils.h"
50 #include "weight/weightinternal.h"
51 
52 using namespace std;
53 
54 [[noreturn]]
55 static void
57 {
58  throw Xapian::InvalidOperationError("Server is read-only");
59 }
60 
62 struct ConnectionClosed { };
63 
64 RemoteServer::RemoteServer(const vector<string>& dbpaths,
65  int fdin_, int fdout_,
66  double active_timeout_, double idle_timeout_,
67  bool writable_)
68  : RemoteConnection(fdin_, fdout_, string()),
69  writable(writable_),
70  active_timeout(active_timeout_), idle_timeout(idle_timeout_)
71 {
72  // Catch errors opening the database and propagate them to the client.
73  try {
74  Assert(!dbpaths.empty());
75  // We always open the database read-only to start with. If we're
76  // writable, the client can ask to be upgraded to write access once
77  // connected if it wants it.
78  db = new Xapian::Database(dbpaths[0]);
79  // Build a better description than Database::get_description() gives
80  // in the variable context. FIXME: improve Database::get_description()
81  // and then just use that instead.
82  context = dbpaths[0];
83 
84  vector<string>::const_iterator i(dbpaths.begin());
85  for (++i; i != dbpaths.end(); ++i) {
87  context += ' ';
88  context += *i;
89  }
90  } catch (const Xapian::Error &err) {
91  // Propagate the exception to the client.
93  // And rethrow it so our caller can log it and close the connection.
94  throw;
95  }
96 
97 #ifndef __WIN32__
98  // It's simplest to just ignore SIGPIPE. We'll still know if the
99  // connection dies because we'll get EPIPE back from write().
100  //
101  // This is OK because RemoteServer subclasses are only used in
102  // specialised programs - if we expose any of them as API classes
103  // then we should use SO_NOSIGPIPE/MSG_NOSIGNAL instead like we do
104  // on the client side.
105  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
106  throw Xapian::NetworkError("Couldn't set SIGPIPE to SIG_IGN", errno);
107 #endif
108 
109  // Send greeting message.
110  msg_update(string_view());
111 }
112 
114 {
115  delete db;
116  // wdb is either NULL or equal to db, so we shouldn't delete it too!
117 }
118 
120 RemoteServer::get_message(double timeout, string & result,
121  message_type required_type)
122 {
123  double end_time = RealTime::end_time(timeout);
124  int type = RemoteConnection::get_message(result, end_time);
125 
126  // Handle "shutdown connection" message here. Treat EOF here for a read-only
127  // database the same way since a read-only client just closes the
128  // connection when done.
129  if (type == MSG_SHUTDOWN || (type < 0 && wdb == NULL))
130  throw ConnectionClosed();
131  if (type < 0)
132  throw Xapian::NetworkError("Connection closed unexpectedly");
133  if (type >= MSG_MAX) {
134  string errmsg("Invalid message type ");
135  errmsg += str(type);
136  throw Xapian::NetworkError(errmsg);
137  }
138  if (required_type != MSG_MAX && type != int(required_type)) {
139  string errmsg("Expecting message type ");
140  errmsg += str(int(required_type));
141  errmsg += ", got ";
142  errmsg += str(type);
143  throw Xapian::NetworkError(errmsg);
144  }
145  return static_cast<message_type>(type);
146 }
147 
148 void
149 RemoteServer::send_message(reply_type type, string_view message)
150 {
152  unsigned char type_as_char = static_cast<unsigned char>(type);
153  RemoteConnection::send_message(type_as_char, message, end_time);
154 }
155 
156 typedef void (RemoteServer::* dispatch_func)(string_view);
157 
158 void
160 {
161  while (true) {
162  try {
163  string message;
164  size_t type = get_message(idle_timeout, message);
165  switch (type) {
166  case MSG_ALLTERMS:
167  msg_allterms(message);
168  continue;
169  case MSG_COLLFREQ:
170  msg_collfreq(message);
171  continue;
172  case MSG_DOCUMENT:
173  msg_document(message);
174  continue;
175  case MSG_TERMEXISTS:
176  msg_termexists(message);
177  continue;
178  case MSG_TERMFREQ:
179  msg_termfreq(message);
180  continue;
181  case MSG_VALUESTATS:
182  msg_valuestats(message);
183  continue;
184  case MSG_KEEPALIVE:
185  msg_keepalive(message);
186  continue;
187  case MSG_DOCLENGTH:
188  msg_doclength(message);
189  continue;
190  case MSG_QUERY:
191  msg_query(message);
192  continue;
193  case MSG_TERMLIST:
194  msg_termlist(message);
195  continue;
196  case MSG_POSITIONLIST:
197  msg_positionlist(message);
198  continue;
199  case MSG_POSTLIST:
200  msg_postlist(message);
201  continue;
202  case MSG_REOPEN:
203  msg_reopen(message);
204  continue;
205  case MSG_UPDATE:
206  msg_update(message);
207  continue;
208  case MSG_ADDDOCUMENT:
209  msg_adddocument(message);
210  continue;
211  case MSG_CANCEL:
212  msg_cancel(message);
213  continue;
215  msg_deletedocumentterm(message);
216  continue;
217  case MSG_COMMIT:
218  msg_commit(message);
219  continue;
220  case MSG_REPLACEDOCUMENT:
221  msg_replacedocument(message);
222  continue;
224  msg_replacedocumentterm(message);
225  continue;
226  case MSG_DELETEDOCUMENT:
227  msg_deletedocument(message);
228  continue;
229  case MSG_WRITEACCESS:
230  msg_writeaccess(message);
231  continue;
232  case MSG_GETMETADATA:
233  msg_getmetadata(message);
234  continue;
235  case MSG_SETMETADATA:
236  msg_setmetadata(message);
237  continue;
238  case MSG_REQUESTDOCUMENT:
239  msg_requestdocument(message);
240  continue;
241  case MSG_ADDSPELLING:
242  msg_addspelling(message);
243  continue;
244  case MSG_REMOVESPELLING:
245  msg_removespelling(message);
246  continue;
247  case MSG_METADATAKEYLIST:
248  msg_metadatakeylist(message);
249  continue;
250  case MSG_FREQS:
251  msg_freqs(message);
252  continue;
253  case MSG_UNIQUETERMS:
254  msg_uniqueterms(message);
255  continue;
256  case MSG_WDFDOCMAX:
257  msg_wdfdocmax(message);
258  continue;
260  msg_positionlistcount(message);
261  continue;
262  case MSG_RECONSTRUCTTEXT:
263  msg_reconstructtext(message);
264  continue;
265  case MSG_SYNONYMTERMLIST:
266  msg_synonymtermlist(message);
267  continue;
268  case MSG_SYNONYMKEYLIST:
269  msg_synonymkeylist(message);
270  continue;
271  case MSG_ADDSYNONYM:
272  msg_addsynonym(message);
273  continue;
274  case MSG_REMOVESYNONYM:
275  msg_removesynonym(message);
276  continue;
277  case MSG_CLEARSYNONYMS:
278  msg_clearsynonyms(message);
279  continue;
280  default: {
281  // MSG_GETMSET - used during a conversation.
282  // MSG_SHUTDOWN - handled by get_message().
283  string errmsg("Unexpected message type ");
284  errmsg += str(type);
285  throw Xapian::InvalidArgumentError(errmsg);
286  }
287  }
288  } catch (const Xapian::NetworkTimeoutError & e) {
289  try {
290  // We've had a timeout, so the client may not be listening, so
291  // set the end_time to 1 and if we can't send the message right
292  // away, just exit and the client will cope.
294  } catch (...) {
295  }
296  // And rethrow it so our caller can log it and close the
297  // connection.
298  throw;
299  } catch (const Xapian::NetworkError &) {
300  // All other network errors mean we are fatally confused and are
301  // unlikely to be able to communicate further across this
302  // connection. So we don't try to propagate the error to the
303  // client, but instead just rethrow the exception so our caller can
304  // log it and close the connection.
305  throw;
306  } catch (const Xapian::Error &e) {
307  // Propagate the exception to the client, then return to the main
308  // message handling loop.
310  } catch (ConnectionClosed &) {
311  return;
312  } catch (...) {
313  // Propagate an unknown exception to the client.
315  // And rethrow it so our caller can log it and close the
316  // connection.
317  throw;
318  }
319  }
320 }
321 
322 void
323 RemoteServer::msg_allterms(string_view prefix)
324 {
325  string reply;
326  string prev(prefix);
327  for (Xapian::TermIterator t = db->allterms_begin(prefix);
328  t != db->allterms_end(prefix);
329  ++t) {
330  const string& term = *t;
331  size_t reuse = common_prefix_length(prev, term, 255);
332  reply.append(1, char(reuse));
333  pack_uint(reply, term.size() - reuse);
334  reply.append(term, reuse, string::npos);
335  pack_uint(reply, t.get_termfreq());
336  prev = term;
337  }
339 }
340 
341 void
342 RemoteServer::msg_termlist(string_view message)
343 {
344  const char *p = message.data();
345  const char *p_end = p + message.size();
346  Xapian::docid did;
347  if (!unpack_uint_last(&p, p_end, &did)) {
348  throw Xapian::NetworkError("Bad MSG_TERMLIST");
349  }
351  Xapian::termcount num_terms = 0;
352  if (t.internal)
353  num_terms = t.internal->get_approx_size();
354  string reply;
355  pack_uint(reply, db->get_doclength(did));
356  pack_uint_last(reply, num_terms);
358 
359  reply.resize(0);
360  string prev;
361  while (t != db->termlist_end(did)) {
362  const string& term = *t;
363  size_t reuse = common_prefix_length(prev, term, 255);
364  reply.append(1, char(reuse));
365  pack_uint(reply, term.size() - reuse);
366  reply.append(term, reuse, string::npos);
367  pack_uint(reply, t.get_wdf());
368  pack_uint(reply, t.get_termfreq());
369  prev = term;
370  ++t;
371  }
373 }
374 
375 void
376 RemoteServer::msg_positionlist(string_view message)
377 {
378  const char *p = message.data();
379  const char *p_end = p + message.size();
380  Xapian::docid did;
381  if (!unpack_uint(&p, p_end, &did)) {
382  throw Xapian::NetworkError("Bad MSG_POSITIONLIST");
383  }
384  string term(p, p_end - p);
385 
386  string reply;
387  Xapian::termpos lastpos = static_cast<Xapian::termpos>(-1);
389  i != db->positionlist_end(did, term);
390  ++i) {
391  Xapian::termpos pos = *i;
392  pack_uint(reply, UNSIGNED_OVERFLOW_OK(pos - lastpos - 1));
393  lastpos = pos;
394  }
396 }
397 
398 void
400 {
401  const char *p = message.data();
402  const char *p_end = p + message.size();
403  Xapian::docid did;
404  if (!unpack_uint(&p, p_end, &did)) {
405  throw Xapian::NetworkError("Bad MSG_POSITIONLISTCOUNT");
406  }
407 
408  // This is kind of clumsy, but what the public API requires.
409  Xapian::termcount result = 0;
410  Xapian::TermIterator termit = db->termlist_begin(did);
411  if (termit != db->termlist_end(did)) {
412  string term(p, p_end - p);
413  termit.skip_to(term);
414  if (termit != db->termlist_end(did) && *termit == term) {
415  result = termit.positionlist_count();
416  }
417  }
418  string reply;
419  pack_uint_last(reply, result);
421 }
422 
423 void
425 {
426  Xapian::doccount termfreq = db->get_termfreq(term);
427  string reply;
428  pack_uint_last(reply, termfreq);
430 
431  reply.resize(0);
432  Xapian::docid lastdocid = 0;
434  i != db->postlist_end(term);
435  ++i) {
436  Xapian::docid newdocid = *i;
437  pack_uint(reply, newdocid - lastdocid - 1);
438  pack_uint(reply, i.get_wdf());
439 
440  lastdocid = newdocid;
441  }
442 
444 }
445 
446 void
448 {
449  if (!writable)
450  throw_read_only();
451 
452  int flags = 0;
453  const char *p = msg.data();
454  const char *p_end = p + msg.size();
455  if (p != p_end) {
456  unsigned flag_bits;
457  if (!unpack_uint_last(&p, p_end, &flag_bits)) {
458  throw Xapian::NetworkError("Bad flags in MSG_WRITEACCESS");
459  }
460  flags = flag_bits &~ Xapian::DB_ACTION_MASK_;
461  }
462 
463  wdb = new Xapian::WritableDatabase(db->lock(flags));
464  delete db;
465  db = wdb;
466  msg_update(msg);
467 }
468 
469 void
470 RemoteServer::msg_reopen(string_view msg)
471 {
472  if (!db->reopen()) {
474  return;
475  }
476  msg_update(msg);
477 }
478 
479 void
481 {
482  static const char protocol[2] = {
485  };
486  string message(protocol, 2);
487  Xapian::doccount num_docs = db->get_doccount();
488  pack_uint(message, num_docs);
489  pack_uint(message, db->get_lastdocid() - num_docs);
491  pack_uint(message, doclen_lb);
492  pack_uint(message, db->get_doclength_upper_bound() - doclen_lb);
493  pack_bool(message, db->has_positions());
494  pack_uint(message, db->get_total_length());
495  message += db->get_uuid();
496  send_message(REPLY_UPDATE, message);
497 }
498 
499 void
500 RemoteServer::msg_query(string_view message_in)
501 {
502  const char *p = message_in.data();
503  const char *p_end = p + message_in.size();
504 
505  // Unserialise the Query.
506  string serialisation;
507  if (!unpack_string(&p, p_end, serialisation)) {
508  throw Xapian::NetworkError("Bad MSG_QUERY");
509  }
510 
512 
513  // Unserialise assorted Enquire settings.
514  Xapian::termcount qlen;
515  Xapian::valueno collapse_max;
516  if (!unpack_uint(&p, p_end, &qlen) ||
517  !unpack_uint(&p, p_end, &collapse_max)) {
518  throw Xapian::NetworkError("Bad MSG_QUERY");
519  }
520 
521  Xapian::valueno collapse_key = Xapian::BAD_VALUENO;
522  if (collapse_max) {
523  if (!unpack_uint(&p, p_end, &collapse_key)) {
524  throw Xapian::NetworkError("Bad MSG_QUERY");
525  }
526  }
527 
528  if (p_end - p < 4 || static_cast<unsigned char>(*p) > 2) {
529  throw Xapian::NetworkError("bad message (docid_order)");
530  }
532  order = static_cast<Xapian::Enquire::docid_order>(*p++);
533 
534  if (static_cast<unsigned char>(*p) > 3) {
535  throw Xapian::NetworkError("bad message (sort_by)");
536  }
538  sort_by = static_cast<Xapian::Enquire::Internal::sort_setting>(*p++);
539 
541  if (sort_by != Xapian::Enquire::Internal::REL) {
542  if (!unpack_uint(&p, p_end, &sort_key)) {
543  throw Xapian::NetworkError("Bad MSG_QUERY");
544  }
545  }
546 
547  bool sort_value_forward;
548  if (!unpack_bool(&p, p_end, &sort_value_forward)) {
549  throw Xapian::NetworkError("bad message (sort_value_forward)");
550  }
551 
552  double time_limit = unserialise_double(&p, p_end);
553 
554  int percent_threshold = *p++;
555  if (percent_threshold < 0 || percent_threshold > 100) {
556  throw Xapian::NetworkError("bad message (percent_threshold)");
557  }
558 
559  double weight_threshold = unserialise_double(&p, p_end);
560  if (weight_threshold < 0) {
561  throw Xapian::NetworkError("bad message (weight_threshold)");
562  }
563 
564  // Unserialise the Weight object.
565  string wtname;
566  if (!unpack_string(&p, p_end, wtname)) {
567  throw Xapian::NetworkError("Bad MSG_QUERY");
568  }
569 
570  const Xapian::Weight * wttype = reg.get_weighting_scheme(wtname);
571  if (wttype == NULL) {
572  // Note: user weighting schemes should be registered by adding them to
573  // a Registry, and setting the context using
574  // RemoteServer::set_registry().
575  throw Xapian::InvalidArgumentError("Weighting scheme " +
576  wtname + " not registered");
577  }
578 
579  if (!unpack_string(&p, p_end, serialisation)) {
580  throw Xapian::NetworkError("Bad MSG_QUERY");
581  }
582  unique_ptr<Xapian::Weight> wt(wttype->unserialise(serialisation));
583 
584  // Unserialise the RSet object.
585  if (!unpack_string(&p, p_end, serialisation)) {
586  throw Xapian::NetworkError("Bad MSG_QUERY");
587  }
588  Xapian::RSet rset = unserialise_rset(serialisation);
589 
590  // Unserialise any MatchSpy objects.
591  vector<Xapian::Internal::opt_intrusive_ptr<Xapian::MatchSpy>> matchspies;
592  while (p != p_end) {
593  string spytype;
594  if (!unpack_string(&p, p_end, spytype)) {
595  throw Xapian::NetworkError("Bad MSG_QUERY");
596  }
597  const Xapian::MatchSpy * spyclass = reg.get_match_spy(spytype);
598  if (spyclass == NULL) {
599  throw Xapian::InvalidArgumentError("Match spy " + spytype +
600  " not registered");
601  }
602 
603  if (!unpack_string(&p, p_end, serialisation)) {
604  throw Xapian::NetworkError("Bad MSG_QUERY");
605  }
606  matchspies.push_back(spyclass->unserialise(serialisation,
607  reg)->release());
608  }
609 
610  Xapian::Weight::Internal local_stats;
611  Matcher matcher(*db,
612  query, qlen, &rset, local_stats, *wt,
613  false,
614  collapse_key, collapse_max,
615  percent_threshold, weight_threshold,
616  order, sort_key, sort_by, sort_value_forward, time_limit,
617  matchspies);
618 
620 
621  string message;
623  p = message.c_str();
624  p_end = p + message.size();
625 
626  Xapian::termcount first;
627  Xapian::termcount maxitems;
628  Xapian::termcount check_at_least;
629  string sorter_type;
630  if (!unpack_uint(&p, p_end, &first) ||
631  !unpack_uint(&p, p_end, &maxitems) ||
632  !unpack_uint(&p, p_end, &check_at_least) ||
633  !unpack_string(&p, p_end, sorter_type)) {
634  throw Xapian::NetworkError("Bad MSG_GETMSET");
635  }
636  unique_ptr<Xapian::KeyMaker> sorter;
637  if (!sorter_type.empty()) {
638  const Xapian::KeyMaker* sorterclass = reg.get_key_maker(sorter_type);
639  if (sorterclass == NULL) {
640  throw Xapian::InvalidArgumentError("KeyMaker " + sorter_type +
641  " not registered");
642  }
643 
644  string serialised_sorter;
645  if (!unpack_string(&p, p_end, serialised_sorter)) {
646  throw Xapian::NetworkError("Bad MSG_GETMSET");
647  }
648  sorter.reset(sorterclass->unserialise(serialised_sorter, reg));
649  }
650 
651  unique_ptr<Xapian::Weight::Internal> total_stats(new Xapian::Weight::Internal);
652  unserialise_stats(p, p_end, *total_stats);
653 
654  Xapian::MSet mset = matcher.get_mset(first, maxitems, check_at_least,
655  *total_stats, *wt, 0, sorter.get(),
656  collapse_key, collapse_max,
657  percent_threshold, weight_threshold,
658  order,
659  sort_key, sort_by, sort_value_forward,
660  time_limit, matchspies);
661  // FIXME: The local side already has these stats, except for the maxpart
662  // information.
663  mset.internal->set_stats(total_stats.release());
664 
665  message.resize(0);
666  for (auto i : matchspies) {
667  pack_string(message, i->serialise_results());
668  }
669  message += mset.internal->serialise();
670  send_message(REPLY_RESULTS, message);
671 }
672 
673 void
674 RemoteServer::msg_document(string_view message)
675 {
676  const char *p = message.data();
677  const char *p_end = p + message.size();
678  Xapian::docid did;
679  if (!unpack_uint_last(&p, p_end, &did)) {
680  throw Xapian::NetworkError("Bad MSG_DOCUMENT");
681  }
682 
683  Xapian::Document doc = db->get_document(did);
684 
686 
688  for (i = doc.values_begin(); i != doc.values_end(); ++i) {
689  string item;
690  pack_uint(item, i.get_valueno());
691  item += *i;
692  send_message(REPLY_VALUE, item);
693  }
695 }
696 
697 void
699 {
700  // Ensure *our* database stays alive, as it may contain remote databases!
701  db->keep_alive();
703 }
704 
705 void
707 {
709  : REPLY_TERMDOESNTEXIST), {});
710 }
711 
712 void
714 {
715  string reply;
718 }
719 
720 void
722 {
723  string reply;
726 }
727 
728 void
730 {
731  string msg;
732  pack_uint(msg, db->get_termfreq(term));
735 }
736 
737 void
738 RemoteServer::msg_valuestats(string_view message)
739 {
740  const char *p = message.data();
741  const char *p_end = p + message.size();
742  Xapian::valueno slot;
743  if (!unpack_uint_last(&p, p_end, &slot)) {
744  throw Xapian::NetworkError("Bad MSG_VALUESTATS");
745  }
746  string message_out;
747  pack_uint(message_out, db->get_value_freq(slot));
748  pack_string(message_out, db->get_value_lower_bound(slot));
749  message_out += db->get_value_upper_bound(slot);
750 
751  send_message(REPLY_VALUESTATS, message_out);
752 }
753 
754 void
755 RemoteServer::msg_doclength(string_view message)
756 {
757  const char *p = message.data();
758  const char *p_end = p + message.size();
759  Xapian::docid did;
760  if (!unpack_uint_last(&p, p_end, &did)) {
761  throw Xapian::NetworkError("Bad MSG_DOCLENGTH");
762  }
763  string reply;
764  pack_uint_last(reply, db->get_doclength(did));
766 }
767 
768 void
769 RemoteServer::msg_uniqueterms(string_view message)
770 {
771  const char *p = message.data();
772  const char *p_end = p + message.size();
773  Xapian::docid did;
774  if (!unpack_uint_last(&p, p_end, &did)) {
775  throw Xapian::NetworkError("Bad MSG_UNIQUETERMS");
776  }
777  string reply;
778  pack_uint_last(reply, db->get_unique_terms(did));
780 }
781 
782 void
783 RemoteServer::msg_wdfdocmax(string_view message)
784 {
785  const char* p = message.data();
786  const char* p_end = p + message.size();
787  Xapian::docid did;
788  if (!unpack_uint_last(&p, p_end, &did)) {
789  throw Xapian::NetworkError("Bad MSG_WDFDOCMAX");
790  }
791  string reply;
792  pack_uint_last(reply, db->get_wdfdocmax(did));
794 }
795 
796 void
798 {
799  const char* p = message.data();
800  const char* p_end = p + message.size();
801  Xapian::docid did;
802  size_t length;
803  Xapian::termpos start_pos, end_pos;
804  if (!unpack_uint(&p, p_end, &did) ||
805  !unpack_uint(&p, p_end, &length) ||
806  !unpack_uint(&p, p_end, &start_pos) ||
807  !unpack_uint(&p, p_end, &end_pos)) {
808  throw Xapian::NetworkError("Bad MSG_RECONSTRUCTTEXT");
809  }
811  db->reconstruct_text(did, length, {p, size_t(p_end - p)},
812  start_pos, end_pos));
813 }
814 
815 void
817 {
818  if (!wdb)
819  throw_read_only();
820 
821  wdb->commit();
822 
824 }
825 
826 void
828 {
829  if (!wdb)
830  throw_read_only();
831 
832  // We can't call cancel since that's an internal method, but this
833  // has the same effect with minimal additional overhead.
834  wdb->begin_transaction(false);
836 
838 }
839 
840 void
841 RemoteServer::msg_adddocument(string_view message)
842 {
843  if (!wdb)
844  throw_read_only();
845 
847 
848  string reply;
849  pack_uint_last(reply, did);
851 }
852 
853 void
855 {
856  if (!wdb)
857  throw_read_only();
858 
859  const char *p = message.data();
860  const char *p_end = p + message.size();
861  Xapian::docid did;
862  if (!unpack_uint_last(&p, p_end, &did)) {
863  throw Xapian::NetworkError("Bad MSG_DELETEDOCUMENT");
864  }
865 
866  wdb->delete_document(did);
867 
869 }
870 
871 void
873 {
874  if (!wdb)
875  throw_read_only();
876 
877  wdb->delete_document(message);
878 
880 }
881 
882 void
884 {
885  if (!wdb)
886  throw_read_only();
887 
888  const char *p = message.data();
889  const char *p_end = p + message.size();
890  Xapian::docid did;
891  if (!unpack_uint(&p, p_end, &did)) {
892  throw Xapian::NetworkError("Bad MSG_REPLACEDOCUMENT");
893  }
894 
895  string_view s(p, p_end - p);
897 
899 }
900 
901 void
903 {
904  if (!wdb)
905  throw_read_only();
906 
907  const char *p = message.data();
908  const char *p_end = p + message.size();
909  string unique_term;
910  if (!unpack_string(&p, p_end, unique_term)) {
911  throw Xapian::NetworkError("Bad MSG_REPLACEDOCUMENTTERM");
912  }
913  string_view s(p, p_end - p);
914  auto did = wdb->replace_document(unique_term, unserialise_document(s));
915  string reply;
916  pack_uint_last(reply, did);
918 }
919 
920 void
921 RemoteServer::msg_getmetadata(string_view message)
922 {
924 }
925 
926 void
928 {
929  string reply;
930  string prev(prefix);
931  for (Xapian::TermIterator t = db->metadata_keys_begin(prefix);
932  t != db->metadata_keys_end(prefix);
933  ++t) {
934  const string& term = *t;
935  size_t reuse = common_prefix_length(prev, term, 255);
936  reply.append(1, char(reuse));
937  pack_uint(reply, term.size() - reuse);
938  reply.append(term, reuse, string::npos);
939  prev = term;
940  }
942 }
943 
944 void
945 RemoteServer::msg_setmetadata(string_view message)
946 {
947  if (!wdb)
948  throw_read_only();
949  const char *p = message.data();
950  const char *p_end = p + message.size();
951  string key;
952  if (!unpack_string(&p, p_end, key)) {
953  throw Xapian::NetworkError("Bad MSG_SETMETADATA");
954  }
955  string val(p, p_end - p);
956  wdb->set_metadata(key, val);
957 
959 }
960 
961 void
963 {
964  const char* p = message.data();
965  const char* p_end = p + message.size();
966  Xapian::docid did;
967  if (!unpack_uint_last(&p, p_end, &did)) {
968  throw Xapian::NetworkError("Bad MSG_REQUESTDOCUMENT");
969  }
970  db->internal->request_document(did);
971 
972  send_message(REPLY_DONE, string_view());
973 }
974 
975 void
976 RemoteServer::msg_addspelling(string_view message)
977 {
978  if (!wdb)
979  throw_read_only();
980  const char *p = message.data();
981  const char *p_end = p + message.size();
982  Xapian::termcount freqinc;
983  if (!unpack_uint(&p, p_end, &freqinc)) {
984  throw Xapian::NetworkError("Bad MSG_ADDSPELLING");
985  }
986  wdb->add_spelling(string_view(p, p_end - p), freqinc);
987 
989 }
990 
991 void
993 {
994  if (!wdb)
995  throw_read_only();
996  const char *p = message.data();
997  const char *p_end = p + message.size();
998  Xapian::termcount freqdec;
999  if (!unpack_uint(&p, p_end, &freqdec)) {
1000  throw Xapian::NetworkError("Bad MSG_REMOVESPELLING");
1001  }
1002  auto result = wdb->remove_spelling(string_view(p, p_end - p), freqdec);
1003  string reply;
1004  pack_uint_last(reply, result);
1006 }
1007 
1008 void
1010 {
1011  Xapian::TermIterator t = db->synonyms_begin(message);
1012  string reply, prev;
1013  while (t != db->synonyms_end(message)) {
1014  const string& term = *t;
1015  size_t reuse = common_prefix_length(prev, term, 255);
1016  reply.append(1, char(reuse));
1017  pack_uint(reply, term.size() - reuse);
1018  reply.append(term, reuse, string::npos);
1019  prev = term;
1020  ++t;
1021  }
1023 }
1024 
1025 void
1027 {
1029  string reply, prev;
1030  while (t != db->synonym_keys_end(message)) {
1031  const string& term = *t;
1032  size_t reuse = common_prefix_length(prev, term, 255);
1033  reply.append(1, char(reuse));
1034  pack_uint(reply, term.size() - reuse);
1035  reply.append(term, reuse, string::npos);
1036  prev = term;
1037  ++t;
1038  }
1040 }
1041 
1042 void
1043 RemoteServer::msg_addsynonym(string_view message)
1044 {
1045  if (!wdb)
1046  throw_read_only();
1047  const char* p = message.data();
1048  const char* p_end = p + message.size();
1049  // Get the term
1050  string term;
1051  if (!unpack_string(&p, p_end, term)) {
1052  throw Xapian::NetworkError("Bad MSG_ADDSYNONYM");
1053  }
1054  wdb->add_synonym(term, string_view(p, p_end - p));
1055  send_message(REPLY_DONE, {});
1056 }
1057 
1058 void
1060 {
1061  if (!wdb)
1062  throw_read_only();
1063  const char* p = message.data();
1064  const char* p_end = p + message.size();
1065  // Get the term
1066  string term;
1067  if (!unpack_string(&p, p_end, term)) {
1068  throw Xapian::NetworkError("Bad MSG_REMOVESYNONYM");
1069  }
1070  wdb->remove_synonym(term, string_view(p, p_end - p));
1071  send_message(REPLY_DONE, {});
1072 }
1073 
1074 void
1076 {
1077  if (!wdb)
1078  throw_read_only();
1079  wdb->clear_synonyms(message);
1080  send_message(REPLY_DONE, {});
1081 }
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
Xapian::MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount check_at_least, Xapian::Weight::Internal &stats, const Xapian::Weight &wtscheme, const Xapian::MatchDecider *mdecider, const Xapian::KeyMaker *sorter, Xapian::valueno collapse_key, Xapian::doccount collapse_max, int percent_threshold, double weight_threshold, Xapian::Enquire::docid_order order, Xapian::valueno sort_key, Xapian::Enquire::Internal::sort_setting sort_by, bool sort_val_reverse, double time_limit, const std::vector< opt_ptr_spy > &matchspies)
Run the match and produce an MSet object.
Definition: matcher.cc:576
A RemoteConnection object provides a bidirectional connection to another RemoteConnection object on a...
void send_message(char type, std::string_view s, double end_time)
Send a message.
int get_message(std::string &result, double end_time)
Read one message from fdin.
std::string context
The context to report with errors.
Remote backend server base class.
Definition: remoteserver.h:37
void msg_wdfdocmax(std::string_view message)
void msg_addsynonym(std::string_view message)
void msg_adddocument(std::string_view message)
void msg_removesynonym(std::string_view message)
void msg_reopen(std::string_view message)
void msg_deletedocument(std::string_view message)
void msg_termfreq(std::string_view message)
void msg_synonymkeylist(std::string_view message)
void msg_freqs(std::string_view message)
void msg_doclength(std::string_view message)
double idle_timeout
Timeout while waiting for a new action from the client.
Definition: remoteserver.h:68
void msg_removespelling(std::string_view message)
void msg_termlist(std::string_view message)
Xapian::Registry reg
The registry, which allows unserialisation of user subclasses.
Definition: remoteserver.h:71
void msg_collfreq(std::string_view message)
void msg_positionlist(std::string_view message)
Xapian::Database * db
The database we're using.
Definition: remoteserver.h:48
double active_timeout
Timeout for actions during a conversation.
Definition: remoteserver.h:61
message_type get_message(double timeout, std::string &result, message_type required_type=MSG_MAX)
Accept a message from the client.
void msg_positionlistcount(std::string_view message)
void msg_deletedocumentterm(std::string_view message)
void msg_commit(std::string_view message)
void msg_update(std::string_view message)
bool writable
Do we support writing?
Definition: remoteserver.h:54
void msg_allterms(std::string_view message)
void msg_writeaccess(std::string_view message)
Xapian::WritableDatabase * wdb
The WritableDatabase we're using, or NULL if we're read-only.
Definition: remoteserver.h:51
RemoteServer(const RemoteServer &)
Don't allow copying.
void msg_metadatakeylist(std::string_view message)
void msg_valuestats(std::string_view message)
void msg_replacedocumentterm(std::string_view message)
void msg_synonymtermlist(std::string_view message)
~RemoteServer()
Destructor.
void msg_cancel(std::string_view message)
void msg_query(std::string_view message)
void msg_requestdocument(std::string_view message)
void msg_setmetadata(std::string_view message)
void msg_postlist(std::string_view message)
void msg_addspelling(std::string_view message)
void msg_getmetadata(std::string_view message)
void run()
Repeatedly accept messages from the client and process them.
void msg_document(std::string_view message)
void msg_keepalive(std::string_view message)
void msg_uniqueterms(std::string_view message)
void send_message(reply_type type, std::string_view message)
Send a message to the client.
void msg_termexists(std::string_view message)
void msg_reconstructtext(std::string_view message)
void msg_clearsynonyms(std::string_view message)
void msg_replacedocument(std::string_view message)
An indexed database of documents.
Definition: database.h:75
Xapian::TermIterator metadata_keys_begin(std::string_view prefix={}) const
An iterator which returns all user-specified metadata keys.
Definition: database.cc:499
Xapian::doccount get_termfreq(std::string_view term) const
Get the number of documents indexed by a specified term.
Definition: database.cc:262
Xapian::TermIterator synonym_keys_begin(std::string_view prefix={}) const
An iterator which returns all terms which have synonyms.
Definition: database.cc:484
Xapian::totallength get_total_length() const
Get the total length of all the documents in the database.
Definition: database.cc:256
PositionIterator positionlist_end(Xapian::docid, std::string_view) const noexcept
End iterator corresponding to positionlist_begin().
Definition: database.h:292
Xapian::WritableDatabase lock(int flags=0)
Lock a read-only database for writing.
Definition: database.cc:517
Xapian::termcount get_doclength_lower_bound() const
Get a lower bound on the length of a document in this DB.
Definition: database.cc:302
PostingIterator postlist_begin(std::string_view term) const
Start iterating the postings of a term.
Definition: database.cc:192
std::string reconstruct_text(Xapian::docid did, size_t length=0, std::string_view prefix={}, Xapian::termpos start_pos=0, Xapian::termpos end_pos=0) const
Reconstruct document text.
Definition: database.cc:533
TermIterator termlist_begin(Xapian::docid did) const
Start iterating the terms in a document.
Definition: database.cc:200
Xapian::termcount get_wdfdocmax(Xapian::docid did) const
Get the maximum wdf value in a specified document.
Definition: database.cc:359
void keep_alive()
Send a keep-alive message.
Definition: database.cc:385
PositionIterator positionlist_begin(Xapian::docid did, std::string_view term) const
Start iterating positions for a term in a document.
Definition: database.cc:221
std::string get_value_upper_bound(Xapian::valueno slot) const
Get an upper bound on the values stored in the given value slot.
Definition: database.cc:296
Xapian::TermIterator synonyms_end(std::string_view) const noexcept
End iterator corresponding to synonyms_begin(term).
Definition: database.h:513
void add_database(const Database &other)
Add shards from another Database.
Definition: database.h:109
Xapian::TermIterator synonym_keys_end(std::string_view={}) const noexcept
End iterator corresponding to synonym_keys_begin(prefix).
Definition: database.h:525
Xapian::termcount get_doclength(Xapian::docid did) const
Get the length of a specified document.
Definition: database.cc:341
Xapian::TermIterator metadata_keys_end(std::string_view={}) const noexcept
End iterator corresponding to metadata_keys_begin().
Definition: database.h:575
bool term_exists(std::string_view term) const
Test is a particular term is present in any document.
Definition: database.cc:378
std::string get_value_lower_bound(Xapian::valueno slot) const
Get a lower bound on the values stored in the given value slot.
Definition: database.cc:290
TermIterator allterms_end(std::string_view={}) const noexcept
End iterator corresponding to allterms_begin(prefix).
Definition: database.h:307
bool has_positions() const
Does this database have any positional information?
Definition: database.cc:215
Xapian::termcount get_collection_freq(std::string_view term) const
Get the total number of occurrences of a specified term.
Definition: database.cc:273
Xapian::doccount get_doccount() const
Get the number of documents in the database.
Definition: database.cc:233
PostingIterator postlist_end(std::string_view) const noexcept
End iterator corresponding to postlist_begin().
Definition: database.h:258
TermIterator termlist_end(Xapian::docid) const noexcept
End iterator corresponding to termlist_begin().
Definition: database.h:271
Xapian::docid get_lastdocid() const
Get the highest document id which has been used in the database.
Definition: database.cc:239
Xapian::doccount get_value_freq(Xapian::valueno slot) const
Return the frequency of a given value slot.
Definition: database.cc:284
TermIterator allterms_begin(std::string_view prefix={}) const
Start iterating all terms in the database with a given prefix.
Definition: database.cc:209
Xapian::TermIterator synonyms_begin(std::string_view term) const
An iterator which returns all the synonyms for a given term.
Definition: database.cc:478
bool reopen()
Reopen the database at the latest available revision.
Definition: database.cc:93
Xapian::termcount get_doclength_upper_bound() const
Get an upper bound on the length of a document in this DB.
Definition: database.cc:308
Xapian::Document get_document(Xapian::docid did, unsigned flags=0) const
Get a document from the database.
Definition: database.cc:368
std::string get_uuid() const
Get the UUID for the database.
Definition: database.cc:505
Xapian::Internal::intrusive_ptr_nonnull< Internal > internal
Definition: database.h:95
std::string get_metadata(std::string_view key) const
Get the user-specified metadata associated with a given key.
Definition: database.cc:490
Xapian::termcount get_unique_terms(Xapian::docid did) const
Get the number of unique terms in a specified document.
Definition: database.cc:350
Class representing a document.
Definition: document.h:64
std::string get_data() const
Get the document data.
Definition: document.cc:75
ValueIterator values_begin() const
Start iterating the values in this document.
Definition: document.cc:208
ValueIterator values_end() const noexcept
End iterator corresponding to values_begin().
Definition: document.h:259
docid_order
Ordering of docids.
Definition: enquire.h:130
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:41
InvalidArgumentError indicates an invalid parameter value was passed to the API.
Definition: error.h:229
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 KeyMaker * unserialise(const std::string &serialised, const Registry &context) const
Unserialise parameters.
Definition: keymaker.cc:62
Class representing a list of search results.
Definition: mset.h:46
Xapian::Internal::intrusive_ptr_nonnull< Internal > internal
Definition: mset.h:78
Abstract base class for match spies.
Definition: matchspy.h:50
MatchSpy * release()
Start reference counting this object.
Definition: matchspy.h:184
virtual MatchSpy * unserialise(const std::string &serialised, const Registry &context) const
Unserialise parameters.
Definition: matchspy.cc:67
Indicates a problem communicating with a remote database.
Definition: error.h:791
Indicates a timeout expired while communicating with a remote database.
Definition: error.h:833
Class for iterating over term positions.
Class for iterating over a list of terms.
Class representing a query.
Definition: query.h:45
static const Query unserialise(std::string_view serialised, const Registry &reg=Registry())
Unserialise a string and return a Query object.
Definition: query.cc:265
Class representing a set of documents judged as relevant.
Definition: rset.h:39
const Xapian::MatchSpy * get_match_spy(std::string_view name) const
Get a match spy given a name.
Definition: registry.cc:345
const Xapian::Weight * get_weighting_scheme(std::string_view name) const
Get the weighting scheme given a name.
Definition: registry.cc:317
const Xapian::KeyMaker * get_key_maker(std::string_view name) const
Get a KeyMaker given a name.
Definition: registry.cc:373
virtual Xapian::termcount get_approx_size() const =0
Return approximate size of this termlist.
Class for iterating over a list of terms.
Definition: termiterator.h:41
void skip_to(std::string_view term)
Advance the iterator to term term.
Xapian::doccount get_termfreq() const
Return the term frequency for the term at the current position.
Xapian::termcount positionlist_count() const
Return the length of the position list for the current position.
Xapian::termcount get_wdf() const
Return the wdf for the term at the current position.
Class for iterating over document values.
Definition: valueiterator.h:39
Xapian::valueno get_valueno() const
Return the value slot number for the current position.
Class to hold statistics for a given collection.
Abstract base class for weighting schemes.
Definition: weight.h:38
virtual Weight * unserialise(const std::string &serialised) const
Unserialise parameters.
Definition: weight.cc:198
This class provides read/write access to a database.
Definition: database.h:963
void delete_document(Xapian::docid did)
Delete a document from the database.
Definition: database.cc:567
void clear_synonyms(std::string_view term) const
Remove all synonyms for a term.
Definition: database.cc:628
void begin_transaction(bool flushed=true)
Begin a transaction.
Definition: database.cc:549
void add_synonym(std::string_view term, std::string_view synonym) const
Add a synonym for a term.
Definition: database.cc:614
void replace_document(Xapian::docid did, const Xapian::Document &document)
Replace a document in the database.
Definition: database.cc:582
void set_metadata(std::string_view key, std::string_view metadata)
Set the user-specified metadata associated with a given key.
Definition: database.cc:634
void cancel_transaction()
Abort the transaction currently in progress.
Definition: database.h:1205
void add_spelling(std::string_view word, Xapian::termcount freqinc=1) const
Add a word to the spelling dictionary.
Definition: database.cc:600
termcount remove_spelling(std::string_view word, termcount freqdec=1) const
Remove a word from the spelling dictionary.
Definition: database.cc:607
void commit()
Commit pending modifications.
Definition: database.cc:543
Xapian::docid add_document(const Xapian::Document &doc)
Add a document to the database.
Definition: database.cc:561
void remove_synonym(std::string_view term, std::string_view synonym) const
Remove a synonym for a term.
Definition: database.cc:621
#define UNSIGNED_OVERFLOW_OK(X)
Definition: config.h:635
Constants in the Xapian namespace.
An indexed database of documents.
string term
PositionList * p
Xapian::termpos pos
Querying session.
Hierarchy of classes which Xapian can throw as exceptions.
Matcher class.
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
const valueno BAD_VALUENO
Reserved value to indicate "no valueno".
Definition: types.h:100
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
Various assertion macros.
#define Assert(COND)
Definition: omassert.h:122
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
Xapian::Query API class.
Functions for handling a time or time interval in a double.
#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_UPDATE
@ MSG_POSITIONLISTCOUNT
@ MSG_DELETEDOCUMENT
@ MSG_QUERY
@ MSG_WRITEACCESS
@ MSG_SHUTDOWN
@ 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_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
static void throw_read_only()
Definition: remoteserver.cc:56
void(RemoteServer::* dispatch_func)(string_view)
Xapian remote backend server base class.
Set of documents judged as relevant.
double unserialise_double(const char **p, const char *end)
Unserialise a double serialised by serialise_double.
functions to serialise and unserialise a double
string serialise_error(const Xapian::Error &e)
Serialise a Xapian::Error object to a string.
functions to convert classes to strings and back
string serialise_stats(const Xapian::Weight::Internal &stats)
Serialise a stats object.
Definition: serialise.cc:42
Xapian::Document unserialise_document(string_view s)
Unserialise a serialised Xapian::Document object.
Definition: serialise.cc:223
Xapian::RSet unserialise_rset(const string &s)
Unserialise a serialised Xapian::RSet object.
Definition: serialise.cc:162
void unserialise_stats(const char *p, const char *p_end, Xapian::Weight::Internal &stat)
Unserialise a serialised stats object.
Definition: serialise.cc:92
functions to convert classes to strings and back
Convert types to std::string.
Various handy string-related helpers.
std::string::size_type common_prefix_length(std::string_view a, std::string_view b)
Definition: stringutils.h:128
Class to throw when we receive the connection closing message.
Definition: remoteserver.cc:62
Abstract base class for termlists.
Class for iterating over document values.
Xapian::Weight::Internal class, holding database and term statistics.