2014-07-06 21:59:20 +00:00
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
#include <Poco/Net/NetException.h>
|
|
|
|
|
|
2016-02-09 17:06:50 +00:00
|
|
|
|
#include <common/ClickHouseRevision.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/Core/Defines.h>
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/IO/CompressedReadBuffer.h>
|
|
|
|
|
#include <DB/IO/CompressedWriteBuffer.h>
|
2014-02-27 22:24:38 +00:00
|
|
|
|
#include <DB/IO/ReadBufferFromPocoSocket.h>
|
|
|
|
|
#include <DB/IO/WriteBufferFromPocoSocket.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
#include <DB/IO/ReadHelpers.h>
|
|
|
|
|
#include <DB/IO/WriteHelpers.h>
|
2014-07-11 00:29:59 +00:00
|
|
|
|
#include <DB/IO/copyData.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/DataStreams/NativeBlockInputStream.h>
|
|
|
|
|
#include <DB/DataStreams/NativeBlockOutputStream.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Client/Connection.h>
|
|
|
|
|
|
2015-10-05 01:26:43 +00:00
|
|
|
|
#include <DB/Common/NetException.h>
|
2016-01-21 01:47:28 +00:00
|
|
|
|
#include <DB/Common/CurrentMetrics.h>
|
2015-03-26 08:47:02 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int NETWORK_ERROR;
|
|
|
|
|
extern const int SOCKET_TIMEOUT;
|
|
|
|
|
extern const int SERVER_REVISION_IS_TOO_OLD;
|
|
|
|
|
extern const int UNEXPECTED_PACKET_FROM_SERVER;
|
|
|
|
|
extern const int UNKNOWN_PACKET_FROM_SERVER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
void Connection::connect()
|
|
|
|
|
{
|
2012-10-15 19:38:33 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2012-10-20 06:40:55 +00:00
|
|
|
|
if (connected)
|
|
|
|
|
disconnect();
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
LOG_TRACE(log_wrapper.get(), "Connecting. Database: " << (default_database.empty() ? "(not specified)" : default_database) << ". User: " << user);
|
2012-10-18 23:38:16 +00:00
|
|
|
|
|
2015-05-28 21:41:28 +00:00
|
|
|
|
socket.connect(resolved_address, connect_timeout);
|
2012-10-15 19:38:33 +00:00
|
|
|
|
socket.setReceiveTimeout(receive_timeout);
|
|
|
|
|
socket.setSendTimeout(send_timeout);
|
2014-04-06 06:53:45 +00:00
|
|
|
|
socket.setNoDelay(true);
|
2012-07-26 19:42:20 +00:00
|
|
|
|
|
2013-01-28 20:32:21 +00:00
|
|
|
|
in = new ReadBufferFromPocoSocket(socket);
|
|
|
|
|
out = new WriteBufferFromPocoSocket(socket);
|
|
|
|
|
|
2012-10-15 19:38:33 +00:00
|
|
|
|
connected = true;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2012-10-15 19:38:33 +00:00
|
|
|
|
sendHello();
|
|
|
|
|
receiveHello();
|
2012-10-16 19:20:58 +00:00
|
|
|
|
|
2014-10-08 19:00:25 +00:00
|
|
|
|
LOG_TRACE(log_wrapper.get(), "Connected to " << server_name
|
2013-01-28 20:32:21 +00:00
|
|
|
|
<< " server version " << server_version_major
|
|
|
|
|
<< "." << server_version_minor
|
|
|
|
|
<< "." << server_revision
|
|
|
|
|
<< ".");
|
2012-10-15 19:38:33 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Poco::Net::NetException & e)
|
|
|
|
|
{
|
2012-10-20 22:49:30 +00:00
|
|
|
|
disconnect();
|
|
|
|
|
|
2013-10-20 06:04:51 +00:00
|
|
|
|
/// Добавляем в сообщение адрес сервера. Также объект Exception запомнит stack trace. Жаль, что более точный тип исключения теряется.
|
2015-05-29 00:33:56 +00:00
|
|
|
|
throw NetException(e.displayText(), "(" + getDescription() + ")", ErrorCodes::NETWORK_ERROR);
|
2012-10-15 19:38:33 +00:00
|
|
|
|
}
|
2012-11-02 20:13:41 +00:00
|
|
|
|
catch (Poco::TimeoutException & e)
|
|
|
|
|
{
|
|
|
|
|
disconnect();
|
|
|
|
|
|
2013-10-20 06:04:51 +00:00
|
|
|
|
/// Добавляем в сообщение адрес сервера. Также объект Exception запомнит stack trace. Жаль, что более точный тип исключения теряется.
|
2015-05-29 00:33:56 +00:00
|
|
|
|
throw NetException(e.displayText(), "(" + getDescription() + ")", ErrorCodes::SOCKET_TIMEOUT);
|
2012-11-02 20:13:41 +00:00
|
|
|
|
}
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-10-18 23:38:16 +00:00
|
|
|
|
void Connection::disconnect()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Disconnecting");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-10-18 23:38:16 +00:00
|
|
|
|
socket.close();
|
2014-04-08 07:31:51 +00:00
|
|
|
|
in = nullptr;
|
|
|
|
|
out = nullptr;
|
2012-10-18 23:38:16 +00:00
|
|
|
|
connected = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
void Connection::sendHello()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Sending hello");
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Client::Hello, *out);
|
2012-05-23 19:51:30 +00:00
|
|
|
|
writeStringBinary((DBMS_NAME " ") + client_name, *out);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(DBMS_VERSION_MAJOR, *out);
|
|
|
|
|
writeVarUInt(DBMS_VERSION_MINOR, *out);
|
2016-02-09 17:06:50 +00:00
|
|
|
|
writeVarUInt(ClickHouseRevision::get(), *out);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
writeStringBinary(default_database, *out);
|
2013-08-10 09:04:45 +00:00
|
|
|
|
writeStringBinary(user, *out);
|
|
|
|
|
writeStringBinary(password, *out);
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
out->next();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Connection::receiveHello()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Receiving hello");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
/// Получить hello пакет.
|
|
|
|
|
UInt64 packet_type = 0;
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readVarUInt(packet_type, *in);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
if (packet_type == Protocol::Server::Hello)
|
|
|
|
|
{
|
|
|
|
|
readStringBinary(server_name, *in);
|
|
|
|
|
readVarUInt(server_version_major, *in);
|
|
|
|
|
readVarUInt(server_version_minor, *in);
|
|
|
|
|
readVarUInt(server_revision, *in);
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
|
|
|
|
/// Старые ревизии сервера не поддерживают имя пользователя и пароль, которые были отправлены в пакете hello.
|
|
|
|
|
if (server_revision < DBMS_MIN_REVISION_WITH_USER_PASSWORD)
|
|
|
|
|
throw Exception("Server revision is too old for this client. You must update server to at least " + toString(DBMS_MIN_REVISION_WITH_USER_PASSWORD) + ".",
|
|
|
|
|
ErrorCodes::SERVER_REVISION_IS_TOO_OLD);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
}
|
|
|
|
|
else if (packet_type == Protocol::Server::Exception)
|
|
|
|
|
receiveException()->rethrow();
|
|
|
|
|
else
|
2012-10-12 18:57:10 +00:00
|
|
|
|
{
|
|
|
|
|
/// Закроем соединение, чтобы не было рассинхронизации.
|
2012-10-18 23:38:16 +00:00
|
|
|
|
disconnect();
|
2013-08-04 00:42:35 +00:00
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
throw NetException("Unexpected packet from server " + getDescription() + " (expected Hello or Exception, got "
|
2013-08-04 00:42:35 +00:00
|
|
|
|
+ String(Protocol::Server::toString(packet_type)) + ")", ErrorCodes::UNEXPECTED_PACKET_FROM_SERVER);
|
2012-10-12 18:57:10 +00:00
|
|
|
|
}
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-04-18 13:59:39 +00:00
|
|
|
|
void Connection::setDefaultDatabase(const String & database)
|
|
|
|
|
{
|
|
|
|
|
default_database = database;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:20:45 +00:00
|
|
|
|
void Connection::getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision)
|
|
|
|
|
{
|
2012-05-21 20:38:34 +00:00
|
|
|
|
if (!connected)
|
|
|
|
|
connect();
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-16 18:20:45 +00:00
|
|
|
|
name = server_name;
|
|
|
|
|
version_major = server_version_major;
|
|
|
|
|
version_minor = server_version_minor;
|
|
|
|
|
revision = server_revision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
void Connection::forceConnected()
|
|
|
|
|
{
|
2012-05-21 20:38:34 +00:00
|
|
|
|
if (!connected)
|
2012-10-18 23:38:16 +00:00
|
|
|
|
{
|
2012-05-21 20:38:34 +00:00
|
|
|
|
connect();
|
2012-10-18 23:38:16 +00:00
|
|
|
|
}
|
|
|
|
|
else if (!ping())
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2014-10-08 19:00:25 +00:00
|
|
|
|
LOG_TRACE(log_wrapper.get(), "Connection was closed, will reconnect.");
|
2012-10-18 23:38:16 +00:00
|
|
|
|
connect();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 09:37:16 +00:00
|
|
|
|
struct PingTimeoutSetter
|
|
|
|
|
{
|
2015-05-28 03:49:28 +00:00
|
|
|
|
PingTimeoutSetter(Poco::Net::StreamSocket & socket_, const Poco::Timespan & ping_timeout_)
|
2015-03-06 09:37:16 +00:00
|
|
|
|
: socket(socket_), ping_timeout(ping_timeout_)
|
|
|
|
|
{
|
|
|
|
|
old_send_timeout = socket.getSendTimeout();
|
|
|
|
|
old_receive_timeout = socket.getReceiveTimeout();
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2015-03-06 09:37:16 +00:00
|
|
|
|
if (old_send_timeout > ping_timeout)
|
|
|
|
|
socket.setSendTimeout(ping_timeout);
|
|
|
|
|
if (old_receive_timeout > ping_timeout)
|
|
|
|
|
socket.setReceiveTimeout(ping_timeout);
|
|
|
|
|
}
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2015-03-06 09:37:16 +00:00
|
|
|
|
~PingTimeoutSetter()
|
|
|
|
|
{
|
|
|
|
|
socket.setSendTimeout(old_send_timeout);
|
|
|
|
|
socket.setReceiveTimeout(old_receive_timeout);
|
|
|
|
|
}
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2015-03-06 09:37:16 +00:00
|
|
|
|
Poco::Net::StreamSocket & socket;
|
|
|
|
|
Poco::Timespan ping_timeout;
|
|
|
|
|
Poco::Timespan old_send_timeout;
|
|
|
|
|
Poco::Timespan old_receive_timeout;
|
|
|
|
|
};
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
bool Connection::ping()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
// LOG_TRACE(log_wrapper.get(), "Ping");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2015-03-06 09:37:16 +00:00
|
|
|
|
PingTimeoutSetter timeout_setter(socket, ping_timeout);
|
2012-10-18 23:38:16 +00:00
|
|
|
|
try
|
2012-06-01 10:45:29 +00:00
|
|
|
|
{
|
2012-10-18 23:38:16 +00:00
|
|
|
|
UInt64 pong = 0;
|
|
|
|
|
writeVarUInt(Protocol::Client::Ping, *out);
|
|
|
|
|
out->next();
|
2012-06-24 23:17:06 +00:00
|
|
|
|
|
|
|
|
|
if (in->eof())
|
|
|
|
|
return false;
|
|
|
|
|
|
2012-06-01 10:45:29 +00:00
|
|
|
|
readVarUInt(pong, *in);
|
|
|
|
|
|
2012-10-18 23:38:16 +00:00
|
|
|
|
/// Можем получить запоздалые пакеты прогресса. TODO: может быть, это можно исправить.
|
|
|
|
|
while (pong == Protocol::Server::Progress)
|
|
|
|
|
{
|
|
|
|
|
receiveProgress();
|
|
|
|
|
|
|
|
|
|
if (in->eof())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
readVarUInt(pong, *in);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pong != Protocol::Server::Pong)
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
throw Exception("Unexpected packet from server " + getDescription() + " (expected Pong, got "
|
2013-08-04 00:42:35 +00:00
|
|
|
|
+ String(Protocol::Server::toString(pong)) + ")",
|
2012-10-18 23:38:16 +00:00
|
|
|
|
ErrorCodes::UNEXPECTED_PACKET_FROM_SERVER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (const Poco::Exception & e)
|
2012-10-12 18:57:10 +00:00
|
|
|
|
{
|
2014-10-08 19:00:25 +00:00
|
|
|
|
LOG_TRACE(log_wrapper.get(), e.displayText());
|
2012-10-18 23:38:16 +00:00
|
|
|
|
return false;
|
2012-10-12 18:57:10 +00:00
|
|
|
|
}
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-03-12 15:37:44 +00:00
|
|
|
|
void Connection::sendQuery(const String & query, const String & query_id_, UInt64 stage, const Settings * settings, bool with_pending_data)
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2015-05-21 14:25:19 +00:00
|
|
|
|
network_compression_method = settings ? settings->network_compression_method.value : CompressionMethod::LZ4;
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
forceConnected();
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2014-02-14 15:59:01 +00:00
|
|
|
|
query_id = query_id_;
|
2012-05-23 19:51:30 +00:00
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Sending query");
|
2013-01-28 20:32:21 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Client::Query, *out);
|
2014-02-14 13:22:45 +00:00
|
|
|
|
|
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_STRING_QUERY_ID)
|
|
|
|
|
writeStringBinary(query_id, *out);
|
|
|
|
|
else
|
2014-02-17 10:27:18 +00:00
|
|
|
|
writeIntBinary<UInt64>(1, *out);
|
2013-02-01 19:02:04 +00:00
|
|
|
|
|
|
|
|
|
/// Настройки на отдельный запрос.
|
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_PER_QUERY_SETTINGS)
|
|
|
|
|
{
|
|
|
|
|
if (settings)
|
|
|
|
|
settings->serialize(*out);
|
|
|
|
|
else
|
|
|
|
|
writeStringBinary("", *out);
|
|
|
|
|
}
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(stage, *out);
|
|
|
|
|
writeVarUInt(compression, *out);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeStringBinary(query, *out);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2014-04-08 07:31:51 +00:00
|
|
|
|
maybe_compressed_in = nullptr;
|
|
|
|
|
maybe_compressed_out = nullptr;
|
|
|
|
|
block_in = nullptr;
|
|
|
|
|
block_out = nullptr;
|
2014-03-12 15:37:44 +00:00
|
|
|
|
|
2014-03-19 13:03:29 +00:00
|
|
|
|
/// Если версия сервера достаточно новая и стоит флаг, отправляем пустой блок, символизируя конец передачи данных.
|
2014-03-27 11:30:08 +00:00
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES && !with_pending_data)
|
2014-04-06 06:43:16 +00:00
|
|
|
|
{
|
2014-03-12 15:37:44 +00:00
|
|
|
|
sendData(Block());
|
2014-04-06 06:43:16 +00:00
|
|
|
|
out->next();
|
|
|
|
|
}
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Connection::sendCancel()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Sending cancel");
|
2014-04-06 06:43:16 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Client::Cancel, *out);
|
|
|
|
|
out->next();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-03-06 14:02:20 +00:00
|
|
|
|
void Connection::sendData(const Block & block, const String & name)
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Sending data");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
if (!block_out)
|
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
if (compression == Protocol::Compression::Enable)
|
2015-05-21 12:48:45 +00:00
|
|
|
|
maybe_compressed_out = new CompressedWriteBuffer(*out, network_compression_method);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
else
|
|
|
|
|
maybe_compressed_out = out;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
block_out = std::make_shared<NativeBlockOutputStream>(*maybe_compressed_out, server_revision);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Client::Data, *out);
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
2014-03-06 14:02:20 +00:00
|
|
|
|
writeStringBinary(name, *out);
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
size_t prev_bytes = out->count();
|
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
block.checkNestedArraysOffsets();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
block_out->write(block);
|
2012-05-28 19:57:44 +00:00
|
|
|
|
maybe_compressed_out->next();
|
2012-05-21 06:49:05 +00:00
|
|
|
|
out->next();
|
2015-02-10 20:48:17 +00:00
|
|
|
|
|
|
|
|
|
if (throttler)
|
|
|
|
|
throttler->add(out->count() - prev_bytes);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-06 06:43:16 +00:00
|
|
|
|
|
2014-08-21 12:58:07 +00:00
|
|
|
|
void Connection::sendPreparedData(ReadBuffer & input, size_t size, const String & name)
|
2014-07-11 00:29:59 +00:00
|
|
|
|
{
|
2015-02-10 20:48:17 +00:00
|
|
|
|
/// NOTE В этом методе не используется throttler (хотя можно использовать, но это пока не важно).
|
|
|
|
|
|
2014-07-11 00:29:59 +00:00
|
|
|
|
writeVarUInt(Protocol::Client::Data, *out);
|
|
|
|
|
|
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
|
|
|
|
writeStringBinary(name, *out);
|
|
|
|
|
|
2014-08-21 12:58:07 +00:00
|
|
|
|
if (0 == size)
|
|
|
|
|
copyData(input, *out);
|
|
|
|
|
else
|
|
|
|
|
copyData(input, *out, size);
|
2014-07-11 00:29:59 +00:00
|
|
|
|
out->next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-03-14 15:42:30 +00:00
|
|
|
|
void Connection::sendExternalTablesData(ExternalTablesData & data)
|
2014-03-04 15:31:56 +00:00
|
|
|
|
{
|
|
|
|
|
/// Если работаем со старым сервером, то никакой информации не отправляем
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (server_revision < DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
2014-04-07 00:31:44 +00:00
|
|
|
|
{
|
|
|
|
|
out->next();
|
2014-03-04 15:31:56 +00:00
|
|
|
|
return;
|
2014-04-07 00:31:44 +00:00
|
|
|
|
}
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2014-07-06 21:59:20 +00:00
|
|
|
|
if (data.empty())
|
|
|
|
|
{
|
|
|
|
|
/// Отправляем пустой блок, символизируя конец передачи данных
|
|
|
|
|
sendData(Block());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stopwatch watch;
|
|
|
|
|
size_t out_bytes = out ? out->count() : 0;
|
|
|
|
|
size_t maybe_compressed_out_bytes = maybe_compressed_out ? maybe_compressed_out->count() : 0;
|
|
|
|
|
size_t rows = 0;
|
|
|
|
|
|
2016-01-21 01:47:28 +00:00
|
|
|
|
CurrentMetrics::Increment metric_increment{CurrentMetrics::SendExternalTables};
|
|
|
|
|
|
2014-07-06 21:59:20 +00:00
|
|
|
|
for (auto & elem : data)
|
2014-03-06 14:02:20 +00:00
|
|
|
|
{
|
2014-07-06 21:59:20 +00:00
|
|
|
|
elem.first->readPrefix();
|
|
|
|
|
while (Block block = elem.first->read())
|
|
|
|
|
{
|
|
|
|
|
rows += block.rowsInFirstColumn();
|
|
|
|
|
sendData(block, elem.second);
|
|
|
|
|
}
|
|
|
|
|
elem.first->readSuffix();
|
2014-03-06 14:02:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-04 15:31:56 +00:00
|
|
|
|
/// Отправляем пустой блок, символизируя конец передачи данных
|
|
|
|
|
sendData(Block());
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
|
|
|
|
out_bytes = out->count() - out_bytes;
|
|
|
|
|
maybe_compressed_out_bytes = maybe_compressed_out->count() - maybe_compressed_out_bytes;
|
|
|
|
|
double elapsed = watch.elapsedSeconds();
|
|
|
|
|
|
|
|
|
|
std::stringstream msg;
|
|
|
|
|
msg << std::fixed << std::setprecision(3);
|
|
|
|
|
msg << "Sent data for " << data.size() << " external tables, total " << rows << " rows in " << elapsed << " sec., "
|
|
|
|
|
<< static_cast<size_t>(rows / watch.elapsedSeconds()) << " rows/sec., "
|
|
|
|
|
<< maybe_compressed_out_bytes / 1048576.0 << " MiB (" << maybe_compressed_out_bytes / 1048576.0 / watch.elapsedSeconds() << " MiB/sec.)";
|
|
|
|
|
|
|
|
|
|
if (compression == Protocol::Compression::Enable)
|
|
|
|
|
msg << ", compressed " << static_cast<double>(maybe_compressed_out_bytes) / out_bytes << " times to "
|
|
|
|
|
<< out_bytes / 1048576.0 << " MiB (" << out_bytes / 1048576.0 / watch.elapsedSeconds() << " MiB/sec.)";
|
|
|
|
|
else
|
|
|
|
|
msg << ", no compression.";
|
|
|
|
|
|
2014-10-08 19:00:25 +00:00
|
|
|
|
LOG_DEBUG(log_wrapper.get(), msg.rdbuf());
|
2014-03-04 15:31:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
bool Connection::poll(size_t timeout_microseconds)
|
|
|
|
|
{
|
2014-02-27 22:24:38 +00:00
|
|
|
|
return static_cast<ReadBufferFromPocoSocket &>(*in).poll(timeout_microseconds);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-01-30 14:06:51 +00:00
|
|
|
|
bool Connection::hasReadBufferPendingData() const
|
2015-01-29 12:13:21 +00:00
|
|
|
|
{
|
2015-01-30 14:06:51 +00:00
|
|
|
|
return static_cast<const ReadBufferFromPocoSocket &>(*in).hasPendingData();
|
2015-01-29 12:13:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
Connection::Packet Connection::receivePacket()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Receiving packet");
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2013-10-26 03:20:51 +00:00
|
|
|
|
try
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2013-10-26 03:20:51 +00:00
|
|
|
|
Packet res;
|
|
|
|
|
readVarUInt(res.type, *in);
|
|
|
|
|
|
|
|
|
|
switch (res.type)
|
|
|
|
|
{
|
|
|
|
|
case Protocol::Server::Data:
|
|
|
|
|
res.block = receiveData();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::Exception:
|
|
|
|
|
res.exception = receiveException();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::Progress:
|
|
|
|
|
res.progress = receiveProgress();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::ProfileInfo:
|
|
|
|
|
res.profile_info = receiveProfileInfo();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::Totals:
|
|
|
|
|
/// Блок с тотальными значениями передаётся так же, как обычный блок данных. Разница только в идентификаторе пакета.
|
|
|
|
|
res.block = receiveData();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::Extremes:
|
|
|
|
|
/// Аналогично.
|
|
|
|
|
res.block = receiveData();
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
case Protocol::Server::EndOfStream:
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/// Закроем соединение, чтобы не было рассинхронизации.
|
|
|
|
|
disconnect();
|
|
|
|
|
throw Exception("Unknown packet "
|
|
|
|
|
+ toString(res.type)
|
2015-05-29 00:33:56 +00:00
|
|
|
|
+ " from server " + getDescription(), ErrorCodes::UNKNOWN_PACKET_FROM_SERVER);
|
2013-10-26 03:20:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception & e)
|
|
|
|
|
{
|
|
|
|
|
/// Дописываем в текст исключения адрес сервера, если надо.
|
|
|
|
|
if (e.code() != ErrorCodes::UNKNOWN_PACKET_FROM_SERVER)
|
2015-05-29 00:33:56 +00:00
|
|
|
|
e.addMessage("while receiving packet from " + getDescription());
|
2013-10-26 03:20:51 +00:00
|
|
|
|
|
|
|
|
|
throw;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Block Connection::receiveData()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Receiving data");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2013-09-05 20:22:43 +00:00
|
|
|
|
initBlockInput();
|
|
|
|
|
|
2014-03-13 15:00:06 +00:00
|
|
|
|
String external_table_name;
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (server_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
|
|
|
|
readStringBinary(external_table_name, *in);
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
size_t prev_bytes = in->count();
|
|
|
|
|
|
2013-09-05 20:22:43 +00:00
|
|
|
|
/// Прочитать из сети один блок
|
2015-02-10 20:48:17 +00:00
|
|
|
|
Block res = block_in->read();
|
|
|
|
|
|
|
|
|
|
if (throttler)
|
|
|
|
|
throttler->add(in->count() - prev_bytes);
|
|
|
|
|
|
|
|
|
|
return res;
|
2013-09-05 20:22:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Connection::initBlockInput()
|
|
|
|
|
{
|
2012-05-16 18:03:00 +00:00
|
|
|
|
if (!block_in)
|
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
if (compression == Protocol::Compression::Enable)
|
|
|
|
|
maybe_compressed_in = new CompressedReadBuffer(*in);
|
|
|
|
|
else
|
|
|
|
|
maybe_compressed_in = in;
|
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
block_in = std::make_shared<NativeBlockInputStream>(*maybe_compressed_in, server_revision);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
void Connection::setDescription()
|
2012-10-12 18:19:44 +00:00
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
description = host + ":" + toString(resolved_address.port());
|
|
|
|
|
auto ip_address = resolved_address.host().toString();
|
|
|
|
|
|
|
|
|
|
if (host != ip_address)
|
|
|
|
|
description += ", " + ip_address;
|
2012-10-12 18:19:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
SharedPtr<Exception> Connection::receiveException()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Receiving exception");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
Exception e;
|
2015-05-29 00:33:56 +00:00
|
|
|
|
readException(e, *in, "Received from " + getDescription());
|
2012-05-16 18:03:00 +00:00
|
|
|
|
return e.clone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Progress Connection::receiveProgress()
|
|
|
|
|
{
|
2015-05-29 00:33:56 +00:00
|
|
|
|
//LOG_TRACE(log_wrapper.get(), "Receiving progress");
|
2014-07-06 21:59:20 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
Progress progress;
|
2014-10-25 18:33:52 +00:00
|
|
|
|
progress.read(*in, server_revision);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
return progress;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-22 14:57:43 +00:00
|
|
|
|
|
|
|
|
|
BlockStreamProfileInfo Connection::receiveProfileInfo()
|
|
|
|
|
{
|
|
|
|
|
BlockStreamProfileInfo profile_info;
|
|
|
|
|
profile_info.read(*in);
|
|
|
|
|
return profile_info;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 14:53:16 +00:00
|
|
|
|
void Connection::fillBlockExtraInfo(BlockExtraInfo & info) const
|
|
|
|
|
{
|
|
|
|
|
info.is_valid = true;
|
|
|
|
|
info.host = host;
|
|
|
|
|
info.resolved_address = resolved_address.toString();
|
|
|
|
|
info.port = port;
|
|
|
|
|
info.user = user;
|
|
|
|
|
}
|
2013-09-05 20:22:43 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|