LCOV - code coverage report
Current view: top level - backends/remote - remote-database.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 363 396 91.7 %
Date: 2011-08-21 Functions: 47 50 94.0 %
Branches: 72 130 55.4 %

           Branch data     Line data    Source code
       1                 :            : /** @file remote-database.cc
       2                 :            :  *  @brief Remote backend database class
       3                 :            :  */
       4                 :            : /* Copyright (C) 2006,2007,2008,2009,2010 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, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "remote-database.h"
      25                 :            : 
      26                 :            : #include "safeerrno.h"
      27                 :            : #include <signal.h>
      28                 :            : 
      29                 :            : #include "autoptr.h"
      30                 :            : #include "emptypostlist.h"
      31                 :            : #include "inmemory_positionlist.h"
      32                 :            : #include "net_postlist.h"
      33                 :            : #include "net_termlist.h"
      34                 :            : #include "remote-document.h"
      35                 :            : #include "omassert.h"
      36                 :            : #include "realtime.h"
      37                 :            : #include "serialise.h"
      38                 :            : #include "serialise-double.h"
      39                 :            : #include "str.h"
      40                 :            : #include "stringutils.h" // For STRINGIZE().
      41                 :            : #include "weightinternal.h"
      42                 :            : 
      43                 :            : #include <string>
      44                 :            : #include <vector>
      45                 :            : 
      46                 :            : #include "xapian/error.h"
      47                 :            : #include "xapian/matchspy.h"
      48                 :            : 
      49                 :            : using namespace std;
      50                 :            : 
      51                 :       1554 : RemoteDatabase::RemoteDatabase(int fd, double timeout_,
      52                 :            :                                const string & context_, bool writable)
      53                 :            :         : link(fd, fd, context_),
      54                 :            :           context(context_),
      55                 :            :           cached_stats_valid(),
      56                 :            :           mru_valstats(),
      57                 :            :           mru_valno(Xapian::BAD_VALUENO),
      58                 :       1554 :           timeout(timeout_)
      59                 :            : {
      60                 :            : #ifndef __WIN32__
      61                 :            :     // It's simplest to just ignore SIGPIPE.  We'll still know if the
      62                 :            :     // connection dies because we'll get EPIPE back from write().
      63   [ #  #  -  + ]:       1554 :     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
      64                 :          0 :         throw Xapian::NetworkError("Couldn't set SIGPIPE to SIG_IGN", errno);
      65                 :            :     }
      66                 :            : #endif
      67                 :            : 
      68 [ #  # ][ +  + ]:       1554 :     if (!writable) {
      69                 :            :         // Transactions only make sense when writing, so flag them as
      70                 :            :         // "unimplemented" so that our destructor doesn't call dtor_called()
      71                 :            :         // since that might try to call commit() which will cause a message to
      72                 :            :         // be sent to the remote server and probably an InvalidOperationError
      73                 :            :         // exception message to be returned.
      74                 :       1140 :         transaction_state = TRANSACTION_UNIMPLEMENTED;
      75                 :            :     }
      76                 :            : 
      77                 :       1554 :     string message;
      78                 :       1554 :     char type = get_message(message);
      79                 :            : 
      80   [ #  #  #  # ]:       1554 :     if (reply_type(type) != REPLY_GREETING || message.size() < 3) {
           [ #  #  +  - ]
         [ -  + ][ -  + ]
      81 [ #  # ][ #  # ]:          0 :         if (type == 'O' && message.size() == size_t('M') && message[0] == ' ') {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      82                 :            :             // The server reply used to start "OM ", which will now be
      83                 :            :             // interpreted as a type 'O' message of length size_t('M')
      84                 :            :             // with first character ' '.
      85                 :          0 :             throw Xapian::NetworkError("Server protocol version too old", context);
      86                 :            :         }
      87                 :          0 :         throw Xapian::NetworkError("Handshake failed - is this a Xapian server?", context);
      88                 :            :     }
      89                 :            : 
      90                 :       1554 :     const char *p = message.c_str();
      91                 :       1554 :     const char *p_end = p + message.size();
      92                 :            : 
      93                 :            :     // The protocol major versions must match.  The protocol minor version of
      94                 :            :     // the server must be >= that of the client.
      95                 :       1554 :     int protocol_major = static_cast<unsigned char>(*p++);
      96                 :       1554 :     int protocol_minor = static_cast<unsigned char>(*p++);
      97 [ #  #  #  #  + :       1554 :     if (protocol_major != XAPIAN_REMOTE_PROTOCOL_MAJOR_VERSION ||
              - ][ -  + ]
      98                 :            :         protocol_minor < XAPIAN_REMOTE_PROTOCOL_MINOR_VERSION) {
      99                 :          0 :         string errmsg("Unknown protocol version ");
     100                 :          0 :         errmsg += str(protocol_major);
     101                 :          0 :         errmsg += '.';
     102                 :          0 :         errmsg += str(protocol_minor);
     103                 :          0 :         errmsg += " ("STRINGIZE(XAPIAN_REMOTE_PROTOCOL_MAJOR_VERSION)"."STRINGIZE(XAPIAN_REMOTE_PROTOCOL_MINOR_VERSION)" supported)";
     104                 :          0 :         throw Xapian::NetworkError(errmsg, context);
     105                 :            :     }
     106                 :            : 
     107                 :       1554 :     doccount = decode_length(&p, p_end, false);
     108                 :       1554 :     lastdocid = decode_length(&p, p_end, false);
     109                 :       1554 :     doclen_lbound = decode_length(&p, p_end, false);
     110                 :       1554 :     doclen_ubound = decode_length(&p, p_end, false);
     111   [ #  #  -  + ]:       1554 :     if (p == p_end) {
     112                 :          0 :         throw Xapian::NetworkError("Bad greeting message received", context);
     113                 :            :     }
     114                 :       1554 :     has_positional_info = (*p++ == '1');
     115                 :       1554 :     total_length = decode_length(&p, p_end, false);
     116                 :       1554 :     uuid.assign(p, p_end);
     117                 :            : 
     118 [ #  # ][ +  + ]:       1554 :     if (writable) update_stats(MSG_WRITEACCESS);
     119                 :       1554 : }
     120                 :            : 
     121                 :            : RemoteDatabase *
     122                 :       4446 : RemoteDatabase::as_remotedatabase()
     123                 :            : {
     124                 :       4446 :     return this;
     125                 :            : }
     126                 :            : 
     127                 :            : void
     128                 :         60 : RemoteDatabase::keep_alive()
     129                 :            : {
     130                 :         60 :     send_message(MSG_KEEPALIVE, string());
     131                 :         60 :     string message;
     132                 :         60 :     get_message(message, REPLY_DONE);
     133                 :         60 : }
     134                 :            : 
     135                 :            : TermList *
     136                 :         48 : RemoteDatabase::open_metadata_keylist(const std::string &prefix) const
     137                 :            : {
     138                 :            :     // Ensure that total_length and doccount are up-to-date.
     139         [ +  + ]:         48 :     if (!cached_stats_valid) update_stats();
     140                 :            : 
     141                 :         48 :     send_message(MSG_METADATAKEYLIST, prefix);
     142                 :            : 
     143                 :         48 :     string message;
     144                 :            :     AutoPtr<NetworkTermList> tlist(
     145                 :            :         new NetworkTermList(0, doccount,
     146                 :            :                             Xapian::Internal::RefCntPtr<const RemoteDatabase>(this),
     147                 :         48 :                             0));
     148                 :         48 :     vector<NetworkTermListItem> & items = tlist->items;
     149                 :            : 
     150                 :            :     char type;
     151         [ +  + ]:        144 :     while ((type = get_message(message)) == REPLY_METADATAKEYLIST) {
     152                 :         96 :         NetworkTermListItem item;
     153                 :         96 :         item.tname = message;
     154                 :         96 :         items.push_back(item);
     155                 :            :     }
     156         [ -  + ]:         48 :     if (type != REPLY_DONE) {
     157                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     158                 :            :     }
     159                 :            : 
     160                 :         48 :     tlist->current_position = tlist->items.begin();
     161                 :         48 :     return tlist.release();
     162                 :            : }
     163                 :            : 
     164                 :            : TermList *
     165                 :      20382 : RemoteDatabase::open_term_list(Xapian::docid did) const
     166                 :            : {
     167                 :            :     Assert(did);
     168                 :            : 
     169                 :            :     // Ensure that total_length and doccount are up-to-date.
     170         [ +  + ]:      20382 :     if (!cached_stats_valid) update_stats();
     171                 :            : 
     172                 :      20388 :     send_message(MSG_TERMLIST, encode_length(did));
     173                 :            : 
     174                 :      20376 :     string message;
     175                 :      20376 :     get_message(message, REPLY_DOCLENGTH);
     176                 :       2322 :     const char * p = message.c_str();
     177                 :       2322 :     const char * p_end = p + message.size();
     178                 :       2322 :     Xapian::termcount doclen = decode_length(&p, p_end, false);
     179         [ -  + ]:       2322 :     if (p != p_end) {
     180                 :          0 :         throw Xapian::NetworkError("Bad REPLY_DOCLENGTH message received", context);
     181                 :            :     }
     182                 :            : 
     183                 :            :     AutoPtr<NetworkTermList> tlist(
     184                 :            :         new NetworkTermList(doclen, doccount,
     185                 :            :                             Xapian::Internal::RefCntPtr<const RemoteDatabase>(this),
     186                 :       2322 :                             did));
     187                 :       2322 :     vector<NetworkTermListItem> & items = tlist->items;
     188                 :            : 
     189                 :            :     char type;
     190         [ +  + ]:      11418 :     while ((type = get_message(message)) == REPLY_TERMLIST) {
     191                 :       9096 :         NetworkTermListItem item;
     192                 :       9096 :         p = message.data();
     193                 :       9096 :         p_end = p + message.size();
     194                 :       9096 :         item.wdf = decode_length(&p, p_end, false);
     195                 :       9096 :         item.termfreq = decode_length(&p, p_end, false);
     196                 :       9096 :         item.tname.assign(p, p_end);
     197                 :       9096 :         items.push_back(item);
     198                 :            :     }
     199         [ -  + ]:       2322 :     if (type != REPLY_DONE) {
     200                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     201                 :            :     }
     202                 :            : 
     203                 :       2322 :     tlist->current_position = tlist->items.begin();
     204                 :      20376 :     return tlist.release();
     205                 :            : }
     206                 :            : 
     207                 :            : TermList *
     208                 :        282 : RemoteDatabase::open_allterms(const string & prefix) const {
     209                 :            :     // Ensure that total_length and doccount are up-to-date.
     210         [ +  + ]:        282 :     if (!cached_stats_valid) update_stats();
     211                 :            : 
     212                 :        282 :     send_message(MSG_ALLTERMS, prefix);
     213                 :            : 
     214                 :            :     AutoPtr<NetworkTermList> tlist(
     215                 :            :         new NetworkTermList(0, doccount,
     216                 :            :                             Xapian::Internal::RefCntPtr<const RemoteDatabase>(this),
     217                 :        282 :                             0));
     218                 :        282 :     vector<NetworkTermListItem> & items = tlist->items;
     219                 :            : 
     220                 :        282 :     string message;
     221                 :            :     char type;
     222         [ +  + ]:       1110 :     while ((type = get_message(message)) == REPLY_ALLTERMS) {
     223                 :        828 :         NetworkTermListItem item;
     224                 :        828 :         const char * p = message.data();
     225                 :        828 :         const char * p_end = p + message.size();
     226                 :        828 :         item.termfreq = decode_length(&p, p_end, false);
     227                 :        828 :         item.tname.assign(p, p_end);
     228                 :        828 :         items.push_back(item);
     229                 :            :     }
     230         [ -  + ]:        276 :     if (type != REPLY_DONE) {
     231                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     232                 :            :     }
     233                 :            : 
     234                 :        276 :     tlist->current_position = tlist->items.begin();
     235                 :        288 :     return tlist.release();
     236                 :            : }
     237                 :            : 
     238                 :            : LeafPostList *
     239                 :        792 : RemoteDatabase::open_post_list(const string &term) const
     240                 :            : {
     241                 :        816 :     return new NetworkPostList(Xapian::Internal::RefCntPtr<const RemoteDatabase>(this), term);
     242                 :            : }
     243                 :            : 
     244                 :            : Xapian::doccount
     245                 :        792 : RemoteDatabase::read_post_list(const string &term, NetworkPostList & pl) const
     246                 :            : {
     247                 :        792 :     send_message(MSG_POSTLIST, term);
     248                 :            : 
     249                 :        780 :     string message;
     250                 :            :     char type;
     251                 :        780 :     get_message(message, REPLY_POSTLISTSTART);
     252                 :            : 
     253                 :        780 :     const char * p = message.data();
     254                 :        780 :     const char * p_end = p + message.size();
     255                 :        780 :     Xapian::doccount termfreq = decode_length(&p, p_end, false);
     256                 :            : 
     257         [ +  + ]:      20472 :     while ((type = get_message(message)) == REPLY_POSTLISTITEM) {
     258                 :      19692 :         pl.append_posting(message);
     259                 :            :     }
     260         [ -  + ]:        780 :     if (type != REPLY_DONE) {
     261                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     262                 :            :     }
     263                 :            : 
     264                 :        780 :     return termfreq;
     265                 :            : }
     266                 :            : 
     267                 :            : PositionList *
     268                 :       2124 : RemoteDatabase::open_position_list(Xapian::docid did, const string &term) const
     269                 :            : {
     270                 :       2124 :     send_message(MSG_POSITIONLIST, encode_length(did) + term);
     271                 :            : 
     272                 :       2124 :     vector<Xapian::termpos> positions;
     273                 :            : 
     274                 :       2124 :     string message;
     275                 :            :     char type;
     276                 :       2124 :     Xapian::termpos lastpos = static_cast<Xapian::termpos>(-1);
     277         [ +  + ]:      38682 :     while ((type = get_message(message)) == REPLY_POSITIONLIST) {
     278                 :      36558 :         const char * p = message.data();
     279                 :      36558 :         const char * p_end = p + message.size();
     280                 :      36558 :         lastpos += decode_length(&p, p_end, false) + 1;
     281                 :      36558 :         positions.push_back(lastpos);
     282                 :            :     }
     283         [ -  + ]:       2124 :     if (type != REPLY_DONE) {
     284                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     285                 :            :     }
     286                 :            : 
     287                 :       2124 :     return new InMemoryPositionList(positions);
     288                 :            : }
     289                 :            : 
     290                 :            : bool
     291                 :         30 : RemoteDatabase::has_positions() const
     292                 :            : {
     293         [ +  + ]:         30 :     if (!cached_stats_valid) update_stats();
     294                 :         24 :     return has_positional_info;
     295                 :            : }
     296                 :            : 
     297                 :            : void
     298                 :        146 : RemoteDatabase::reopen()
     299                 :            : {
     300                 :        146 :     update_stats(MSG_REOPEN);
     301                 :        134 :     mru_valno = Xapian::BAD_VALUENO;
     302                 :        134 : }
     303                 :            : 
     304                 :            : void
     305                 :         24 : RemoteDatabase::close()
     306                 :            : {
     307                 :         24 :     do_close();
     308                 :         24 : }
     309                 :            : 
     310                 :            : // Currently lazy is used when fetching documents from the MSet, and in three
     311                 :            : // cases in multimatch.cc.  One of the latter is when using a MatchDecider,
     312                 :            : // which we don't support with the remote backend currently.  The others are
     313                 :            : // for the sort key and collapse key which in the remote cases are fetched
     314                 :            : // during the remote match and passed across with the MSet.  So we can safely
     315                 :            : // ignore "lazy" here for now without any performance penalty during the match
     316                 :            : // process.
     317                 :            : Xapian::Document::Internal *
     318                 :     469046 : RemoteDatabase::open_document(Xapian::docid did, bool /*lazy*/) const
     319                 :            : {
     320                 :            :     Assert(did);
     321                 :            : 
     322                 :     469058 :     send_message(MSG_DOCUMENT, encode_length(did));
     323                 :     469034 :     string doc_data;
     324                 :     469034 :     map<Xapian::valueno, string> values;
     325                 :     469034 :     get_message(doc_data, REPLY_DOCDATA);
     326                 :            : 
     327                 :            :     reply_type type;
     328                 :     450950 :     string message;
     329         [ +  + ]:    5304462 :     while ((type = get_message(message)) == REPLY_VALUE) {
     330                 :    4853512 :         const char * p = message.data();
     331                 :    4853512 :         const char * p_end = p + message.size();
     332                 :    4853512 :         Xapian::valueno valueno = decode_length(&p, p_end, false);
     333                 :    4853512 :         values.insert(make_pair(valueno, string(p, p_end)));
     334                 :            :     }
     335         [ -  + ]:     450950 :     if (type != REPLY_DONE) {
     336                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     337                 :            :     }
     338                 :            : 
     339                 :     487118 :     return new RemoteDocument(this, did, doc_data, values);
     340                 :            : }
     341                 :            : 
     342                 :            : void
     343                 :       2204 : RemoteDatabase::update_stats(message_type msg_code) const
     344                 :            : {
     345                 :       2228 :     send_message(msg_code, string());
     346                 :       2180 :     string message;
     347                 :       2180 :     get_message(message, REPLY_UPDATE);
     348                 :       2180 :     const char * p = message.c_str();
     349                 :       2180 :     const char * p_end = p + message.size();
     350                 :       2180 :     doccount = decode_length(&p, p_end, false);
     351                 :       2180 :     lastdocid = decode_length(&p, p_end, false);
     352                 :       2180 :     doclen_lbound = decode_length(&p, p_end, false);
     353                 :       2180 :     doclen_ubound = decode_length(&p, p_end, false);
     354         [ -  + ]:       2180 :     if (p == p_end) {
     355                 :          0 :         throw Xapian::NetworkError("Bad REPLY_UPDATE message received", context);
     356                 :            :     }
     357                 :       2180 :     has_positional_info = (*p++ == '1');
     358                 :       2180 :     total_length = decode_length(&p, p_end, false);
     359                 :       2180 :     uuid.assign(p, p_end);
     360                 :       2180 :     cached_stats_valid = true;
     361                 :       2180 : }
     362                 :            : 
     363                 :            : Xapian::doccount
     364                 :       6532 : RemoteDatabase::get_doccount() const
     365                 :            : {
     366         [ +  + ]:       6532 :     if (!cached_stats_valid) update_stats();
     367                 :       6526 :     return doccount;
     368                 :            : }
     369                 :            : 
     370                 :            : Xapian::docid
     371                 :       2746 : RemoteDatabase::get_lastdocid() const
     372                 :            : {
     373         [ +  + ]:       2746 :     if (!cached_stats_valid) update_stats();
     374                 :       2746 :     return lastdocid;
     375                 :            : }
     376                 :            : 
     377                 :            : totlen_t
     378                 :          0 : RemoteDatabase::get_total_length() const
     379                 :            : {
     380         [ #  # ]:          0 :     if (!cached_stats_valid) update_stats();
     381                 :          0 :     return total_length;
     382                 :            : }
     383                 :            : 
     384                 :            : Xapian::doclength
     385                 :        318 : RemoteDatabase::get_avlength() const
     386                 :            : {
     387         [ -  + ]:        318 :     if (!cached_stats_valid) update_stats();
     388                 :        318 :     return Xapian::doclength(total_length) / doccount;
     389                 :            : }
     390                 :            : 
     391                 :            : bool
     392                 :        396 : RemoteDatabase::term_exists(const string & tname) const
     393                 :            : {
     394                 :            :     Assert(!tname.empty());
     395                 :        396 :     send_message(MSG_TERMEXISTS, tname);
     396                 :        396 :     string message;
     397                 :        396 :     reply_type type = get_message(message);
     398   [ +  +  -  + ]:        396 :     if (type != REPLY_TERMEXISTS && type != REPLY_TERMDOESNTEXIST) {
     399                 :          0 :         throw Xapian::NetworkError("Bad message received", context);
     400                 :            :     }
     401                 :        396 :     return (type == REPLY_TERMEXISTS);
     402                 :            : }
     403                 :            : 
     404                 :            : Xapian::doccount
     405                 :       1740 : RemoteDatabase::get_termfreq(const string & tname) const
     406                 :            : {
     407                 :            :     Assert(!tname.empty());
     408                 :       1740 :     send_message(MSG_TERMFREQ, tname);
     409                 :       1740 :     string message;
     410                 :       1740 :     get_message(message, REPLY_TERMFREQ);
     411                 :       1740 :     const char * p = message.data();
     412                 :       1740 :     const char * p_end = p + message.size();
     413                 :       1740 :     return decode_length(&p, p_end, false);
     414                 :            : }
     415                 :            : 
     416                 :            : Xapian::termcount
     417                 :        570 : RemoteDatabase::get_collection_freq(const string & tname) const
     418                 :            : {
     419                 :            :     Assert(!tname.empty());
     420                 :        570 :     send_message(MSG_COLLFREQ, tname);
     421                 :        570 :     string message;
     422                 :        570 :     get_message(message, REPLY_COLLFREQ);
     423                 :        570 :     const char * p = message.data();
     424                 :        570 :     const char * p_end = p + message.size();
     425                 :        570 :     return decode_length(&p, p_end, false);
     426                 :            : }
     427                 :            : 
     428                 :            : 
     429                 :            : void
     430                 :        718 : RemoteDatabase::read_value_stats(Xapian::valueno valno) const
     431                 :            : {
     432         [ +  + ]:        718 :     if (mru_valno != valno) {
     433                 :        254 :         send_message(MSG_VALUESTATS, encode_length(valno));
     434                 :        254 :         string message;
     435                 :        254 :         get_message(message, REPLY_VALUESTATS);
     436                 :        208 :         const char * p = message.data();
     437                 :        208 :         const char * p_end = p + message.size();
     438                 :        208 :         mru_valno = valno;
     439                 :        208 :         mru_valstats.freq = decode_length(&p, p_end, false);
     440                 :        208 :         size_t len = decode_length(&p, p_end, true);
     441                 :        208 :         mru_valstats.lower_bound.assign(p, len);
     442                 :        208 :         p += len;
     443                 :        208 :         len = decode_length(&p, p_end, true);
     444                 :        208 :         mru_valstats.upper_bound.assign(p, len);
     445                 :        208 :         p += len;
     446         [ -  + ]:        208 :         if (p != p_end) {
     447                 :          0 :             throw Xapian::NetworkError("Bad REPLY_VALUESTATS message received", context);
     448                 :        254 :         }
     449                 :            :     }
     450                 :        672 : }
     451                 :            : 
     452                 :            : Xapian::doccount
     453                 :        274 : RemoteDatabase::get_value_freq(Xapian::valueno valno) const
     454                 :            : {
     455                 :        274 :     read_value_stats(valno);
     456                 :        248 :     return mru_valstats.freq;
     457                 :            : }
     458                 :            : 
     459                 :            : std::string
     460                 :        188 : RemoteDatabase::get_value_lower_bound(Xapian::valueno valno) const
     461                 :            : {
     462                 :        188 :     read_value_stats(valno);
     463                 :        188 :     return mru_valstats.lower_bound;
     464                 :            : }
     465                 :            : 
     466                 :            : std::string
     467                 :        256 : RemoteDatabase::get_value_upper_bound(Xapian::valueno valno) const
     468                 :            : {
     469                 :        256 :     read_value_stats(valno);
     470                 :        236 :     return mru_valstats.upper_bound;
     471                 :            : }
     472                 :            : 
     473                 :            : Xapian::termcount
     474                 :        180 : RemoteDatabase::get_doclength_lower_bound() const
     475                 :            : {
     476                 :        180 :     return doclen_lbound;
     477                 :            : }
     478                 :            : 
     479                 :            : Xapian::termcount
     480                 :        132 : RemoteDatabase::get_doclength_upper_bound() const
     481                 :            : {
     482                 :        132 :     return doclen_ubound;
     483                 :            : }
     484                 :            : 
     485                 :            : Xapian::termcount
     486                 :        372 : RemoteDatabase::get_wdf_upper_bound(const string &) const
     487                 :            : {
     488                 :            :     // The default implementation returns get_collection_freq(), but we
     489                 :            :     // don't want the overhead of a remote message and reply per query
     490                 :            :     // term, and we can get called in the middle of a remote exchange
     491                 :            :     // too.  FIXME: handle this bound in the stats local/remote code...
     492                 :        372 :     return doclen_ubound;
     493                 :            : }
     494                 :            : 
     495                 :            : Xapian::termcount
     496                 :      18726 : RemoteDatabase::get_doclength(Xapian::docid did) const
     497                 :            : {
     498                 :            :     Assert(did != 0);
     499                 :      18738 :     send_message(MSG_DOCLENGTH, encode_length(did));
     500                 :      18714 :     string message;
     501                 :      18714 :     get_message(message, REPLY_DOCLENGTH);
     502                 :        672 :     const char * p = message.c_str();
     503                 :        672 :     const char * p_end = p + message.size();
     504                 :        672 :     Xapian::termcount doclen = decode_length(&p, p_end, false);
     505         [ -  + ]:        672 :     if (p != p_end) {
     506                 :          0 :         throw Xapian::NetworkError("Bad REPLY_DOCLENGTH message received", context);
     507                 :            :     }
     508                 :      18714 :     return doclen;
     509                 :            : }
     510                 :            : 
     511                 :            : reply_type
     512                 :    5999824 : RemoteDatabase::get_message(string &result, reply_type required_type) const
     513                 :            : {
     514                 :    5999824 :     double end_time = RealTime::end_time(timeout);
     515                 :    5999824 :     reply_type type = static_cast<reply_type>(link.get_message(result, end_time));
     516         [ +  + ]:    5999824 :     if (type == REPLY_EXCEPTION) {
     517                 :     163578 :         unserialise_error(result, "REMOTE:", context);
     518                 :            :     }
     519 [ +  + ][ -  + ]:    5945298 :     if (required_type != REPLY_MAX && type != required_type) {
     520                 :          0 :         string errmsg("Expecting reply type ");
     521                 :          0 :         errmsg += str(int(required_type));
     522                 :          0 :         errmsg += ", got ";
     523                 :          0 :         errmsg += str(int(type));
     524                 :          0 :         throw Xapian::NetworkError(errmsg);
     525                 :            :     }
     526                 :            : 
     527                 :    5945298 :     return type;
     528                 :            : }
     529                 :            : 
     530                 :            : void
     531                 :     643116 : RemoteDatabase::send_message(message_type type, const string &message) const
     532                 :            : {
     533                 :     643116 :     double end_time = RealTime::end_time(timeout);
     534                 :     643116 :     link.send_message(static_cast<unsigned char>(type), message, end_time);
     535                 :     643038 : }
     536                 :            : 
     537                 :            : void
     538                 :       1578 : RemoteDatabase::do_close()
     539                 :            : {
     540                 :            :     // In the constructor, we set transaction_state to
     541                 :            :     // TRANSACTION_UNIMPLEMENTED if we aren't writable so that we can check
     542                 :            :     // it here.
     543                 :       1578 :     bool writable = (transaction_state != TRANSACTION_UNIMPLEMENTED);
     544                 :            : 
     545                 :            :     // Only call dtor_called() if we're writable.
     546         [ +  + ]:       1578 :     if (writable) dtor_called();
     547                 :            : 
     548                 :            :     // If we're writable, wait for a confirmation of the close, so we know that
     549                 :            :     // changes have been written and flushed, and the database write lock
     550                 :            :     // released.  For the non-writable case, there's no need to wait, so don't
     551                 :            :     // slow down searching by waiting here.
     552                 :       1578 :     link.do_close(writable);
     553                 :       1578 : }
     554                 :            : 
     555                 :            : void
     556                 :       4422 : RemoteDatabase::set_query(const Xapian::Query::Internal *query,
     557                 :            :                          Xapian::termcount qlen,
     558                 :            :                          Xapian::doccount collapse_max,
     559                 :            :                          Xapian::valueno collapse_key,
     560                 :            :                          Xapian::Enquire::docid_order order,
     561                 :            :                          Xapian::valueno sort_key,
     562                 :            :                          Xapian::Enquire::Internal::sort_setting sort_by,
     563                 :            :                          bool sort_value_forward,
     564                 :            :                          int percent_cutoff, Xapian::weight weight_cutoff,
     565                 :            :                          const Xapian::Weight *wtscheme,
     566                 :            :                          const Xapian::RSet &omrset,
     567                 :            :                          const vector<Xapian::MatchSpy *> & matchspies)
     568                 :            : {
     569                 :       4422 :     string tmp = query->serialise();
     570                 :       4410 :     string message = encode_length(tmp.size());
     571                 :       4410 :     message += tmp;
     572                 :            : 
     573                 :            :     // Serialise assorted Enquire settings.
     574                 :       4410 :     message += encode_length(qlen);
     575                 :       4410 :     message += encode_length(collapse_max);
     576         [ +  + ]:       4410 :     if (collapse_max) message += encode_length(collapse_key);
     577                 :       4410 :     message += char('0' + order);
     578                 :       4410 :     message += encode_length(sort_key);
     579                 :       4410 :     message += char('0' + sort_by);
     580                 :       4410 :     message += char('0' + sort_value_forward);
     581                 :       4410 :     message += char(percent_cutoff);
     582                 :       4410 :     message += serialise_double(weight_cutoff);
     583                 :            : 
     584                 :       4410 :     tmp = wtscheme->name();
     585                 :       4410 :     message += encode_length(tmp.size());
     586                 :       4410 :     message += tmp;
     587                 :            : 
     588                 :       4410 :     tmp = wtscheme->serialise();
     589                 :       4410 :     message += encode_length(tmp.size());
     590                 :       4410 :     message += tmp;
     591                 :            : 
     592                 :       4410 :     tmp = serialise_rset(omrset);
     593                 :       4410 :     message += encode_length(tmp.size());
     594                 :       4410 :     message += tmp;
     595                 :            : 
     596                 :       4410 :     vector<Xapian::MatchSpy *>::const_iterator i;
     597         [ +  + ]:       4476 :     for (i = matchspies.begin(); i != matchspies.end(); ++i) {
     598                 :         66 :         tmp = (*i)->name();
     599         [ -  + ]:         66 :         if (tmp.empty()) {
     600                 :          0 :             throw Xapian::UnimplementedError("MatchSpy not suitable for use with remote searches - name() method returned empty string");
     601                 :            :         }
     602                 :         66 :         message += encode_length(tmp.size());
     603                 :         66 :         message += tmp;
     604                 :            : 
     605                 :         66 :         tmp = (*i)->serialise();
     606                 :         66 :         message += encode_length(tmp.size());
     607                 :         66 :         message += tmp;
     608                 :            :     }
     609                 :            : 
     610                 :       4422 :     send_message(MSG_QUERY, message);
     611                 :       4404 : }
     612                 :            : 
     613                 :            : bool
     614                 :       4407 : RemoteDatabase::get_remote_stats(bool nowait, Xapian::Weight::Internal &out)
     615                 :            : {
     616 [ +  + ][ +  + ]:       4407 :     if (nowait && !link.ready_to_read()) return false;
                 [ +  + ]
     617                 :            : 
     618                 :       4404 :     string message;
     619                 :       4404 :     get_message(message, REPLY_STATS);
     620                 :       4404 :     out = unserialise_stats(message);
     621                 :            : 
     622                 :       4407 :     return true;
     623                 :            : }
     624                 :            : 
     625                 :            : void
     626                 :       4404 : RemoteDatabase::send_global_stats(Xapian::doccount first,
     627                 :            :                                   Xapian::doccount maxitems,
     628                 :            :                                   Xapian::doccount check_at_least,
     629                 :            :                                   const Xapian::Weight::Internal &stats)
     630                 :            : {
     631                 :       4404 :     string message = encode_length(first);
     632                 :       4404 :     message += encode_length(maxitems);
     633                 :       4404 :     message += encode_length(check_at_least);
     634                 :       4404 :     message += serialise_stats(stats);
     635                 :       4404 :     send_message(MSG_GETMSET, message);
     636                 :       4404 : }
     637                 :            : 
     638                 :            : void
     639                 :       4404 : RemoteDatabase::get_mset(Xapian::MSet &mset,
     640                 :            :                          const vector<Xapian::MatchSpy *> & matchspies)
     641                 :            : {
     642                 :       4404 :     string message;
     643                 :       4404 :     get_message(message, REPLY_RESULTS);
     644                 :       4404 :     const char * p = message.data();
     645                 :       4404 :     const char * p_end = p + message.size();
     646                 :            : 
     647                 :       4404 :     vector<Xapian::MatchSpy *>::const_iterator i;
     648         [ +  + ]:       4470 :     for (i = matchspies.begin(); i != matchspies.end(); ++i) {
     649         [ -  + ]:         66 :         if (p == p_end)
     650                 :          0 :             throw Xapian::NetworkError("Expected serialised matchspy");
     651                 :         66 :         size_t len = decode_length(&p, p_end, true);
     652                 :         66 :         string spyresults(p, len);
     653                 :         66 :         p += len;
     654                 :         66 :         (*i)->merge_results(spyresults);
     655                 :            :     }
     656                 :       4404 :     mset = unserialise_mset(p, p_end);
     657                 :       4404 : }
     658                 :            : 
     659                 :            : void
     660                 :        978 : RemoteDatabase::commit()
     661                 :            : {
     662                 :        984 :     send_message(MSG_COMMIT, string());
     663                 :            : 
     664                 :            :     // We need to wait for a response to ensure documents have been committed.
     665                 :        972 :     string message;
     666                 :        984 :     get_message(message, REPLY_DONE);
     667                 :        960 : }
     668                 :            : 
     669                 :            : void
     670                 :         28 : RemoteDatabase::cancel()
     671                 :            : {
     672                 :         28 :     cached_stats_valid = false;
     673                 :         28 :     mru_valno = Xapian::BAD_VALUENO;
     674                 :            : 
     675                 :         28 :     send_message(MSG_CANCEL, string());
     676                 :         28 : }
     677                 :            : 
     678                 :            : Xapian::docid
     679                 :      79698 : RemoteDatabase::add_document(const Xapian::Document & doc)
     680                 :            : {
     681                 :      79698 :     cached_stats_valid = false;
     682                 :      79698 :     mru_valno = Xapian::BAD_VALUENO;
     683                 :            : 
     684                 :      79698 :     send_message(MSG_ADDDOCUMENT, serialise_document(doc));
     685                 :            : 
     686                 :      79698 :     string message;
     687                 :      79698 :     get_message(message, REPLY_ADDDOCUMENT);
     688                 :            : 
     689                 :      79422 :     const char * p = message.data();
     690                 :      79422 :     const char * p_end = p + message.size();
     691                 :      79698 :     return decode_length(&p, p_end, false);
     692                 :            : }
     693                 :            : 
     694                 :            : void
     695                 :      18148 : RemoteDatabase::delete_document(Xapian::docid did)
     696                 :            : {
     697                 :      18148 :     cached_stats_valid = false;
     698                 :      18148 :     mru_valno = Xapian::BAD_VALUENO;
     699                 :            : 
     700                 :      18148 :     send_message(MSG_DELETEDOCUMENT, encode_length(did));
     701                 :      18148 :     string dummy;
     702                 :      18154 :     get_message(dummy, REPLY_DONE);
     703                 :      18142 : }
     704                 :            : 
     705                 :            : void
     706                 :         18 : RemoteDatabase::delete_document(const std::string & unique_term)
     707                 :            : {
     708                 :         18 :     cached_stats_valid = false;
     709                 :         18 :     mru_valno = Xapian::BAD_VALUENO;
     710                 :            : 
     711                 :         18 :     send_message(MSG_DELETEDOCUMENTTERM, unique_term);
     712                 :         18 : }
     713                 :            : 
     714                 :            : void
     715                 :      18364 : RemoteDatabase::replace_document(Xapian::docid did,
     716                 :            :                                  const Xapian::Document & doc)
     717                 :            : {
     718                 :      18364 :     cached_stats_valid = false;
     719                 :      18364 :     mru_valno = Xapian::BAD_VALUENO;
     720                 :            : 
     721                 :      18364 :     string message = encode_length(did);
     722                 :      18364 :     message += serialise_document(doc);
     723                 :            : 
     724                 :      18364 :     send_message(MSG_REPLACEDOCUMENT, message);
     725                 :      18364 : }
     726                 :            : 
     727                 :            : Xapian::docid
     728                 :        114 : RemoteDatabase::replace_document(const std::string & unique_term,
     729                 :            :                                  const Xapian::Document & doc)
     730                 :            : {
     731                 :        114 :     cached_stats_valid = false;
     732                 :        114 :     mru_valno = Xapian::BAD_VALUENO;
     733                 :            : 
     734                 :        114 :     string message = encode_length(unique_term.size());
     735                 :        114 :     message += unique_term;
     736                 :        114 :     message += serialise_document(doc);
     737                 :            : 
     738                 :        114 :     send_message(MSG_REPLACEDOCUMENTTERM, message);
     739                 :            : 
     740                 :        114 :     get_message(message, REPLY_ADDDOCUMENT);
     741                 :            : 
     742                 :        114 :     const char * p = message.data();
     743                 :        114 :     const char * p_end = p + message.size();
     744                 :        114 :     return decode_length(&p, p_end, false);
     745                 :            : }
     746                 :            : 
     747                 :            : string
     748                 :         36 : RemoteDatabase::get_uuid() const
     749                 :            : {
     750                 :         36 :     return uuid;
     751                 :            : }
     752                 :            : 
     753                 :            : string
     754                 :        138 : RemoteDatabase::get_metadata(const string & key) const
     755                 :            : {
     756                 :        138 :     send_message(MSG_GETMETADATA, key);
     757                 :        138 :     string metadata;
     758                 :        138 :     get_message(metadata, REPLY_METADATA);
     759                 :          0 :     return metadata;
     760                 :            : }
     761                 :            : 
     762                 :            : void
     763                 :        114 : RemoteDatabase::set_metadata(const string & key, const string & value)
     764                 :            : {
     765                 :        114 :     string data = encode_length(key.size());
     766                 :        114 :     data += key;
     767                 :        114 :     data += value;
     768                 :        114 :     send_message(MSG_SETMETADATA, data);
     769                 :        114 : }
     770                 :            : 
     771                 :            : void
     772                 :         30 : RemoteDatabase::add_spelling(const string & word,
     773                 :            :                              Xapian::termcount freqinc) const
     774                 :            : {
     775                 :         30 :     string data = encode_length(freqinc);
     776                 :         30 :     data += word;
     777                 :         30 :     send_message(MSG_ADDSPELLING, data);
     778                 :         30 : }
     779                 :            : 
     780                 :            : void
     781                 :         48 : RemoteDatabase::remove_spelling(const string & word,
     782                 :            :                                 Xapian::termcount freqdec) const
     783                 :            : {
     784                 :         48 :     string data = encode_length(freqdec);
     785                 :         48 :     data += word;
     786                 :         48 :     send_message(MSG_REMOVESPELLING, data);
     787                 :         48 : }

Generated by: LCOV version 1.8