2012-03-19 12:57:56 +00:00
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
2013-01-13 22:13:54 +00:00
|
|
|
|
#include <Poco/Net/NetException.h>
|
|
|
|
|
|
2016-02-09 17:06:50 +00:00
|
|
|
|
#include <common/ClickHouseRevision.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2015-10-05 00:44:40 +00:00
|
|
|
|
#include <DB/Common/Stopwatch.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2012-05-16 18:32:32 +00:00
|
|
|
|
#include <DB/Core/Progress.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2012-03-11 08:52:56 +00:00
|
|
|
|
#include <DB/IO/CompressedReadBuffer.h>
|
|
|
|
|
#include <DB/IO/CompressedWriteBuffer.h>
|
2014-02-27 22:35:49 +00:00
|
|
|
|
#include <DB/IO/ReadBufferFromPocoSocket.h>
|
|
|
|
|
#include <DB/IO/WriteBufferFromPocoSocket.h>
|
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include <DB/IO/copyData.h>
|
|
|
|
|
|
2012-10-20 05:54:35 +00:00
|
|
|
|
#include <DB/DataStreams/AsynchronousBlockInputStream.h>
|
2015-01-03 03:18:49 +00:00
|
|
|
|
#include <DB/DataStreams/NativeBlockInputStream.h>
|
|
|
|
|
#include <DB/DataStreams/NativeBlockOutputStream.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include <DB/Interpreters/executeQuery.h>
|
2015-05-29 21:37:17 +00:00
|
|
|
|
#include <DB/Interpreters/Quota.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2014-03-04 15:31:56 +00:00
|
|
|
|
#include <DB/Storages/StorageMemory.h>
|
|
|
|
|
|
2014-04-08 13:43:20 +00:00
|
|
|
|
#include <DB/Common/ExternalTable.h>
|
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include "TCPHandler.h"
|
|
|
|
|
|
2015-10-05 01:26:43 +00:00
|
|
|
|
#include <DB/Common/NetException.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int CLIENT_HAS_CONNECTED_TO_WRONG_PORT;
|
|
|
|
|
extern const int UNKNOWN_DATABASE;
|
|
|
|
|
extern const int UNKNOWN_EXCEPTION;
|
|
|
|
|
extern const int UNKNOWN_PACKET_FROM_CLIENT;
|
|
|
|
|
extern const int POCO_EXCEPTION;
|
|
|
|
|
extern const int STD_EXCEPTION;
|
|
|
|
|
extern const int SOCKET_TIMEOUT;
|
|
|
|
|
extern const int UNEXPECTED_PACKET_FROM_CLIENT;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
|
|
|
|
void TCPHandler::runImpl()
|
|
|
|
|
{
|
2013-09-14 05:14:22 +00:00
|
|
|
|
connection_context = *server.global_context;
|
2012-08-02 17:33:31 +00:00
|
|
|
|
connection_context.setSessionContext(connection_context);
|
2012-07-26 20:16:57 +00:00
|
|
|
|
|
2013-09-14 05:14:22 +00:00
|
|
|
|
Settings global_settings = server.global_context->getSettings();
|
2012-08-16 18:02:15 +00:00
|
|
|
|
|
|
|
|
|
socket().setReceiveTimeout(global_settings.receive_timeout);
|
|
|
|
|
socket().setSendTimeout(global_settings.send_timeout);
|
2014-04-06 06:53:45 +00:00
|
|
|
|
socket().setNoDelay(true);
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2016-05-28 14:14:18 +00:00
|
|
|
|
in = std::make_shared<ReadBufferFromPocoSocket>(socket());
|
|
|
|
|
out = std::make_shared<WriteBufferFromPocoSocket>(socket());
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
2016-01-06 20:37:50 +00:00
|
|
|
|
if (in->eof())
|
|
|
|
|
{
|
|
|
|
|
LOG_WARNING(log, "Client has not sent any data.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-10 09:04:45 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
receiveHello();
|
|
|
|
|
}
|
2013-10-26 03:20:51 +00:00
|
|
|
|
catch (const Exception & e) /// Типично при неправильном имени пользователя, пароле, адресе.
|
2013-08-10 09:04:45 +00:00
|
|
|
|
{
|
2014-03-02 19:52:55 +00:00
|
|
|
|
if (e.code() == ErrorCodes::CLIENT_HAS_CONNECTED_TO_WRONG_PORT)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG(log, "Client has connected to wrong port.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-06 20:37:50 +00:00
|
|
|
|
if (e.code() == ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF)
|
|
|
|
|
{
|
|
|
|
|
LOG_WARNING(log, "Client has gone away.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-10 09:04:45 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
/// Пытаемся отправить информацию об ошибке клиенту.
|
|
|
|
|
sendException(e);
|
|
|
|
|
}
|
|
|
|
|
catch (...) {}
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2012-05-30 06:46:57 +00:00
|
|
|
|
|
2014-08-12 09:35:15 +00:00
|
|
|
|
/// При соединении может быть указана БД по умолчанию.
|
2012-05-30 06:46:57 +00:00
|
|
|
|
if (!default_database.empty())
|
|
|
|
|
{
|
2012-08-02 17:33:31 +00:00
|
|
|
|
if (!connection_context.isDatabaseExist(default_database))
|
2012-05-30 06:46:57 +00:00
|
|
|
|
{
|
|
|
|
|
Exception e("Database " + default_database + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE);
|
2013-10-26 03:20:51 +00:00
|
|
|
|
LOG_ERROR(log, "Code: " << e.code() << ", e.displayText() = " << e.displayText()
|
2012-05-30 06:46:57 +00:00
|
|
|
|
<< ", Stack trace:\n\n" << e.getStackTrace().toString());
|
|
|
|
|
sendException(e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-02 17:33:31 +00:00
|
|
|
|
connection_context.setCurrentDatabase(default_database);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
}
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
sendHello();
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2014-10-25 18:33:52 +00:00
|
|
|
|
connection_context.setProgressCallback([this] (const Progress & value) { return this->updateProgress(value); });
|
2013-02-16 14:55:14 +00:00
|
|
|
|
|
2012-08-16 17:50:54 +00:00
|
|
|
|
while (1)
|
2012-03-09 15:46:52 +00:00
|
|
|
|
{
|
2012-08-16 17:50:54 +00:00
|
|
|
|
/// Ждём пакета от клиента. При этом, каждые POLL_INTERVAL сек. проверяем, не требуется ли завершить работу.
|
2016-02-09 17:06:50 +00:00
|
|
|
|
while (!static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000) && !BaseDaemon::instance().isCancelled())
|
2012-08-16 17:50:54 +00:00
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
/// Если требуется завершить работу, или клиент отсоединился.
|
2016-02-09 17:06:50 +00:00
|
|
|
|
if (BaseDaemon::instance().isCancelled() || in->eof())
|
2012-08-16 17:50:54 +00:00
|
|
|
|
break;
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
Stopwatch watch;
|
2012-05-09 08:16:09 +00:00
|
|
|
|
state.reset();
|
2012-12-06 17:32:48 +00:00
|
|
|
|
|
|
|
|
|
/** Исключение во время выполнения запроса (его надо отдать по сети клиенту).
|
2013-01-13 22:13:54 +00:00
|
|
|
|
* Клиент сможет его принять, если оно не произошло во время отправки другого пакета и клиент ещё не разорвал соединение.
|
2012-12-06 17:32:48 +00:00
|
|
|
|
*/
|
2016-05-28 14:14:18 +00:00
|
|
|
|
std::unique_ptr<Exception> exception;
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2012-05-08 05:42:05 +00:00
|
|
|
|
try
|
2013-02-01 19:02:04 +00:00
|
|
|
|
{
|
|
|
|
|
/// Восстанавливаем контекст запроса.
|
|
|
|
|
query_context = connection_context;
|
2015-06-26 20:48:10 +00:00
|
|
|
|
query_context.setInterface(Context::Interface::TCP);
|
2013-02-01 19:02:04 +00:00
|
|
|
|
|
2013-09-14 07:58:42 +00:00
|
|
|
|
/** Если Query - обрабатываем. Если Ping или Cancel - возвращаемся в начало.
|
2013-02-01 19:02:04 +00:00
|
|
|
|
* Могут прийти настройки на отдельный запрос, которые модифицируют query_context.
|
|
|
|
|
*/
|
2013-09-14 07:58:42 +00:00
|
|
|
|
if (!receivePacket())
|
|
|
|
|
continue;
|
2012-05-08 05:42:05 +00:00
|
|
|
|
|
2014-03-04 15:31:56 +00:00
|
|
|
|
/// Получить блоки временных таблиц
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
2014-03-04 15:31:56 +00:00
|
|
|
|
readData(global_settings);
|
|
|
|
|
|
2014-03-28 11:57:03 +00:00
|
|
|
|
/// Очищаем, так как, получая данные внешних таблиц, мы получили пустой блок.
|
|
|
|
|
/// А значит, stream помечен как cancelled и читать из него нельзя.
|
2016-05-28 14:14:18 +00:00
|
|
|
|
state.block_in.reset();
|
|
|
|
|
state.maybe_compressed_in.reset(); /// Для более корректного учёта MemoryTracker-ом.
|
2014-03-27 11:30:08 +00:00
|
|
|
|
|
2012-05-17 19:15:53 +00:00
|
|
|
|
/// Обрабатываем Query
|
2014-03-04 15:31:56 +00:00
|
|
|
|
state.io = executeQuery(state.query, query_context, false, state.stage);
|
|
|
|
|
|
|
|
|
|
if (state.io.out)
|
2014-11-08 23:54:03 +00:00
|
|
|
|
state.need_receive_data_for_insert = true;
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
2012-05-09 15:15:45 +00:00
|
|
|
|
after_check_cancelled.restart();
|
|
|
|
|
after_send_progress.restart();
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
/// Запрос требует приёма данных от клиента?
|
2014-11-08 23:54:03 +00:00
|
|
|
|
if (state.need_receive_data_for_insert)
|
2013-12-20 10:07:10 +00:00
|
|
|
|
processInsertQuery(global_settings);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
else
|
|
|
|
|
processOrdinaryQuery();
|
|
|
|
|
|
|
|
|
|
sendEndOfStream();
|
2012-12-06 17:32:48 +00:00
|
|
|
|
|
|
|
|
|
state.reset();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2013-10-26 03:20:51 +00:00
|
|
|
|
catch (const Exception & e)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2015-06-29 21:35:35 +00:00
|
|
|
|
state.io.onException();
|
2016-05-28 14:14:18 +00:00
|
|
|
|
exception.reset(e.clone());
|
2012-05-28 19:34:55 +00:00
|
|
|
|
|
|
|
|
|
if (e.code() == ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT)
|
|
|
|
|
throw;
|
2012-05-08 05:42:05 +00:00
|
|
|
|
}
|
2013-01-13 22:13:54 +00:00
|
|
|
|
catch (const Poco::Net::NetException & e)
|
|
|
|
|
{
|
2013-01-28 17:31:08 +00:00
|
|
|
|
/** Сюда мы можем попадать, если была ошибка в соединении с клиентом,
|
|
|
|
|
* или в соединении с удалённым сервером, который использовался для обработки запроса.
|
|
|
|
|
* Здесь не получается отличить эти два случая.
|
|
|
|
|
* Хотя в одном из них, мы должны отправить эксепшен клиенту, а в другом - не можем.
|
|
|
|
|
* Будем пытаться отправить эксепшен клиенту в любом случае - см. ниже.
|
|
|
|
|
*/
|
2015-06-29 21:35:35 +00:00
|
|
|
|
state.io.onException();
|
2016-05-28 14:14:18 +00:00
|
|
|
|
exception = std::make_unique<Exception>(e.displayText(), ErrorCodes::POCO_EXCEPTION);
|
2013-01-13 22:13:54 +00:00
|
|
|
|
}
|
|
|
|
|
catch (const Poco::Exception & e)
|
2012-05-08 05:42:05 +00:00
|
|
|
|
{
|
2015-06-29 21:35:35 +00:00
|
|
|
|
state.io.onException();
|
2016-05-28 14:14:18 +00:00
|
|
|
|
exception = std::make_unique<Exception>(e.displayText(), ErrorCodes::POCO_EXCEPTION);
|
2012-05-08 05:42:05 +00:00
|
|
|
|
}
|
2013-01-13 22:13:54 +00:00
|
|
|
|
catch (const std::exception & e)
|
2012-05-08 05:42:05 +00:00
|
|
|
|
{
|
2015-06-29 21:35:35 +00:00
|
|
|
|
state.io.onException();
|
2016-05-28 14:14:18 +00:00
|
|
|
|
exception = std::make_unique<Exception>(e.what(), ErrorCodes::STD_EXCEPTION);
|
2012-05-08 05:42:05 +00:00
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
2015-06-29 21:35:35 +00:00
|
|
|
|
state.io.onException();
|
2016-05-28 14:14:18 +00:00
|
|
|
|
exception = std::make_unique<Exception>("Unknown exception", ErrorCodes::UNKNOWN_EXCEPTION);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2013-01-28 17:31:08 +00:00
|
|
|
|
bool network_error = false;
|
|
|
|
|
|
2013-01-13 22:13:54 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2013-01-28 17:31:08 +00:00
|
|
|
|
if (exception)
|
2013-01-13 22:13:54 +00:00
|
|
|
|
sendException(*exception);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
/** Не удалось отправить информацию об эксепшене клиенту. */
|
2013-01-28 17:31:08 +00:00
|
|
|
|
network_error = true;
|
|
|
|
|
LOG_WARNING(log, "Client has gone away.");
|
2013-01-13 22:13:54 +00:00
|
|
|
|
}
|
2012-12-06 21:13:50 +00:00
|
|
|
|
|
2013-01-13 22:13:54 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
state.reset();
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
2012-12-06 17:32:48 +00:00
|
|
|
|
{
|
2013-01-13 22:13:54 +00:00
|
|
|
|
/** В процессе обработки запроса было исключение, которое мы поймали и, возможно, отправили клиенту.
|
|
|
|
|
* При уничтожении конвейера выполнения запроса, было второе исключение.
|
|
|
|
|
* Например, конвейер мог выполняться в нескольких потоках, и в каждом из них могло возникнуть исключение.
|
|
|
|
|
* Проигнорируем его.
|
|
|
|
|
*/
|
2012-12-06 17:32:48 +00:00
|
|
|
|
}
|
2012-05-08 05:42:05 +00:00
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
watch.stop();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
|
|
|
|
|
LOG_INFO(log, std::fixed << std::setprecision(3)
|
|
|
|
|
<< "Processed in " << watch.elapsedSeconds() << " sec.");
|
2013-01-28 17:31:08 +00:00
|
|
|
|
|
|
|
|
|
if (network_error)
|
|
|
|
|
break;
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-03-04 15:31:56 +00:00
|
|
|
|
void TCPHandler::readData(const Settings & global_settings)
|
2012-05-21 06:49:05 +00:00
|
|
|
|
{
|
2013-12-20 10:07:10 +00:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
2015-05-29 20:36:09 +00:00
|
|
|
|
Stopwatch watch(CLOCK_MONOTONIC_COARSE);
|
|
|
|
|
|
2013-12-20 10:07:10 +00:00
|
|
|
|
/// Ждём пакета от клиента. При этом, каждые POLL_INTERVAL сек. проверяем, не требуется ли завершить работу.
|
2015-05-29 20:36:09 +00:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
if (static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000))
|
|
|
|
|
break;
|
2013-12-20 10:07:10 +00:00
|
|
|
|
|
2015-05-29 20:36:09 +00:00
|
|
|
|
/// Если требуется завершить работу.
|
2016-02-09 17:06:50 +00:00
|
|
|
|
if (BaseDaemon::instance().isCancelled())
|
2015-05-29 20:36:09 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/** Если ждём данных уже слишком долго.
|
|
|
|
|
* Если периодически poll-ить соединение, то receive_timeout у сокета сам по себе не срабатывает.
|
|
|
|
|
* Поэтому, добавлена дополнительная проверка.
|
|
|
|
|
*/
|
|
|
|
|
if (watch.elapsedSeconds() > global_settings.receive_timeout.totalSeconds())
|
|
|
|
|
throw Exception("Timeout exceeded while receiving data from client", ErrorCodes::SOCKET_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Если клиент отсоединился.
|
|
|
|
|
if (in->eof())
|
2013-12-20 10:07:10 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2015-05-29 20:36:09 +00:00
|
|
|
|
/// Принимаем и обрабатываем данные. А если они закончились, то выходим.
|
2013-12-20 10:07:10 +00:00
|
|
|
|
if (!receivePacket())
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-03-04 15:31:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::processInsertQuery(const Settings & global_settings)
|
|
|
|
|
{
|
2014-09-18 19:49:31 +00:00
|
|
|
|
/** Сделано выше остальных строк, чтобы в случае, когда функция writePrefix кидает эксепшен,
|
|
|
|
|
* клиент получил эксепшен до того, как начнёт отправлять данные.
|
|
|
|
|
*/
|
|
|
|
|
state.io.out->writePrefix();
|
|
|
|
|
|
2014-03-04 15:31:56 +00:00
|
|
|
|
/// Отправляем клиенту блок - структура таблицы.
|
|
|
|
|
Block block = state.io.out_sample;
|
|
|
|
|
sendData(block);
|
|
|
|
|
|
|
|
|
|
readData(global_settings);
|
2012-08-08 19:45:34 +00:00
|
|
|
|
state.io.out->writeSuffix();
|
2015-07-14 03:05:10 +00:00
|
|
|
|
state.io.onFinish();
|
2012-05-21 06:49:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::processOrdinaryQuery()
|
|
|
|
|
{
|
2016-07-31 03:53:16 +00:00
|
|
|
|
/// Pull query execution result, if exists, and send it to network.
|
2012-05-21 06:49:05 +00:00
|
|
|
|
if (state.io.in)
|
|
|
|
|
{
|
2016-07-31 03:53:16 +00:00
|
|
|
|
/// Send header-block, to allow client to prepare output format for data to send.
|
|
|
|
|
if (state.io.in_sample)
|
2013-06-18 14:12:10 +00:00
|
|
|
|
sendData(state.io.in_sample);
|
2013-09-13 20:33:09 +00:00
|
|
|
|
|
2012-10-20 05:54:35 +00:00
|
|
|
|
AsynchronousBlockInputStream async_in(state.io.in);
|
2013-12-27 13:22:32 +00:00
|
|
|
|
async_in.readPrefix();
|
2012-05-30 03:30:29 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
while (true)
|
|
|
|
|
{
|
2012-10-20 05:54:35 +00:00
|
|
|
|
Block block;
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2012-10-20 05:54:35 +00:00
|
|
|
|
while (true)
|
|
|
|
|
{
|
2013-06-29 19:58:23 +00:00
|
|
|
|
if (isQueryCancelled())
|
2012-10-20 05:54:35 +00:00
|
|
|
|
{
|
2013-11-02 21:18:54 +00:00
|
|
|
|
/// Получен пакет с просьбой прекратить выполнение запроса.
|
2013-06-29 19:58:23 +00:00
|
|
|
|
async_in.cancel();
|
2012-10-20 05:54:35 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2013-11-03 05:32:42 +00:00
|
|
|
|
else
|
2012-10-20 06:40:55 +00:00
|
|
|
|
{
|
2014-10-25 18:33:52 +00:00
|
|
|
|
if (state.progress.rows && after_send_progress.elapsed() / 1000 >= query_context.getSettingsRef().interactive_delay)
|
2013-11-03 05:32:42 +00:00
|
|
|
|
{
|
|
|
|
|
/// Прошло некоторое время и есть прогресс.
|
|
|
|
|
after_send_progress.restart();
|
|
|
|
|
sendProgress();
|
|
|
|
|
}
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
2013-11-03 05:32:42 +00:00
|
|
|
|
if (async_in.poll(query_context.getSettingsRef().interactive_delay / 1000))
|
|
|
|
|
{
|
|
|
|
|
/// Есть следующий блок результата.
|
|
|
|
|
block = async_in.read();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-11-02 21:18:54 +00:00
|
|
|
|
}
|
2012-10-20 05:54:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-04 05:05:17 +00:00
|
|
|
|
/** Если закончились данные, то отправим данные профайлинга и тотальные значения до
|
|
|
|
|
* последнего нулевого блока, чтобы иметь возможность использовать
|
|
|
|
|
* эту информацию в выводе суффикса output stream'а.
|
|
|
|
|
* Если запрос был прерван, то вызывать методы sendTotals и другие нельзя,
|
|
|
|
|
* потому что мы прочитали ещё не все данные, и в это время могут производиться какие-то
|
|
|
|
|
* вычисления в других потоках.
|
|
|
|
|
*/
|
|
|
|
|
if (!block && !isQueryCancelled())
|
2013-09-05 20:22:43 +00:00
|
|
|
|
{
|
|
|
|
|
sendTotals();
|
2013-09-07 02:03:13 +00:00
|
|
|
|
sendExtremes();
|
2013-05-22 14:57:43 +00:00
|
|
|
|
sendProfileInfo();
|
2013-11-03 01:12:10 +00:00
|
|
|
|
sendProgress();
|
2013-09-05 20:22:43 +00:00
|
|
|
|
}
|
2014-08-22 02:31:54 +00:00
|
|
|
|
|
|
|
|
|
sendData(block);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
if (!block)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-07-21 07:02:55 +00:00
|
|
|
|
|
2013-12-27 13:22:32 +00:00
|
|
|
|
async_in.readSuffix();
|
2012-07-21 07:02:55 +00:00
|
|
|
|
}
|
2015-07-14 03:05:10 +00:00
|
|
|
|
|
|
|
|
|
state.io.onFinish();
|
2012-07-21 07:02:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-22 14:57:43 +00:00
|
|
|
|
void TCPHandler::sendProfileInfo()
|
|
|
|
|
{
|
|
|
|
|
if (const IProfilingBlockInputStream * input = dynamic_cast<const IProfilingBlockInputStream *>(&*state.io.in))
|
|
|
|
|
{
|
|
|
|
|
writeVarUInt(Protocol::Server::ProfileInfo, *out);
|
|
|
|
|
input->getInfo().write(*out);
|
|
|
|
|
out->next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-09-05 20:22:43 +00:00
|
|
|
|
void TCPHandler::sendTotals()
|
|
|
|
|
{
|
2013-09-08 08:27:06 +00:00
|
|
|
|
if (IProfilingBlockInputStream * input = dynamic_cast<IProfilingBlockInputStream *>(&*state.io.in))
|
2013-09-05 20:22:43 +00:00
|
|
|
|
{
|
|
|
|
|
const Block & totals = input->getTotals();
|
|
|
|
|
|
|
|
|
|
if (totals)
|
|
|
|
|
{
|
|
|
|
|
initBlockOutput();
|
|
|
|
|
|
|
|
|
|
writeVarUInt(Protocol::Server::Totals, *out);
|
2014-03-28 15:33:30 +00:00
|
|
|
|
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
|
|
|
|
writeStringBinary("", *out);
|
2013-09-05 20:22:43 +00:00
|
|
|
|
|
2013-09-06 23:43:11 +00:00
|
|
|
|
state.block_out->write(totals);
|
2013-09-05 20:22:43 +00:00
|
|
|
|
state.maybe_compressed_out->next();
|
|
|
|
|
out->next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-09-07 02:03:13 +00:00
|
|
|
|
void TCPHandler::sendExtremes()
|
|
|
|
|
{
|
|
|
|
|
if (const IProfilingBlockInputStream * input = dynamic_cast<const IProfilingBlockInputStream *>(&*state.io.in))
|
|
|
|
|
{
|
|
|
|
|
const Block & extremes = input->getExtremes();
|
|
|
|
|
|
|
|
|
|
if (extremes)
|
|
|
|
|
{
|
|
|
|
|
initBlockOutput();
|
|
|
|
|
|
|
|
|
|
writeVarUInt(Protocol::Server::Extremes, *out);
|
2014-03-28 15:33:30 +00:00
|
|
|
|
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
|
|
|
|
writeStringBinary("", *out);
|
2013-09-07 02:03:13 +00:00
|
|
|
|
|
|
|
|
|
state.block_out->write(extremes);
|
|
|
|
|
state.maybe_compressed_out->next();
|
|
|
|
|
out->next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
void TCPHandler::receiveHello()
|
2012-05-16 18:03:00 +00:00
|
|
|
|
{
|
|
|
|
|
/// Получить hello пакет.
|
|
|
|
|
UInt64 packet_type = 0;
|
|
|
|
|
String client_name;
|
|
|
|
|
UInt64 client_version_major = 0;
|
|
|
|
|
UInt64 client_version_minor = 0;
|
2013-08-10 09:04:45 +00:00
|
|
|
|
String user = "default";
|
|
|
|
|
String password;
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readVarUInt(packet_type, *in);
|
2012-05-16 18:03:00 +00:00
|
|
|
|
if (packet_type != Protocol::Client::Hello)
|
2014-03-02 19:52:55 +00:00
|
|
|
|
{
|
|
|
|
|
/** Если случайно обратились по протоколу HTTP на порт, предназначенный для внутреннего TCP-протокола,
|
|
|
|
|
* то вместо номера пакета будет G (GET) или P (POST), в большинстве случаев.
|
|
|
|
|
*/
|
|
|
|
|
if (packet_type == 'G' || packet_type == 'P')
|
|
|
|
|
{
|
|
|
|
|
writeString("HTTP/1.0 400 Bad Request\r\n\r\n"
|
2014-05-12 00:49:24 +00:00
|
|
|
|
"Port " + server.config().getString("tcp_port") + " is for clickhouse-client program.\r\n"
|
2016-07-30 01:08:00 +00:00
|
|
|
|
"You must use port " + server.config().getString("http_port") + " for HTTP.\r\n",
|
2014-03-02 19:52:55 +00:00
|
|
|
|
*out);
|
|
|
|
|
|
|
|
|
|
throw Exception("Client has connected to wrong port", ErrorCodes::CLIENT_HAS_CONNECTED_TO_WRONG_PORT);
|
|
|
|
|
}
|
|
|
|
|
else
|
2015-03-26 08:47:02 +00:00
|
|
|
|
throw NetException("Unexpected packet from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
2014-03-02 19:52:55 +00:00
|
|
|
|
}
|
2012-05-16 18:03:00 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readStringBinary(client_name, *in);
|
|
|
|
|
readVarUInt(client_version_major, *in);
|
|
|
|
|
readVarUInt(client_version_minor, *in);
|
|
|
|
|
readVarUInt(client_revision, *in);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
readStringBinary(default_database, *in);
|
2016-07-31 03:53:16 +00:00
|
|
|
|
readStringBinary(user, *in);
|
|
|
|
|
readStringBinary(password, *in);
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
2012-05-16 18:20:45 +00:00
|
|
|
|
LOG_DEBUG(log, "Connected " << client_name
|
|
|
|
|
<< " version " << client_version_major
|
2012-05-16 18:03:00 +00:00
|
|
|
|
<< "." << client_version_minor
|
|
|
|
|
<< "." << client_revision
|
2012-05-30 06:46:57 +00:00
|
|
|
|
<< (!default_database.empty() ? ", database: " + default_database : "")
|
2013-08-10 09:04:45 +00:00
|
|
|
|
<< (!user.empty() ? ", user: " + user : "")
|
2013-01-13 21:02:41 +00:00
|
|
|
|
<< ".");
|
2013-08-10 09:04:45 +00:00
|
|
|
|
|
2013-08-12 00:36:18 +00:00
|
|
|
|
connection_context.setUser(user, password, socket().peerAddress().host(), "");
|
2012-05-16 18:03:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
void TCPHandler::sendHello()
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Hello, *out);
|
|
|
|
|
writeStringBinary(DBMS_NAME, *out);
|
|
|
|
|
writeVarUInt(DBMS_VERSION_MAJOR, *out);
|
|
|
|
|
writeVarUInt(DBMS_VERSION_MINOR, *out);
|
2016-02-09 17:06:50 +00:00
|
|
|
|
writeVarUInt(ClickHouseRevision::get(), *out);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
out->next();
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-17 19:15:53 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
bool TCPHandler::receivePacket()
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
2013-09-14 07:58:42 +00:00
|
|
|
|
UInt64 packet_type = 0;
|
|
|
|
|
readVarUInt(packet_type, *in);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2013-09-14 07:58:42 +00:00
|
|
|
|
// std::cerr << "Packet: " << packet_type << std::endl;
|
2012-03-19 12:57:56 +00:00
|
|
|
|
|
2013-09-14 07:58:42 +00:00
|
|
|
|
switch (packet_type)
|
|
|
|
|
{
|
|
|
|
|
case Protocol::Client::Query:
|
|
|
|
|
if (!state.empty())
|
2015-03-26 08:47:02 +00:00
|
|
|
|
throw NetException("Unexpected packet Query received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
2013-09-14 07:58:42 +00:00
|
|
|
|
receiveQuery();
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case Protocol::Client::Data:
|
|
|
|
|
if (state.empty())
|
2015-03-26 08:47:02 +00:00
|
|
|
|
throw NetException("Unexpected packet Data received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
2013-09-14 07:58:42 +00:00
|
|
|
|
return receiveData();
|
|
|
|
|
|
|
|
|
|
case Protocol::Client::Ping:
|
|
|
|
|
writeVarUInt(Protocol::Server::Pong, *out);
|
|
|
|
|
out->next();
|
|
|
|
|
return false;
|
2012-05-17 19:15:53 +00:00
|
|
|
|
|
2013-09-14 07:58:42 +00:00
|
|
|
|
case Protocol::Client::Cancel:
|
|
|
|
|
return false;
|
2012-10-20 06:40:55 +00:00
|
|
|
|
|
2013-09-14 07:58:42 +00:00
|
|
|
|
case Protocol::Client::Hello:
|
|
|
|
|
throw Exception("Unexpected packet " + String(Protocol::Client::toString(packet_type)) + " received from client",
|
|
|
|
|
ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown packet from client", ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
2012-03-09 15:46:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-17 19:15:53 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
void TCPHandler::receiveQuery()
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
|
|
|
|
UInt64 stage = 0;
|
|
|
|
|
UInt64 compression = 0;
|
2013-09-14 07:58:42 +00:00
|
|
|
|
|
2014-02-14 15:59:01 +00:00
|
|
|
|
state.is_empty = false;
|
2016-07-31 03:53:16 +00:00
|
|
|
|
readStringBinary(state.query_id, *in);
|
2014-02-12 17:31:02 +00:00
|
|
|
|
|
|
|
|
|
query_context.setCurrentQueryId(state.query_id);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2016-07-31 03:53:16 +00:00
|
|
|
|
/// Per query settings.
|
|
|
|
|
query_context.getSettingsRef().deserialize(*in);
|
2013-02-01 19:02:04 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readVarUInt(stage, *in);
|
2012-05-09 13:12:38 +00:00
|
|
|
|
state.stage = QueryProcessingStage::Enum(stage);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readVarUInt(compression, *in);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
state.compression = Protocol::Compression::Enum(compression);
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readStringBinary(state.query, *in);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
|
|
|
|
bool TCPHandler::receiveData()
|
2013-09-05 20:22:43 +00:00
|
|
|
|
{
|
|
|
|
|
initBlockInput();
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
|
|
|
|
/// Имя временной таблицы для записи данных, по умолчанию пустая строка
|
2014-03-13 15:00:06 +00:00
|
|
|
|
String external_table_name;
|
|
|
|
|
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
|
|
|
|
readStringBinary(external_table_name, *in);
|
2014-03-04 15:31:56 +00:00
|
|
|
|
|
|
|
|
|
/// Прочитать из сети один блок и записать его
|
2013-09-05 20:22:43 +00:00
|
|
|
|
Block block = state.block_in->read();
|
2014-03-27 11:30:08 +00:00
|
|
|
|
|
|
|
|
|
if (block)
|
2013-09-05 20:22:43 +00:00
|
|
|
|
{
|
2014-03-04 15:31:56 +00:00
|
|
|
|
/// Если запрос на вставку, то данные нужно писать напрямую в state.io.out.
|
2014-03-13 15:00:06 +00:00
|
|
|
|
/// Иначе пишем блоки во временную таблицу external_table_name.
|
2014-11-08 23:54:03 +00:00
|
|
|
|
if (!state.need_receive_data_for_insert)
|
2014-03-04 15:31:56 +00:00
|
|
|
|
{
|
|
|
|
|
StoragePtr storage;
|
|
|
|
|
/// Если такой таблицы не существовало, создаем ее.
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (!(storage = query_context.tryGetExternalTable(external_table_name)))
|
2014-03-04 15:31:56 +00:00
|
|
|
|
{
|
2016-05-28 08:15:50 +00:00
|
|
|
|
NamesAndTypesListPtr columns = std::make_shared<NamesAndTypesList>(block.getColumnsList());
|
2014-03-13 15:00:06 +00:00
|
|
|
|
storage = StorageMemory::create(external_table_name, columns);
|
|
|
|
|
query_context.addExternalTable(external_table_name, storage);
|
2014-03-04 15:31:56 +00:00
|
|
|
|
}
|
|
|
|
|
/// Данные будем писать напрямую в таблицу.
|
2015-09-10 21:36:48 +00:00
|
|
|
|
state.io.out = storage->write(ASTPtr(), query_context.getSettingsRef());
|
2014-03-04 15:31:56 +00:00
|
|
|
|
}
|
2014-03-19 15:07:29 +00:00
|
|
|
|
if (block)
|
|
|
|
|
state.io.out->write(block);
|
2013-09-05 20:22:43 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::initBlockInput()
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
2012-03-19 12:57:56 +00:00
|
|
|
|
if (!state.block_in)
|
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
if (state.compression == Protocol::Compression::Enable)
|
2016-05-28 14:14:18 +00:00
|
|
|
|
state.maybe_compressed_in = std::make_shared<CompressedReadBuffer>(*in);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
else
|
|
|
|
|
state.maybe_compressed_in = in;
|
2012-03-19 12:57:56 +00:00
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
state.block_in = std::make_shared<NativeBlockInputStream>(
|
2012-03-19 12:57:56 +00:00
|
|
|
|
*state.maybe_compressed_in,
|
2015-01-03 03:18:49 +00:00
|
|
|
|
client_revision);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2013-09-05 20:22:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::initBlockOutput()
|
|
|
|
|
{
|
|
|
|
|
if (!state.block_out)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2013-09-05 20:22:43 +00:00
|
|
|
|
if (state.compression == Protocol::Compression::Enable)
|
2016-05-28 14:14:18 +00:00
|
|
|
|
state.maybe_compressed_out = std::make_shared<CompressedWriteBuffer>(
|
2016-07-01 21:02:13 +00:00
|
|
|
|
*out, query_context.getSettingsRef().network_compression_method);
|
2013-09-05 20:22:43 +00:00
|
|
|
|
else
|
|
|
|
|
state.maybe_compressed_out = out;
|
|
|
|
|
|
2016-05-28 12:22:22 +00:00
|
|
|
|
state.block_out = std::make_shared<NativeBlockOutputStream>(
|
2013-09-05 20:22:43 +00:00
|
|
|
|
*state.maybe_compressed_out,
|
2015-01-03 03:18:49 +00:00
|
|
|
|
client_revision);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
|
|
|
|
bool TCPHandler::isQueryCancelled()
|
2012-05-09 08:16:09 +00:00
|
|
|
|
{
|
2012-05-09 16:55:56 +00:00
|
|
|
|
if (state.is_cancelled || state.sent_all_data)
|
2012-05-09 15:50:42 +00:00
|
|
|
|
return true;
|
2012-10-20 05:54:35 +00:00
|
|
|
|
|
2013-02-01 19:02:04 +00:00
|
|
|
|
if (after_check_cancelled.elapsed() / 1000 < query_context.getSettingsRef().interactive_delay)
|
2012-05-09 15:15:45 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
after_check_cancelled.restart();
|
2012-10-20 05:54:35 +00:00
|
|
|
|
|
2012-05-09 08:16:09 +00:00
|
|
|
|
/// Во время выполнения запроса, единственный пакет, который может прийти от клиента - это остановка выполнения запроса.
|
2014-02-27 22:24:38 +00:00
|
|
|
|
if (static_cast<ReadBufferFromPocoSocket &>(*in).poll(0))
|
2012-05-09 08:16:09 +00:00
|
|
|
|
{
|
|
|
|
|
UInt64 packet_type = 0;
|
2012-05-21 06:49:05 +00:00
|
|
|
|
readVarUInt(packet_type, *in);
|
2012-05-09 08:16:09 +00:00
|
|
|
|
|
|
|
|
|
switch (packet_type)
|
|
|
|
|
{
|
|
|
|
|
case Protocol::Client::Cancel:
|
|
|
|
|
if (state.empty())
|
2015-03-26 08:47:02 +00:00
|
|
|
|
throw NetException("Unexpected packet Cancel received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
2012-05-09 08:16:09 +00:00
|
|
|
|
LOG_INFO(log, "Query was cancelled.");
|
2012-05-09 15:50:42 +00:00
|
|
|
|
state.is_cancelled = true;
|
2012-05-09 08:16:09 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
2015-03-26 08:47:02 +00:00
|
|
|
|
throw NetException("Unknown packet from client", ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
2012-05-09 08:16:09 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
|
|
|
|
void TCPHandler::sendData(Block & block)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2013-09-05 20:22:43 +00:00
|
|
|
|
initBlockOutput();
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Data, *out);
|
2014-03-13 15:00:06 +00:00
|
|
|
|
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
2014-03-04 15:31:56 +00:00
|
|
|
|
writeStringBinary("", *out);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
|
|
|
|
state.block_out->write(block);
|
|
|
|
|
state.maybe_compressed_out->next();
|
|
|
|
|
out->next();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
2012-05-30 06:46:57 +00:00
|
|
|
|
void TCPHandler::sendException(const Exception & e)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Exception, *out);
|
2012-05-30 06:46:57 +00:00
|
|
|
|
writeException(e, *out);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
out->next();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
|
|
|
|
void TCPHandler::sendEndOfStream()
|
2012-05-08 11:19:00 +00:00
|
|
|
|
{
|
2012-07-15 21:43:04 +00:00
|
|
|
|
state.sent_all_data = true;
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::EndOfStream, *out);
|
|
|
|
|
out->next();
|
2012-05-08 11:19:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 06:49:05 +00:00
|
|
|
|
|
2014-10-25 18:33:52 +00:00
|
|
|
|
void TCPHandler::updateProgress(const Progress & value)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2014-10-25 18:33:52 +00:00
|
|
|
|
state.progress.incrementPiecewiseAtomically(value);
|
2013-11-02 21:18:54 +00:00
|
|
|
|
}
|
2012-05-09 15:15:45 +00:00
|
|
|
|
|
|
|
|
|
|
2013-11-02 21:18:54 +00:00
|
|
|
|
void TCPHandler::sendProgress()
|
|
|
|
|
{
|
2012-05-21 06:49:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Progress, *out);
|
2014-10-25 18:33:52 +00:00
|
|
|
|
Progress increment = state.progress.fetchAndResetPiecewiseAtomically();
|
|
|
|
|
increment.write(*out, client_revision);
|
2012-05-21 06:49:05 +00:00
|
|
|
|
out->next();
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
|
|
|
|
void TCPHandler::run()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
runImpl();
|
|
|
|
|
|
|
|
|
|
LOG_INFO(log, "Done processing connection.");
|
|
|
|
|
}
|
|
|
|
|
catch (Poco::Exception & e)
|
|
|
|
|
{
|
2012-08-02 18:02:57 +00:00
|
|
|
|
/// Таймаут - не ошибка.
|
|
|
|
|
if (!strcmp(e.what(), "Timeout"))
|
|
|
|
|
{
|
2016-01-14 03:17:11 +00:00
|
|
|
|
LOG_DEBUG(log, "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
|
|
|
|
|
<< ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what());
|
2012-08-02 18:02:57 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2016-01-14 03:17:11 +00:00
|
|
|
|
throw;
|
2012-03-09 15:46:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|