mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 01:22:04 +00:00
Merge branch 'master' into joins
This commit is contained in:
commit
5147e2ad03
@ -90,8 +90,6 @@ if (GLIBC_COMPATIBILITY)
|
||||
set (USE_INTERNAL_MEMCPY ON)
|
||||
endif ()
|
||||
|
||||
set (COMPILER_FLAGS "${COMPILER_FLAGS}")
|
||||
|
||||
string(REGEX MATCH "-?[0-9]+(.[0-9]+)?$" COMPILER_POSTFIX ${CMAKE_CXX_COMPILER})
|
||||
|
||||
find_program (LLD_PATH NAMES "lld${COMPILER_POSTFIX}" "lld")
|
||||
@ -108,10 +106,15 @@ if (LINKER_NAME)
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=${LINKER_NAME}")
|
||||
endif ()
|
||||
|
||||
option (PIPE "-pipe compiler option [less /tmp usage, more ram usage]" ON)
|
||||
if (PIPE)
|
||||
set (COMPILER_FLAGS "${COMPILER_FLAGS} -pipe")
|
||||
endif ()
|
||||
cmake_host_system_information(RESULT AVAILABLE_PHYSICAL_MEMORY QUERY AVAILABLE_PHYSICAL_MEMORY) # Not available under freebsd
|
||||
if(NOT AVAILABLE_PHYSICAL_MEMORY OR AVAILABLE_PHYSICAL_MEMORY GREATER 8000)
|
||||
option(COMPILER_PIPE "-pipe compiler option [less /tmp usage, more ram usage]" ON)
|
||||
endif()
|
||||
if(COMPILER_PIPE)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -pipe")
|
||||
else()
|
||||
message(STATUS "Disabling compiler -pipe option (have only ${AVAILABLE_PHYSICAL_MEMORY} mb of memory)")
|
||||
endif()
|
||||
|
||||
include (cmake/test_cpu.cmake)
|
||||
|
||||
|
@ -6,7 +6,7 @@ set (OPENSSL_USE_STATIC_LIBS ${USE_STATIC_LIBRARIES})
|
||||
|
||||
if (NOT USE_INTERNAL_SSL_LIBRARY)
|
||||
if (APPLE)
|
||||
set (OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
|
||||
set (OPENSSL_ROOT_DIR "/usr/local/opt/openssl" CACHE INTERNAL "")
|
||||
# https://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=2232
|
||||
if (USE_STATIC_LIBRARIES)
|
||||
message(WARNING "Disable USE_STATIC_LIBRARIES if you have linking problems with OpenSSL on MacOS")
|
||||
|
@ -4,6 +4,7 @@
|
||||
# include (cmake/limit_jobs.cmake)
|
||||
|
||||
cmake_host_system_information(RESULT AVAILABLE_PHYSICAL_MEMORY QUERY AVAILABLE_PHYSICAL_MEMORY) # Not available under freebsd
|
||||
cmake_host_system_information(RESULT NUMBER_OF_LOGICAL_CORES QUERY NUMBER_OF_LOGICAL_CORES)
|
||||
|
||||
option(PARALLEL_COMPILE_JOBS "Define the maximum number of concurrent compilation jobs" "")
|
||||
if (NOT PARALLEL_COMPILE_JOBS AND AVAILABLE_PHYSICAL_MEMORY AND MAX_COMPILER_MEMORY)
|
||||
@ -12,7 +13,7 @@ if (NOT PARALLEL_COMPILE_JOBS AND AVAILABLE_PHYSICAL_MEMORY AND MAX_COMPILER_MEM
|
||||
set (PARALLEL_COMPILE_JOBS 1)
|
||||
endif ()
|
||||
endif ()
|
||||
if (PARALLEL_COMPILE_JOBS)
|
||||
if (PARALLEL_COMPILE_JOBS AND (NOT NUMBER_OF_LOGICAL_CORES OR PARALLEL_COMPILE_JOBS LESS NUMBER_OF_LOGICAL_CORES))
|
||||
set(CMAKE_JOB_POOL_COMPILE compile_job_pool${CMAKE_CURRENT_SOURCE_DIR})
|
||||
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_COMPILE ${CMAKE_JOB_POOL_COMPILE})
|
||||
set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_COMPILE}=${PARALLEL_COMPILE_JOBS})
|
||||
@ -25,13 +26,12 @@ if (NOT PARALLEL_LINK_JOBS AND AVAILABLE_PHYSICAL_MEMORY AND MAX_LINKER_MEMORY)
|
||||
set (PARALLEL_LINK_JOBS 1)
|
||||
endif ()
|
||||
endif ()
|
||||
if (PARALLEL_COMPILE_JOBS OR PARALLEL_LINK_JOBS)
|
||||
message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Have ${AVAILABLE_PHYSICAL_MEMORY} megabytes of memory. Limiting concurrent linkers jobs to ${PARALLEL_LINK_JOBS} and compiler jobs to ${PARALLEL_COMPILE_JOBS}")
|
||||
endif ()
|
||||
|
||||
if (LLVM_PARALLEL_LINK_JOBS)
|
||||
if (PARALLEL_LINK_JOBS AND (NOT NUMBER_OF_LOGICAL_CORES OR PARALLEL_COMPILE_JOBS LESS NUMBER_OF_LOGICAL_CORES))
|
||||
set(CMAKE_JOB_POOL_LINK link_job_pool${CMAKE_CURRENT_SOURCE_DIR})
|
||||
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_LINK ${CMAKE_JOB_POOL_LINK})
|
||||
set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_LINK}=${PARALLEL_LINK_JOBS})
|
||||
endif ()
|
||||
|
||||
if (PARALLEL_COMPILE_JOBS OR PARALLEL_LINK_JOBS)
|
||||
message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Have ${AVAILABLE_PHYSICAL_MEMORY} megabytes of memory. Limiting concurrent linkers jobs to ${PARALLEL_LINK_JOBS} and compiler jobs to ${PARALLEL_COMPILE_JOBS}")
|
||||
endif ()
|
||||
|
1
contrib/CMakeLists.txt
vendored
1
contrib/CMakeLists.txt
vendored
@ -139,6 +139,7 @@ if (USE_INTERNAL_CAPNP_LIBRARY)
|
||||
endif ()
|
||||
|
||||
if (USE_INTERNAL_POCO_LIBRARY)
|
||||
set (POCO_VERBOSE_MESSAGES 0 CACHE INTERNAL "")
|
||||
set (save_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
set (save_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
|
||||
set (_save ${ENABLE_TESTS})
|
||||
|
@ -2,13 +2,17 @@ if (USE_INCLUDE_WHAT_YOU_USE)
|
||||
set (CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
|
||||
endif ()
|
||||
|
||||
set (MAX_COMPILER_MEMORY 2500 CACHE INTERNAL "")
|
||||
if (MAKE_STATIC_LIBRARIES)
|
||||
set (MAX_LINKER_MEMORY 3500 CACHE INTERNAL "")
|
||||
if(COMPILER_PIPE)
|
||||
set(MAX_COMPILER_MEMORY 2500)
|
||||
else()
|
||||
set (MAX_LINKER_MEMORY 2500 CACHE INTERNAL "")
|
||||
endif ()
|
||||
include (../cmake/limit_jobs.cmake)
|
||||
set(MAX_COMPILER_MEMORY 1500)
|
||||
endif()
|
||||
if(MAKE_STATIC_LIBRARIES)
|
||||
set(MAX_LINKER_MEMORY 3500)
|
||||
else()
|
||||
set(MAX_LINKER_MEMORY 2500)
|
||||
endif()
|
||||
include(../cmake/limit_jobs.cmake)
|
||||
|
||||
include(cmake/find_vectorclass.cmake)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
add_library (clickhouse-client-lib ${LINK_MODE} Client.cpp)
|
||||
target_link_libraries (clickhouse-client-lib PRIVATE clickhouse_common_io clickhouse_functions clickhouse_aggregate_functions ${LINE_EDITING_LIBS} ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
target_link_libraries (clickhouse-client-lib PRIVATE clickhouse_common_config clickhouse_functions clickhouse_aggregate_functions clickhouse_common_io ${LINE_EDITING_LIBS} ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
if (READLINE_INCLUDE_DIR)
|
||||
target_include_directories (clickhouse-client-lib SYSTEM PRIVATE ${READLINE_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
@ -1997,7 +1997,7 @@ protected:
|
||||
};
|
||||
|
||||
{
|
||||
ThreadPool thread_pool(std::min(num_shards, UInt64(getNumberOfPhysicalCPUCores())));
|
||||
ThreadPool thread_pool(std::min<UInt64>(num_shards, getNumberOfPhysicalCPUCores()));
|
||||
|
||||
for (UInt64 shard_index = 0; shard_index < num_shards; ++shard_index)
|
||||
thread_pool.schedule([=] { do_for_shard(shard_index); });
|
||||
|
@ -9,7 +9,7 @@ add_library (clickhouse-odbc-bridge-lib ${LINK_MODE}
|
||||
validateODBCConnectionString.cpp
|
||||
)
|
||||
|
||||
target_link_libraries (clickhouse-odbc-bridge-lib PRIVATE clickhouse_common_io daemon dbms)
|
||||
target_link_libraries (clickhouse-odbc-bridge-lib PRIVATE clickhouse_dictionaries daemon dbms clickhouse_common_io)
|
||||
target_include_directories (clickhouse-odbc-bridge-lib PUBLIC ${ClickHouse_SOURCE_DIR}/libs/libdaemon/include)
|
||||
|
||||
if (USE_POCO_SQLODBC)
|
||||
|
@ -411,7 +411,7 @@ int Server::main(const std::vector<std::string> & /*args*/)
|
||||
global_context->setMarkCache(mark_cache_size);
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
size_t compiled_expression_cache_size = config().getUInt64("compiled_expression_cache_size", std::numeric_limits<UInt64>::max());
|
||||
size_t compiled_expression_cache_size = config().getUInt64("compiled_expression_cache_size", 500);
|
||||
if (compiled_expression_cache_size)
|
||||
global_context->setCompiledExpressionCache(compiled_expression_cache_size);
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
#cmakedefine01 USE_BASE64
|
||||
#cmakedefine01 USE_HDFS
|
||||
#cmakedefine01 USE_XXHASH
|
||||
#cmakedefine01 USE_INTERNAL_LLVM_LIBRARY
|
||||
|
||||
#cmakedefine01 CLICKHOUSE_SPLIT_BINARY
|
||||
#cmakedefine01 LLVM_HAS_RTTI
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <TableFunctions/parseRemoteDescription.h>
|
||||
#include "parseRemoteDescription.h"
|
||||
#include <Common/Exception.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
|
@ -20,9 +20,7 @@ endif()
|
||||
|
||||
if(USE_POCO_SQLODBC)
|
||||
target_link_libraries(clickhouse_dictionaries PRIVATE ${Poco_SQLODBC_LIBRARY} ${Poco_SQL_LIBRARY})
|
||||
if (NOT USE_INTERNAL_POCO_LIBRARY)
|
||||
target_include_directories(clickhouse_dictionaries SYSTEM PRIVATE ${ODBC_INCLUDE_DIRECTORIES} ${Poco_SQLODBC_INCLUDE_DIR} ${Poco_SQL_INCLUDE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(Poco_Data_FOUND)
|
||||
@ -31,9 +29,7 @@ endif()
|
||||
|
||||
if(USE_POCO_DATAODBC)
|
||||
target_link_libraries(clickhouse_dictionaries PRIVATE ${Poco_DataODBC_LIBRARY} ${Poco_Data_LIBRARY})
|
||||
if (NOT USE_INTERNAL_POCO_LIBRARY)
|
||||
target_include_directories(clickhouse_dictionaries SYSTEM PRIVATE ${ODBC_INCLUDE_DIRECTORIES} ${Poco_DataODBC_INCLUDE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_POCO_MONGODB)
|
||||
|
@ -47,9 +47,11 @@ if (ENABLE_TESTS)
|
||||
endif ()
|
||||
|
||||
if (USE_EMBEDDED_COMPILER)
|
||||
target_include_directories (clickhouse_functions SYSTEM BEFORE PUBLIC ${LLVM_INCLUDE_DIRS})
|
||||
llvm_libs_all(REQUIRED_LLVM_LIBRARIES)
|
||||
target_link_libraries(clickhouse_functions PRIVATE ${REQUIRED_LLVM_LIBRARIES})
|
||||
target_include_directories(clickhouse_functions SYSTEM BEFORE PUBLIC ${LLVM_INCLUDE_DIRS})
|
||||
endif ()
|
||||
|
||||
if (USE_BASE64)
|
||||
target_include_directories (clickhouse_functions SYSTEM PRIVATE ${BASE64_INCLUDE_DIR})
|
||||
if(USE_BASE64)
|
||||
target_include_directories(clickhouse_functions SYSTEM PRIVATE ${BASE64_INCLUDE_DIR})
|
||||
endif()
|
||||
|
@ -512,8 +512,8 @@ static std::optional<DataTypes> removeNullables(const DataTypes & types)
|
||||
if (!typeid_cast<const DataTypeNullable *>(type.get()))
|
||||
continue;
|
||||
DataTypes filtered;
|
||||
for (const auto & type : types)
|
||||
filtered.emplace_back(removeNullable(type));
|
||||
for (const auto & sub_type : types)
|
||||
filtered.emplace_back(removeNullable(sub_type));
|
||||
return filtered;
|
||||
}
|
||||
return {};
|
||||
|
@ -137,11 +137,8 @@ void AsynchronousMetrics::update()
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
{
|
||||
if (auto compiled_expression_cache = context.getCompiledExpressionCache())
|
||||
{
|
||||
set("CompiledExpressionCacheBytes", compiled_expression_cache->weight());
|
||||
set("CompiledExpressionCacheCount", compiled_expression_cache->count());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set("Uptime", context.getUptimeSeconds());
|
||||
|
@ -16,18 +16,21 @@ struct ColumnNamesContext
|
||||
{
|
||||
struct JoinedTable
|
||||
{
|
||||
const ASTTableExpression * expr;
|
||||
const ASTTableJoin * join;
|
||||
const ASTTableExpression * expr = nullptr;
|
||||
const ASTTableJoin * join = nullptr;
|
||||
|
||||
std::optional<String> alias() const
|
||||
{
|
||||
String alias;
|
||||
if (expr)
|
||||
{
|
||||
if (expr->database_and_table_name)
|
||||
alias = expr->database_and_table_name->tryGetAlias();
|
||||
else if (expr->table_function)
|
||||
alias = expr->table_function->tryGetAlias();
|
||||
else if (expr->subquery)
|
||||
alias = expr->subquery->tryGetAlias();
|
||||
}
|
||||
if (!alias.empty())
|
||||
return alias;
|
||||
return {};
|
||||
@ -35,6 +38,7 @@ struct ColumnNamesContext
|
||||
|
||||
std::optional<String> name() const
|
||||
{
|
||||
if (expr)
|
||||
if (auto * node = expr->database_and_table_name.get())
|
||||
if (auto * identifier = typeid_cast<const ASTIdentifier *>(node))
|
||||
return identifier->name;
|
||||
|
@ -161,21 +161,21 @@ auto wrapJITSymbolResolver(llvm::JITSymbolResolver & jsr)
|
||||
// Actually this should work for 7.0.0 but now we have OLDER 7.0.0svn in contrib
|
||||
auto flags = [&](const llvm::orc::SymbolNameSet & symbols)
|
||||
{
|
||||
llvm::orc::SymbolFlagsMap flags;
|
||||
llvm::orc::SymbolFlagsMap flags_map;
|
||||
for (const auto & symbol : symbols)
|
||||
{
|
||||
auto resolved = jsr.lookupFlags({*symbol});
|
||||
if (resolved && resolved->size())
|
||||
flags.emplace(symbol, resolved->begin()->second);
|
||||
flags_map.emplace(symbol, resolved->begin()->second);
|
||||
}
|
||||
return flags;
|
||||
return flags_map;
|
||||
};
|
||||
#endif
|
||||
|
||||
auto symbols = [&](std::shared_ptr<llvm::orc::AsynchronousSymbolQuery> query, llvm::orc::SymbolNameSet symbols)
|
||||
auto symbols = [&](std::shared_ptr<llvm::orc::AsynchronousSymbolQuery> query, llvm::orc::SymbolNameSet symbols_set)
|
||||
{
|
||||
llvm::orc::SymbolNameSet missing;
|
||||
for (const auto & symbol : symbols)
|
||||
for (const auto & symbol : symbols_set)
|
||||
{
|
||||
auto resolved = jsr.lookup({*symbol});
|
||||
if (resolved && resolved->size())
|
||||
@ -189,70 +189,36 @@ auto wrapJITSymbolResolver(llvm::JITSymbolResolver & jsr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 6
|
||||
struct CountingMMapper final : public llvm::SectionMemoryManager::MemoryMapper
|
||||
{
|
||||
MemoryTracker memory_tracker{VariableContext::Global};
|
||||
|
||||
llvm::sys::MemoryBlock allocateMappedMemory(llvm::SectionMemoryManager::AllocationPurpose /*purpose*/,
|
||||
size_t num_bytes,
|
||||
const llvm::sys::MemoryBlock * const near_block,
|
||||
unsigned flags,
|
||||
std::error_code & error_code) override
|
||||
{
|
||||
memory_tracker.alloc(num_bytes);
|
||||
return llvm::sys::Memory::allocateMappedMemory(num_bytes, near_block, flags, error_code);
|
||||
}
|
||||
|
||||
std::error_code protectMappedMemory(const llvm::sys::MemoryBlock & block, unsigned flags) override
|
||||
{
|
||||
return llvm::sys::Memory::protectMappedMemory(block, flags);
|
||||
}
|
||||
|
||||
std::error_code releaseMappedMemory(llvm::sys::MemoryBlock & block) override
|
||||
{
|
||||
memory_tracker.free(block.size());
|
||||
return llvm::sys::Memory::releaseMappedMemory(block);
|
||||
}
|
||||
};
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
using ModulePtr = std::unique_ptr<llvm::Module>;
|
||||
#else
|
||||
using ModulePtr = std::shared_ptr<llvm::Module>;
|
||||
#endif
|
||||
|
||||
struct LLVMContext
|
||||
{
|
||||
static inline std::atomic<size_t> id_counter{0};
|
||||
llvm::LLVMContext context;
|
||||
std::shared_ptr<llvm::LLVMContext> context;
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
llvm::orc::ExecutionSession execution_session;
|
||||
std::unique_ptr<llvm::Module> module;
|
||||
#else
|
||||
std::shared_ptr<llvm::Module> module;
|
||||
#endif
|
||||
ModulePtr module;
|
||||
std::unique_ptr<llvm::TargetMachine> machine;
|
||||
#if LLVM_VERSION_MAJOR >= 6
|
||||
std::unique_ptr<CountingMMapper> memory_mapper;
|
||||
#endif
|
||||
std::shared_ptr<llvm::SectionMemoryManager> memory_manager;
|
||||
llvm::orc::RTDyldObjectLinkingLayer object_layer;
|
||||
llvm::orc::IRCompileLayer<decltype(object_layer), llvm::orc::SimpleCompiler> compile_layer;
|
||||
llvm::DataLayout layout;
|
||||
llvm::IRBuilder<> builder;
|
||||
std::unordered_map<std::string, void *> symbols;
|
||||
size_t id;
|
||||
|
||||
LLVMContext()
|
||||
: context(std::make_shared<llvm::LLVMContext>())
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
: module(std::make_unique<llvm::Module>("jit", context))
|
||||
, module(std::make_unique<llvm::Module>("jit", *context))
|
||||
#else
|
||||
: module(std::make_shared<llvm::Module>("jit", context))
|
||||
, module(std::make_shared<llvm::Module>("jit", *context))
|
||||
#endif
|
||||
, machine(getNativeMachine())
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 6
|
||||
, memory_mapper(std::make_unique<CountingMMapper>())
|
||||
, memory_manager(std::make_shared<llvm::SectionMemoryManager>(memory_mapper.get()))
|
||||
#else
|
||||
, memory_manager(std::make_shared<llvm::SectionMemoryManager>())
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 7
|
||||
, object_layer(execution_session, [this](llvm::orc::VModuleKey)
|
||||
{
|
||||
@ -263,32 +229,31 @@ struct LLVMContext
|
||||
#endif
|
||||
, compile_layer(object_layer, llvm::orc::SimpleCompiler(*machine))
|
||||
, layout(machine->createDataLayout())
|
||||
, builder(context)
|
||||
, id(id_counter++)
|
||||
, builder(*context)
|
||||
{
|
||||
module->setDataLayout(layout);
|
||||
module->setTargetTriple(machine->getTargetTriple().getTriple());
|
||||
}
|
||||
|
||||
/// returns used memory
|
||||
size_t compileAllFunctionsToNativeCode()
|
||||
void compileAllFunctionsToNativeCode()
|
||||
{
|
||||
if (!module->size())
|
||||
return 0;
|
||||
llvm::PassManagerBuilder builder;
|
||||
return;
|
||||
llvm::PassManagerBuilder pass_manager_builder;
|
||||
llvm::legacy::PassManager mpm;
|
||||
llvm::legacy::FunctionPassManager fpm(module.get());
|
||||
builder.OptLevel = 3;
|
||||
builder.SLPVectorize = true;
|
||||
builder.LoopVectorize = true;
|
||||
builder.RerollLoops = true;
|
||||
builder.VerifyInput = true;
|
||||
builder.VerifyOutput = true;
|
||||
machine->adjustPassManager(builder);
|
||||
pass_manager_builder.OptLevel = 3;
|
||||
pass_manager_builder.SLPVectorize = true;
|
||||
pass_manager_builder.LoopVectorize = true;
|
||||
pass_manager_builder.RerollLoops = true;
|
||||
pass_manager_builder.VerifyInput = true;
|
||||
pass_manager_builder.VerifyOutput = true;
|
||||
machine->adjustPassManager(pass_manager_builder);
|
||||
fpm.add(llvm::createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis()));
|
||||
mpm.add(llvm::createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis()));
|
||||
builder.populateFunctionPassManager(fpm);
|
||||
builder.populateModulePassManager(mpm);
|
||||
pass_manager_builder.populateFunctionPassManager(fpm);
|
||||
pass_manager_builder.populateModulePassManager(mpm);
|
||||
fpm.doInitialization();
|
||||
for (auto & function : *module)
|
||||
fpm.run(function);
|
||||
@ -323,26 +288,20 @@ struct LLVMContext
|
||||
throw Exception("Function " + name + " failed to link", ErrorCodes::CANNOT_COMPILE_CODE);
|
||||
symbols[name] = reinterpret_cast<void *>(*address);
|
||||
}
|
||||
#if LLVM_VERSION_MAJOR >= 6
|
||||
return memory_mapper->memory_tracker.get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class LLVMPreparedFunction : public PreparedFunctionImpl
|
||||
{
|
||||
std::string name;
|
||||
std::shared_ptr<LLVMContext> context;
|
||||
void * function;
|
||||
|
||||
public:
|
||||
LLVMPreparedFunction(std::string name_, std::shared_ptr<LLVMContext> context)
|
||||
: name(std::move(name_)), context(context)
|
||||
LLVMPreparedFunction(const std::string & name_, const std::unordered_map<std::string, void *> & symbols)
|
||||
: name(name_)
|
||||
{
|
||||
auto it = context->symbols.find(name);
|
||||
if (context->symbols.end() == it)
|
||||
auto it = symbols.find(name);
|
||||
if (symbols.end() == it)
|
||||
throw Exception("Cannot find symbol " + name + " in LLVMContext", ErrorCodes::LOGICAL_ERROR);
|
||||
function = it->second;
|
||||
}
|
||||
@ -373,16 +332,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static void compileFunctionToLLVMByteCode(std::shared_ptr<LLVMContext> & context, const IFunctionBase & f)
|
||||
static void compileFunctionToLLVMByteCode(LLVMContext & context, const IFunctionBase & f)
|
||||
{
|
||||
ProfileEvents::increment(ProfileEvents::CompileFunction);
|
||||
|
||||
auto & arg_types = f.getArgumentTypes();
|
||||
auto & b = context->builder;
|
||||
auto & b = context.builder;
|
||||
auto * size_type = b.getIntNTy(sizeof(size_t) * 8);
|
||||
auto * data_type = llvm::StructType::get(b.getInt8PtrTy(), b.getInt8PtrTy(), size_type);
|
||||
auto * func_type = llvm::FunctionType::get(b.getVoidTy(), { size_type, data_type->getPointerTo() }, /*isVarArg=*/false);
|
||||
auto * func = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage, f.getName(), context->module.get());
|
||||
auto * func = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage, f.getName(), context.module.get());
|
||||
auto args = func->args().begin();
|
||||
llvm::Value * counter_arg = &*args++;
|
||||
llvm::Value * columns_arg = &*args++;
|
||||
@ -504,12 +463,21 @@ static CompilableExpression subexpression(const IFunctionBase & f, std::vector<C
|
||||
};
|
||||
}
|
||||
|
||||
LLVMFunction::LLVMFunction(const ExpressionActions::Actions & actions, std::shared_ptr<LLVMContext> context, const Block & sample_block)
|
||||
: name(actions.back().result_name), context(context)
|
||||
struct LLVMModuleState
|
||||
{
|
||||
std::unordered_map<std::string, void *> symbols;
|
||||
std::shared_ptr<llvm::LLVMContext> major_context;
|
||||
std::shared_ptr<llvm::SectionMemoryManager> memory_manager;
|
||||
};
|
||||
|
||||
LLVMFunction::LLVMFunction(const ExpressionActions::Actions & actions, const Block & sample_block)
|
||||
: name(actions.back().result_name)
|
||||
, module_state(std::make_unique<LLVMModuleState>())
|
||||
{
|
||||
LLVMContext context;
|
||||
for (const auto & c : sample_block)
|
||||
/// TODO: implement `getNativeValue` for all types & replace the check with `c.column && toNativeType(...)`
|
||||
if (c.column && getNativeValue(toNativeType(context->builder, c.type), *c.column, 0))
|
||||
if (c.column && getNativeValue(toNativeType(context.builder, c.type), *c.column, 0))
|
||||
subexpressions[c.name] = subexpression(c.column, c.type);
|
||||
for (const auto & action : actions)
|
||||
{
|
||||
@ -530,6 +498,11 @@ LLVMFunction::LLVMFunction(const ExpressionActions::Actions & actions, std::shar
|
||||
originals.push_back(action.function_base);
|
||||
}
|
||||
compileFunctionToLLVMByteCode(context, *this);
|
||||
context.compileAllFunctionsToNativeCode();
|
||||
|
||||
module_state->symbols = context.symbols;
|
||||
module_state->major_context = context.context;
|
||||
module_state->memory_manager = context.memory_manager;
|
||||
}
|
||||
|
||||
llvm::Value * LLVMFunction::compile(llvm::IRBuilderBase & builder, ValuePlaceholders values) const
|
||||
@ -540,8 +513,7 @@ llvm::Value * LLVMFunction::compile(llvm::IRBuilderBase & builder, ValuePlacehol
|
||||
return it->second(builder, values);
|
||||
}
|
||||
|
||||
|
||||
PreparedFunctionPtr LLVMFunction::prepare(const Block &, const ColumnNumbers &, size_t) const { return std::make_shared<LLVMPreparedFunction>(name, context); }
|
||||
PreparedFunctionPtr LLVMFunction::prepare(const Block &, const ColumnNumbers &, size_t) const { return std::make_shared<LLVMPreparedFunction>(name, module_state->symbols); }
|
||||
|
||||
bool LLVMFunction::isDeterministic() const
|
||||
{
|
||||
@ -622,28 +594,6 @@ static bool isCompilable(const IFunctionBase & function)
|
||||
return function.isCompilable();
|
||||
}
|
||||
|
||||
size_t CompiledExpressionCache::weight() const
|
||||
{
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 6
|
||||
std::lock_guard lock(mutex);
|
||||
size_t result{0};
|
||||
std::unordered_set<size_t> seen;
|
||||
for (const auto & cell : cells)
|
||||
{
|
||||
auto function_context = cell.second.value->getContext();
|
||||
if (!seen.count(function_context->id))
|
||||
{
|
||||
result += function_context->memory_mapper->memory_tracker.get();
|
||||
seen.insert(function_context->id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return Base::weight();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::unordered_set<std::optional<size_t>>> getActionsDependents(const ExpressionActions::Actions & actions, const Names & output_columns)
|
||||
{
|
||||
/// an empty optional is a poisoned value prohibiting the column's producer from being removed
|
||||
@ -748,21 +698,16 @@ void compileFunctions(ExpressionActions::Actions & actions, const Names & output
|
||||
std::tie(fn, std::ignore) = compilation_cache->getOrSet(hash_key, [&inlined_func=std::as_const(fused[i]), &sample_block] ()
|
||||
{
|
||||
Stopwatch watch;
|
||||
std::shared_ptr<LLVMContext> context = std::make_shared<LLVMContext>();
|
||||
auto result_fn = std::make_shared<LLVMFunction>(inlined_func, context, sample_block);
|
||||
size_t used_memory = context->compileAllFunctionsToNativeCode();
|
||||
ProfileEvents::increment(ProfileEvents::CompileExpressionsBytes, used_memory);
|
||||
std::shared_ptr<LLVMFunction> result_fn;
|
||||
result_fn = std::make_shared<LLVMFunction>(inlined_func, sample_block);
|
||||
ProfileEvents::increment(ProfileEvents::CompileExpressionsMicroseconds, watch.elapsedMicroseconds());
|
||||
return result_fn;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::shared_ptr<LLVMContext> context = std::make_shared<LLVMContext>();
|
||||
Stopwatch watch;
|
||||
fn = std::make_shared<LLVMFunction>(fused[i], context, sample_block);
|
||||
size_t used_memory = context->compileAllFunctionsToNativeCode();
|
||||
ProfileEvents::increment(ProfileEvents::CompileExpressionsBytes, used_memory);
|
||||
fn = std::make_shared<LLVMFunction>(fused[i], sample_block);
|
||||
ProfileEvents::increment(ProfileEvents::CompileExpressionsMicroseconds, watch.elapsedMicroseconds());
|
||||
}
|
||||
|
||||
|
@ -14,19 +14,23 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
struct LLVMContext;
|
||||
using CompilableExpression = std::function<llvm::Value * (llvm::IRBuilderBase &, const ValuePlaceholders &)>;
|
||||
|
||||
struct LLVMModuleState;
|
||||
|
||||
class LLVMFunction : public IFunctionBase
|
||||
{
|
||||
std::string name;
|
||||
Names arg_names;
|
||||
DataTypes arg_types;
|
||||
std::shared_ptr<LLVMContext> context;
|
||||
|
||||
std::vector<FunctionBasePtr> originals;
|
||||
std::unordered_map<StringRef, CompilableExpression> subexpressions;
|
||||
|
||||
std::unique_ptr<LLVMModuleState> module_state;
|
||||
|
||||
public:
|
||||
LLVMFunction(const ExpressionActions::Actions & actions, std::shared_ptr<LLVMContext> context, const Block & sample_block);
|
||||
LLVMFunction(const ExpressionActions::Actions & actions, const Block & sample_block);
|
||||
|
||||
bool isCompilable() const override { return true; }
|
||||
|
||||
@ -54,8 +58,7 @@ public:
|
||||
|
||||
Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override;
|
||||
|
||||
std::shared_ptr<LLVMContext> getContext() const { return context; }
|
||||
|
||||
const LLVMModuleState * getLLVMModuleState() const { return module_state.get(); }
|
||||
};
|
||||
|
||||
/** This child of LRUCache breaks one of it's invariants: total weight may be changed after insertion.
|
||||
@ -63,13 +66,9 @@ public:
|
||||
*/
|
||||
class CompiledExpressionCache : public LRUCache<UInt128, LLVMFunction, UInt128Hash>
|
||||
{
|
||||
private:
|
||||
using Base = LRUCache<UInt128, LLVMFunction, UInt128Hash>;
|
||||
|
||||
public:
|
||||
using Base = LRUCache<UInt128, LLVMFunction, UInt128Hash>;
|
||||
using Base::Base;
|
||||
|
||||
size_t weight() const;
|
||||
};
|
||||
|
||||
/// For each APPLY_FUNCTION action, try to compile the function to native code; if the only uses of a compilable
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <DataStreams/IProfilingBlockInputStream.h>
|
||||
#include <DataStreams/OwningBlockInputStream.h>
|
||||
#include <Poco/Path.h>
|
||||
#include <TableFunctions/parseRemoteDescription.h>
|
||||
#include <Common/parseRemoteDescription.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include "TableFunctionRemote.h"
|
||||
|
||||
#include <Storages/getStructureOfRemoteTable.h>
|
||||
#include <Storages/StorageDistributed.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
@ -8,10 +10,8 @@
|
||||
#include <Interpreters/Cluster.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
#include <TableFunctions/TableFunctionRemote.h>
|
||||
#include <Common/parseRemoteDescription.h>
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include <TableFunctions/parseRemoteDescription.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -1,4 +1,6 @@
|
||||
FROM ubuntu:18.10
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN echo "deb [trusted=yes] http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >> /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update -y \
|
||||
&& env DEBIAN_FRONTEND=noninteractive \
|
||||
@ -21,9 +23,6 @@ RUN apt-get update -y \
|
||||
lld-7 \
|
||||
libclang-7-dev \
|
||||
liblld-7-dev \
|
||||
llvm-7 \
|
||||
libllvm7 \
|
||||
llvm-7-dev \
|
||||
libicu-dev \
|
||||
libreadline-dev \
|
||||
ninja-build \
|
||||
|
@ -1,8 +1,10 @@
|
||||
FROM ubuntu:18.10
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update -y \
|
||||
RUN echo "deb [trusted=yes] http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" >> /etc/apt/sources.list
|
||||
|
||||
RUN apt-get --allow-unauthenticated update -y \
|
||||
&& env DEBIAN_FRONTEND=noninteractive \
|
||||
apt-get install --yes --no-install-recommends \
|
||||
apt-get --allow-unauthenticated install --yes --no-install-recommends \
|
||||
bash \
|
||||
fakeroot \
|
||||
cmake \
|
||||
@ -22,9 +24,6 @@ RUN apt-get update -y \
|
||||
lld-7 \
|
||||
libclang-7-dev \
|
||||
liblld-7-dev \
|
||||
llvm-7 \
|
||||
libllvm7 \
|
||||
llvm-7-dev \
|
||||
libicu-dev \
|
||||
libreadline-dev \
|
||||
ninja-build \
|
||||
@ -33,8 +32,8 @@ RUN apt-get update -y \
|
||||
devscripts \
|
||||
debhelper \
|
||||
git \
|
||||
libc++abi-dev \
|
||||
libc++-dev \
|
||||
libc++abi-dev \
|
||||
libboost-program-options-dev \
|
||||
libboost-system-dev \
|
||||
libboost-filesystem-dev \
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Array of `T`-type items.
|
||||
|
||||
`T` can be anything, including an array. Use multi-dimensional arrays with caution. ClickHouse has limited support for multi-dimensional arrays. For example, they can't be stored in `MergeTree` tables.
|
||||
`T` can be anything, including an array.
|
||||
|
||||
## Creating an array
|
||||
|
||||
|
@ -625,11 +625,11 @@ Path to temporary data for processing large queries.
|
||||
```
|
||||
|
||||
|
||||
## uncompressed_cache_size
|
||||
## uncompressed_cache_size {#server-settings-uncompressed_cache_size}
|
||||
|
||||
Cache size (in bytes) for uncompressed data used by table engines from the [MergeTree](../../operations/table_engines/mergetree.md).
|
||||
|
||||
There is one shared cache for the server. Memory is allocated on demand. The cache is used if the option [use_uncompressed_cache](../settings/settings.md) is enabled.
|
||||
There is one shared cache for the server. Memory is allocated on demand. The cache is used if the option [use_uncompressed_cache](../settings/settings.md#setting-use_uncompressed_cache) is enabled.
|
||||
|
||||
The uncompressed cache is advantageous for very short queries in individual cases.
|
||||
|
||||
|
@ -110,6 +110,56 @@ Used for the same purpose as `max_block_size`, but it sets the recommended block
|
||||
However, the block size cannot be more than `max_block_size` rows.
|
||||
Disabled by default (set to 0). It only works when reading from MergeTree engines.
|
||||
|
||||
## merge_tree_uniform_read_distribution {#setting-merge_tree_uniform_read_distribution}
|
||||
|
||||
When reading from [MergeTree*](../table_engines/mergetree.md) tables, ClickHouse uses several threads. This setting turns on/off the uniform distribution of reading tasks over the working threads. The algorithm of the uniform distribution aims to make execution time for all the threads approximately equal in a `SELECT` query.
|
||||
|
||||
**Possible values**
|
||||
|
||||
- 0 — Uniform read distribution turned off.
|
||||
- 1 — Uniform read distribution turned on.
|
||||
|
||||
**Default value** — 1.
|
||||
|
||||
## merge_tree_min_rows_for_concurrent_read {#setting-merge_tree_min_rows_for_concurrent_read}
|
||||
|
||||
If a number of rows to be read from a file of [MergeTree*](../table_engines/mergetree.md) table exceeds `merge_tree_min_rows_for_concurrent_read` then ClickHouse tries to perform a concurrent reading from this file by several threads.
|
||||
|
||||
**Possible values**
|
||||
|
||||
Any positive integer.
|
||||
|
||||
**Default value** — 163840.
|
||||
|
||||
## merge_tree_min_rows_for_seek {#setting-merge_tree_min_rows_for_seek}
|
||||
|
||||
If the distance between two data blocks to be read in one file less than `merge_tree_min_rows_for_seek` rows, then ClickHouse does not seek through the file, it reads the data sequentially.
|
||||
|
||||
**Possible values**
|
||||
|
||||
Any positive integer.
|
||||
|
||||
**Default value** — 0.
|
||||
|
||||
## merge_tree_coarse_index_granularity {#setting-merge_tree_coarse_index_granularity}
|
||||
|
||||
When searching data, ClickHouse checks the data marks in the index file. If ClickHouse finds that required keys are in some range, it divides this range for `merge_tree_coarse_index_granularity` subranges and searches the required keys there recursively.
|
||||
|
||||
**Possible values**
|
||||
|
||||
Any positive even integer.
|
||||
|
||||
**Default value** — 8.
|
||||
|
||||
## merge_tree_max_rows_to_use_cache {#setting-merge_tree_max_rows_to_use_cache}
|
||||
|
||||
If ClickHouse should read more than `merge_tree_max_rows_to_use_cache` rows in one query, it does not use the cash of uncompressed blocks. The [uncompressed_cache_size](../server_settings/settings.md#server-settings-uncompressed_cache_size) server setting defines the size of the cache of uncompressed blocks.
|
||||
|
||||
**Possible values**
|
||||
|
||||
Any positive integer.
|
||||
|
||||
**Default value** — 1048576.
|
||||
|
||||
## log_queries
|
||||
|
||||
@ -242,10 +292,10 @@ Whether to count extreme values (the minimums and maximums in columns of a query
|
||||
For more information, see the section "Extreme values".
|
||||
|
||||
|
||||
## use_uncompressed_cache
|
||||
## use_uncompressed_cache {#setting-use_uncompressed_cache}
|
||||
|
||||
Whether to use a cache of uncompressed blocks. Accepts 0 or 1. By default, 0 (disabled).
|
||||
The uncompressed cache (only for tables in the MergeTree family) allows significantly reducing latency and increasing throughput when working with a large number of short queries. Enable this setting for users who send frequent short requests. Also pay attention to the 'uncompressed_cache_size' configuration parameter (only set in the config file) – the size of uncompressed cache blocks. By default, it is 8 GiB. The uncompressed cache is filled in as needed; the least-used data is automatically deleted.
|
||||
The uncompressed cache (only for tables in the MergeTree family) allows significantly reducing latency and increasing throughput when working with a large number of short queries. Enable this setting for users who send frequent short requests. Also pay attention to the [uncompressed_cache_size](../server_settings/settings.md#server-settings-uncompressed_cache_size) configuration parameter (only set in the config file) – the size of uncompressed cache blocks. By default, it is 8 GiB. The uncompressed cache is filled in as needed; the least-used data is automatically deleted.
|
||||
|
||||
For queries that read at least a somewhat large volume of data (one million rows or more), the uncompressed cache is disabled automatically in order to save space for truly small queries. So you can keep the 'use_uncompressed_cache' setting always set to 1.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
# clickhouse-local
|
||||
|
||||
Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../../query_language/index.md#queries) ClickHouse.
|
||||
Принимает на вход данные, которые можно представить в табличном виде и выполняет над ними операции, заданные на [языке запросов](../../query_language/index.md) ClickHouse.
|
||||
|
||||
`clickhouse-local` использует движок сервера ClickHouse, т.е. поддерживает все форматы данных и движки таблиц, с которыми работает ClickHouse, при этом для выполнения операций не требуется запущенный сервер.
|
||||
|
||||
|
@ -1,40 +1,69 @@
|
||||
## ATTACH {#queries}
|
||||
# Прочие виды запросов
|
||||
|
||||
## ATTACH
|
||||
|
||||
Запрос полностью аналогичен запросу `CREATE`, но:
|
||||
|
||||
- вместо слова `CREATE` используется слово `ATTACH`;
|
||||
- запрос не создаёт данные на диске, а предполагает, что данные уже лежат в соответствующих местах, и всего лишь добавляет информацию о таблице в сервер.
|
||||
- запрос не создаёт данные на диске, а предполагает, что данные уже лежат в соответствующих местах, и всего лишь добавляет информацию о таблице на сервер. После выполнения запроса `ATTACH` сервер будет знать о существовании таблицы.
|
||||
|
||||
После выполнения `ATTACH`, сервер будет знать о существовании таблицы.
|
||||
Если таблица перед этим была отсоединена (`DETACH`), т.е. её структура известна, можно использовать сокращенную форму записи без определения структуры.
|
||||
|
||||
Если таблица перед этим была отсоединена (`DETACH`), т.е. её структура известна, то можно использовать сокращенную форму записи без определения структуры.
|
||||
|
||||
``` sql
|
||||
```sql
|
||||
ATTACH TABLE [IF NOT EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
Этот запрос используется при старте сервера. Сервер хранит метаданные таблиц в виде файлов с запросами `ATTACH`, которые он просто исполняет при запуске (за исключением системных таблиц, создание которых явно вписано в сервер).
|
||||
Этот запрос используется при старте сервера. Сервер хранит метаданные таблиц в виде файлов с запросами `ATTACH`, которые он просто исполняет при запуске (за исключением системных таблиц, которые явно создаются на сервере).
|
||||
|
||||
## DROP
|
||||
Запрос имеет два вида: `DROP DATABASE` и `DROP TABLE`.
|
||||
## CHECK TABLE
|
||||
|
||||
``` sql
|
||||
DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster]
|
||||
Проверяет таблицу на повреждение данных.
|
||||
|
||||
```sql
|
||||
CHECK TABLE [db.]name
|
||||
```
|
||||
|
||||
Удаляет все таблицы внутри базы данных db, а затем саму базу данных db.
|
||||
Если указано `IF EXISTS` - не выдавать ошибку, если база данных не существует.
|
||||
Запрос `CHECK TABLE` сравнивает текущие размеры файлов (в которых хранятся данные из колонок) с ожидаемыми значениями. Если значения не совпадают, данные в таблице считаются поврежденными. Искажение возможно, например, из-за сбоя при записи данных.
|
||||
|
||||
``` sql
|
||||
DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
Ответ содержит колонку `result`, содержащую одну строку с типом [Boolean](../data_types/boolean.md). Допустимые значения:
|
||||
|
||||
- 0 - данные в таблице повреждены;
|
||||
- 1 - данные не повреждены.
|
||||
|
||||
Запрос `CHECK TABLE` поддерживается только для следующих движков:
|
||||
|
||||
- [Log](../operations/table_engines/log.md)
|
||||
- [TinyLog](../operations/table_engines/tinylog.md)
|
||||
- StripeLog
|
||||
|
||||
В этих движках не предусмотрено автоматическое восстановление данных после сбоя. Поэтому используйте запрос `CHECK TABLE`, чтобы своевременно выявить повреждение данных.
|
||||
|
||||
Обратите внимание, высокая защита целостности данных обеспечивается в таблицах семейства [MergeTree](../operations/table_engines/mergetree.md). Для избежания потери данных рекомендуется использовать именно эти таблицы.
|
||||
|
||||
**Что делать, если данные повреждены**
|
||||
|
||||
В этом случае можно скопировать оставшиеся неповрежденные данные в другую таблицу. Для этого:
|
||||
|
||||
1. Создайте новую таблицу с такой же структурой, как у поврежденной таблицы. Для этого выполните запрос `CREATE TABLE <new_table_name> AS <damaged_table_name>`.
|
||||
2. Установите значение параметра [max_threads](../operations/settings/settings.md#settings-max_threads) в 1. Это нужно для того, чтобы выполнить следующий запрос в одном потоке. Установить значение параметра можно через запрос: `SET max_threads = 1`.
|
||||
3. Выполните запрос `INSERT INTO <new_table_name> SELECT * FROM <damaged_table_name>`. В результате неповрежденные данные будут скопированы в другую таблицу. Обратите внимание, будут скопированы только те данные, которые следуют до поврежденного участка.
|
||||
4. Перезапустите `clickhouse-client`, чтобы вернуть предыдущее значение параметра `max_threads`.
|
||||
|
||||
## DESCRIBE TABLE
|
||||
|
||||
```sql
|
||||
DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Удаляет таблицу.
|
||||
Если указано `IF EXISTS` - не выдавать ошибку, если таблица не существует или база данных не существует.
|
||||
Возвращает два столбца: `name`, `type` типа `String`, в которых описаны имена и типы столбцов указанной таблицы.
|
||||
|
||||
Вложенные структуры данных выводятся в "развёрнутом" виде. То есть, каждый столбец - по отдельности, с именем через точку.
|
||||
|
||||
## DETACH
|
||||
|
||||
Удаляет из сервера информацию о таблице name. Сервер перестаёт знать о существовании таблицы.
|
||||
|
||||
``` sql
|
||||
```sql
|
||||
DETACH TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
@ -43,139 +72,35 @@ DETACH TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
|
||||
Запроса `DETACH DATABASE` нет.
|
||||
|
||||
## RENAME
|
||||
Переименовывает одну или несколько таблиц.
|
||||
## DROP
|
||||
|
||||
``` sql
|
||||
RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster]
|
||||
Запрос имеет два вида: `DROP DATABASE` и `DROP TABLE`.
|
||||
|
||||
```sql
|
||||
DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
Все таблицы переименовываются под глобальной блокировкой. Переименовывание таблицы является лёгкой операцией. Если вы указали после TO другую базу данных, то таблица будет перенесена в эту базу данных. При этом, директории с базами данных должны быть расположены в одной файловой системе (иначе возвращается ошибка).
|
||||
Удаляет все таблицы внутри базы данных db, а затем саму базу данных db.
|
||||
Если указано `IF EXISTS` - не выдавать ошибку, если база данных не существует.
|
||||
|
||||
## SHOW DATABASES
|
||||
|
||||
``` sql
|
||||
SHOW DATABASES [INTO OUTFILE filename] [FORMAT format]
|
||||
```sql
|
||||
DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
Выводит список всех баз данных.
|
||||
Запрос полностью аналогичен запросу `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Смотрите также раздел "Форматы".
|
||||
|
||||
## SHOW TABLES
|
||||
|
||||
``` sql
|
||||
SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Выводит список таблиц
|
||||
|
||||
- из текущей БД или из БД db, если указано FROM db;
|
||||
- всех, или имя которых соответствует шаблону pattern, если указано LIKE 'pattern';
|
||||
|
||||
Запрос полностью аналогичен запросу: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Смотрите также раздел "Оператор LIKE".
|
||||
|
||||
## SHOW PROCESSLIST
|
||||
|
||||
``` sql
|
||||
SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Выводит список запросов, выполняющихся в данный момент времени, кроме запросов `SHOW PROCESSLIST`.
|
||||
|
||||
Выдаёт таблицу, содержащую столбцы:
|
||||
|
||||
**user** - пользователь, под которым был задан запрос. Следует иметь ввиду, что при распределённой обработке запроса на удалённые серверы запросы отправляются под пользователем default. И SHOW PROCESSLIST показывает имя пользователя для конкретного запроса, а не для запроса, который данный запрос инициировал.
|
||||
|
||||
**address** - имя хоста, с которого был отправлен запрос. При распределённой обработке запроса на удалённых серверах — это имя хоста-инициатора запроса. Чтобы проследить, откуда был задан распределённый запрос изначально, следует смотреть SHOW PROCESSLIST на сервере-инициаторе запроса.
|
||||
|
||||
**elapsed** - время выполнения запроса, в секундах. Запросы выводятся упорядоченными по убыванию времени выполнения.
|
||||
|
||||
**rows_read**, **bytes_read** - сколько было прочитано строк, байт несжатых данных при обработке запроса. При распределённой обработке запроса суммируются данные со всех удалённых серверов. Именно эти данные используются для ограничений и квот.
|
||||
|
||||
**memory_usage** - текущее потребление оперативки в байтах. Смотрите настройку max_memory_usage.
|
||||
|
||||
**query** - сам запрос. В запросах INSERT данные для вставки не выводятся.
|
||||
|
||||
**query_id** - идентификатор запроса. Непустой, только если был явно задан пользователем. При распределённой обработке запроса идентификатор запроса не передаётся на удалённые серверы.
|
||||
|
||||
Запрос полностью аналогичен запросу: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Полезный совет (выполните в консоли):
|
||||
|
||||
```bash
|
||||
watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'"
|
||||
```
|
||||
|
||||
## SHOW CREATE TABLE
|
||||
|
||||
``` sql
|
||||
SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Возвращает один столбец statement типа `String`, содержащий одно значение - запрос `CREATE`, с помощью которого создана указанная таблица.
|
||||
|
||||
## DESCRIBE TABLE
|
||||
|
||||
``` sql
|
||||
DESC|DESCRIBE TABLE [db.]table [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Возвращает два столбца: `name`, `type` типа `String`, в которых описаны имена и типы столбцов указанной таблицы.
|
||||
|
||||
Вложенные структуры данных выводятся в "развёрнутом" виде. То есть, каждый столбец - по отдельности, с именем через точку.
|
||||
Удаляет таблицу.
|
||||
Если указано `IF EXISTS` - не выдавать ошибку, если таблица не существует или база данных не существует.
|
||||
|
||||
## EXISTS
|
||||
|
||||
``` sql
|
||||
```sql
|
||||
EXISTS [TEMPORARY] TABLE [db.]name [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Возвращает один столбец типа `UInt8`, содержащий одно значение - `0`, если таблицы или БД не существует и `1`, если таблица в указанной БД существует.
|
||||
|
||||
## USE
|
||||
|
||||
``` sql
|
||||
USE db
|
||||
```
|
||||
|
||||
Позволяет установить текущую базу данных для сессии.
|
||||
Текущая база данных используется для поиска таблиц, если база данных не указана в запросе явно через точку перед именем таблицы.
|
||||
При использовании HTTP протокола, запрос не может быть выполнен, так как понятия сессии не существует.
|
||||
|
||||
## SET
|
||||
|
||||
``` sql
|
||||
SET param = value
|
||||
```
|
||||
|
||||
Позволяет установить настройку `param` в значение `value`. Также можно одним запросом установить все настройки из заданного профиля настроек - для этого, укажите в качестве имени настройки profile. Подробнее смотри раздел "Настройки".
|
||||
Настройка устанавливается на сессию, или на сервер (глобально), если указано `GLOBAL`.
|
||||
При установке глобальной настройки, настройка на все уже запущенные сессии, включая текущую сессию, не устанавливается, а будет использована только для новых сессий.
|
||||
|
||||
При перезапуске сервера, теряются настройки, установленные с помощью `SET`.
|
||||
Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера.
|
||||
|
||||
## OPTIMIZE
|
||||
|
||||
``` sql
|
||||
OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition] [FINAL]
|
||||
```
|
||||
|
||||
Просит движок таблицы сделать что-нибудь, что может привести к более оптимальной работе.
|
||||
Поддерживается только движками `*MergeTree`, в котором выполнение этого запроса инициирует внеочередное слияние кусков данных.
|
||||
Если указан `PARTITION`, то оптимизация будет производиться только для указаной партиции.
|
||||
Если указан `FINAL`, то оптимизация будет производиться даже когда все данные уже лежат в одном куске.
|
||||
|
||||
!!! warning "Внимание"
|
||||
Запрос OPTIMIZE не может устранить причину появления ошибки "Too many parts".
|
||||
|
||||
## KILL QUERY
|
||||
|
||||
``` sql
|
||||
```sql
|
||||
KILL QUERY [ON CLUSTER cluster]
|
||||
WHERE <where expression to SELECT FROM system.processes query>
|
||||
[SYNC|ASYNC|TEST]
|
||||
@ -185,8 +110,9 @@ KILL QUERY [ON CLUSTER cluster]
|
||||
Пытается принудительно остановить исполняющиеся в данный момент запросы.
|
||||
Запросы для принудительной остановки выбираются из таблицы system.processes с помощью условия, указанного в секции `WHERE` запроса `KILL`.
|
||||
|
||||
Примеры:
|
||||
``` sql
|
||||
Примеры
|
||||
|
||||
```sql
|
||||
-- Принудительно останавливает все запросы с указанным query_id:
|
||||
KILL QUERY WHERE query_id='2-857d-4a57-9ee0-327da5d60a90'
|
||||
|
||||
@ -208,3 +134,126 @@ Readonly-пользователи могут останавливать толь
|
||||
Тестовый вариант запроса (`TEST`) только проверяет права пользователя и выводит список запросов для остановки.
|
||||
|
||||
[Оригинальная статья](https://clickhouse.yandex/docs/ru/query_language/misc/) <!--hide-->
|
||||
|
||||
## OPTIMIZE
|
||||
|
||||
```sql
|
||||
OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition] [FINAL]
|
||||
```
|
||||
|
||||
Просит движок таблицы сделать что-нибудь, что может привести к более оптимальной работе.
|
||||
Поддерживается только движками `*MergeTree`, в котором выполнение этого запроса инициирует внеочередное слияние кусков данных.
|
||||
Если указан `PARTITION`, то оптимизация будет производиться только для указаной партиции.
|
||||
Если указан `FINAL`, то оптимизация будет производиться даже когда все данные уже лежат в одном куске.
|
||||
|
||||
!!! warning "Внимание"Запрос OPTIMIZE не может устранить причину появления ошибки "Too many parts".
|
||||
|
||||
## RENAME
|
||||
|
||||
Переименовывает одну или несколько таблиц.
|
||||
|
||||
```sql
|
||||
RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
Все таблицы переименовываются под глобальной блокировкой. Переименовывание таблицы является лёгкой операцией. Если вы указали после TO другую базу данных, то таблица будет перенесена в эту базу данных. При этом, директории с базами данных должны быть расположены в одной файловой системе (иначе возвращается ошибка).
|
||||
|
||||
## SET
|
||||
|
||||
```sql
|
||||
SET param = value
|
||||
```
|
||||
|
||||
Позволяет установить настройку `param` в значение `value`. Также можно одним запросом установить все настройки из заданного профиля настроек. Для этого укажите 'profile' в качестве имени настройки. Подробнее смотрите в разделе "Настройки".
|
||||
Настройка устанавливается на сессию, или на сервер (глобально), если указано `GLOBAL`.
|
||||
При установке глобальных настроек, эти настройки не применяются к уже запущенной сессии, включая текущую сессию. Она будет использована только для новых сессий.
|
||||
|
||||
При перезапуске сервера теряются настройки, установленные с помощью `SET`.
|
||||
Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера.
|
||||
|
||||
## SHOW CREATE TABLE
|
||||
|
||||
```sql
|
||||
SHOW CREATE [TEMPORARY] TABLE [db.]table [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Возвращает один столбец statement типа `String`, содержащий одно значение - запрос `CREATE`, с помощью которого создана указанная таблица.
|
||||
|
||||
## SHOW DATABASES
|
||||
|
||||
```sql
|
||||
SHOW DATABASES [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Выводит список всех баз данных.
|
||||
Запрос полностью аналогичен запросу `SELECT name FROM system.databases [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Смотрите также раздел "Форматы".
|
||||
|
||||
## SHOW PROCESSLIST
|
||||
|
||||
```sql
|
||||
SHOW PROCESSLIST [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Выводит список запросов, выполняющихся в данный момент времени, кроме запросов `SHOW PROCESSLIST`.
|
||||
|
||||
Выдаёт таблицу, содержащую столбцы:
|
||||
|
||||
**user** - пользователь, под которым был задан запрос. Следует иметь ввиду, что при распределённой обработке запроса на удалённые серверы запросы отправляются под пользователем 'default'. И SHOW PROCESSLIST показывает имя пользователя для конкретного запроса, а не для запроса, который данный запрос инициировал.
|
||||
|
||||
**address** - имя хоста, с которого был отправлен запрос. При распределённой обработке запроса на удалённых серверах — это имя хоста-инициатора запроса. Чтобы проследить, откуда был задан распределённый запрос изначально, следует смотреть SHOW PROCESSLIST на сервере-инициаторе запроса.
|
||||
|
||||
**elapsed** - время выполнения запроса, в секундах. Запросы выводятся в порядке убывания времени выполнения.
|
||||
|
||||
**rows_read**, **bytes_read** - сколько было прочитано строк, байт несжатых данных при обработке запроса. При распределённой обработке запроса суммируются данные со всех удалённых серверов. Именно эти данные используются для ограничений и квот.
|
||||
|
||||
**memory_usage** - текущее потребление оперативки в байтах. Смотрите настройку 'max_memory_usage'.
|
||||
|
||||
**query** - сам запрос. В запросах INSERT данные для вставки не выводятся.
|
||||
|
||||
**query_id** - идентификатор запроса. Непустой, только если был явно задан пользователем. При распределённой обработке запроса идентификатор запроса не передаётся на удалённые серверы.
|
||||
|
||||
Запрос полностью аналогичен запросу: `SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Полезный совет (выполните в консоли):
|
||||
|
||||
```bash
|
||||
watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'"
|
||||
```
|
||||
|
||||
## SHOW TABLES
|
||||
|
||||
```sql
|
||||
SHOW [TEMPORARY] TABLES [FROM db] [LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
Выводит список таблиц:
|
||||
|
||||
- из текущей базы данных или из базы db, если указано `FROM db`;
|
||||
- всех, или имя которых соответствует шаблону pattern, если указано `LIKE 'pattern'`;
|
||||
|
||||
Запрос полностью аналогичен запросу: `SELECT name FROM system.tables WHERE database = 'db' [AND name LIKE 'pattern'] [INTO OUTFILE filename] [FORMAT format]`.
|
||||
|
||||
Смотрите также раздел "Оператор LIKE".
|
||||
|
||||
## TRUNCATE
|
||||
|
||||
```sql
|
||||
TRUNCATE TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster]
|
||||
```
|
||||
|
||||
Удаляет все данные из таблицы. Если условие `IF EXISTS` не указано, запрос вернет ошибку, если таблицы не существует.
|
||||
|
||||
Запрос `TRUNCATE` не поддерживается для следующих движков: [View](../operations/table_engines/view.md), [File](../operations/table_engines/file.md), [URL](../operations/table_engines/url.md) and [Null](../operations/table_engines/null.md).
|
||||
|
||||
## USE
|
||||
|
||||
```sql
|
||||
USE db
|
||||
```
|
||||
|
||||
Позволяет установить текущую базу данных для сессии.
|
||||
Текущая база данных используется для поиска таблиц, если база данных не указана в запросе явно через точку перед именем таблицы.
|
||||
При использовании HTTP протокола запрос не может быть выполнен, так как понятия сессии не существует.
|
||||
|
||||
|
@ -178,11 +178,11 @@ nav:
|
||||
|
||||
- '开发者指南':
|
||||
- 'hidden': 'development/index.md'
|
||||
- 'Overview of ClickHouse architecture': 'development/architecture.md'
|
||||
- 'How to build ClickHouse on Linux': 'development/build.md'
|
||||
- 'How to build ClickHouse on Mac OS X': 'development/build_osx.md'
|
||||
- 'How to write C++ code': 'development/style.md'
|
||||
- 'How to run ClickHouse tests': 'development/tests.md'
|
||||
- 'ClickHouse架构概述': 'development/architecture.md'
|
||||
- '如何在Linux中编译ClickHouse': 'development/build.md'
|
||||
- '如何在Mac OS X中编译ClickHouse': 'development/build_osx.md'
|
||||
- '如何编写C++代码': 'development/style.md'
|
||||
- '如何运行ClickHouse测试': 'development/tests.md'
|
||||
|
||||
- '新功能特性':
|
||||
- '路线图': 'roadmap.md'
|
||||
|
@ -99,7 +99,7 @@ def build_for_lang(lang, args):
|
||||
site_dir=os.path.join(args.output_dir, lang),
|
||||
strict=True,
|
||||
theme=theme_cfg,
|
||||
copyright='©2016–2018 Yandex LLC',
|
||||
copyright='©2016–2019 Yandex LLC',
|
||||
use_directory_urls=True,
|
||||
repo_name='yandex/ClickHouse',
|
||||
repo_url='https://github.com/yandex/ClickHouse/',
|
||||
|
@ -40,8 +40,10 @@
|
||||
{% block htmltitle %}
|
||||
{% if page and page.meta and page.meta.title %}
|
||||
<title>{{ page.meta.title }}</title>
|
||||
{% elif page and page.title and not page.is_homepage %}
|
||||
{% elif page and page.title and not page.is_homepage and page.title != 'hidden' %}
|
||||
<title>{{ page.title }} - {{ config.site_name }}</title>
|
||||
{% elif page and page.title and not page.is_homepage and page.title == 'hidden' and page.ancestors %}
|
||||
<title>{{ (page.ancestors | first).title }} - {{ config.site_name }}</title>
|
||||
{% else %}
|
||||
<title>{{ config.site_name }}</title>
|
||||
{% endif %}
|
||||
|
@ -1 +0,0 @@
|
||||
../../en/development/tests.md
|
257
docs/zh/development/tests.md
Normal file
257
docs/zh/development/tests.md
Normal file
@ -0,0 +1,257 @@
|
||||
# ClickHouse 测试
|
||||
|
||||
|
||||
## 功能性测试
|
||||
|
||||
功能性测试是最简便使用的。绝大部分 ClickHouse 的功能可以通过功能性测试来测试,任何代码的更改都必须通过该测试。
|
||||
|
||||
每个功能测试会向正在运行的 ClickHouse服 务器发送一个或多个查询,并将结果与预期结果进行比较。
|
||||
|
||||
测试用例在 `dbms/src/tests/queries` 目录中。这里有两个子目录:`stateless` 和 `stateful`目录。 无状态的测试无需预加载测试数据集 - 通常是在测试运行期间动态创建小量的数据集。有状态测试需要来自 Yandex.Metrica 的预加载测试数据,而不向一般公众提供。 我们倾向于仅使用“无状态”测试并避免添加新的“有状态”测试。
|
||||
|
||||
每个测试用例可以是两种类型之一:`.sql` 和 `.sh`。`.sql` 测试文件是用于管理`clickhouse-client --multiquery --testmode`的简单SQL脚本。`.sh` 测试文件是一个可以自己运行的脚本。
|
||||
|
||||
要运行所有测试,请使用 `dbms/tests/clickhouse-test` 工具,用 `--help` 可以获取所有的选项列表。您可以简单地运行所有测试或运行测试名称中的子字符串过滤的测试子集:`./clickhouse-test substring`。
|
||||
|
||||
调用功能测试最简单的方法是将 `clickhouse-client` 复制到`/usr/bin/`,运行`clickhouse-server`,然后从自己的目录运行`./ clickhouse-test`。
|
||||
|
||||
要添加新测试,请在 `dbms/src/tests/queries/0_stateless` 目录内添加新的 `.sql` 或 `.sh` 文件,手动检查,然后按以下方式生成 `.reference` 文件: `clickhouse-client -n --testmode < 00000_test.sql > 00000_test.reference` or `./00000_test.sh > ./00000_test.reference`。
|
||||
|
||||
测试应该只使用(创建,删除等)`test` 数据库中的表,这些表假定是事先创建的; 测试也可以使用临时表。
|
||||
|
||||
如果要在功能测试中使用分布式查询,可以利用 `remote` 表函数和 `127.0.0.{1..2}` 地址为服务器查询自身; 或者您可以在服务器配置文件中使用预定义的测试集群,例如`test_shard_localhost`。
|
||||
|
||||
有些测试在名称中标有 `zookeeper`,`shard` 或 `long`。`zookeeper` 用于使用ZooKeeper的测试; `shard` 用于需要服务器监听`127.0.0.*`的测试。`long` 适用于运行时间稍长一秒的测试。
|
||||
|
||||
|
||||
## 已知的bug
|
||||
|
||||
如果我们知道一些可以通过功能测试轻松复制的错误,我们将准备好的功能测试放在 `dbms/src/tests/queries/bugs` 目录中。当修复错误时,这些测试将被移动到 `dbms/src/tests/queries/0_stateless` 目录中。
|
||||
|
||||
|
||||
## 集成测试
|
||||
|
||||
集成测试允许在集群配置中测试 ClickHouse,并与其他服务器(如MySQL,Postgres,MongoDB)进行 ClickHouse 交互。它们可用于模拟网络拆分,数据包丢弃等。这些测试在Docker 下运行,并使用各种软件创建多个容器。
|
||||
|
||||
参考 `dbms/tests/integration/README.md` 文档关于如何使用集成测试。
|
||||
|
||||
请注意,ClickHouse 与第三方驱动程序的集成未经过测试。此外,我们目前还没有与 JDBC 和ODBC 驱动程序进行集成测试。
|
||||
|
||||
|
||||
## 单元测试
|
||||
|
||||
当您想要测试整个 ClickHouse,而不是单个独立的库或类时,单元测试非常有用。您可以使用`ENABLE_TESTS` CMake 选项启用或禁用测试构建。单元测试(和其他测试程序)位于代码中的`tests` 子目录中。要运行单元测试,请键入 `ninja test`。有些测试使用 `gtest`,但有些只是在测试失败时返回非零状态码。
|
||||
|
||||
如果代码已经被功能测试覆盖(并且功能测试通常使用起来要简单得多),则不一定要进行单元测试。
|
||||
|
||||
|
||||
## 性能测试
|
||||
|
||||
性能测试允许测量和比较综合查询中 ClickHouse 的某些独立部分的性能。测试位于`dbms/tests/performance` 目录中。每个测试都由 `.xml` 文件表示,并附有测试用例的描述。使用 `clickhouse performance-test` 工具(嵌入在 `clickhouse` 二进制文件中)运行测试。请参阅 `--help` 以进行调用。
|
||||
|
||||
每个测试在循环中运行一个或多个查询(可能带有参数组合),并具有一些停止条件(如“最大执行速度不会在三秒内更改”)并测量一些有关查询性能的指标(如“最大执行速度”))。某些测试可以包含预加载的测试数据集的前提条件。
|
||||
|
||||
如果要在某些情况下提高 ClickHouse 的性能,并且如果可以在简单查询上观察到改进,则强烈建议编写性能测试。在测试过程中使用 `perf top` 或其他 perf 工具总是有意义的。
|
||||
|
||||
|
||||
性能测试不是基于每个提交运行的。不收集性能测试结果,我们手动比较它们。
|
||||
|
||||
|
||||
## 测试工具和脚本
|
||||
|
||||
`tests`目录中的一些程序不是准备测试,而是测试工具。例如,对于`Lexer`,有一个工具`dbms/src/Parsers/tests/lexer` 标准输出。您可以使用这些工具作为代码示例以及探索和手动测试。
|
||||
|
||||
您还可以将一对文件 `.sh` 和 `.reference` 与工具放在一些预定义的输入上运行它 - 然后可以将脚本结果与 `.reference` 文件进行比较。这些测试不是自动化的。
|
||||
|
||||
|
||||
## 杂项测试
|
||||
|
||||
有一些外部字典的测试位于 `dbms/tests/external_dictionaries`,机器学习模型在`dbms/tests/external_models`目录。这些测试未更新,必须转移到集成测试。
|
||||
|
||||
对于分布式数据的插入,有单独的测试。此测试在单独的服务器上运行 ClickHouse 集群并模拟各种故障情况:网络拆分,数据包丢弃(ClickHouse 节点之间,ClickHouse 和 ZooKeeper之间,ClickHouse 服务器和客户端之间等),进行 `kill -9`,`kill -STOP` 和`kill -CONT` 等操作,类似[Jepsen](https://aphyr.com/tags/Jepsen)。然后,测试检查是否已写入所有已确认的插入,并且所有已拒绝的插入都未写入。
|
||||
|
||||
|
||||
在 ClickHouse 开源之前,分布式测试是由单独的团队编写的,但该团队不再使用 ClickHouse,测试是在 Java 中意外编写的。由于这些原因,必须重写分布式测试并将其移至集成测试。
|
||||
|
||||
|
||||
## 手动测试
|
||||
|
||||
当您开发了新的功能,做手动测试也是合理的。可以按照以下步骤来进行:
|
||||
|
||||
编译 ClickHouse。在命令行中运行 ClickHouse:进入 `dbms/src/programs/clickhouse-server` 目录并运行 `./clickhouse-server`。它会默认使用当前目录的配置文件 (`config.xml`, `users.xml` 以及在 `config.d` 和 `users.d` 目录的文件)。可以使用 `dbms/src/programs/clickhouse-client/clickhouse-client` 来连接数据库。
|
||||
|
||||
或者,您可以安装 ClickHouse 软件包:从 Yandex 存储库中获得稳定版本,或者您可以在ClickHouse源根目录中使用 `./release` 构建自己的软件包。然后使用 `sudo service clickhouse-server start` 启动服务器(或停止服务器)。在 `/etc/clickhouse-server/clickhouse-server.log` 中查找日志。
|
||||
|
||||
当您的系统上已经安装了 ClickHouse 时,您可以构建一个新的 `clickhouse` 二进制文件并替换现有的二进制文件:
|
||||
|
||||
```
|
||||
sudo service clickhouse-server stop
|
||||
sudo cp ./clickhouse /usr/bin/
|
||||
sudo service clickhouse-server start
|
||||
```
|
||||
|
||||
您也可以停止 clickhouse-server 并使用相同的配置运行您自己的服务器,日志打印到终端:
|
||||
```
|
||||
sudo service clickhouse-server stop
|
||||
sudo -u clickhouse /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
|
||||
```
|
||||
|
||||
使用 gdb 的一个示例:
|
||||
```
|
||||
sudo -u clickhouse gdb --args /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
|
||||
```
|
||||
|
||||
如果 clickhouse-server 已经运行并且您不想停止它,您可以更改 `config.xml` 中的端口号(或在 `config.d` 目录中的文件中覆盖它们),配置适当的数据路径,然后运行它。
|
||||
|
||||
`clickhouse` 二进制文件几乎没有依赖关系,适用于各种 Linux 发行版。要快速地测试服务器上的更改,您可以简单地将新建的 `clickhouse` 二进制文件 `scp` 到其他服务器,然后按照上面的示例运行它。
|
||||
|
||||
|
||||
## 测试环境
|
||||
|
||||
在将版本发布为稳定之前,我们将其部署在测试环境中 测试环境是一个处理[Yandex.Metrica](https://metrica.yandex.com/)总数据的1/39部分大小的集群。 我们与 Yandex.Metrica 团队公用我们的测试环境。ClickHouse 在现有数据的基础上无需停机即可升级。 我们首先看到数据处理成功而不会实时滞后,复制继续工作,并且 Yandex.Metrica 团队无法看到问题。 首先的检查可以通过以下方式完成:
|
||||
|
||||
```
|
||||
SELECT hostName() AS h, any(version()), any(uptime()), max(UTCEventTime), count() FROM remote('example01-01-{1..3}t', merge, hits) WHERE EventDate >= today() - 2 GROUP BY h ORDER BY h;
|
||||
```
|
||||
|
||||
在某些情况下,我们还部署到 Yandex 的合作团队的测试环境:市场,云等。此外,我们还有一些用于开发目的的硬件服务器。
|
||||
|
||||
## 负载测试
|
||||
|
||||
部署到测试环境后,我们使用生产群集中的查询运行负载测试。 这是手动完成的。
|
||||
|
||||
确保在生产集群中开启了 `query_log` 选项。
|
||||
|
||||
收集一天或更多的查询日志:
|
||||
```
|
||||
clickhouse-client --query="SELECT DISTINCT query FROM system.query_log WHERE event_date = today() AND query LIKE '%ym:%' AND query NOT LIKE '%system.query_log%' AND type = 2 AND is_initial_query" > queries.tsv
|
||||
```
|
||||
|
||||
这是一个复杂的例子。`type = 2` 将过滤成功执行的查询。`query LIKE'%ym:%'` 用于从 Yandex.Metrica 中选择相关查询。`is_initial_query` 是仅选择由客户端发起的查询,而不是由 ClickHouse 本身(作为分布式查询处理的一部分)。
|
||||
|
||||
`scp` 这份日志到测试机器,并运行以下操作:
|
||||
|
||||
```
|
||||
clickhouse benchmark --concurrency 16 < queries.tsv
|
||||
```
|
||||
(可能你需要指定运行的用户 `--user`)
|
||||
|
||||
然后离开它一晚或周末休息一下。
|
||||
|
||||
你要检查下 `clickhouse-server` 是否崩溃,内存占用是否合理,性能也不会随着时间的推移而降低。
|
||||
|
||||
由于查询和环境的高度可变性,不会记录精确的查询执行时序并且不进行比较。
|
||||
|
||||
|
||||
## 编译测试
|
||||
|
||||
构建测试允许检查构建在各种替代配置和某些外部系统上是否被破坏。测试位于`ci`目录。 它们从 Docker,Vagrant 中的源代码运行构建,有时在 Docker 中运行 `qemu-user-static`。这些测试正在开发中,测试运行不是自动化的。
|
||||
|
||||
动机:
|
||||
|
||||
通常我们会在 ClickHouse 构建的单个版本上发布并运行所有测试。 但是有一些未经过彻底测试的替代构建版本。 例子:
|
||||
|
||||
- 在 FreeBSD 中的构建;
|
||||
- 在 Debian 中使用系统包中的库进行构建;
|
||||
- 使用库的共享链接构建;
|
||||
- 在 AArch64 平台进行构建。
|
||||
|
||||
例如,使用系统包构建是不好的做法,因为我们无法保证系统具有的确切版本的软件包。但 Debian 维护者确实需要这样做。出于这个原因,我们至少必须支持这种构建。另一个例子:共享链接是一个常见的麻烦来源,但是对于一些爱好者来说需要它。
|
||||
|
||||
虽然我们无法对所有构建版本运行所有测试,但我们想要检查至少不会破坏各种构建变体。为此,我们使用构建测试。
|
||||
|
||||
|
||||
## 测试协议兼容性
|
||||
|
||||
当我们扩展 ClickHouse 网络协议时,我们手动测试旧的 clickhouse-client 与新的 clickhouse-server 和新的clickhouse-client 一起使用旧的 clickhouse-server (只需从相应的包中运行二进制文件)
|
||||
|
||||
|
||||
## 来自编译器的帮助
|
||||
|
||||
ClickHouse 主要的代码 (位于`dbms`目录中) 使用 `-Wall -Wextra -Werror` 构建,并带有一些其他已启用的警告。 虽然没有为第三方库启用这些选项。
|
||||
|
||||
Clang 有更多有用的警告 - 您可以使用 `-Weverything` 查找它们并选择默认构建的东西。
|
||||
|
||||
对于生产构建,使用 gcc(它仍然生成比 clang 稍高效的代码)。对于开发来说,clang 通常更方便使用。您可以使用调试模式在自己的机器上构建(以节省笔记本电脑的电量),但请注意,由于更好的控制流程和过程分析,编译器使用 `-O3` 会生成更多警告。 当使用 clang 构建时,使用 `libc++` 而不是 `libstdc++`,并且在使用调试模式构建时,使用调试版本的 `libc++`,它允许在运行时捕获更多错误。
|
||||
|
||||
## Sanitizers
|
||||
|
||||
**Address sanitizer**.
|
||||
我们在每个提交的基础上在 ASan 下运行功能和集成测试。
|
||||
|
||||
**Valgrind (Memcheck)**.
|
||||
我们在 Valgrind 过夜进行功能测试。 这需要几个小时。 目前在 `re2` 库中有一个已知的误报,请参阅 [文章](https://research.swtch.com/sparse)。
|
||||
|
||||
**Thread sanitizer**.
|
||||
我们在 TSan 下进行功能测试。ClickHouse 必须通过所有测试。在 TSan 下运行不是自动化的,只是偶尔执行。
|
||||
|
||||
**Memory sanitizer**.
|
||||
目前我们不使用 MSan。
|
||||
|
||||
**Undefined behaviour sanitizer.**
|
||||
我们仍然不会在每次提交的基础上使用 UBSan。 有一些地方需要解决。
|
||||
|
||||
**Debug allocator.**
|
||||
您可以使用 `DEBUG_TCMALLOC` CMake 选项启用 `tcmalloc` 的调试版本。我们在每次提交的基础上使用调试分配器运行测试。
|
||||
|
||||
更多请参阅 `dbms/tests/instructions/sanitizers.txt`。
|
||||
|
||||
|
||||
## 模糊测试
|
||||
|
||||
我们使用简单的模糊测试来生成随机SQL查询并检查服务器是否正常,使用 Address sanitizer 执行模糊测试。你可以在`00746_sql_fuzzy.pl` 找到它。 测试应连续进行(过夜和更长时间)。
|
||||
|
||||
截至2018年12月,我们仍然不使用库代码的孤立模糊测试。
|
||||
|
||||
## 安全审计
|
||||
|
||||
Yandex Cloud 部门的人员从安全角度对 ClickHouse 功能进行了一些基本概述。
|
||||
|
||||
|
||||
## 静态分析
|
||||
|
||||
我们偶尔使用静态分析。我们已经评估过 `clang-tidy`, `Coverity`, `cppcheck`, `PVS-Studio`, `tscancode`。您将在 `dbms/tests/instructions/` 目录中找到使用说明。你也可以阅读[俄文文章](https://habr.com/company/yandex/blog/342018/).
|
||||
|
||||
如果您使用 `CLion` 作为 IDE,您可以开箱即用一些 `clang-tidy` 检查。
|
||||
|
||||
## 其他强化
|
||||
|
||||
默认情况下使用 `FORTIFY_SOURCE`。它几乎没用,但在极少数情况下仍然有意义,我们不会禁用它。
|
||||
|
||||
|
||||
## 代码风格
|
||||
|
||||
代码风格在[这里](https://clickhouse.yandex/docs/en/development/style/) 有说明。
|
||||
|
||||
要检查一些常见的样式冲突,您可以使用 `utils/check-style` 脚本。
|
||||
|
||||
为了强制你的代码的正确风格,你可以使用 `clang-format` 文件。`.clang-format` 位于源代码根目录, 它主要与我们的实际代码风格对应。但不建议将 `clang-format` 应用于现有文件,因为它会使格式变得更糟。您可以使用 `clang-format-diff` 工具,您可以在 clang 源代码库中找到
|
||||
|
||||
或者,您可以尝试`uncrustify` 工具来格式化您的代码。配置文件在源代码的根目录中的`uncrustify.cfg`。它比 `clang-format` 经过更少的测试。
|
||||
|
||||
`CLion` 有自己的代码格式化程序,必须调整为我们的代码风格。
|
||||
|
||||
|
||||
## Metrica B2B 测试
|
||||
|
||||
每个 ClickHouse 版本都经过 Yandex Metrica 和 AppMetrica 引擎的测试。测试和稳定版本的 ClickHouse 部署在虚拟机上,并使用处理输入数据固定样本的度量引擎的小副本运行。 将度量引擎的两个实例的结果一起进行比较
|
||||
|
||||
这些测试是由单独的团队自动完成的。由于移动部件的数量很多,大部分时间的测试都是完全无关的,很难弄清楚。很可能这些测试对我们来说是负值。然而,这些测试被证明是有用的大约一个或两个倍的数百。
|
||||
|
||||
|
||||
## 测试覆盖率
|
||||
|
||||
截至2018年7月,我们不会跟踪测试复盖率。
|
||||
|
||||
|
||||
## 自动化测试
|
||||
|
||||
我们使用 Yandex 内部 CI 和名为"沙箱"的作业自动化系统运行测试。 我们还继续使用 Jenkins(可在Yandex内部使用)。
|
||||
|
||||
构建作业和测试在沙箱中按每次提交的基础上运行。结果包和测试结果发布在 GitHub 上,可以通过直接链接下载,结果会被永久存储。当您在 GitHub 上发送拉取请求时,我们将其标记为"可以测试",我们的 CI 系统将为您构建 ClickHouse 包(发布,调试,地址消除等)。
|
||||
|
||||
由于时间和计算能力的限制,我们不使用 Travis CI。
|
||||
|
||||
在 Jenkins,我们运行字典测试,指标B2B测试。 我们使用 Jenkins 来准备和发布版本。 Jenkins是一种传统的技术,所有的工作将被转移到沙箱中。
|
||||
|
||||
[来源文章](https://clickhouse.yandex/docs/zh/development/tests/) <!--hide-->
|
@ -7,6 +7,7 @@ add_executable (date_lut4 date_lut4.cpp)
|
||||
add_executable (date_lut_default_timezone date_lut_default_timezone.cpp)
|
||||
add_executable (multi_version multi_version.cpp)
|
||||
add_executable (local_date_time_comparison local_date_time_comparison.cpp)
|
||||
add_executable (realloc-perf allocator.cpp)
|
||||
|
||||
set(PLATFORM_LIBS ${CMAKE_DL_LIBS})
|
||||
|
||||
@ -17,6 +18,7 @@ target_link_libraries (date_lut4 common ${PLATFORM_LIBS})
|
||||
target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS})
|
||||
target_link_libraries (multi_version common)
|
||||
target_link_libraries (local_date_time_comparison common)
|
||||
target_link_libraries (realloc-perf common)
|
||||
add_check(multi_version)
|
||||
add_check(local_date_time_comparison)
|
||||
|
||||
|
47
libs/libcommon/src/tests/allocator.cpp
Normal file
47
libs/libcommon/src/tests/allocator.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
|
||||
void thread_func()
|
||||
{
|
||||
for (size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
size_t size = 4096;
|
||||
|
||||
void * buf = malloc(size);
|
||||
if (!buf)
|
||||
abort();
|
||||
memset(buf, 0, size);
|
||||
|
||||
while (size < 1048576)
|
||||
{
|
||||
size_t next_size = size * 4;
|
||||
|
||||
void * new_buf = realloc(buf, next_size);
|
||||
if (!new_buf)
|
||||
abort();
|
||||
buf = new_buf;
|
||||
|
||||
memset(reinterpret_cast<char*>(buf) + size, 0, next_size - size);
|
||||
size = next_size;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
std::vector<std::thread> threads(16);
|
||||
for (size_t i = 0; i < 1000; ++i)
|
||||
{
|
||||
for (auto & thread : threads)
|
||||
thread = std::thread(thread_func);
|
||||
for (auto & thread : threads)
|
||||
thread.join();
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -3,12 +3,12 @@ if (NOT NO_WERROR)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
endif ()
|
||||
|
||||
if (MAKE_STATIC_LIBRARIES)
|
||||
set (MAX_LINKER_MEMORY 3500 CACHE INTERNAL "")
|
||||
if(MAKE_STATIC_LIBRARIES)
|
||||
set(MAX_LINKER_MEMORY 3500)
|
||||
else()
|
||||
set (MAX_LINKER_MEMORY 2500 CACHE INTERNAL "")
|
||||
endif ()
|
||||
include (../cmake/limit_jobs.cmake)
|
||||
set(MAX_LINKER_MEMORY 2500)
|
||||
endif()
|
||||
include(../cmake/limit_jobs.cmake)
|
||||
|
||||
# Utils used in package
|
||||
add_subdirectory (config-processor)
|
||||
|
@ -22,5 +22,5 @@ env TEST_RUN=1 \
|
||||
`# Use all possible contrib libs from system` \
|
||||
`# psmisc - killall` \
|
||||
`# gdb - symbol test in pbuilder` \
|
||||
EXTRAPACKAGES="psmisc libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev zlib1g-dev liblz4-dev libdouble-conversion-dev libsparsehash-dev librdkafka-dev libpoco-dev unixodbc-dev libsparsehash-dev libgoogle-perftools-dev libzstd-dev libre2-dev libunwind-dev googletest libcctz-dev libcapnp-dev libjemalloc-dev libssl-dev $EXTRAPACKAGES" \
|
||||
EXTRAPACKAGES="psmisc libboost-program-options-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev zlib1g-dev liblz4-dev libdouble-conversion-dev libsparsehash-dev librdkafka-dev libpoco-dev unixodbc-dev libsparsehash-dev libgoogle-perftools-dev libzstd-dev libre2-dev libunwind-dev googletest libcctz-dev libcapnp-dev libjemalloc-dev libssl-dev libunwind-dev libxml2-dev libgsasl7-dev $EXTRAPACKAGES" \
|
||||
pdebuild --configfile $ROOT_DIR/debian/.pbuilderrc $PDEBUILD_OPT
|
||||
|
6
utils/build/build_debian_unbundled_split.sh
Executable file
6
utils/build/build_debian_unbundled_split.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
CMAKE_FLAGS+=" -DCLICKHOUSE_SPLIT_BINARY=1 "
|
||||
. $CUR_DIR/build_debian_unbundled.sh
|
Loading…
Reference in New Issue
Block a user