2014-08-12 13:46:46 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <DB/Storages/StorageDistributed.h>
|
2014-08-13 12:52:30 +00:00
|
|
|
|
|
|
|
#include <DB/IO/WriteBufferFromFile.h>
|
|
|
|
#include <DB/IO/CompressedWriteBuffer.h>
|
|
|
|
#include <DB/DataStreams/NativeBlockOutputStream.h>
|
|
|
|
|
|
|
|
#include <statdaemons/Increment.h>
|
|
|
|
|
2014-08-12 13:46:46 +00:00
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
class DistributedBlockOutputStream : public IBlockOutputStream
|
|
|
|
{
|
|
|
|
public:
|
2014-08-13 12:52:30 +00:00
|
|
|
DistributedBlockOutputStream(StorageDistributed & storage, Cluster & cluster, const std::string & query_string)
|
|
|
|
: storage(storage), cluster(cluster), query_string(query_string)
|
2014-08-12 13:46:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void write(const Block & block) override
|
|
|
|
{
|
2014-08-13 09:20:15 +00:00
|
|
|
if (storage.getShardingKeyExpr() && cluster.shard_info_vec.size() > 1)
|
2014-08-12 13:46:46 +00:00
|
|
|
splitWrite(block, block);
|
|
|
|
else
|
|
|
|
writeImpl(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void splitWrite(const Block & block, Block block_with_key)
|
|
|
|
{
|
2014-08-13 09:20:15 +00:00
|
|
|
storage.getShardingKeyExpr()->execute(block_with_key);
|
2014-08-12 13:46:46 +00:00
|
|
|
|
2014-08-13 09:20:15 +00:00
|
|
|
const auto & key_column = block_with_key.getByName(storage.getShardingKeyColumnName()).column;
|
2014-08-12 13:46:46 +00:00
|
|
|
const auto total_weight = cluster.slot_to_shard.size();
|
2014-08-13 09:45:39 +00:00
|
|
|
|
|
|
|
/// shard => block mapping
|
|
|
|
std::unordered_map<size_t, Block> target_blocks;
|
|
|
|
/// return iterator to target block, creating one if necessary
|
|
|
|
const auto get_target_block = [&target_blocks, &block] (const size_t idx) {
|
|
|
|
const auto it = target_blocks.find(idx);
|
|
|
|
|
|
|
|
if (it == std::end(target_blocks))
|
|
|
|
return target_blocks.emplace(idx, block.cloneEmpty()).first;
|
|
|
|
|
|
|
|
return it;
|
|
|
|
};
|
2014-08-12 13:46:46 +00:00
|
|
|
|
|
|
|
for (size_t row = 0; row < block.rows(); ++row)
|
|
|
|
{
|
2014-08-13 11:26:13 +00:00
|
|
|
const auto target_block_idx = cluster.slot_to_shard[key_column->get64(row) % total_weight];
|
2014-08-13 09:45:39 +00:00
|
|
|
auto & target_block = get_target_block(target_block_idx)->second;;
|
2014-08-12 13:46:46 +00:00
|
|
|
|
|
|
|
for (size_t col = 0; col < block.columns(); ++col)
|
|
|
|
{
|
|
|
|
target_block.getByPosition(col).column->insertFrom(
|
|
|
|
*block.getByPosition(col).column, row
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-13 09:45:39 +00:00
|
|
|
for (const auto & shard_block_pair : target_blocks)
|
|
|
|
writeImpl(shard_block_pair.second, shard_block_pair.first);
|
2014-08-12 13:46:46 +00:00
|
|
|
}
|
|
|
|
|
2014-08-13 11:26:13 +00:00
|
|
|
void writeImpl(const Block & block, const size_t shard_id = 0)
|
2014-08-12 13:46:46 +00:00
|
|
|
{
|
2014-08-13 11:26:13 +00:00
|
|
|
const auto & dir_name = cluster.shard_info_vec[shard_id].dir_name;
|
2014-08-13 12:52:30 +00:00
|
|
|
const auto & path = storage.getPath() + dir_name + '/';
|
2014-08-13 11:26:13 +00:00
|
|
|
|
|
|
|
/// ensure shard subdirectory creation and notify storage if necessary
|
2014-08-13 12:52:30 +00:00
|
|
|
if (Poco::File(path).createDirectory())
|
2014-08-13 11:26:13 +00:00
|
|
|
storage.createDirectoryMonitor(dir_name);
|
|
|
|
|
2014-08-13 12:52:30 +00:00
|
|
|
const auto number = Increment(path + "increment").get(true);
|
|
|
|
const auto block_file_path = path + std::to_string(number);
|
|
|
|
|
|
|
|
DB::WriteBufferFromFile out{block_file_path};
|
|
|
|
DB::CompressedWriteBuffer compress{out};
|
|
|
|
DB::NativeBlockOutputStream stream{compress};
|
|
|
|
|
|
|
|
DB::writeStringBinary(query_string, out);
|
2014-08-13 13:43:54 +00:00
|
|
|
|
|
|
|
stream.writePrefix();
|
|
|
|
stream.write(block);
|
|
|
|
stream.writeSuffix();
|
2014-08-12 13:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StorageDistributed & storage;
|
|
|
|
Cluster & cluster;
|
2014-08-13 12:52:30 +00:00
|
|
|
std::string query_string;
|
2014-08-12 13:46:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|