Skip to content

Commit

Permalink
Remote Database directory selection support.
Browse files Browse the repository at this point in the history
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.

* RemoteDatabase requires database index if server has none set.

* Remote server implements database selection through msg_writeaccess
  and msg_readaccess.
  • Loading branch information
Kronuz committed Sep 9, 2016
1 parent cf28705 commit 89792af
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 82 deletions.
53 changes: 41 additions & 12 deletions xapian-core/backends/dbfactory_remote.cc
Expand Up @@ -33,39 +33,68 @@ namespace Xapian {

Database
Remote::open(const string &host, unsigned int port, useconds_t timeout_,
useconds_t connect_timeout)
useconds_t connect_timeout, int flags, const string &dir)
{
LOGCALL_STATIC(API, Database, "Remote::open", host | port | timeout_ | connect_timeout);
LOGCALL_STATIC(API, Database, "Remote::open", host | port | timeout_ | connect_timeout | flags | dir);
RETURN(Database(new RemoteTcpClient(host, port, timeout_ * 1e-3,
connect_timeout * 1e-3, false, 0)));
connect_timeout * 1e-3, false, flags, dir)));
}

Database
Remote::open(const string &host, unsigned int port, useconds_t timeout_,
useconds_t connect_timeout)
{
return Remote::open(host, port, timeout_, connect_timeout, 0, std::string());
}

WritableDatabase
Remote::open_writable(const string &host, unsigned int port,
useconds_t timeout_, useconds_t connect_timeout,
int flags)
int flags, const string &dir)
{
LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", host | port | timeout_ | connect_timeout | flags);
LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", host | port | timeout_ | connect_timeout | flags | dir);
RETURN(WritableDatabase(new RemoteTcpClient(host, port, timeout_ * 1e-3,
connect_timeout * 1e-3, true,
flags)));
flags, dir)));
}

WritableDatabase
Remote::open_writable(const string &host, unsigned int port,
useconds_t timeout_, useconds_t connect_timeout,
int flags)
{
return Remote::open_writable(host, port, timeout_, connect_timeout, flags, std::string());
}

Database
Remote::open(const string &program, const string &args,
useconds_t timeout_)
useconds_t timeout_, int flags, const string &dir)
{
LOGCALL_STATIC(API, Database, "Remote::open", program | args | timeout_);
RETURN(Database(new ProgClient(program, args, timeout_ * 1e-3, false, 0)));
LOGCALL_STATIC(API, Database, "Remote::open", program | args | timeout_ | flags | dir);
RETURN(Database(new ProgClient(program, args, timeout_ * 1e-3, false, flags, dir)));
}

Database
Remote::open(const string &program, const string &args,
useconds_t timeout_, int flags)
{
return Remote::open(program, args, timeout_, flags, std::string());
}

WritableDatabase
Remote::open_writable(const string &program, const string &args,
useconds_t timeout_, int flags)
useconds_t timeout_, int flags, const string &dir)
{
LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", program | args | timeout_ | flags);
LOGCALL_STATIC(API, WritableDatabase, "Remote::open_writable", program | args | timeout_ | flags | dir);
RETURN(WritableDatabase(new ProgClient(program, args,
timeout_ * 1e-3, true, flags)));
timeout_ * 1e-3, true, flags, dir)));
}

WritableDatabase
Remote::open_writable(const string &program, const string &args,
useconds_t timeout_, int flags)
{
return Remote::open_writable(program, args, timeout_, flags, std::string());
}

}
66 changes: 50 additions & 16 deletions xapian-core/backends/remote/remote-database.cc
Expand Up @@ -68,9 +68,12 @@ throw_connection_closed_unexpectedly()
}

RemoteDatabase::RemoteDatabase(int fd, double timeout_,
const string & context_, bool writable,
int flags)
: link(fd, fd, context_),
const string & context_, bool writable_,
int flags_, const string & dir)
: db_dir(dir),
writable(writable_),
flags(flags_),
link(fd, fd, context_),
context(context_),
cached_stats_valid(),
mru_valstats(),
Expand All @@ -95,15 +98,6 @@ RemoteDatabase::RemoteDatabase(int fd, double timeout_,
}

update_stats(MSG_MAX);

if (writable) {
if (flags & Xapian::DB_RETRY_LOCK) {
const string & body = encode_length(flags & Xapian::DB_RETRY_LOCK);
update_stats(MSG_WRITEACCESS, body);
} else {
update_stats(MSG_WRITEACCESS);
}
}
}

void
Expand Down Expand Up @@ -339,7 +333,7 @@ RemoteDatabase::update_stats(message_type msg_code, const string & body) const

string message;
reply_type type = get_message(message);
if (type != REPLY_UPDATE || message.size() < 3) {
if (type != REPLY_UPDATE || message.size() < 2) {
if (type == REPLY_DONE) {
// The database was already open at the latest revision.
return false;
Expand Down Expand Up @@ -373,6 +367,46 @@ RemoteDatabase::update_stats(message_type msg_code, const string & body) const
throw Xapian::NetworkError(errmsg, context);
}

if (p == p_end) {
message = encode_length(flags);
message += encode_length(db_dir.size());
message += db_dir;

if (writable) {
send_message(MSG_WRITEACCESS, message);
} else {
send_message(MSG_READACCESS, message);
}

get_message(message, REPLY_UPDATE);
if (message.size() < 3) {
throw Xapian::NetworkError("Database was not selected", context);
}

p = message.c_str();
p_end = p + message.size();

// The protocol versions where already checked.
p += 2;
} else if (msg_code == MSG_MAX && writable) {
if (flags) {
send_message(MSG_WRITEACCESS, encode_length(flags));
} else {
send_message(MSG_WRITEACCESS, string());
}

get_message(message, REPLY_UPDATE);
if (message.size() < 3) {
throw Xapian::NetworkError("Database was not selected", context);
}

p = message.c_str();
p_end = p + message.size();

// The protocol versions where already checked.
p += 2;
}

decode_length(&p, p_end, doccount);
decode_length(&p, p_end, lastdocid);
lastdocid += doccount;
Expand Down Expand Up @@ -597,16 +631,16 @@ RemoteDatabase::do_close()
// In the constructor, we set transaction_state to
// TRANSACTION_UNIMPLEMENTED if we aren't writable so that we can check
// it here.
bool writable = (transaction_state != TRANSACTION_UNIMPLEMENTED);
bool writable_ = (transaction_state != TRANSACTION_UNIMPLEMENTED);

// Only call dtor_called() if we're writable.
if (writable) dtor_called();
if (writable_) dtor_called();

// If we're writable, wait for a confirmation of the close, so we know that
// changes have been written and flushed, and the database write lock
// released. For the non-writable case, there's no need to wait, so don't
// slow down searching by waiting here.
link.do_close(writable);
link.do_close(writable_);
}

void
Expand Down
14 changes: 12 additions & 2 deletions xapian-core/backends/remote/remote-database.h
Expand Up @@ -49,6 +49,15 @@ class RemoteDatabase : public Xapian::Database::Internal {
/// Don't allow copying.
RemoteDatabase(const RemoteDatabase &);

// Directory to store databases in.
const std::string db_dir;

// The database is writable.
const bool writable;

// Bitwise-or of Xapian::DB_* flags.
const int flags;

/// The object which does the I/O.
mutable RemoteConnection link;

Expand Down Expand Up @@ -103,10 +112,11 @@ class RemoteDatabase : public Xapian::Database::Internal {
* operations will never timeout.
* @param context_ The context to return with any error messages.
* @param writable Is this a WritableDatabase?
* @param flags Xapian::DB_RETRY_LOCK or 0.
* @param flags Xapian::DB_RETRY_LOCK or Bitwise-or of Xapian::DB_* constants.
* @param dir Database directory index to open.
*/
RemoteDatabase(int fd, double timeout_, const string & context_,
bool writable, int flags);
bool writable, int flags, const string & dir);

/// Receive a message from the server.
reply_type get_message(string & message, reply_type required_type = REPLY_MAX) const;
Expand Down
1 change: 1 addition & 0 deletions xapian-core/common/remoteprotocol.h
Expand Up @@ -89,6 +89,7 @@ enum message_type {
MSG_METADATAKEYLIST, // Iterator for metadata keys
MSG_FREQS, // Get termfreq and collfreq
MSG_UNIQUETERMS, // Get number of unique terms in doc
MSG_READACCESS, // Select currenty active read access database
MSG_MAX
};

Expand Down
30 changes: 26 additions & 4 deletions xapian-core/include/xapian/dbfactory.h
Expand Up @@ -176,7 +176,13 @@ namespace Remote {
* Xapian::NetworkTimeoutError is thrown. A
* timeout of 0 means don't timeout. (Default is
* 10000ms, which is 10 seconds).
*/
* @param flags bitwise-or of Xapian::DB_* constants.
* @param dir database directory index to open.
*/
XAPIAN_VISIBILITY_DEFAULT
Database open(const std::string &host, unsigned int port, useconds_t timeout, useconds_t connect_timeout, int flags, const std::string &dir = std::string());

// FIXME: legacy form of above (not breaking ABI when flags and dir are not passed)
XAPIAN_VISIBILITY_DEFAULT
Database open(const std::string &host, unsigned int port, useconds_t timeout = 10000, useconds_t connect_timeout = 10000);

Expand All @@ -197,8 +203,14 @@ Database open(const std::string &host, unsigned int port, useconds_t timeout = 1
* Xapian::NetworkTimeoutError is thrown. A
* timeout of 0 means don't timeout. (Default is
* 10000ms, which is 10 seconds).
* @param flags Xapian::DB_RETRY_LOCK or bitwise-or of Xapian::DB_* constants.
* @param dir database directory index to open.
*/
XAPIAN_VISIBILITY_DEFAULT
WritableDatabase open_writable(const std::string &host, unsigned int port, useconds_t timeout, useconds_t connect_timeout, int flags, const std::string &dir);

// FIXME: legacy form of above (not breaking ABI when dir is not passed)
XAPIAN_VISIBILITY_DEFAULT
WritableDatabase open_writable(const std::string &host, unsigned int port, useconds_t timeout = 0, useconds_t connect_timeout = 10000, int flags = 0);

/** Construct a Database object for read-only access to a remote database
Expand All @@ -214,10 +226,15 @@ WritableDatabase open_writable(const std::string &host, unsigned int port, useco
* then Xapian::NetworkTimeoutError is thrown. A timeout
* of 0 means don't timeout. (Default is 10000ms, which
* is 10 seconds).
* @param flags Xapian::DB_RETRY_LOCK or 0.
* @param flags bitwise-or of Xapian::DB_* constants.
* @param dir database directory index to open.
*/
XAPIAN_VISIBILITY_DEFAULT
Database open(const std::string &program, const std::string &args, useconds_t timeout = 10000);
Database open(const std::string &program, const std::string &args, useconds_t timeout, int flags, const std::string &dir);

// FIXME: legacy form of above (not breaking ABI when dir is not passed)
XAPIAN_VISIBILITY_DEFAULT
Database open(const std::string &program, const std::string &args, useconds_t timeout = 10000, int flags = 0);

/** Construct a WritableDatabase object for update access to a remote database
* accessed via a program.
Expand All @@ -231,9 +248,14 @@ Database open(const std::string &program, const std::string &args, useconds_t ti
* for any individual operation on the remote database
* then Xapian::NetworkTimeoutError is thrown. (Default
* is 0, which means don't timeout).
* @param flags Xapian::DB_RETRY_LOCK or 0.
* @param flags Xapian::DB_RETRY_LOCK or bitwise-or of Xapian::DB_* constants.
* @param dir database directory index to open.
*/
XAPIAN_VISIBILITY_DEFAULT
WritableDatabase open_writable(const std::string &program, const std::string &args, useconds_t timeout, int flags, const std::string &dir);

// FIXME: legacy form of above (not breaking ABI when dir is not passed)
XAPIAN_VISIBILITY_DEFAULT
WritableDatabase open_writable(const std::string &program, const std::string &args, useconds_t timeout = 0, int flags = 0);

}
Expand Down
6 changes: 3 additions & 3 deletions xapian-core/net/progclient.cc
Expand Up @@ -64,16 +64,16 @@ split_words(const string &text, vector<string> &words, char ws = ' ')
#endif

ProgClient::ProgClient(const string &progname, const string &args,
double timeout_, bool writable, int flags)
double timeout_, bool writable, int flags, const string & dir)
: RemoteDatabase(run_program(progname, args
#ifndef __WIN32__
, pid
#endif
),
timeout_, get_progcontext(progname, args), writable,
flags)
flags, dir)
{
LOGCALL_CTOR(DB, "ProgClient", progname | args | timeout_ | writable | flags);
LOGCALL_CTOR(DB, "ProgClient", progname | args | timeout_ | writable | flags | dir);
}

string
Expand Down
3 changes: 2 additions & 1 deletion xapian-core/net/progclient.h
Expand Up @@ -88,7 +88,8 @@ class ProgClient : public RemoteDatabase {
const std::string &arg,
double msecs_timeout,
bool writable,
int flags);
int flags,
const std::string & dir);

/** Destructor. */
~ProgClient();
Expand Down

0 comments on commit 89792af

Please sign in to comment.