ClickHouse/dbms/include/DB/DataStreams/AsynchronousBlockInputStream.h

92 lines
2.0 KiB
C
Raw Normal View History

2011-11-28 05:48:52 +00:00
#pragma once
2011-11-28 06:22:25 +00:00
#include <statdaemons/threadpool.hpp>
2011-11-28 05:48:52 +00:00
2011-11-28 06:22:25 +00:00
#include <DB/DataStreams/IProfilingBlockInputStream.h>
2011-11-28 05:48:52 +00:00
namespace DB
{
/** Выполняет другой BlockInputStream в отдельном потоке, используя двойную буферизацию.
*/
2011-11-28 06:22:25 +00:00
class AsynchronousBlockInputStream : public IProfilingBlockInputStream
2011-11-28 05:48:52 +00:00
{
public:
2011-11-28 06:22:25 +00:00
AsynchronousBlockInputStream(BlockInputStreamPtr in_) : in(in_), pool(1), started(false)
2011-11-28 05:48:52 +00:00
{
children.push_back(in);
}
2011-11-28 06:22:25 +00:00
Block readImpl()
2011-11-28 05:48:52 +00:00
{
/// Если вычислений ещё не было - вычислим первый блок синхронно
2011-11-28 06:22:25 +00:00
if (!started)
{
2011-11-28 05:48:52 +00:00
calculate();
2011-11-28 06:22:25 +00:00
started = true;
}
2011-11-28 05:48:52 +00:00
else /// Если вычисления уже идут - подождём результата
2011-11-28 06:22:25 +00:00
pool.wait();
2011-11-28 05:48:52 +00:00
if (exception)
2011-12-12 06:15:34 +00:00
exception->rethrow();
2011-11-28 05:48:52 +00:00
Block res = block;
if (!res)
return res;
/// Запустим вычисления следующего блока
block = Block();
2011-11-28 06:22:25 +00:00
pool.schedule(boost::bind(&AsynchronousBlockInputStream::calculate, this));
2011-11-28 05:48:52 +00:00
return res;
}
String getName() const { return "AsynchronousBlockInputStream"; }
BlockInputStreamPtr clone() { return new AsynchronousBlockInputStream(in); }
2012-03-05 02:34:20 +00:00
~AsynchronousBlockInputStream()
{
if (started)
pool.wait();
}
2011-11-28 05:48:52 +00:00
protected:
BlockInputStreamPtr in;
2011-11-28 06:22:25 +00:00
boost::threadpool::pool pool;
bool started;
2011-11-28 05:48:52 +00:00
Block block;
SharedPtr<Exception> exception;
/// Вычисления, которые могут выполняться в отдельном потоке
void calculate()
{
try
{
block = in->read();
}
catch (const Exception & e)
{
exception = new Exception(e);
}
catch (const Poco::Exception & e)
{
exception = new Exception(e.message(), ErrorCodes::POCO_EXCEPTION);
}
catch (const std::exception & e)
{
exception = new Exception(e.what(), ErrorCodes::STD_EXCEPTION);
}
catch (...)
{
exception = new Exception("Unknown exception", ErrorCodes::UNKNOWN_EXCEPTION);
}
}
};
}