2011-09-26 01:50:32 +00:00
|
|
|
|
#include <math.h>
|
|
|
|
|
|
2011-09-04 21:23:19 +00:00
|
|
|
|
#include <DB/DataStreams/IProfilingBlockInputStream.h>
|
|
|
|
|
#include <DB/DataStreams/IBlockInputStream.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int TOO_DEEP_PIPELINE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-05 02:34:20 +00:00
|
|
|
|
|
2012-06-25 03:42:08 +00:00
|
|
|
|
String IBlockInputStream::getTreeID() const
|
|
|
|
|
{
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << getName();
|
|
|
|
|
|
|
|
|
|
if (!children.empty())
|
|
|
|
|
{
|
|
|
|
|
s << "(";
|
|
|
|
|
for (BlockInputStreams::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (it != children.begin())
|
|
|
|
|
s << ", ";
|
|
|
|
|
s << (*it)->getTreeID();
|
|
|
|
|
}
|
|
|
|
|
s << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s.str();
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-25 20:36:35 +00:00
|
|
|
|
|
|
|
|
|
size_t IBlockInputStream::checkDepth(size_t max_depth) const
|
|
|
|
|
{
|
|
|
|
|
return checkDepthImpl(max_depth, max_depth);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-26 20:29:28 +00:00
|
|
|
|
size_t IBlockInputStream::checkDepthImpl(size_t max_depth, size_t level) const
|
2012-12-25 20:36:35 +00:00
|
|
|
|
{
|
|
|
|
|
if (children.empty())
|
|
|
|
|
return 0;
|
|
|
|
|
|
2012-12-26 20:29:28 +00:00
|
|
|
|
if (level > max_depth)
|
2013-06-21 20:34:19 +00:00
|
|
|
|
throw Exception("Query pipeline is too deep. Maximum: " + toString(max_depth), ErrorCodes::TOO_DEEP_PIPELINE);
|
2012-12-25 20:36:35 +00:00
|
|
|
|
|
|
|
|
|
size_t res = 0;
|
|
|
|
|
for (BlockInputStreams::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
{
|
2012-12-26 20:29:28 +00:00
|
|
|
|
size_t child_depth = (*it)->checkDepth(level + 1);
|
2012-12-25 20:36:35 +00:00
|
|
|
|
if (child_depth > res)
|
|
|
|
|
res = child_depth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-25 03:42:08 +00:00
|
|
|
|
|
|
|
|
|
void IBlockInputStream::dumpTree(std::ostream & ostr, size_t indent, size_t multiplier)
|
2011-09-04 21:23:19 +00:00
|
|
|
|
{
|
2012-03-09 05:10:34 +00:00
|
|
|
|
/// Не будем отображать в дереве обёртку потока блоков в AsynchronousBlockInputStream.
|
2015-06-08 20:22:02 +00:00
|
|
|
|
if (getName() != "Asynchronous")
|
2012-03-09 05:10:34 +00:00
|
|
|
|
{
|
2015-06-08 20:22:02 +00:00
|
|
|
|
ostr << String(indent, ' ') << getName();
|
2012-06-25 03:42:08 +00:00
|
|
|
|
if (multiplier > 1)
|
|
|
|
|
ostr << " × " << multiplier;
|
|
|
|
|
ostr << std::endl;
|
2012-03-09 05:10:34 +00:00
|
|
|
|
++indent;
|
2012-03-05 02:34:20 +00:00
|
|
|
|
|
2012-06-25 03:42:08 +00:00
|
|
|
|
/// Если поддерево повторяется несколько раз, то будем выводить его один раз с множителем.
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Multipliers = std::map<String, size_t>;
|
2012-06-25 03:42:08 +00:00
|
|
|
|
Multipliers multipliers;
|
|
|
|
|
|
|
|
|
|
for (BlockInputStreams::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
++multipliers[(*it)->getTreeID()];
|
|
|
|
|
|
|
|
|
|
for (BlockInputStreams::iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
String id = (*it)->getTreeID();
|
|
|
|
|
size_t & subtree_multiplier = multipliers[id];
|
|
|
|
|
if (subtree_multiplier != 0) /// Уже выведенные поддеревья помечаем нулём в массиве множителей.
|
|
|
|
|
{
|
|
|
|
|
(*it)->dumpTree(ostr, indent, subtree_multiplier);
|
|
|
|
|
subtree_multiplier = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (BlockInputStreams::iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
(*it)->dumpTree(ostr, indent, multiplier);
|
|
|
|
|
}
|
2012-03-05 02:34:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-03-09 04:45:27 +00:00
|
|
|
|
BlockInputStreams IBlockInputStream::getLeaves()
|
|
|
|
|
{
|
|
|
|
|
BlockInputStreams res;
|
|
|
|
|
getLeavesImpl(res);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-08-23 23:49:28 +00:00
|
|
|
|
void IBlockInputStream::getLeafRowsBytes(size_t & rows, size_t & bytes)
|
|
|
|
|
{
|
|
|
|
|
BlockInputStreams leaves = getLeaves();
|
|
|
|
|
rows = 0;
|
|
|
|
|
bytes = 0;
|
|
|
|
|
|
|
|
|
|
for (BlockInputStreams::const_iterator it = leaves.begin(); it != leaves.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (const IProfilingBlockInputStream * profiling = dynamic_cast<const IProfilingBlockInputStream *>(&**it))
|
|
|
|
|
{
|
|
|
|
|
const BlockStreamProfileInfo & info = profiling->getInfo();
|
|
|
|
|
rows += info.rows;
|
|
|
|
|
bytes += info.bytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-03-09 04:45:27 +00:00
|
|
|
|
void IBlockInputStream::getLeavesImpl(BlockInputStreams & res, BlockInputStreamPtr this_shared_ptr)
|
|
|
|
|
{
|
|
|
|
|
if (children.empty())
|
|
|
|
|
{
|
|
|
|
|
if (this_shared_ptr)
|
|
|
|
|
res.push_back(this_shared_ptr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
for (BlockInputStreams::iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
(*it)->getLeavesImpl(res, *it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-09-04 21:23:19 +00:00
|
|
|
|
}
|
|
|
|
|
|