Ticket #711: remote_protocol_msg_readaccess_select.diff

File remote_protocol_msg_readaccess_select.diff, 26.2 KB (added by German M. Bravo, 9 years ago)
  • xapian-core/backends/dbfactory_remote.cc

    commit 6fe691aabd7133073585197112ee3ac8fdbaa905
    Author: German M. Bravo <german.mb@deipi.com>
    Date:   Wed Apr 1 09:39:06 2015 -0600
    
        Remote protocol with support for selection of database directory.
        
        If the user requests to open a remote database server, it can
        optionally require the remote backend to tell the server what database
        it wants to open, if the remote server is configured as a server
        without a default directory (xapian-tcpsrv remains to always have a
        default directory at the moment).
        
        The binary protocol was changed in the way that a new command can be
        sent to the server (MSG_READACCESS) in case the server tells the
        client no default directory is selected, the server then reacts to
        this command by opening and selecting the requested database as the
        active database.
    
    diff --git a/xapian-core/backends/dbfactory_remote.cc b/xapian-core/backends/dbfactory_remote.cc
    index 5eaab61..6747d8a 100644
    a b namespace Xapian {  
    3333
    3434Database
    3535Remote::open(const string &host, unsigned int port, useconds_t timeout_,
    36              useconds_t connect_timeout)
     36             useconds_t connect_timeout, int flags, const string &dir)
    3737{
    38     LOGCALL_STATIC(API, Database, "Remote::open", host | port | timeout_ | connect_timeout);
     38    LOGCALL_STATIC(API, Database, "Remote::open", host | port | timeout_ | connect_timeout | flags | dir);
    3939    RETURN(Database(new RemoteTcpClient(host, port, timeout_ * 1e-3,
    40                                         connect_timeout * 1e-3, false, 0)));
     40                                        connect_timeout * 1e-3, false, flags, dir)));
    4141}
    4242
    4343WritableDatabase
    4444Remote::open_writable(const string &host, unsigned int port,
    4545                      useconds_t timeout_, useconds_t connect_timeout,
    46                       int flags)
     46                      int flags, const string &dir)
    4747{
    48     LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", host | port | timeout_ | connect_timeout | flags);
     48    LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", host | port | timeout_ | connect_timeout | flags | dir);
    4949    RETURN(WritableDatabase(new RemoteTcpClient(host, port, timeout_ * 1e-3,
    5050                                                connect_timeout * 1e-3, true,
    51                                                 flags)));
     51                                                flags, dir)));
    5252}
    5353
    5454Database
    5555Remote::open(const string &program, const string &args,
    56              useconds_t timeout_)
     56             useconds_t timeout_, int flags, const string &dir)
    5757{
    58     LOGCALL_STATIC(API, Database, "Remote::open", program | args | timeout_);
    59     RETURN(Database(new ProgClient(program, args, timeout_ * 1e-3, false, 0)));
     58    LOGCALL_STATIC(API, Database, "Remote::open", program | args | timeout_ | flags | dir);
     59    RETURN(Database(new ProgClient(program, args, timeout_ * 1e-3, false, flags, dir)));
    6060}
    6161
    6262WritableDatabase
    6363Remote::open_writable(const string &program, const string &args,
    64                       useconds_t timeout_, int flags)
     64                      useconds_t timeout_, int flags, const string &dir)
    6565{
    66     LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", program | args | timeout_ | flags);
     66    LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", program | args | timeout_ | flags | dir);
    6767    RETURN(WritableDatabase(new ProgClient(program, args,
    68                                            timeout_ * 1e-3, true, flags)));
     68                                           timeout_ * 1e-3, true, flags, dir)));
    6969}
    7070
    7171}
  • xapian-core/backends/remote/remote-database.cc

    diff --git a/xapian-core/backends/remote/remote-database.cc b/xapian-core/backends/remote/remote-database.cc
    index 37609c1..89911f4 100644
    a b throw_connection_closed_unexpectedly()  
    6868}
    6969
    7070RemoteDatabase::RemoteDatabase(int fd, double timeout_,
    71                                const string & context_, bool writable,
    72                                int flags)
    73         : link(fd, fd, context_),
     71                               const string & context_, bool writable_,
     72                               int flags_, const string & dir)
     73        : db_dir(dir),
     74          writable(writable_),
     75          flags(flags_),
     76          link(fd, fd, context_),
    7477          context(context_),
    7578          cached_stats_valid(),
    7679          mru_valstats(),
    RemoteDatabase::RemoteDatabase(int fd, double timeout_,  
    9598    }
    9699
    97100    update_stats(MSG_MAX);
    98 
    99     if (writable) {
    100         if (flags & Xapian::DB_RETRY_LOCK) {
    101             const string & body = encode_length(flags & Xapian::DB_RETRY_LOCK);
    102             update_stats(MSG_WRITEACCESS, body);
    103         } else {
    104             update_stats(MSG_WRITEACCESS);
    105         }
    106     }
    107101}
    108102
    109103void
    RemoteDatabase::update_stats(message_type msg_code, const string & body) const  
    339333
    340334    string message;
    341335    reply_type type = get_message(message);
    342     if (type != REPLY_UPDATE || message.size() < 3) {
     336    if (type != REPLY_UPDATE || message.size() < 2) {
    343337        if (type == REPLY_DONE) {
    344338            // The database was already open at the latest revision.
    345339            return false;
    RemoteDatabase::update_stats(message_type msg_code, const string & body) const  
    373367        throw Xapian::NetworkError(errmsg, context);
    374368    }
    375369
     370    if (p == p_end) {
     371        message = encode_length(flags);
     372        message += encode_length(db_dir.size());
     373        message += db_dir;
     374
     375        if (writable) {
     376            send_message(MSG_WRITEACCESS, message);
     377        } else {
     378            send_message(MSG_READACCESS, message);
     379        }
     380
     381        get_message(message, REPLY_UPDATE);
     382        if (message.size() < 3) {
     383            throw Xapian::NetworkError("Database was not selected", context);
     384        }
     385
     386        p = message.c_str();
     387        p_end = p + message.size();
     388
     389        // The protocol versions where already checked.
     390        p += 2;
     391    } else if (writable) {
     392        if (flags) {
     393            send_message(MSG_WRITEACCESS, encode_length(flags));
     394        } else {
     395            send_message(MSG_WRITEACCESS, string());
     396        }
     397
     398        get_message(message, REPLY_UPDATE);
     399        if (message.size() < 3) {
     400            throw Xapian::NetworkError("Database was not selected", context);
     401        }
     402
     403        p = message.c_str();
     404        p_end = p + message.size();
     405
     406        // The protocol versions where already checked.
     407        p += 2;
     408    }
     409
    376410    decode_length(&p, p_end, doccount);
    377411    decode_length(&p, p_end, lastdocid);
    378412    lastdocid += doccount;
    RemoteDatabase::do_close()  
    597631    // In the constructor, we set transaction_state to
    598632    // TRANSACTION_UNIMPLEMENTED if we aren't writable so that we can check
    599633    // it here.
    600     bool writable = (transaction_state != TRANSACTION_UNIMPLEMENTED);
     634    bool writable_ = (transaction_state != TRANSACTION_UNIMPLEMENTED);
    601635
    602636    // Only call dtor_called() if we're writable.
    603     if (writable) dtor_called();
     637    if (writable_) dtor_called();
    604638
    605639    // If we're writable, wait for a confirmation of the close, so we know that
    606640    // changes have been written and flushed, and the database write lock
    607641    // released.  For the non-writable case, there's no need to wait, so don't
    608642    // slow down searching by waiting here.
    609     link.do_close(writable);
     643    link.do_close(writable_);
    610644}
    611645
    612646void
  • xapian-core/backends/remote/remote-database.h

    diff --git a/xapian-core/backends/remote/remote-database.h b/xapian-core/backends/remote/remote-database.h
    index b275c52..e593eec 100644
    a b class RemoteDatabase : public Xapian::Database::Internal {  
    4949    /// Don't allow copying.
    5050    RemoteDatabase(const RemoteDatabase &);
    5151
     52    // Directory to store databases in.
     53    const std::string db_dir;
     54
     55    // The database is writable.
     56    const bool writable;
     57
     58    // Bitwise-or of Xapian::DB_* flags.
     59    const int flags;
     60
    5261    /// The object which does the I/O.
    5362    mutable RemoteConnection link;
    5463
    class RemoteDatabase : public Xapian::Database::Internal {  
    103112     *                  operations will never timeout.
    104113     *  @param context_ The context to return with any error messages.
    105114     *  @param writable Is this a WritableDatabase?
    106      *  @param flags    Xapian::DB_RETRY_LOCK or 0.
     115     *  @param flags    Bitwise-or of Xapian::DB_* constants.
     116     *  @param dir      Database directory index to open.
    107117     */
    108118    RemoteDatabase(int fd, double timeout_, const string & context_,
    109                    bool writable, int flags);
     119                   bool writable, int flags, const string & dir);
    110120
    111121    /// Receive a message from the server.
    112122    reply_type get_message(string & message, reply_type required_type = REPLY_MAX) const;
  • xapian-core/bin/xapian-tcpsrv.cc

    diff --git a/xapian-core/bin/xapian-tcpsrv.cc b/xapian-core/bin/xapian-tcpsrv.cc
    index 25743da..f7f23a4 100644
    a b static const struct option long_opts[] = {  
    7272};
    7373
    7474static void show_usage() {
    75     cout << "Usage: " PROG_NAME " [OPTIONS] DATABASE_DIRECTORY...\n\n"
     75    cout << "Usage: " PROG_NAME " [OPTIONS] [DATABASE_DIRECTORY] ...\n\n"
    7676"Options:\n"
    7777"  --port PORTNUM          listen on port PORTNUM for connections (no default)\n"
    7878"  --interface ADDRESS     listen on the interface associated with name or\n"
    int main(int argc, char **argv) {  
    143143        }
    144144    }
    145145
    146     if (syntax_error || argv[optind] == NULL) {
     146    if (syntax_error) {
    147147        show_usage();
    148148        exit(1);
    149149    }
  • xapian-core/common/remoteprotocol.h

    diff --git a/xapian-core/common/remoteprotocol.h b/xapian-core/common/remoteprotocol.h
    index fcaa1ec..03adba7 100644
    a b enum message_type {  
    8989    MSG_METADATAKEYLIST,        // Iterator for metadata keys
    9090    MSG_FREQS,                  // Get termfreq and collfreq
    9191    MSG_UNIQUETERMS,            // Get number of unique terms in doc
     92    MSG_READACCESS,             // Select currenty active read access database
    9293    MSG_MAX
    9394};
    9495
  • xapian-core/include/xapian/dbfactory.h

    diff --git a/xapian-core/include/xapian/dbfactory.h b/xapian-core/include/xapian/dbfactory.h
    index 3e29786..1fd1489 100644
    a b namespace Remote {  
    171171 *                              Xapian::NetworkTimeoutError is thrown.  A
    172172 *                              timeout of 0 means don't timeout.  (Default is
    173173 *                              10000ms, which is 10 seconds).
    174  */
     174 * @param flags         bitwise-or of Xapian::DB_* constants.
     175 * @param dir           database directory index to open.
     176*/
    175177XAPIAN_VISIBILITY_DEFAULT
    176 Database open(const std::string &host, unsigned int port, useconds_t timeout = 10000, useconds_t connect_timeout = 10000);
     178Database open(const std::string &host, unsigned int port, useconds_t timeout = 10000, useconds_t connect_timeout = 10000, int flags = 0, const std::string &dir = std::string());
    177179
    178180/** Construct a WritableDatabase object for update access to a remote database
    179181 *  accessed via a TCP connection.
    Database open(const std::string &host, unsigned int port, useconds_t timeout = 1  
    192194 *                              Xapian::NetworkTimeoutError is thrown.  A
    193195 *                              timeout of 0 means don't timeout.  (Default is
    194196 *                              10000ms, which is 10 seconds).
     197 * @param flags         bitwise-or of Xapian::DB_* constants.
     198 * @param dir           database directory index to open.
    195199 */
    196200XAPIAN_VISIBILITY_DEFAULT
    197 WritableDatabase open_writable(const std::string &host, unsigned int port, useconds_t timeout = 0, useconds_t connect_timeout = 10000, int flags = 0);
     201WritableDatabase open_writable(const std::string &host, unsigned int port, useconds_t timeout = 0, useconds_t connect_timeout = 10000, int flags = 0, const std::string &dir = std::string());
    198202
    199203/** Construct a Database object for read-only access to a remote database
    200204 *  accessed via a program.
    WritableDatabase open_writable(const std::string &host, unsigned int port, useco  
    209213 *                      then Xapian::NetworkTimeoutError is thrown.  A timeout
    210214 *                      of 0 means don't timeout.  (Default is 10000ms, which
    211215 *                      is 10 seconds).
    212  * @param flags         Xapian::DB_RETRY_LOCK or 0.
     216 * @param flags         bitwise-or of Xapian::DB_* constants.
     217 * @param dir           database directory index to open.
    213218 */
    214219XAPIAN_VISIBILITY_DEFAULT
    215 Database open(const std::string &program, const std::string &args, useconds_t timeout = 10000);
     220Database open(const std::string &program, const std::string &args, useconds_t timeout = 10000, int flags = 0, const std::string &dir = std::string());
    216221
    217222/** Construct a WritableDatabase object for update access to a remote database
    218223 *  accessed via a program.
    Database open(const std::string &program, const std::string &args, useconds_t ti  
    226231 *                      for any individual operation on the remote database
    227232 *                      then Xapian::NetworkTimeoutError is thrown.  (Default
    228233 *                      is 0, which means don't timeout).
    229  * @param flags         Xapian::DB_RETRY_LOCK or 0.
     234 * @param flags         bitwise-or of Xapian::DB_* constants.
     235 * @param dir           database directory index to open.
    230236 */
    231237XAPIAN_VISIBILITY_DEFAULT
    232 WritableDatabase open_writable(const std::string &program, const std::string &args, useconds_t timeout = 0, int flags = 0);
     238WritableDatabase open_writable(const std::string &program, const std::string &args, useconds_t timeout = 0, int flags = 0, const std::string &dir = std::string());
    233239
    234240}
    235241#endif
  • xapian-core/net/progclient.cc

    diff --git a/xapian-core/net/progclient.cc b/xapian-core/net/progclient.cc
    index bf10cf2..b928e2d 100644
    a b split_words(const string &text, vector<string> &words, char ws = ' ')  
    6464#endif
    6565
    6666ProgClient::ProgClient(const string &progname, const string &args,
    67                        double timeout_, bool writable, int flags)
     67                       double timeout_, bool writable, int flags, const string & dir)
    6868        : RemoteDatabase(run_program(progname, args
    6969#ifndef __WIN32__
    7070                                                   , pid
    7171#endif
    7272        ),
    7373                         timeout_, get_progcontext(progname, args), writable,
    74                          flags)
     74                         flags, dir)
    7575{
    76     LOGCALL_CTOR(DB, "ProgClient", progname | args | timeout_ | writable | flags);
     76    LOGCALL_CTOR(DB, "ProgClient", progname | args | timeout_ | writable | flags | dir);
    7777}
    7878
    7979string
  • xapian-core/net/progclient.h

    diff --git a/xapian-core/net/progclient.h b/xapian-core/net/progclient.h
    index 5567e55..9ebcde9 100644
    a b class ProgClient : public RemoteDatabase {  
    8888               const std::string &arg,
    8989               double msecs_timeout,
    9090               bool writable,
    91                int flags);
     91               int flags,
     92               const std::string & dir);
    9293
    9394    /** Destructor. */
    9495    ~ProgClient();
  • xapian-core/net/remoteserver.cc

    diff --git a/xapian-core/net/remoteserver.cc b/xapian-core/net/remoteserver.cc
    index 9b467b1..b8ad018 100644
    a b throw_read_only()  
    5454    throw Xapian::InvalidOperationError("Server is read-only");
    5555}
    5656
     57XAPIAN_NORETURN(static void throw_no_db());
     58static void
     59throw_no_db()
     60{
     61    throw Xapian::InvalidOperationError("Server has no open database");
     62}
     63
    5764/// Class to throw when we receive the connection closing message.
    5865struct ConnectionClosed { };
    5966
    60 RemoteServer::RemoteServer(const std::vector<std::string> &dbpaths,
     67RemoteServer::RemoteServer(const std::vector<std::string> &dbpaths_,
    6168                           int fdin_, int fdout_,
    6269                           double active_timeout_, double idle_timeout_,
    6370                           bool writable_)
    RemoteServer::RemoteServer(const std::vector<std::string> &dbpaths,  
    6774{
    6875    // Catch errors opening the database and propagate them to the client.
    6976    try {
    70         Assert(!dbpaths.empty());
    71         // We always open the database read-only to start with.  If we're
    72         // writable, the client can ask to be upgraded to write access once
    73         // connected if it wants it.
    74         db = new Xapian::Database(dbpaths[0]);
    75         // Build a better description than Database::get_description() gives
    76         // in the variable context.  FIXME: improve Database::get_description()
    77         // and then just use that instead.
    78         context = dbpaths[0];
    79 
    80         if (!writable) {
    81             vector<std::string>::const_iterator i(dbpaths.begin());
    82             for (++i; i != dbpaths.end(); ++i) {
    83                 db->add_database(Xapian::Database(*i));
    84                 context += ' ';
    85                 context += *i;
    86             }
    87         } else {
    88             AssertEq(dbpaths.size(), 1); // Expecting exactly one database.
     77        if (!dbpaths_.empty()) {
     78            // We always open the database read-only to start with.  If we're
     79            // writable, the client can ask to be upgraded to write access once
     80            // connected if it wants it.
     81            select_db(dbpaths_, false, Xapian::DB_OPEN);
    8982        }
    9083    } catch (const Xapian::Error &err) {
    9184        // Propagate the exception to the client.
    RemoteServer::run()  
    192185                &RemoteServer::msg_openmetadatakeylist,
    193186                &RemoteServer::msg_freqs,
    194187                &RemoteServer::msg_uniqueterms,
     188                &RemoteServer::msg_readaccess,
    195189            };
    196190
    197191            string message;
    RemoteServer::run()  
    239233void
    240234RemoteServer::msg_allterms(const string &message)
    241235{
     236    if (!db)
     237        throw_no_db();
     238
    242239    string prev = message;
    243240    string reply;
    244241
    RemoteServer::msg_allterms(const string &message)  
    262259void
    263260RemoteServer::msg_termlist(const string &message)
    264261{
     262    if (!db)
     263        throw_no_db();
     264
    265265    const char *p = message.data();
    266266    const char *p_end = p + message.size();
    267267    Xapian::docid did;
    RemoteServer::msg_termlist(const string &message)  
    289289void
    290290RemoteServer::msg_positionlist(const string &message)
    291291{
     292    if (!db)
     293        throw_no_db();
     294
    292295    const char *p = message.data();
    293296    const char *p_end = p + message.size();
    294297    Xapian::docid did;
    RemoteServer::msg_positionlist(const string &message)  
    310313void
    311314RemoteServer::msg_postlist(const string &message)
    312315{
     316    if (!db)
     317        throw_no_db();
     318
    313319    const string & term = message;
    314320
    315321    Xapian::doccount termfreq = db->get_termfreq(term);
    RemoteServer::msg_postlist(const string &message)  
    333339}
    334340
    335341void
    336 RemoteServer::msg_writeaccess(const string & msg)
     342RemoteServer::msg_readaccess(const string &message)
    337343{
    338     if (!writable)
     344    int flags = Xapian::DB_OPEN;
     345    const char *p = message.c_str();
     346    const char *p_end = p + message.size();
     347    if (p != p_end) {
     348        unsigned flag_bits;
     349        decode_length(&p, p_end, flag_bits);
     350        flags |= flag_bits &~ Xapian::DB_ACTION_MASK_;
     351    }
     352
     353    if (p != p_end) {
     354        std::vector<string> dbpaths_;
     355        while (p != p_end) {
     356            size_t len;
     357            decode_length_and_check(&p, p_end, len);
     358            string dbpath(p, len);
     359            dbpaths_.push_back(dbpath);
     360            p += len;
     361        }
     362        select_db(dbpaths_, false, flags);
     363    } else {
     364        select_db(dbpaths, false, flags);
     365    }
     366
     367    msg_update(message);
     368}
     369
     370
     371void
     372RemoteServer::msg_writeaccess(const string & message)
     373{
     374    if (!writable)
    339375        throw_read_only();
    340376
    341377    int flags = Xapian::DB_OPEN;
    342     const char *p = msg.c_str();
    343     const char *p_end = p + msg.size();
     378    const char *p = message.c_str();
     379    const char *p_end = p + message.size();
    344380    if (p != p_end) {
    345381        unsigned flag_bits;
    346382        decode_length(&p, p_end, flag_bits);
    347383        flags |= flag_bits &~ Xapian::DB_ACTION_MASK_;
     384    }
     385
     386    if (p != p_end) {
     387        std::vector<string> dbpaths_;
     388        size_t len;
     389        decode_length_and_check(&p, p_end, len);
     390        string dbpath(p, len);
     391        dbpaths_.push_back(dbpath);
     392        p += len;
    348393        if (p != p_end) {
    349             throw Xapian::NetworkError("Junk at end of MSG_WRITEACCESS");
     394            throw Xapian::NetworkError("only one database directory allowed on writable databases");
    350395        }
     396        select_db(dbpaths_, true, flags);
     397    } else {
     398        select_db(dbpaths, true, flags);
    351399    }
    352400
    353     wdb = new Xapian::WritableDatabase(context, flags);
    354     delete db;
    355     db = wdb;
    356     msg_update(msg);
     401    msg_update(message);
    357402}
    358403
    359404void
    360405RemoteServer::msg_reopen(const string & msg)
    361406{
     407    if (!db)
     408        throw_no_db();
     409
    362410    if (!db->reopen()) {
    363411        send_message(REPLY_DONE, string());
    364412        return;
    RemoteServer::msg_update(const string &)  
    373421        char(XAPIAN_REMOTE_PROTOCOL_MAJOR_VERSION),
    374422        char(XAPIAN_REMOTE_PROTOCOL_MINOR_VERSION)
    375423    };
     424
    376425    string message(protocol, 2);
    377     Xapian::doccount num_docs = db->get_doccount();
    378     message += encode_length(num_docs);
    379     message += encode_length(db->get_lastdocid() - num_docs);
    380     Xapian::termcount doclen_lb = db->get_doclength_lower_bound();
    381     message += encode_length(doclen_lb);
    382     message += encode_length(db->get_doclength_upper_bound() - doclen_lb);
    383     message += (db->has_positions() ? '1' : '0');
    384     // FIXME: clumsy to reverse calculate total_len like this:
    385     totlen_t total_len = totlen_t(db->get_avlength() * db->get_doccount() + .5);
    386     message += encode_length(total_len);
    387     //message += encode_length(db->get_total_length());
    388     string uuid = db->get_uuid();
    389     message += uuid;
     426
     427    if (db) {
     428        Xapian::doccount num_docs = db->get_doccount();
     429        message += encode_length(num_docs);
     430        message += encode_length(db->get_lastdocid() - num_docs);
     431        Xapian::termcount doclen_lb = db->get_doclength_lower_bound();
     432        message += encode_length(doclen_lb);
     433        message += encode_length(db->get_doclength_upper_bound() - doclen_lb);
     434        message += (db->has_positions() ? '1' : '0');
     435        // FIXME: clumsy to reverse calculate total_len like this:
     436        totlen_t total_len = totlen_t(db->get_avlength() * db->get_doccount() + .5);
     437        message += encode_length(total_len);
     438        //message += encode_length(db->get_total_length());
     439        string uuid = db->get_uuid();
     440        message += uuid;
     441    }
     442
    390443    send_message(REPLY_UPDATE, message);
    391444}
    392445
    RemoteServer::msg_query(const string &message_in)  
    485538        p += len;
    486539    }
    487540
     541    if (!db)
     542        throw_no_db();
     543
    488544    Xapian::Weight::Internal local_stats;
    489545    MultiMatch match(*db, query, qlen, &rset, collapse_max, collapse_key,
    490546                     percent_cutoff, weight_cutoff, order,
    RemoteServer::msg_query(const string &message_in)  
    528584void
    529585RemoteServer::msg_document(const string &message)
    530586{
     587    if (!db)
     588        throw_no_db();
     589
    531590    const char *p = message.data();
    532591    const char *p_end = p + message.size();
    533592    Xapian::docid did;
    RemoteServer::msg_document(const string &message)  
    549608void
    550609RemoteServer::msg_keepalive(const string &)
    551610{
     611    if (!db)
     612        throw_no_db();
     613
    552614    // Ensure *our* database stays alive, as it may contain remote databases!
    553615    db->keep_alive();
    554616    send_message(REPLY_DONE, string());
    RemoteServer::msg_keepalive(const string &)  
    557619void
    558620RemoteServer::msg_termexists(const string &term)
    559621{
     622    if (!db)
     623        throw_no_db();
     624
    560625    send_message((db->term_exists(term) ? REPLY_TERMEXISTS : REPLY_TERMDOESNTEXIST), string());
    561626}
    562627
    563628void
    564629RemoteServer::msg_collfreq(const string &term)
    565630{
     631    if (!db)
     632        throw_no_db();
     633
    566634    send_message(REPLY_COLLFREQ, encode_length(db->get_collection_freq(term)));
    567635}
    568636
    569637void
    570638RemoteServer::msg_termfreq(const string &term)
    571639{
     640    if (!db)
     641        throw_no_db();
     642
    572643    send_message(REPLY_TERMFREQ, encode_length(db->get_termfreq(term)));
    573644}
    574645
    575646void
    576647RemoteServer::msg_freqs(const string &term)
    577648{
     649    if (!db)
     650        throw_no_db();
     651
    578652    string msg = encode_length(db->get_termfreq(term));
    579653    msg += encode_length(db->get_collection_freq(term));
    580654    send_message(REPLY_FREQS, msg);
    RemoteServer::msg_freqs(const string &term)  
    583657void
    584658RemoteServer::msg_valuestats(const string & message)
    585659{
     660    if (!db)
     661        throw_no_db();
     662
    586663    const char *p = message.data();
    587664    const char *p_end = p + message.size();
    588665    while (p != p_end) {
    RemoteServer::msg_valuestats(const string & message)  
    604681void
    605682RemoteServer::msg_doclength(const string &message)
    606683{
     684    if (!db)
     685        throw_no_db();
     686
    607687    const char *p = message.data();
    608688    const char *p_end = p + message.size();
    609689    Xapian::docid did;
    RemoteServer::msg_doclength(const string &message)  
    614694void
    615695RemoteServer::msg_uniqueterms(const string &message)
    616696{
     697    if (!db)
     698        throw_no_db();
     699
    617700    const char *p = message.data();
    618701    const char *p_end = p + message.size();
    619702    Xapian::docid did;
    RemoteServer::msg_replacedocumentterm(const string & message)  
    715798void
    716799RemoteServer::msg_getmetadata(const string & message)
    717800{
     801    if (!db)
     802        throw_no_db();
     803
    718804    send_message(REPLY_METADATA, db->get_metadata(message));
    719805}
    720806
    721807void
    722808RemoteServer::msg_openmetadatakeylist(const string & message)
    723809{
     810    if (!db)
     811        throw_no_db();
     812
    724813    string prev = message;
    725814    string reply;
    726815
    RemoteServer::msg_removespelling(const string & message)  
    778867    decode_length(&p, p_end, freqdec);
    779868    wdb->remove_spelling(string(p, p_end - p), freqdec);
    780869}
     870
     871void
     872RemoteServer::select_db(const std::vector<std::string> &dbpaths_, bool writable_, int flags) {
     873    if (writable_) {
     874        AssertEq(dbpaths_.size(), 1); // Expecting exactly one database.
     875        Xapian::WritableDatabase * wdb_ = new Xapian::WritableDatabase(dbpaths_[0], flags);
     876        context = dbpaths_[0];
     877        delete db;
     878        db = wdb_;
     879        wdb = wdb_;
     880    } else {
     881        Assert(!dbpaths_.empty());  // Expecting at least one database.
     882        Xapian::Database * db_;
     883        if (dbpaths_.size() == 1) {
     884            db_ = new Xapian::Database(dbpaths_[0], flags);
     885            context = dbpaths_[0];
     886        } else {
     887            db_ = new Xapian::Database();
     888            // Build a better description than Database::get_description() gives
     889            // in the variable context.  FIXME: improve Database::get_description()
     890            // and then just use that instead.
     891            context = "";
     892            for (auto& path : dbpaths_) {
     893                db->add_database(Xapian::Database(path, flags));
     894                context += ' ';
     895                context += path;
     896            }
     897        }
     898        delete db;
     899        db = db_;
     900        wdb = NULL;
     901    }
     902    dbpaths = dbpaths_;
     903}
  • xapian-core/net/remoteserver.h

    diff --git a/xapian-core/net/remoteserver.h b/xapian-core/net/remoteserver.h
    index 857d791..37c0dab 100644
    a b class XAPIAN_VISIBILITY_DEFAULT RemoteServer : private RemoteConnection {  
    6969    /// The registry, which allows unserialisation of user subclasses.
    7070    Xapian::Registry reg;
    7171
     72    std::vector<std::string> dbpaths;
     73
    7274    /// Accept a message from the client.
    7375    message_type get_message(double timeout, std::string & result,
    7476                             message_type required_type = MSG_MAX);
    class XAPIAN_VISIBILITY_DEFAULT RemoteServer : private RemoteConnection {  
    170172    // get number of unique terms
    171173    void msg_uniqueterms(const std::string & message);
    172174
     175    // select an active database for read access
     176    void msg_readaccess(const std::string & message);
     177
     178    void select_db(const std::vector<std::string> &dbpaths_, bool writable_, int flags);
     179
    173180  public:
    174181    /** Construct a RemoteServer.
    175182     *
  • xapian-core/net/remotetcpclient.h

    diff --git a/xapian-core/net/remotetcpclient.h b/xapian-core/net/remotetcpclient.h
    index 9da59a8..da46e71 100644
    a b class RemoteTcpClient : SOCKET_INITIALIZER_MIXIN public RemoteDatabase {  
    7575     */
    7676    RemoteTcpClient(const std::string & hostname, int port,
    7777                    double timeout_, double timeout_connect, bool writable,
    78                     int flags)
     78                    int flags, const std::string & dir)
    7979        : RemoteDatabase(open_socket(hostname, port, timeout_connect),
    8080                         timeout_, get_tcpcontext(hostname, port),
    81                          writable, flags) { }
     81                         writable, flags, dir) { }
    8282
    8383    /** Destructor. */
    8484    ~RemoteTcpClient();