ClickHouse/dbms/include/DB/Interpreters/Compiler.h
2016-08-02 04:46:05 +03:00

127 lines
4.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <dlfcn.h>
#include <string>
#include <mutex>
#include <functional>
#include <unordered_set>
#include <unordered_map>
#include <common/logger_useful.h>
#include <DB/Core/Types.h>
#include <DB/Common/Exception.h>
#include <DB/Common/UInt128.h>
#include <DB/Common/ThreadPool.h>
namespace DB
{
/** Позволяет открыть динамическую библиотеку и получить из неё указатель на функцию.
*/
class SharedLibrary : private boost::noncopyable
{
public:
SharedLibrary(const std::string & path)
{
handle = dlopen(path.c_str(), RTLD_LAZY);
if (!handle)
throw Exception(std::string("Cannot dlopen: ") + dlerror());
}
~SharedLibrary()
{
if (handle && dlclose(handle))
std::terminate();
}
template <typename Func>
Func get(const std::string & name)
{
dlerror();
Func res = reinterpret_cast<Func>(dlsym(handle, name.c_str()));
if (char * error = dlerror())
throw Exception(std::string("Cannot dlsym: ") + error);
return res;
}
private:
void * handle;
};
using SharedLibraryPtr = std::shared_ptr<SharedLibrary>;
/** Позволяет скомпилировать кусок кода, использующий заголовочные файлы сервера, в динамическую библиотеку.
* Ведёт статистику вызовов, и инициирует компиляцию только на N-ый по счёту вызов для одного ключа.
* Компиляция выполняется асинхронно, в отдельных потоках, если есть свободные потоки.
* NOTE: Нет очистки устаревших и ненужных результатов.
*/
class Compiler
{
public:
/** path - путь к директории с временными файлами - результатами компиляции.
* Результаты компиляции сохраняются при перезапуске сервера,
* но используют в качестве части ключа номер ревизии. То есть, устаревают при обновлении сервера.
*/
Compiler(const std::string & path_, size_t threads);
~Compiler();
using HashedKey = UInt128;
using CodeGenerator = std::function<std::string()>;
using ReadyCallback = std::function<void(SharedLibraryPtr&)>;
/** Увеличить счётчик для заданного ключа key на единицу.
* Если результат компиляции уже есть (уже открыт, или есть файл с библиотекой),
* то вернуть готовую SharedLibrary.
* Иначе, если min_count_to_compile == 0, то инициировать компиляцию в том же потоке, дождаться её, и вернуть результат.
* Иначе, если счётчик достиг min_count_to_compile,
* инициировать компиляцию в отдельном потоке, если есть свободные потоки, и вернуть nullptr.
* Иначе вернуть nullptr.
*/
SharedLibraryPtr getOrCount(
const std::string & key,
UInt32 min_count_to_compile,
const std::string & additional_compiler_flags,
CodeGenerator get_code,
ReadyCallback on_ready);
private:
using Counts = std::unordered_map<HashedKey, UInt32, UInt128Hash>;
using Libraries = std::unordered_map<HashedKey, SharedLibraryPtr, UInt128Hash>;
using Files = std::unordered_set<std::string>;
const std::string path;
ThreadPool pool;
/// Количество вызовов функции getOrCount.
Counts counts;
/// Скомпилированные и открытые библиотеки. Или nullptr для библиотек в процессе компиляции.
Libraries libraries;
/// Скомпилированные файлы, оставшиеся от предыдущих запусков, но ещё не открытые.
Files files;
std::mutex mutex;
Logger * log = &Logger::get("Compiler");
void compile(
HashedKey hashed_key,
std::string file_name,
const std::string & additional_compiler_flags,
CodeGenerator get_code,
ReadyCallback on_ready);
};
}