CH local: Treat localhost:port as a remote database

This commit is contained in:
Raúl Marín 2021-07-23 13:16:35 +02:00
parent 60ca9990e5
commit 383c982715
9 changed files with 126 additions and 29 deletions

View File

@ -193,7 +193,17 @@ ClusterPtr DatabaseReplicated::getClusterImpl() const
UInt16 default_port = getContext()->getTCPPort();
bool secure = db_settings.cluster_secure_connection;
return std::make_shared<Cluster>(getContext()->getSettingsRef(), shards, username, password, default_port, false, secure);
bool treat_local_as_remote = false;
bool treat_local_port_as_remote = getContext()->getApplicationType() == Context::ApplicationType::LOCAL;
return std::make_shared<Cluster>(
getContext()->getSettingsRef(),
shards,
username,
password,
default_port,
treat_local_as_remote,
treat_local_port_as_remote,
secure);
}
void DatabaseReplicated::tryConnectToZooKeeperAndInitDatabase(bool force_attach)

View File

@ -127,13 +127,16 @@ ColumnPtr FunctionHasColumnInTable::executeImpl(const ColumnsWithTypeAndName & a
{
std::vector<std::vector<String>> host_names = {{ host_name }};
bool treat_local_as_remote = false;
bool treat_local_port_as_remote = getContext()->getApplicationType() == Context::ApplicationType::LOCAL;
auto cluster = std::make_shared<Cluster>(
getContext()->getSettings(),
host_names,
!user_name.empty() ? user_name : "default",
password,
getContext()->getTCPPort(),
false);
treat_local_as_remote,
treat_local_port_as_remote);
// FIXME this (probably) needs a non-constant access to query context,
// because it might initialized a storage. Ideally, the tables required

View File

@ -115,23 +115,44 @@ Cluster::Address::Address(
Cluster::Address::Address(
const String & host_port_,
const String & user_,
const String & password_,
UInt16 clickhouse_port,
bool secure_,
Int64 priority_,
UInt32 shard_index_,
UInt32 replica_index_)
: user(user_)
, password(password_)
const String & host_port_,
const String & user_,
const String & password_,
UInt16 clickhouse_port,
bool treat_local_port_as_remote,
bool secure_,
Int64 priority_,
UInt32 shard_index_,
UInt32 replica_index_)
: user(user_), password(password_)
{
auto parsed_host_port = parseAddress(host_port_, clickhouse_port);
bool can_be_local = true;
std::pair<std::string, UInt16> parsed_host_port;
if (!treat_local_port_as_remote)
{
parsed_host_port = parseAddress(host_port_, clickhouse_port);
}
else
{
/// For clickhouse-local (treat_local_port_as_remote) try to read the address without passing a default port
/// If it works we have a full address that includes a port, which means it won't be local
/// since clickhouse-local doesn't listen in any port
/// If it doesn't include a port then use the default one and it could be local (if the address is)
try
{
parsed_host_port = parseAddress(host_port_, 0);
can_be_local = false;
}
catch (...)
{
parsed_host_port = parseAddress(host_port_, clickhouse_port);
}
}
host_name = parsed_host_port.first;
port = parsed_host_port.second;
secure = secure_ ? Protocol::Secure::Enable : Protocol::Secure::Disable;
priority = priority_;
is_local = isLocal(clickhouse_port);
is_local = can_be_local && isLocal(clickhouse_port);
shard_index = shard_index_;
replica_index = replica_index_;
}
@ -482,9 +503,16 @@ Cluster::Cluster(const Poco::Util::AbstractConfiguration & config,
}
Cluster::Cluster(const Settings & settings, const std::vector<std::vector<String>> & names,
const String & username, const String & password, UInt16 clickhouse_port, bool treat_local_as_remote,
bool secure, Int64 priority)
Cluster::Cluster(
const Settings & settings,
const std::vector<std::vector<String>> & names,
const String & username,
const String & password,
UInt16 clickhouse_port,
bool treat_local_as_remote,
bool treat_local_port_as_remote,
bool secure,
Int64 priority)
{
UInt32 current_shard_num = 1;
@ -492,7 +520,16 @@ Cluster::Cluster(const Settings & settings, const std::vector<std::vector<String
{
Addresses current;
for (const auto & replica : shard)
current.emplace_back(replica, username, password, clickhouse_port, secure, priority, current_shard_num, current.size() + 1);
current.emplace_back(
replica,
username,
password,
clickhouse_port,
treat_local_port_as_remote,
secure,
priority,
current_shard_num,
current.size() + 1);
addresses_with_failover.emplace_back(current);

View File

@ -39,14 +39,21 @@ public:
/// Construct a cluster by the names of shards and replicas.
/// Local are treated as well as remote ones if treat_local_as_remote is true.
/// Local are also treated as remote if treat_local_port_as_remote is set and the local address includes a port
/// 'clickhouse_port' - port that this server instance listen for queries.
/// This parameter is needed only to check that some address is local (points to ourself).
///
/// Used for remote() function.
Cluster(const Settings & settings, const std::vector<std::vector<String>> & names,
const String & username, const String & password,
UInt16 clickhouse_port, bool treat_local_as_remote,
bool secure = false, Int64 priority = 1);
Cluster(
const Settings & settings,
const std::vector<std::vector<String>> & names,
const String & username,
const String & password,
UInt16 clickhouse_port,
bool treat_local_as_remote,
bool treat_local_port_as_remote,
bool secure = false,
Int64 priority = 1);
Cluster(const Cluster &)= delete;
Cluster & operator=(const Cluster &) = delete;
@ -115,6 +122,7 @@ public:
const String & user_,
const String & password_,
UInt16 clickhouse_port,
bool treat_local_port_as_remote,
bool secure_ = false,
Int64 priority_ = 1,
UInt32 shard_index_ = 0,

View File

@ -192,13 +192,16 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
}
}
bool treat_local_as_remote = false;
bool treat_local_port_as_remote = context->getApplicationType() == Context::ApplicationType::LOCAL;
cluster = std::make_shared<Cluster>(
context->getSettings(),
names,
username,
password,
(secure ? (maybe_secure_port ? *maybe_secure_port : DBMS_DEFAULT_SECURE_PORT) : context->getTCPPort()),
false,
treat_local_as_remote,
treat_local_port_as_remote,
secure);
}

View File

@ -9,5 +9,3 @@
0
0
0
1
1

View File

@ -25,7 +25,3 @@ $CLICKHOUSE_CLIENT -q "SELECT * FROM remote('${CLICKHOUSE_HOST}:${CLICKHOUSE_POR
$CLICKHOUSE_CLIENT -q "SELECT * FROM remote(test_shard_localhost, system, one);"
$CLICKHOUSE_CLIENT -q "SELECT * FROM remote(test_shard_localhost, system, one, 'default', '');"
$CLICKHOUSE_CLIENT -q "SELECT * FROM cluster('test_shard_localhost', system, one);"
# Actually tcp_port is not used because we query localhost and it is done without IPC into clickhouse-local itself.
$CLICKHOUSE_LOCAL --query "SELECT count() FROM remote('127.0.0.1', system.one)"
$CLICKHOUSE_LOCAL --query "SELECT count() FROM remote('127.0.0.1', system.one)" -- --tcp_port=59000

View File

@ -0,0 +1,8 @@
Code:81.
"test2",0
"test2",1
"test2",2
Code:81.
"test4",0
"test4",1
"test4",2

View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CUR_DIR"/../shell_config.sh
${CLICKHOUSE_CLIENT} --query "CREATE TABLE ${CLICKHOUSE_DATABASE}.remote_table (a Int64) ENGINE=TinyLog AS SELECT * FROM system.numbers limit 10;"
if [ "$CLICKHOUSE_HOST" == "localhost" ]; then
# Connecting to 127.0.0.1 will connect to clickhouse-local itself, where the table doesn't exist
${CLICKHOUSE_LOCAL} -q "SELECT 'test1', * FROM remote('127.0.0.1', '${CLICKHOUSE_DATABASE}.remote_table') LIMIT 3;" 2>&1 | awk '{print $1 $2}'
# Now connecting to 127.0.0.1:9000 will connect to the database we are running tests against
${CLICKHOUSE_LOCAL} -q "SELECT 'test2', * FROM remote('127.0.0.1:${CLICKHOUSE_PORT_TCP}', '${CLICKHOUSE_DATABASE}.remote_table') LIMIT 3 FORMAT CSV;"
# Same test now against localhost
${CLICKHOUSE_LOCAL} -q "SELECT 'test3', * FROM remote('localhost', '${CLICKHOUSE_DATABASE}.remote_table') LIMIT 3;" 2>&1 | awk '{print $1 $2}'
${CLICKHOUSE_LOCAL} -q "SELECT 'test4', * FROM remote('localhost:${CLICKHOUSE_PORT_TCP}', '${CLICKHOUSE_DATABASE}.remote_table') LIMIT 3 FORMAT CSV;"
else
# Can't test without localhost
echo Code:81.
echo \"test2\",0
echo \"test2\",1
echo \"test2\",2
echo Code:81.
echo \"test4\",0
echo \"test4\",1
echo \"test4\",2
fi
${CLICKHOUSE_CLIENT} --query "DROP TABLE ${CLICKHOUSE_DATABASE}.remote_table;"