2014-10-26 00:01:36 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
#include <thread>
|
2017-06-06 17:18:32 +00:00
|
|
|
#include <ext/shared_ptr_helper.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Core/NamesAndTypes.h>
|
2019-01-14 19:22:09 +00:00
|
|
|
#include <Common/ThreadPool.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Storages/IStorage.h>
|
|
|
|
#include <DataStreams/IBlockOutputStream.h>
|
2017-02-07 15:38:57 +00:00
|
|
|
#include <Poco/Event.h>
|
2014-10-26 00:01:36 +00:00
|
|
|
|
|
|
|
|
2017-01-21 04:24:28 +00:00
|
|
|
namespace Poco { class Logger; }
|
|
|
|
|
|
|
|
|
2014-10-26 00:01:36 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-12-08 02:49:04 +00:00
|
|
|
class Context;
|
|
|
|
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/** During insertion, buffers the data in the RAM until certain thresholds are exceeded.
|
|
|
|
* When thresholds are exceeded, flushes the data to another table.
|
|
|
|
* When reading, it reads both from its buffers and from the subordinate table.
|
2014-10-26 00:01:36 +00:00
|
|
|
*
|
2017-04-16 15:00:33 +00:00
|
|
|
* The buffer is a set of num_shards blocks.
|
|
|
|
* When writing, select the block number by the remainder of the `ThreadNumber` division by `num_shards` (or one of the others),
|
|
|
|
* and add rows to the corresponding block.
|
2017-06-06 17:06:14 +00:00
|
|
|
* When using a block, it is locked by some mutex. If during write the corresponding block is already occupied
|
|
|
|
* - try to lock the next block in a round-robin fashion, and so no more than `num_shards` times (then wait for lock).
|
2017-04-16 15:00:33 +00:00
|
|
|
* Thresholds are checked on insertion, and, periodically, in the background thread (to implement time thresholds).
|
|
|
|
* Thresholds act independently for each shard. Each shard can be flushed independently of the others.
|
|
|
|
* If a block is inserted into the table, which itself exceeds the max-thresholds, it is written directly to the subordinate table without buffering.
|
|
|
|
* Thresholds can be exceeded. For example, if max_rows = 1 000 000, the buffer already had 500 000 rows,
|
2017-06-06 17:06:14 +00:00
|
|
|
* and a part of 800 000 rows is added, then there will be 1 300 000 rows in the buffer, and then such a block will be written to the subordinate table.
|
2014-10-26 00:01:36 +00:00
|
|
|
*
|
2017-06-06 17:06:14 +00:00
|
|
|
* When you destroy a Buffer table, all remaining data is flushed to the subordinate table.
|
2017-04-16 15:00:33 +00:00
|
|
|
* The data in the buffer is not replicated, not logged to disk, not indexed. With a rough restart of the server, the data is lost.
|
2014-10-26 00:01:36 +00:00
|
|
|
*/
|
2017-06-06 18:36:13 +00:00
|
|
|
class StorageBuffer : public ext::shared_ptr_helper<StorageBuffer>, public IStorage
|
2014-10-26 00:01:36 +00:00
|
|
|
{
|
2019-08-26 19:07:29 +00:00
|
|
|
friend struct ext::shared_ptr_helper<StorageBuffer>;
|
2014-10-26 00:01:36 +00:00
|
|
|
friend class BufferBlockInputStream;
|
|
|
|
friend class BufferBlockOutputStream;
|
|
|
|
|
|
|
|
public:
|
2017-04-16 15:00:33 +00:00
|
|
|
/// Thresholds.
|
2017-04-01 07:20:54 +00:00
|
|
|
struct Thresholds
|
|
|
|
{
|
2017-04-16 15:00:33 +00:00
|
|
|
time_t time; /// The number of seconds from the insertion of the first row into the block.
|
|
|
|
size_t rows; /// The number of rows in the block.
|
|
|
|
size_t bytes; /// The number of (uncompressed) bytes in the block.
|
2017-04-01 07:20:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
std::string getName() const override { return "Buffer"; }
|
2019-07-09 15:40:21 +00:00
|
|
|
std::string getTableName() const override { return table_name; }
|
|
|
|
std::string getDatabaseName() const override { return database_name; }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-04-19 14:47:09 +00:00
|
|
|
QueryProcessingStage::Enum getQueryProcessingStage(const Context & context) const override;
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
BlockInputStreams read(
|
|
|
|
const Names & column_names,
|
2017-07-15 03:48:36 +00:00
|
|
|
const SelectQueryInfo & query_info,
|
2017-04-01 07:20:54 +00:00
|
|
|
const Context & context,
|
2018-04-19 14:47:09 +00:00
|
|
|
QueryProcessingStage::Enum processed_stage,
|
2019-02-18 23:38:44 +00:00
|
|
|
size_t max_block_size,
|
2017-06-02 15:54:39 +00:00
|
|
|
unsigned num_streams) override;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2019-02-27 18:26:24 +00:00
|
|
|
BlockOutputStreamPtr write(const ASTPtr & query, const Context & context) override;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-06-06 17:06:14 +00:00
|
|
|
void startup() override;
|
|
|
|
/// Flush all buffers into the subordinate table and stop background thread.
|
2017-04-01 07:20:54 +00:00
|
|
|
void shutdown() override;
|
2017-09-06 20:34:26 +00:00
|
|
|
bool optimize(const ASTPtr & query, const ASTPtr & partition, bool final, bool deduplicate, const Context & context) override;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2019-08-27 23:47:30 +00:00
|
|
|
void rename(const String & /*new_path_to_db*/, const String & new_database_name, const String & new_table_name, TableStructureWriteLockHolder &) override
|
|
|
|
{
|
|
|
|
table_name = new_table_name;
|
|
|
|
database_name = new_database_name;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
bool supportsSampling() const override { return true; }
|
2019-03-13 09:33:43 +00:00
|
|
|
bool supportsPrewhere() const override
|
|
|
|
{
|
|
|
|
if (no_destination)
|
|
|
|
return false;
|
|
|
|
auto dest = global_context.tryGetTable(destination_database, destination_table);
|
|
|
|
if (dest && dest.get() != this)
|
|
|
|
return dest->supportsPrewhere();
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
bool supportsFinal() const override { return true; }
|
|
|
|
bool supportsIndexForIn() const override { return true; }
|
|
|
|
|
2019-02-27 18:26:24 +00:00
|
|
|
bool mayBenefitFromIndexForIn(const ASTPtr & left_in_operand, const Context & query_context) const override;
|
2018-03-16 09:00:04 +00:00
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/// The structure of the subordinate table is not checked and does not change.
|
2019-03-05 10:12:20 +00:00
|
|
|
void alter(
|
2019-08-26 14:50:34 +00:00
|
|
|
const AlterCommands & params, const Context & context, TableStructureWriteLockHolder & table_lock_holder) override;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2019-08-26 19:07:29 +00:00
|
|
|
~StorageBuffer() override;
|
|
|
|
|
2014-10-26 00:01:36 +00:00
|
|
|
private:
|
2019-07-09 15:40:21 +00:00
|
|
|
String table_name;
|
|
|
|
String database_name;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2019-01-04 12:10:00 +00:00
|
|
|
Context global_context;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
struct Buffer
|
|
|
|
{
|
|
|
|
time_t first_write_time = 0;
|
|
|
|
Block data;
|
|
|
|
std::mutex mutex;
|
|
|
|
};
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/// There are `num_shards` of independent buffers.
|
2017-04-01 07:20:54 +00:00
|
|
|
const size_t num_shards;
|
|
|
|
std::vector<Buffer> buffers;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
const Thresholds min_thresholds;
|
|
|
|
const Thresholds max_thresholds;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
const String destination_database;
|
|
|
|
const String destination_table;
|
2017-04-16 15:00:33 +00:00
|
|
|
bool no_destination; /// If set, do not write data from the buffer, but simply empty the buffer.
|
2018-01-12 13:03:19 +00:00
|
|
|
bool allow_materialized;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
Poco::Logger * log;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
Poco::Event shutdown_event;
|
2017-04-16 15:00:33 +00:00
|
|
|
/// Resets data by timeout.
|
2019-01-14 19:22:09 +00:00
|
|
|
ThreadFromGlobalPool flush_thread;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
void flushAllBuffers(bool check_thresholds = true);
|
2017-04-16 15:00:33 +00:00
|
|
|
/// Reset the buffer. If check_thresholds is set - resets only if thresholds are exceeded.
|
2018-08-24 14:51:34 +00:00
|
|
|
void flushBuffer(Buffer & buffer, bool check_thresholds, bool locked = false);
|
2017-04-01 07:20:54 +00:00
|
|
|
bool checkThresholds(const Buffer & buffer, time_t current_time, size_t additional_rows = 0, size_t additional_bytes = 0) const;
|
|
|
|
bool checkThresholdsImpl(size_t rows, size_t bytes, time_t time_passed) const;
|
2014-10-26 00:01:36 +00:00
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/// `table` argument is passed, as it is sometimes evaluated beforehand. It must match the `destination`.
|
2017-04-01 07:20:54 +00:00
|
|
|
void writeBlockToDestination(const Block & block, StoragePtr table);
|
2014-10-27 04:18:13 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
void flushThread();
|
2017-11-03 21:50:22 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
/** num_shards - the level of internal parallelism (the number of independent buffers)
|
|
|
|
* The buffer is flushed if all minimum thresholds or at least one of the maximum thresholds are exceeded.
|
|
|
|
*/
|
2019-08-24 21:20:20 +00:00
|
|
|
StorageBuffer(const std::string & database_name_, const std::string & table_name_,
|
|
|
|
const ColumnsDescription & columns_, const ConstraintsDescription & constraints_,
|
2017-11-03 21:50:22 +00:00
|
|
|
Context & context_,
|
|
|
|
size_t num_shards_, const Thresholds & min_thresholds_, const Thresholds & max_thresholds_,
|
2018-01-12 13:03:19 +00:00
|
|
|
const String & destination_database_, const String & destination_table_, bool allow_materialized_);
|
2014-10-26 00:01:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|