Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion src/jrd/replication/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "../common/isc_f_proto.h"
#include "../common/status.h"
#include "../common/StatusArg.h"
#include "../common/utils_proto.h"
#include "../common/os/os_utils.h"
#include "../jrd/constants.h"

#include "Utils.h"
Expand All @@ -50,6 +52,8 @@ using namespace Replication;
namespace
{
const char* REPLICATION_CFGFILE = "replication.conf";
constexpr const char* KEY_ENV = "env";
constexpr const char* KEY_FILE = "file";

const ULONG DEFAULT_BUFFER_SIZE = 1024 * 1024; // 1 MB
const ULONG DEFAULT_SEGMENT_SIZE = 16 * 1024 * 1024; // 16 MB
Expand Down Expand Up @@ -216,7 +220,69 @@ Config* Config::get(const PathName& lookupName)

if (key == "sync_replica")
{
config->syncReplicas.add(value);
SyncReplica syncReplica(config->getPool());
if (el.sub)
{
syncReplica.database = value;
for (const auto& sub_el : el.sub->getParameters())
{
string sub_key(sub_el.name.c_str());
string sub_value(sub_el.value);

if (sub_value.isEmpty())
continue;

auto pos = sub_key.rfind('_');
if (pos != string::npos)
{
const string key_source = sub_key.substr(pos + 1);
sub_key = sub_key.substr(0, pos);

if (key_source.equals(KEY_ENV))
{
fb_utils::readenv(sub_value.c_str(), sub_value);
if (sub_value.isEmpty())
configError("missing environment variable", value, sub_value);
}
else if (key_source.equals(KEY_FILE))
{
const PathName sub_filename =
fb_utils::getPrefix(IConfigManager::DIR_CONF, sub_value.c_str());

AutoPtr<FILE> file(os_utils::fopen(sub_filename.c_str(), "rt"));
if (!file)
configError("missing file", value, sub_filename.c_str());

// skip first empty lines
sub_value = "";
do
{
if (feof(file))
break;

if (!sub_value.LoadFromFile(file))
break;

sub_value.alltrim(" \t\r");
} while (sub_value.isEmpty());

if (sub_value.isEmpty())
configError("empty file", value, sub_filename.c_str());
}
}

if (sub_key == "username")
syncReplica.username = sub_value.c_str();
else if (sub_key == "password")
syncReplica.password = sub_value.c_str();
else
configError("unknown parameter", value, sub_key);
}
}
else
splitConnectionString(value, syncReplica.database, syncReplica.username, syncReplica.password);

config->syncReplicas.add(syncReplica);
}
else if (key == "buffer_size")
{
Expand Down Expand Up @@ -427,3 +493,35 @@ void Config::enumerate(ReplicaList& replicas)
logReplicaStatus(dbName, &localStatus);
}
}

// This routine is used for split input connection string to parts
// input => [<username>[:<password>]@]<database>
//
// Examples:
// server2:/my/replica/database.fdb
// john:smith@server2:/my/replica/database.fdb

void Config::splitConnectionString(const string& input, string& database, string& username, string& password)
{
database = input;

auto pos = database.rfind('@');
if (pos != string::npos)
{
//john:smith
const string temp = database.substr(0, pos);
//server2:/my/replica/database.fdb
database = database.substr(pos + 1);

pos = temp.find(':');
if (pos != string::npos)
{
username = temp.substr(0, pos);
password = temp.substr(pos + 1);
}
else
{
username = temp;
}
}
}
19 changes: 18 additions & 1 deletion src/jrd/replication/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@

namespace Replication
{
struct SyncReplica
{
SyncReplica(MemoryPool& p)
: database(p), username(p), password(p)
{}

SyncReplica(MemoryPool& p, const SyncReplica& other)
: database(p, other.database), username(p, other.username), password(p, other.password)
{}

Firebird::string database;
Firebird::string username;
Firebird::string password;
};

struct Config : public Firebird::GlobalStorage
{
typedef Firebird::HalfStaticArray<Config*, 4> ReplicaList;
Expand All @@ -42,6 +57,8 @@ namespace Replication

static Config* get(const Firebird::PathName& dbName);
static void enumerate(ReplicaList& replicas);
static void splitConnectionString(const Firebird::string& input, Firebird::string& database,
Firebird::string& username, Firebird::string& password);

Firebird::PathName dbName;
ULONG bufferSize;
Expand All @@ -55,7 +72,7 @@ namespace Replication
Firebird::PathName archiveDirectory;
Firebird::string archiveCommand;
ULONG archiveTimeout;
Firebird::ObjectsArray<Firebird::string> syncReplicas;
Firebird::ObjectsArray<SyncReplica> syncReplicas;
Firebird::PathName sourceDirectory;
std::optional<Firebird::Guid> sourceGuid;
bool verboseLogging;
Expand Down
31 changes: 5 additions & 26 deletions src/jrd/replication/Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,39 +128,18 @@ Manager::Manager(const string& dbId,

for (const auto& iter : m_config->syncReplicas)
{
string database = iter;
string login, password;

auto pos = database.find('@');
if (pos != string::npos)
{
const string temp = database.substr(0, pos);
database = database.substr(pos + 1);

pos = temp.find(':');
if (pos != string::npos)
{
login = temp.substr(0, pos);
password = temp.substr(pos + 1);
}
else
{
login = temp;
}
}

ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_no_db_triggers, 1);

if (login.hasData())
if (iter.username.hasData())
{
dpb.insertString(isc_dpb_user_name, login);
dpb.insertString(isc_dpb_user_name, iter.username);

if (password.hasData())
dpb.insertString(isc_dpb_password, password);
if (iter.password.hasData())
dpb.insertString(isc_dpb_password, iter.password);
}

const auto attachment = provider->attachDatabase(&localStatus, database.c_str(),
const auto attachment = provider->attachDatabase(&localStatus, iter.database.c_str(),
dpb.getBufferLength(), dpb.getBuffer());
if (localStatus->getState() & IStatus::STATE_ERRORS)
{
Expand Down
Loading