2015-01-10 02:30:03 +00:00
|
|
|
|
#include <Poco/DirectoryIterator.h>
|
2016-02-09 17:06:50 +00:00
|
|
|
|
#include <common/ClickHouseRevision.h>
|
2015-10-05 00:33:43 +00:00
|
|
|
|
#include <ext/unlock_guard.hpp>
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/Common/SipHash.h>
|
2015-12-13 09:20:13 +00:00
|
|
|
|
#include <DB/Common/ShellCommand.h>
|
2016-07-14 05:22:09 +00:00
|
|
|
|
#include <DB/Common/StringUtils.h>
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/IO/Operators.h>
|
|
|
|
|
#include <DB/IO/ReadBufferFromString.h>
|
|
|
|
|
#include <DB/IO/ReadBufferFromFileDescriptor.h>
|
|
|
|
|
#include <DB/IO/WriteBufferFromFile.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Interpreters/Compiler.h>
|
|
|
|
|
|
|
|
|
|
|
2016-10-24 02:02:37 +00:00
|
|
|
|
namespace ProfileEvents
|
|
|
|
|
{
|
|
|
|
|
extern const Event CompileAttempt;
|
|
|
|
|
extern const Event CompileSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Compiler::Compiler(const std::string & path_, size_t threads)
|
|
|
|
|
: path(path_), pool(threads)
|
|
|
|
|
{
|
|
|
|
|
Poco::File(path).createDirectory();
|
|
|
|
|
|
|
|
|
|
Poco::DirectoryIterator dir_end;
|
|
|
|
|
for (Poco::DirectoryIterator dir_it(path); dir_end != dir_it; ++dir_it)
|
|
|
|
|
{
|
|
|
|
|
std::string name = dir_it.name();
|
2016-07-14 05:22:09 +00:00
|
|
|
|
if (endsWith(name, ".so"))
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
files.insert(name.substr(0, name.size() - 3));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO(log, "Having " << files.size() << " compiled files from previous start.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Compiler::~Compiler()
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG(log, "Waiting for threads to finish.");
|
|
|
|
|
pool.wait();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static Compiler::HashedKey getHash(const std::string & key)
|
|
|
|
|
{
|
|
|
|
|
SipHash hash;
|
|
|
|
|
|
2016-02-09 17:06:50 +00:00
|
|
|
|
auto revision = ClickHouseRevision::get();
|
2015-01-10 02:30:03 +00:00
|
|
|
|
hash.update(reinterpret_cast<const char *>(&revision), sizeof(revision));
|
|
|
|
|
hash.update(key.data(), key.size());
|
|
|
|
|
|
|
|
|
|
Compiler::HashedKey res;
|
|
|
|
|
hash.get128(res.first, res.second);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Без расширения .so.
|
|
|
|
|
static std::string hashedKeyToFileName(Compiler::HashedKey hashed_key)
|
|
|
|
|
{
|
|
|
|
|
std::string file_name;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
WriteBufferFromString out(file_name);
|
|
|
|
|
out << hashed_key.first << '_' << hashed_key.second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return file_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-01-11 02:00:26 +00:00
|
|
|
|
SharedLibraryPtr Compiler::getOrCount(
|
2015-01-10 02:30:03 +00:00
|
|
|
|
const std::string & key,
|
|
|
|
|
UInt32 min_count_to_compile,
|
2015-01-18 01:18:39 +00:00
|
|
|
|
const std::string & additional_compiler_flags,
|
2015-01-11 02:00:26 +00:00
|
|
|
|
CodeGenerator get_code,
|
|
|
|
|
ReadyCallback on_ready)
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
HashedKey hashed_key = getHash(key);
|
|
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
|
|
|
|
|
|
UInt32 count = ++counts[hashed_key];
|
|
|
|
|
|
|
|
|
|
/// Есть готовая открытая библиотека? Или, если библиотека в процессе компиляции, там будет nullptr.
|
|
|
|
|
Libraries::iterator it = libraries.find(hashed_key);
|
|
|
|
|
if (libraries.end() != it)
|
|
|
|
|
{
|
|
|
|
|
if (!it->second)
|
2015-01-18 01:18:39 +00:00
|
|
|
|
LOG_INFO(log, "Library " << hashedKeyToFileName(hashed_key) << " is already compiling or compilation was failed.");
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
2015-01-13 01:57:22 +00:00
|
|
|
|
/// TODO В этом случае, после окончания компиляции, не будет дёрнут колбэк.
|
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
return it->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Есть файл с библиотекой, оставшийся от предыдущего запуска?
|
|
|
|
|
std::string file_name = hashedKeyToFileName(hashed_key);
|
|
|
|
|
if (files.count(file_name))
|
2015-01-11 02:00:26 +00:00
|
|
|
|
{
|
|
|
|
|
std::string so_file_path = path + '/' + file_name + ".so";
|
|
|
|
|
LOG_INFO(log, "Loading existing library " << so_file_path);
|
|
|
|
|
|
|
|
|
|
SharedLibraryPtr lib(new SharedLibrary(so_file_path));
|
|
|
|
|
libraries[hashed_key] = lib;
|
|
|
|
|
return lib;
|
|
|
|
|
}
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
/// Достигнуто ли min_count_to_compile?
|
|
|
|
|
if (count >= min_count_to_compile)
|
|
|
|
|
{
|
2015-01-18 01:18:39 +00:00
|
|
|
|
/// Значение min_count_to_compile, равное нулю, обозначает необходимость синхронной компиляции.
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
/// Есть ли свободные потоки.
|
2015-01-18 01:18:39 +00:00
|
|
|
|
if (min_count_to_compile == 0 || pool.active() < pool.size())
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
/// Обозначает, что библиотека в процессе компиляции.
|
|
|
|
|
libraries[hashed_key] = nullptr;
|
|
|
|
|
|
2015-01-13 03:03:45 +00:00
|
|
|
|
LOG_INFO(log, "Compiling code " << file_name << ", key: " << key);
|
|
|
|
|
|
2015-01-18 01:18:39 +00:00
|
|
|
|
if (min_count_to_compile == 0)
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
{
|
2015-01-18 01:18:39 +00:00
|
|
|
|
ext::unlock_guard<std::mutex> unlock(mutex);
|
|
|
|
|
compile(hashed_key, file_name, additional_compiler_flags, get_code, on_ready);
|
2015-01-10 02:30:03 +00:00
|
|
|
|
}
|
2015-01-18 01:18:39 +00:00
|
|
|
|
|
|
|
|
|
return libraries[hashed_key];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pool.schedule([=]
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
2015-01-18 01:18:39 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
compile(hashed_key, file_name, additional_compiler_flags, get_code, on_ready);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
tryLogCurrentException("Compiler");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2015-01-10 02:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
LOG_INFO(log, "All threads are busy.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-01-18 01:18:39 +00:00
|
|
|
|
void Compiler::compile(
|
|
|
|
|
HashedKey hashed_key,
|
|
|
|
|
std::string file_name,
|
|
|
|
|
const std::string & additional_compiler_flags,
|
|
|
|
|
CodeGenerator get_code,
|
|
|
|
|
ReadyCallback on_ready)
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
2015-05-05 15:50:20 +00:00
|
|
|
|
ProfileEvents::increment(ProfileEvents::CompileAttempt);
|
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
std::string prefix = path + "/" + file_name;
|
|
|
|
|
std::string cpp_file_path = prefix + ".cpp";
|
|
|
|
|
std::string so_file_path = prefix + ".so";
|
2016-06-10 19:29:39 +00:00
|
|
|
|
std::string so_tmp_file_path = prefix + ".so.tmp";
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
WriteBufferFromFile out(cpp_file_path);
|
|
|
|
|
out << get_code();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::stringstream command;
|
|
|
|
|
|
|
|
|
|
/// Слегка неудобно.
|
|
|
|
|
command <<
|
2015-01-17 04:33:43 +00:00
|
|
|
|
"LD_LIBRARY_PATH=/usr/share/clickhouse/bin/"
|
|
|
|
|
" /usr/share/clickhouse/bin/clang"
|
2016-05-05 19:10:28 +00:00
|
|
|
|
" -B /usr/share/clickhouse/bin/"
|
2016-06-10 19:36:35 +00:00
|
|
|
|
" -x c++ -std=gnu++1y -O3 -g -Wall -Werror -Wnon-virtual-dtor -march=native -msse4 -mpopcnt -D NDEBUG"
|
2015-01-10 02:30:03 +00:00
|
|
|
|
" -shared -fPIC -fvisibility=hidden -fno-implement-inlines"
|
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/local/include/"
|
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/include/"
|
2015-01-19 07:25:02 +00:00
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/include/c++/*/"
|
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/include/x86_64-linux-gnu/"
|
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/include/x86_64-linux-gnu/c++/*/"
|
|
|
|
|
" -isystem /usr/share/clickhouse/headers/usr/local/lib/clang/*/include/"
|
2015-01-10 02:30:03 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/dbms/include/"
|
2016-05-23 02:16:11 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/contrib/libcityhash/include/"
|
2016-01-08 00:02:33 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/contrib/libdouble-conversion/"
|
2016-01-20 19:51:45 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/contrib/libpoco/Foundation/include/"
|
|
|
|
|
" -I /usr/share/clickhouse/headers/contrib/libpoco/Util/include/"
|
2016-02-07 14:49:20 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/contrib/libboost-threadpool/"
|
2015-01-10 02:30:03 +00:00
|
|
|
|
" -I /usr/share/clickhouse/headers/libs/libcommon/include/"
|
|
|
|
|
" -I /usr/share/clickhouse/headers/libs/libmysqlxx/include/"
|
2015-01-18 01:18:39 +00:00
|
|
|
|
" " << additional_compiler_flags <<
|
2016-06-10 19:29:39 +00:00
|
|
|
|
" -o " << so_tmp_file_path << " " << cpp_file_path
|
2015-01-10 02:30:03 +00:00
|
|
|
|
<< " 2>&1 || echo Exit code: $?";
|
|
|
|
|
|
|
|
|
|
std::string compile_result;
|
|
|
|
|
|
|
|
|
|
{
|
2015-12-13 09:20:13 +00:00
|
|
|
|
auto process = ShellCommand::execute(command.str());
|
2016-08-06 22:31:58 +00:00
|
|
|
|
readStringUntilEOF(compile_result, process->out);
|
2015-12-13 09:20:13 +00:00
|
|
|
|
process->wait();
|
2015-01-10 02:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!compile_result.empty())
|
|
|
|
|
throw Exception("Cannot compile code:\n\n" + command.str() + "\n\n" + compile_result);
|
|
|
|
|
|
|
|
|
|
/// Если до этого была ошибка, то файл с кодом остаётся для возможности просмотра.
|
|
|
|
|
Poco::File(cpp_file_path).remove();
|
|
|
|
|
|
2016-06-10 19:29:39 +00:00
|
|
|
|
Poco::File(so_tmp_file_path).renameTo(so_file_path);
|
2015-01-11 02:00:26 +00:00
|
|
|
|
SharedLibraryPtr lib(new SharedLibrary(so_file_path));
|
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2015-01-11 02:00:26 +00:00
|
|
|
|
libraries[hashed_key] = lib;
|
2015-01-10 02:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO(log, "Compiled code " << file_name);
|
2015-05-05 15:50:20 +00:00
|
|
|
|
ProfileEvents::increment(ProfileEvents::CompileSuccess);
|
2015-01-11 02:00:26 +00:00
|
|
|
|
|
|
|
|
|
on_ready(lib);
|
2015-01-10 02:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|