2012-05-21 20:38:34 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/logger_useful.h>
|
2012-10-16 19:20:58 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
#include <Poco/Net/StreamSocket.h>
|
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
#include <DB/Common/Throttler.h>
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
#include <DB/Core/Block.h>
|
2014-03-13 15:00:06 +00:00
|
|
|
|
#include <DB/Core/Defines.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
#include <DB/Core/Progress.h>
|
|
|
|
|
#include <DB/Core/Protocol.h>
|
|
|
|
|
#include <DB/Core/QueryProcessingStage.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/DataStreams/IBlockInputStream.h>
|
|
|
|
|
#include <DB/DataStreams/IBlockOutputStream.h>
|
2015-01-18 08:25:56 +00:00
|
|
|
|
#include <DB/DataStreams/BlockStreamProfileInfo.h>
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2013-02-01 19:02:04 +00:00
|
|
|
|
#include <DB/Interpreters/Settings.h>
|
|
|
|
|
|
2014-10-08 19:00:25 +00:00
|
|
|
|
#include <atomic>
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
using Poco::SharedPtr;
|
|
|
|
|
|
2015-02-04 10:27:06 +00:00
|
|
|
|
class ParallelReplicas;
|
2015-01-14 10:06:30 +00:00
|
|
|
|
|
2014-03-13 15:00:06 +00:00
|
|
|
|
/// Поток блоков читающих из таблицы и ее имя
|
2014-03-06 14:02:20 +00:00
|
|
|
|
typedef std::pair<BlockInputStreamPtr, std::string> ExternalTableData;
|
2014-03-13 15:00:06 +00:00
|
|
|
|
/// Вектор пар, описывающих таблицы
|
|
|
|
|
typedef std::vector<ExternalTableData> ExternalTablesData;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
/** Соединение с сервером БД для использования в клиенте.
|
|
|
|
|
* Как использовать - см. Core/Protocol.h
|
|
|
|
|
* (Реализацию на стороне сервера - см. Server/TCPHandler.h)
|
2012-05-30 06:46:57 +00:00
|
|
|
|
*
|
|
|
|
|
* В качестве default_database может быть указана пустая строка
|
|
|
|
|
* - в этом случае сервер использует свою БД по-умолчанию.
|
2012-05-16 18:03:00 +00:00
|
|
|
|
*/
|
2012-10-22 19:03:01 +00:00
|
|
|
|
class Connection : private boost::noncopyable
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2015-02-04 10:27:06 +00:00
|
|
|
|
friend class ParallelReplicas;
|
2015-01-14 10:06:30 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
public:
|
2012-05-30 06:46:57 +00:00
|
|
|
|
Connection(const String & host_, UInt16 port_, const String & default_database_,
|
2013-08-10 09:04:45 +00:00
|
|
|
|
const String & user_, const String & password_,
|
2012-05-23 19:51:30 +00:00
|
|
|
|
const String & client_name_ = "client",
|
2012-07-26 19:42:20 +00:00
|
|
|
|
Protocol::Compression::Enum compression_ = Protocol::Compression::Enable,
|
|
|
|
|
Poco::Timespan connect_timeout_ = Poco::Timespan(DBMS_DEFAULT_CONNECT_TIMEOUT_SEC, 0),
|
|
|
|
|
Poco::Timespan receive_timeout_ = Poco::Timespan(DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC, 0),
|
2015-03-06 09:37:16 +00:00
|
|
|
|
Poco::Timespan send_timeout_ = Poco::Timespan(DBMS_DEFAULT_SEND_TIMEOUT_SEC, 0),
|
|
|
|
|
Poco::Timespan ping_timeout_ = Poco::Timespan(DBMS_DEFAULT_PING_TIMEOUT_SEC, 0))
|
2013-08-10 09:04:45 +00:00
|
|
|
|
:
|
|
|
|
|
host(host_), port(port_), default_database(default_database_),
|
2015-05-28 21:41:28 +00:00
|
|
|
|
user(user_), password(password_), resolved_address(host, port),
|
|
|
|
|
client_name(client_name_),
|
|
|
|
|
compression(compression_),
|
|
|
|
|
connect_timeout(connect_timeout_), receive_timeout(receive_timeout_), send_timeout(send_timeout_),
|
|
|
|
|
ping_timeout(ping_timeout_),
|
|
|
|
|
log_wrapper(*this)
|
|
|
|
|
{
|
|
|
|
|
/// Соединеняемся не сразу, а при первой необходимости.
|
|
|
|
|
|
|
|
|
|
if (user.empty())
|
|
|
|
|
user = "default";
|
2015-05-29 00:33:56 +00:00
|
|
|
|
|
|
|
|
|
setDescription();
|
2015-05-28 21:41:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Connection(const String & host_, UInt16 port_, const Poco::Net::SocketAddress & resolved_address_,
|
|
|
|
|
const String & default_database_,
|
|
|
|
|
const String & user_, const String & password_,
|
|
|
|
|
const String & client_name_ = "client",
|
|
|
|
|
Protocol::Compression::Enum compression_ = Protocol::Compression::Enable,
|
|
|
|
|
Poco::Timespan connect_timeout_ = Poco::Timespan(DBMS_DEFAULT_CONNECT_TIMEOUT_SEC, 0),
|
|
|
|
|
Poco::Timespan receive_timeout_ = Poco::Timespan(DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC, 0),
|
|
|
|
|
Poco::Timespan send_timeout_ = Poco::Timespan(DBMS_DEFAULT_SEND_TIMEOUT_SEC, 0),
|
|
|
|
|
Poco::Timespan ping_timeout_ = Poco::Timespan(DBMS_DEFAULT_PING_TIMEOUT_SEC, 0))
|
|
|
|
|
:
|
|
|
|
|
host(host_), port(port_),
|
|
|
|
|
default_database(default_database_),
|
2013-08-10 09:04:45 +00:00
|
|
|
|
user(user_), password(password_),
|
2015-05-28 21:41:28 +00:00
|
|
|
|
resolved_address(resolved_address_),
|
2015-02-01 07:21:19 +00:00
|
|
|
|
client_name(client_name_),
|
2015-05-28 03:49:28 +00:00
|
|
|
|
compression(compression_),
|
2012-10-16 19:20:58 +00:00
|
|
|
|
connect_timeout(connect_timeout_), receive_timeout(receive_timeout_), send_timeout(send_timeout_),
|
2015-03-06 09:37:16 +00:00
|
|
|
|
ping_timeout(ping_timeout_),
|
2015-05-28 21:41:28 +00:00
|
|
|
|
log_wrapper(*this)
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
2012-05-21 20:38:34 +00:00
|
|
|
|
/// Соединеняемся не сразу, а при первой необходимости.
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
|
|
|
|
if (user.empty())
|
|
|
|
|
user = "default";
|
2015-05-29 00:33:56 +00:00
|
|
|
|
|
|
|
|
|
setDescription();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~Connection() {};
|
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
/// Установить ограничитель сетевого трафика. Один ограничитель может использоваться одновременно для нескольких разных соединений.
|
|
|
|
|
void setThrottler(const ThrottlerPtr & throttler_)
|
|
|
|
|
{
|
|
|
|
|
throttler = throttler_;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
/// Пакет, который может быть получен от сервера.
|
|
|
|
|
struct Packet
|
|
|
|
|
{
|
|
|
|
|
UInt64 type;
|
|
|
|
|
|
|
|
|
|
Block block;
|
|
|
|
|
SharedPtr<Exception> exception;
|
|
|
|
|
Progress progress;
|
2013-05-22 14:57:43 +00:00
|
|
|
|
BlockStreamProfileInfo profile_info;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
|
|
|
|
Packet() : type(Protocol::Server::Hello) {}
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-18 13:59:39 +00:00
|
|
|
|
/// Изменить базу данных по умолчанию. Изменения начинают использоваться только при следующем переподключении.
|
|
|
|
|
void setDefaultDatabase(const String & database);
|
|
|
|
|
|
2012-05-16 18:20:45 +00:00
|
|
|
|
void getServerVersion(String & name, UInt64 & version_major, UInt64 & version_minor, UInt64 & revision);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
/// Для сообщений в логе и в эксепшенах.
|
|
|
|
|
const String & getDescription() const
|
|
|
|
|
{
|
|
|
|
|
return description;
|
|
|
|
|
}
|
2012-10-16 18:14:51 +00:00
|
|
|
|
|
2015-05-28 21:41:28 +00:00
|
|
|
|
const String & getHost() const
|
|
|
|
|
{
|
|
|
|
|
return host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UInt16 getPort() const
|
|
|
|
|
{
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 15:42:30 +00:00
|
|
|
|
/// Если последний флаг true, то затем необходимо вызвать sendExternalTablesData
|
2014-02-14 15:59:01 +00:00
|
|
|
|
void sendQuery(const String & query, const String & query_id_ = "", UInt64 stage = QueryProcessingStage::Complete,
|
2014-04-08 07:31:51 +00:00
|
|
|
|
const Settings * settings = nullptr, bool with_pending_data = false);
|
2014-07-11 00:29:59 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
void sendCancel();
|
2014-03-14 15:42:30 +00:00
|
|
|
|
/// Отправить блок данных, на сервере сохранить во временную таблицу name
|
2014-03-06 14:02:20 +00:00
|
|
|
|
void sendData(const Block & block, const String & name = "");
|
2014-03-14 15:42:30 +00:00
|
|
|
|
/// Отправить все содержимое внешних таблиц
|
|
|
|
|
void sendExternalTablesData(ExternalTablesData & data);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2014-07-11 00:29:59 +00:00
|
|
|
|
/// Отправить блок данных, который уже был заранее сериализован (и, если надо, сжат), который следует прочитать из input-а.
|
2014-08-21 12:58:07 +00:00
|
|
|
|
/// можно передать размер сериализованного/сжатого блока.
|
|
|
|
|
void sendPreparedData(ReadBuffer & input, size_t size, const String & name = "");
|
2014-07-11 00:29:59 +00:00
|
|
|
|
|
2014-06-02 12:28:53 +00:00
|
|
|
|
/// Проверить, есть ли данные, которые можно прочитать.
|
2012-05-16 18:03:00 +00:00
|
|
|
|
bool poll(size_t timeout_microseconds = 0);
|
|
|
|
|
|
2015-01-29 12:13:21 +00:00
|
|
|
|
/// Проверить, есть ли данные в буфере для чтения.
|
2015-01-30 14:06:51 +00:00
|
|
|
|
bool hasReadBufferPendingData() const;
|
2015-01-29 12:13:21 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
/// Получить пакет от сервера.
|
|
|
|
|
Packet receivePacket();
|
2012-10-12 18:19:44 +00:00
|
|
|
|
|
2012-11-02 20:13:41 +00:00
|
|
|
|
/// Если ещё не соединено, или соединение разорвано - соединиться. Если не получилось - кинуть исключение.
|
|
|
|
|
void forceConnected();
|
|
|
|
|
|
2013-01-28 20:32:21 +00:00
|
|
|
|
/** Разорвать соединение.
|
|
|
|
|
* Это может быть нужно, например, чтобы соединение не осталось висеть в
|
|
|
|
|
* рассинхронизированном состоянии (когда кто-то чего-то продолжает ждать) после эксепшена.
|
|
|
|
|
*/
|
|
|
|
|
void disconnect();
|
|
|
|
|
|
2015-10-12 14:53:16 +00:00
|
|
|
|
/** Заполнить информацию, которая необходима при получении блока для некоторых задач
|
|
|
|
|
* (пока только для запроса DESCRIBE TABLE с Distributed-таблицами).
|
|
|
|
|
*/
|
|
|
|
|
void fillBlockExtraInfo(BlockExtraInfo & info) const;
|
|
|
|
|
|
2014-11-27 19:35:31 +00:00
|
|
|
|
size_t outBytesCount() const { return !out.isNull() ? out->count() : 0; }
|
|
|
|
|
size_t inBytesCount() const { return !in.isNull() ? in->count() : 0; }
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
private:
|
|
|
|
|
String host;
|
|
|
|
|
UInt16 port;
|
2012-05-30 06:46:57 +00:00
|
|
|
|
String default_database;
|
2013-08-10 09:04:45 +00:00
|
|
|
|
String user;
|
|
|
|
|
String password;
|
2012-05-16 18:20:45 +00:00
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
/** Адрес может быть заранее отрезолвен и передан в конструктор. Тогда поля host и port имеют смысл только для логгирования.
|
|
|
|
|
* Иначе адрес резолвится в конструкторе. То есть, DNS балансировка не поддерживается.
|
|
|
|
|
*/
|
2015-05-28 21:41:28 +00:00
|
|
|
|
Poco::Net::SocketAddress resolved_address;
|
|
|
|
|
|
2015-05-29 00:33:56 +00:00
|
|
|
|
/// Для сообщений в логе и в эксепшенах.
|
|
|
|
|
String description;
|
|
|
|
|
void setDescription();
|
|
|
|
|
|
2012-05-23 19:51:30 +00:00
|
|
|
|
String client_name;
|
|
|
|
|
|
2015-02-01 07:21:19 +00:00
|
|
|
|
bool connected = false;
|
2012-05-21 20:38:34 +00:00
|
|
|
|
|
2012-05-16 18:20:45 +00:00
|
|
|
|
String server_name;
|
2015-02-01 07:21:19 +00:00
|
|
|
|
UInt64 server_version_major = 0;
|
|
|
|
|
UInt64 server_version_minor = 0;
|
|
|
|
|
UInt64 server_revision = 0;
|
2014-07-11 00:29:59 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
Poco::Net::StreamSocket socket;
|
2014-02-27 22:24:38 +00:00
|
|
|
|
SharedPtr<ReadBuffer> in;
|
|
|
|
|
SharedPtr<WriteBuffer> out;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2014-02-12 17:31:02 +00:00
|
|
|
|
String query_id;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
UInt64 compression; /// Сжимать ли данные при взаимодействии с сервером.
|
2015-05-22 09:48:49 +00:00
|
|
|
|
/// каким алгоритмом сжимать данные при INSERT и данные внешних таблиц
|
|
|
|
|
CompressionMethod network_compression_method = CompressionMethod::LZ4;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2015-02-10 20:48:17 +00:00
|
|
|
|
/** Если не nullptr, то используется, чтобы ограничить сетевой трафик.
|
|
|
|
|
* Учитывается только трафик при передаче блоков. Другие пакеты не учитываются.
|
|
|
|
|
*/
|
|
|
|
|
ThrottlerPtr throttler;
|
|
|
|
|
|
2012-07-26 19:42:20 +00:00
|
|
|
|
Poco::Timespan connect_timeout;
|
|
|
|
|
Poco::Timespan receive_timeout;
|
|
|
|
|
Poco::Timespan send_timeout;
|
2015-03-06 09:37:16 +00:00
|
|
|
|
Poco::Timespan ping_timeout;
|
2012-07-26 19:42:20 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
/// Откуда читать результат выполнения запроса.
|
|
|
|
|
SharedPtr<ReadBuffer> maybe_compressed_in;
|
|
|
|
|
BlockInputStreamPtr block_in;
|
|
|
|
|
|
|
|
|
|
/// Куда писать данные INSERT-а.
|
|
|
|
|
SharedPtr<WriteBuffer> maybe_compressed_out;
|
|
|
|
|
BlockOutputStreamPtr block_out;
|
|
|
|
|
|
2014-10-08 19:00:25 +00:00
|
|
|
|
/// логгер, создаваемый лениво, чтобы не обращаться к DNS в конструкторе
|
|
|
|
|
class LoggerWrapper
|
|
|
|
|
{
|
|
|
|
|
public:
|
2015-05-28 21:41:28 +00:00
|
|
|
|
LoggerWrapper(Connection & parent_)
|
|
|
|
|
: log(nullptr), parent(parent_)
|
2014-10-08 19:00:25 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger * get()
|
|
|
|
|
{
|
|
|
|
|
if (!log)
|
2015-05-29 00:33:56 +00:00
|
|
|
|
log = &Logger::get("Connection (" + parent.getDescription() + ")");
|
2014-10-08 19:00:25 +00:00
|
|
|
|
|
|
|
|
|
return log;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::atomic<Logger *> log;
|
2015-05-28 21:41:28 +00:00
|
|
|
|
Connection & parent;
|
2014-10-08 19:00:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LoggerWrapper log_wrapper;
|
2012-10-16 19:20:58 +00:00
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
void connect();
|
|
|
|
|
void sendHello();
|
|
|
|
|
void receiveHello();
|
|
|
|
|
bool ping();
|
|
|
|
|
|
|
|
|
|
Block receiveData();
|
|
|
|
|
SharedPtr<Exception> receiveException();
|
|
|
|
|
Progress receiveProgress();
|
2013-05-22 14:57:43 +00:00
|
|
|
|
BlockStreamProfileInfo receiveProfileInfo();
|
2013-09-05 20:22:43 +00:00
|
|
|
|
|
|
|
|
|
void initBlockInput();
|
2012-05-16 18:03:00 +00:00
|
|
|
|
};
|
|
|
|
|
|
2012-05-21 20:38:34 +00:00
|
|
|
|
|
|
|
|
|
typedef SharedPtr<Connection> ConnectionPtr;
|
|
|
|
|
typedef std::vector<ConnectionPtr> Connections;
|
|
|
|
|
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|