2020-06-02 16:27:05 +00:00
|
|
|
#pragma once
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Client/ConnectionPool.h>
|
|
|
|
#include <Client/MultiplexedConnections.h>
|
2020-12-02 17:02:14 +00:00
|
|
|
#include <Common/FiberStack.h>
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
class Throttler;
|
|
|
|
using ThrottlerPtr = std::shared_ptr<Throttler>;
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
struct Progress;
|
|
|
|
using ProgressCallback = std::function<void(const Progress & progress)>;
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
struct BlockStreamProfileInfo;
|
|
|
|
using ProfileInfoCallback = std::function<void(const BlockStreamProfileInfo & info)>;
|
|
|
|
|
|
|
|
/// This class allows one to launch queries on remote replicas of one shard and get results
|
|
|
|
class RemoteQueryExecutor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/// Takes already set connection.
|
|
|
|
/// If `settings` is nullptr, settings will be taken from context.
|
|
|
|
RemoteQueryExecutor(
|
|
|
|
Connection & connection,
|
|
|
|
const String & query_, const Block & header_, const Context & context_, const Settings * settings = nullptr,
|
|
|
|
ThrottlerPtr throttler_ = nullptr, const Scalars & scalars_ = Scalars(), const Tables & external_tables_ = Tables(),
|
|
|
|
QueryProcessingStage::Enum stage_ = QueryProcessingStage::Complete);
|
|
|
|
|
|
|
|
/// Accepts several connections already taken from pool.
|
|
|
|
/// If `settings` is nullptr, settings will be taken from context.
|
|
|
|
RemoteQueryExecutor(
|
|
|
|
std::vector<IConnectionPool::Entry> && connections,
|
|
|
|
const String & query_, const Block & header_, const Context & context_, const Settings * settings = nullptr,
|
|
|
|
const ThrottlerPtr & throttler = nullptr, const Scalars & scalars_ = Scalars(), const Tables & external_tables_ = Tables(),
|
|
|
|
QueryProcessingStage::Enum stage_ = QueryProcessingStage::Complete);
|
|
|
|
|
|
|
|
/// Takes a pool and gets one or several connections from it.
|
|
|
|
/// If `settings` is nullptr, settings will be taken from context.
|
|
|
|
RemoteQueryExecutor(
|
|
|
|
const ConnectionPoolWithFailoverPtr & pool,
|
|
|
|
const String & query_, const Block & header_, const Context & context_, const Settings * settings = nullptr,
|
|
|
|
const ThrottlerPtr & throttler = nullptr, const Scalars & scalars_ = Scalars(), const Tables & external_tables_ = Tables(),
|
|
|
|
QueryProcessingStage::Enum stage_ = QueryProcessingStage::Complete);
|
|
|
|
|
|
|
|
~RemoteQueryExecutor();
|
|
|
|
|
2020-12-02 17:02:14 +00:00
|
|
|
struct ReadContext
|
|
|
|
{
|
|
|
|
bool is_read_in_progress = false;
|
|
|
|
|
|
|
|
/// If is_read_in_progress, use this fd to poll
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/// If not is_read_in_progress, result block is set.
|
|
|
|
Block result;
|
|
|
|
|
|
|
|
/// Internal data
|
|
|
|
|
|
|
|
boost::context::fiber fiber;
|
|
|
|
Packet packet;
|
|
|
|
std::exception_ptr exception;
|
|
|
|
FiberStack<> stack;
|
|
|
|
ReadBufferFromPocoSocket::Fiber fiber_context;
|
|
|
|
};
|
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
/// Create connection and send query, external tables and scalars.
|
|
|
|
void sendQuery();
|
|
|
|
|
|
|
|
/// Read next block of data. Returns empty block if query is finished.
|
|
|
|
Block read();
|
2020-12-02 17:02:14 +00:00
|
|
|
void read(ReadContext & read_context);
|
2020-06-02 16:27:05 +00:00
|
|
|
|
|
|
|
/// Receive all remain packets and finish query.
|
|
|
|
/// It should be cancelled after read returned empty block.
|
|
|
|
void finish();
|
|
|
|
|
|
|
|
/// Cancel query execution. Sends Cancel packet and ignore others.
|
|
|
|
/// This method may be called from separate thread.
|
|
|
|
void cancel();
|
|
|
|
|
|
|
|
/// Get totals and extremes if any.
|
2020-06-04 13:16:58 +00:00
|
|
|
Block getTotals() { return std::move(totals); }
|
|
|
|
Block getExtremes() { return std::move(extremes); }
|
2020-06-02 16:27:05 +00:00
|
|
|
|
|
|
|
/// Set callback for progress. It will be called on Progress packet.
|
|
|
|
void setProgressCallback(ProgressCallback callback) { progress_callback = std::move(callback); }
|
|
|
|
|
|
|
|
/// Set callback for profile info. It will be called on ProfileInfo packet.
|
|
|
|
void setProfileInfoCallback(ProfileInfoCallback callback) { profile_info_callback = std::move(callback); }
|
|
|
|
|
|
|
|
/// Set the query_id. For now, used by performance test to later find the query
|
|
|
|
/// in the server query_log. Must be called before sending the query to the server.
|
|
|
|
void setQueryId(const std::string& query_id_) { assert(!sent_query); query_id = query_id_; }
|
|
|
|
|
|
|
|
/// Specify how we allocate connections on a shard.
|
|
|
|
void setPoolMode(PoolMode pool_mode_) { pool_mode = pool_mode_; }
|
|
|
|
|
|
|
|
void setMainTable(StorageID main_table_) { main_table = std::move(main_table_); }
|
|
|
|
|
|
|
|
void setLogger(Poco::Logger * logger) { log = logger; }
|
|
|
|
|
|
|
|
const Block & getHeader() const { return header; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Block header;
|
|
|
|
Block totals;
|
|
|
|
Block extremes;
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
std::function<std::unique_ptr<MultiplexedConnections>()> create_multiplexed_connections;
|
|
|
|
std::unique_ptr<MultiplexedConnections> multiplexed_connections;
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
const String query;
|
|
|
|
String query_id = "";
|
|
|
|
Context context;
|
|
|
|
|
|
|
|
ProgressCallback progress_callback;
|
|
|
|
ProfileInfoCallback profile_info_callback;
|
|
|
|
|
|
|
|
/// Scalars needed to be sent to remote servers
|
|
|
|
Scalars scalars;
|
|
|
|
/// Temporary tables needed to be sent to remote servers
|
|
|
|
Tables external_tables;
|
|
|
|
QueryProcessingStage::Enum stage;
|
|
|
|
|
|
|
|
/// Streams for reading from temporary tables and following sending of data
|
|
|
|
/// to remote servers for GLOBAL-subqueries
|
|
|
|
std::vector<ExternalTablesData> external_tables_data;
|
|
|
|
std::mutex external_tables_mutex;
|
|
|
|
|
|
|
|
/// Connections to replicas are established, but no queries are sent yet
|
|
|
|
std::atomic<bool> established { false };
|
|
|
|
|
|
|
|
/// Query is sent (used before getting first block)
|
|
|
|
std::atomic<bool> sent_query { false };
|
|
|
|
|
|
|
|
/** All data from all replicas are received, before EndOfStream packet.
|
|
|
|
* To prevent desynchronization, if not all data is read before object
|
|
|
|
* destruction, it's required to send cancel query request to replicas and
|
|
|
|
* read all packets before EndOfStream
|
|
|
|
*/
|
|
|
|
std::atomic<bool> finished { false };
|
|
|
|
|
|
|
|
/** Cancel query request was sent to all replicas because data is not needed anymore
|
|
|
|
* This behaviour may occur when:
|
|
|
|
* - data size is already satisfactory (when using LIMIT, for example)
|
|
|
|
* - an exception was thrown from client side
|
|
|
|
*/
|
|
|
|
std::atomic<bool> was_cancelled { false };
|
|
|
|
std::mutex was_cancelled_mutex;
|
|
|
|
|
|
|
|
/** An exception from replica was received. No need in receiving more packets or
|
|
|
|
* requesting to cancel query execution
|
|
|
|
*/
|
|
|
|
std::atomic<bool> got_exception_from_replica { false };
|
|
|
|
|
|
|
|
/** Unknown packet was received from replica. No need in receiving more packets or
|
|
|
|
* requesting to cancel query execution
|
|
|
|
*/
|
|
|
|
std::atomic<bool> got_unknown_packet_from_replica { false };
|
|
|
|
|
|
|
|
PoolMode pool_mode = PoolMode::GET_MANY;
|
|
|
|
StorageID main_table = StorageID::createEmpty();
|
|
|
|
|
|
|
|
Poco::Logger * log = nullptr;
|
|
|
|
|
|
|
|
/// Send all scalars to remote servers
|
|
|
|
void sendScalars();
|
|
|
|
|
|
|
|
/// Send all temporary tables to remote servers
|
|
|
|
void sendExternalTables();
|
|
|
|
|
|
|
|
/// If wasn't sent yet, send request to cancel all connections to replicas
|
|
|
|
void tryCancel(const char * reason);
|
|
|
|
|
|
|
|
/// Returns true if query was sent
|
|
|
|
bool isQueryPending() const;
|
|
|
|
|
|
|
|
/// Returns true if exception was thrown
|
|
|
|
bool hasThrownException() const;
|
2020-12-02 17:02:14 +00:00
|
|
|
|
|
|
|
/// Process packet for read and return data block if possible.
|
|
|
|
std::optional<Block> processPacket(Packet packet);
|
2020-06-02 16:27:05 +00:00
|
|
|
};
|
2020-06-02 15:59:57 +00:00
|
|
|
|
2020-06-02 16:27:05 +00:00
|
|
|
}
|