2012-03-19 12:57:56 +00:00
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
2012-05-09 08:16:09 +00:00
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
|
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include <Yandex/Revision.h>
|
|
|
|
|
|
|
|
|
|
#include <statdaemons/Stopwatch.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/IO/ReadBufferFromPocoSocket.h>
|
|
|
|
|
#include <DB/IO/WriteBufferFromPocoSocket.h>
|
2012-03-11 08:52:56 +00:00
|
|
|
|
#include <DB/IO/CompressedReadBuffer.h>
|
|
|
|
|
#include <DB/IO/CompressedWriteBuffer.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include <DB/IO/copyData.h>
|
|
|
|
|
|
2012-05-09 08:16:09 +00:00
|
|
|
|
#include <DB/DataStreams/IProfilingBlockInputStream.h>
|
2012-03-09 15:46:52 +00:00
|
|
|
|
#include <DB/Interpreters/executeQuery.h>
|
|
|
|
|
|
|
|
|
|
#include "TCPHandler.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::runImpl()
|
|
|
|
|
{
|
|
|
|
|
ReadBufferFromPocoSocket in(socket());
|
|
|
|
|
WriteBufferFromPocoSocket out(socket());
|
2012-03-19 12:57:56 +00:00
|
|
|
|
WriteBufferFromPocoSocket out_for_chunks(socket());
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
|
|
|
|
/// Сразу после соединения, отправляем hello-пакет.
|
|
|
|
|
sendHello(out);
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
while (!in.eof())
|
2012-03-09 15:46:52 +00:00
|
|
|
|
{
|
2012-03-19 12:57:56 +00:00
|
|
|
|
Stopwatch watch;
|
2012-05-09 08:16:09 +00:00
|
|
|
|
state.reset();
|
2012-05-08 05:42:05 +00:00
|
|
|
|
|
|
|
|
|
try
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2012-05-08 05:42:05 +00:00
|
|
|
|
/// Пакет с запросом.
|
2012-05-09 13:12:38 +00:00
|
|
|
|
receivePacket(in, out);
|
2012-05-08 05:42:05 +00:00
|
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Query ID: " << state.query_id);
|
|
|
|
|
LOG_DEBUG(log, "Query: " << state.query);
|
|
|
|
|
LOG_DEBUG(log, "In format: " << state.in_format);
|
|
|
|
|
LOG_DEBUG(log, "Out format: " << state.out_format);
|
|
|
|
|
|
|
|
|
|
state.exception = NULL;
|
|
|
|
|
|
|
|
|
|
/// Читаем из сети данные для INSERT-а, если надо, и вставляем их.
|
|
|
|
|
if (state.io.out)
|
|
|
|
|
{
|
2012-05-09 13:12:38 +00:00
|
|
|
|
while (receivePacket(in, out))
|
2012-05-08 05:42:05 +00:00
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Вынимаем результат выполнения запроса, если есть, и пишем его в сеть.
|
|
|
|
|
if (state.io.in)
|
|
|
|
|
{
|
2012-05-09 08:16:09 +00:00
|
|
|
|
if (IProfilingBlockInputStream * profiling_in = dynamic_cast<IProfilingBlockInputStream *>(&*state.io.in))
|
|
|
|
|
profiling_in->setIsCancelledCallback(boost::bind(&TCPHandler::isQueryCancelled, this, boost::ref(in)));
|
|
|
|
|
|
2012-05-08 05:42:05 +00:00
|
|
|
|
while (sendData(out, out_for_chunks))
|
|
|
|
|
;
|
|
|
|
|
}
|
2012-05-08 11:19:00 +00:00
|
|
|
|
else
|
|
|
|
|
sendOk(out);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2012-05-08 05:42:05 +00:00
|
|
|
|
catch (DB::Exception & e)
|
2012-03-19 12:57:56 +00:00
|
|
|
|
{
|
2012-05-08 05:42:05 +00:00
|
|
|
|
LOG_ERROR(log, "DB::Exception. Code: " << e.code() << ", e.displayText() = " << e.displayText()
|
|
|
|
|
<< ", Stack trace:\n\n" << e.getStackTrace().toString());
|
|
|
|
|
state.exception = e.clone();
|
|
|
|
|
}
|
|
|
|
|
catch (Poco::Exception & e)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(log, "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code() << ", e.displayText() = " << e.displayText());
|
|
|
|
|
state.exception = new Exception(e.message(), e.code());
|
|
|
|
|
}
|
|
|
|
|
catch (std::exception & e)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(log, "std::exception. Code: " << ErrorCodes::STD_EXCEPTION << ", e.what() = " << e.what());
|
|
|
|
|
state.exception = new Exception(e.what(), ErrorCodes::STD_EXCEPTION);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(log, "Unknown exception. Code: " << ErrorCodes::UNKNOWN_EXCEPTION);
|
|
|
|
|
state.exception = new Exception("Unknown exception", ErrorCodes::UNKNOWN_EXCEPTION);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
2012-03-09 15:46:52 +00:00
|
|
|
|
|
2012-05-08 05:42:05 +00:00
|
|
|
|
if (state.exception)
|
|
|
|
|
sendException(out);
|
|
|
|
|
|
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.");
|
|
|
|
|
}
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TCPHandler::sendHello(WriteBuffer & out)
|
|
|
|
|
{
|
|
|
|
|
writeVarUInt(Protocol::Server::Hello, out);
|
|
|
|
|
writeStringBinary(DBMS_NAME, out);
|
|
|
|
|
writeVarUInt(DBMS_VERSION_MAJOR, out);
|
|
|
|
|
writeVarUInt(DBMS_VERSION_MINOR, out);
|
|
|
|
|
writeVarUInt(Revision::get(), out);
|
|
|
|
|
out.next();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-09 13:12:38 +00:00
|
|
|
|
bool TCPHandler::receivePacket(ReadBuffer & in, WriteBuffer & out)
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
2012-05-09 13:12:38 +00:00
|
|
|
|
while (true) /// Если пришёл пакет типа Ping, то игнорируем его и получаем следующий пакет.
|
|
|
|
|
{
|
|
|
|
|
UInt64 packet_type = 0;
|
|
|
|
|
readVarUInt(packet_type, in);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-09 13:12:38 +00:00
|
|
|
|
std::cerr << "Packet: " << packet_type << std::endl;
|
2012-03-19 12:57:56 +00:00
|
|
|
|
|
2012-05-09 13:12:38 +00:00
|
|
|
|
switch (packet_type)
|
|
|
|
|
{
|
|
|
|
|
case Protocol::Client::Query:
|
|
|
|
|
if (!state.empty())
|
|
|
|
|
throw Exception("Unexpected packet Query received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
|
|
|
|
receiveQuery(in);
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case Protocol::Client::Data:
|
|
|
|
|
if (state.empty())
|
|
|
|
|
throw Exception("Unexpected packet Data received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
|
|
|
|
return receiveData(in);
|
|
|
|
|
|
|
|
|
|
case Protocol::Client::Ping:
|
|
|
|
|
writeVarUInt(Protocol::Server::Pong, out);
|
|
|
|
|
out.next();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown packet from client", ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
|
|
|
|
}
|
2012-03-09 15:46:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-11 08:52:56 +00:00
|
|
|
|
void TCPHandler::receiveQuery(ReadBuffer & in)
|
|
|
|
|
{
|
|
|
|
|
UInt64 stage = 0;
|
|
|
|
|
UInt64 compression = 0;
|
|
|
|
|
|
|
|
|
|
readIntBinary(state.query_id, in);
|
|
|
|
|
|
|
|
|
|
readVarUInt(stage, in);
|
2012-05-09 13:12:38 +00:00
|
|
|
|
state.stage = QueryProcessingStage::Enum(stage);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
|
|
|
|
readVarUInt(compression, in);
|
|
|
|
|
state.compression = Protocol::Compression::Enum(compression);
|
|
|
|
|
|
|
|
|
|
readStringBinary(state.in_format, in);
|
|
|
|
|
readStringBinary(state.out_format, in);
|
|
|
|
|
|
|
|
|
|
readStringBinary(state.query, in);
|
2012-03-19 12:57:56 +00:00
|
|
|
|
|
|
|
|
|
state.context = server.global_context;
|
|
|
|
|
state.io = executeQuery(state.query, state.context);
|
2012-03-11 08:52:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
bool TCPHandler::receiveData(ReadBuffer & in)
|
2012-03-11 08:52:56 +00:00
|
|
|
|
{
|
2012-03-19 12:57:56 +00:00
|
|
|
|
if (!state.block_in)
|
|
|
|
|
{
|
|
|
|
|
state.chunked_in = new ChunkedReadBuffer(in, state.query_id);
|
|
|
|
|
state.maybe_compressed_in = state.compression == Protocol::Compression::Enable
|
|
|
|
|
? new CompressedReadBuffer(*state.chunked_in)
|
|
|
|
|
: state.chunked_in;
|
|
|
|
|
|
|
|
|
|
state.block_in = state.context.format_factory->getInput(
|
|
|
|
|
state.out_format,
|
|
|
|
|
*state.maybe_compressed_in,
|
|
|
|
|
state.io.out_sample,
|
|
|
|
|
state.context.settings.max_block_size,
|
|
|
|
|
*state.context.data_type_factory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Прочитать из сети один блок и засунуть его в state.io.out (данные для INSERT-а)
|
|
|
|
|
Block block = state.block_in->read();
|
|
|
|
|
if (block)
|
|
|
|
|
{
|
|
|
|
|
state.io.out->write(block);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-09 08:16:09 +00:00
|
|
|
|
bool TCPHandler::isQueryCancelled(ReadBufferFromPocoSocket & in)
|
|
|
|
|
{
|
|
|
|
|
/// Во время выполнения запроса, единственный пакет, который может прийти от клиента - это остановка выполнения запроса.
|
|
|
|
|
std::cerr << "checking cancelled" << std::endl;
|
|
|
|
|
if (in.poll(0))
|
|
|
|
|
{
|
|
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(is_cancelled_mutex);
|
|
|
|
|
|
|
|
|
|
std::cerr << "checking cancelled; socket has data" << std::endl;
|
|
|
|
|
|
|
|
|
|
UInt64 packet_type = 0;
|
|
|
|
|
readVarUInt(packet_type, in);
|
|
|
|
|
|
|
|
|
|
switch (packet_type)
|
|
|
|
|
{
|
|
|
|
|
case Protocol::Client::Cancel:
|
|
|
|
|
if (state.empty())
|
|
|
|
|
throw Exception("Unexpected packet Cancel received from client", ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT);
|
|
|
|
|
LOG_INFO(log, "Query was cancelled.");
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown packet from client", ErrorCodes::UNKNOWN_PACKET_FROM_CLIENT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
bool TCPHandler::sendData(WriteBuffer & out, WriteBuffer & out_for_chunks)
|
|
|
|
|
{
|
2012-05-09 08:16:09 +00:00
|
|
|
|
/// Получить один блок результата выполнения запроса из state.io.in.
|
|
|
|
|
Block block = state.io.in->read();
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Data, out);
|
|
|
|
|
out.next();
|
|
|
|
|
|
|
|
|
|
if (!state.block_out)
|
|
|
|
|
{
|
2012-05-09 08:16:09 +00:00
|
|
|
|
std::cerr << "query_id: " << state.query_id << std::endl;
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
state.chunked_out = new ChunkedWriteBuffer(out_for_chunks, state.query_id);
|
|
|
|
|
state.maybe_compressed_out = state.compression == Protocol::Compression::Enable
|
|
|
|
|
? new CompressedWriteBuffer(*state.chunked_out)
|
|
|
|
|
: state.chunked_out;
|
|
|
|
|
|
|
|
|
|
state.block_out = state.context.format_factory->getOutput(
|
|
|
|
|
state.in_format,
|
|
|
|
|
*state.maybe_compressed_out,
|
|
|
|
|
state.io.in_sample);
|
|
|
|
|
}
|
2012-03-11 08:52:56 +00:00
|
|
|
|
|
2012-05-09 08:16:09 +00:00
|
|
|
|
/// Если блок есть - записать его в сеть. Иначе записать в сеть признак конца данных.
|
2012-03-19 12:57:56 +00:00
|
|
|
|
if (block)
|
|
|
|
|
{
|
|
|
|
|
state.block_out->write(block);
|
2012-03-25 07:52:31 +00:00
|
|
|
|
state.maybe_compressed_out->next();
|
|
|
|
|
state.chunked_out->next();
|
|
|
|
|
out_for_chunks.next();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dynamic_cast<ChunkedWriteBuffer &>(*state.chunked_out).finish();
|
2012-03-25 07:52:31 +00:00
|
|
|
|
out_for_chunks.next();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TCPHandler::sendException(WriteBuffer & out)
|
|
|
|
|
{
|
2012-05-08 05:42:05 +00:00
|
|
|
|
writeVarUInt(Protocol::Server::Exception, out);
|
|
|
|
|
writeException(*state.exception, out);
|
|
|
|
|
out.next();
|
2012-03-19 12:57:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-08 11:19:00 +00:00
|
|
|
|
void TCPHandler::sendOk(WriteBuffer & out)
|
|
|
|
|
{
|
|
|
|
|
writeVarUInt(Protocol::Server::Ok, out);
|
|
|
|
|
out.next();
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 12:57:56 +00:00
|
|
|
|
void TCPHandler::sendProgress(WriteBuffer & out)
|
|
|
|
|
{
|
|
|
|
|
/// TODO
|
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)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << "Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
|
|
|
|
|
<< ", e.message() = " << e.message() << ", e.what() = " << e.what();
|
|
|
|
|
LOG_ERROR(log, s.str());
|
|
|
|
|
}
|
|
|
|
|
catch (std::exception & e)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << "Code: " << ErrorCodes::STD_EXCEPTION << ". " << e.what();
|
|
|
|
|
LOG_ERROR(log, s.str());
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << "Code: " << ErrorCodes::UNKNOWN_EXCEPTION << ". Unknown exception.";
|
|
|
|
|
LOG_ERROR(log, s.str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|