diff --git a/base/base/scope_guard_safe.h b/base/base/scope_guard_safe.h
index 73c85b65b57..98521dd17c1 100644
--- a/base/base/scope_guard_safe.h
+++ b/base/base/scope_guard_safe.h
@@ -2,7 +2,7 @@
#include
#include
-#include
+#include
/// Same as SCOPE_EXIT() but block the MEMORY_LIMIT_EXCEEDED errors.
///
@@ -12,8 +12,7 @@
///
/// NOTE: it should be used with caution.
#define SCOPE_EXIT_MEMORY(...) SCOPE_EXIT( \
- MemoryTracker::LockExceptionInThread \
- lock_memory_tracker(VariableContext::Global); \
+ LockMemoryExceptionInThread lock_memory_tracker(VariableContext::Global); \
__VA_ARGS__; \
)
@@ -57,8 +56,7 @@
#define SCOPE_EXIT_MEMORY_SAFE(...) SCOPE_EXIT( \
try \
{ \
- MemoryTracker::LockExceptionInThread \
- lock_memory_tracker(VariableContext::Global); \
+ LockMemoryExceptionInThread lock_memory_tracker(VariableContext::Global); \
__VA_ARGS__; \
} \
catch (...) \
diff --git a/base/daemon/BaseDaemon.cpp b/base/daemon/BaseDaemon.cpp
index b92a68f104e..f3026d7c87a 100644
--- a/base/daemon/BaseDaemon.cpp
+++ b/base/daemon/BaseDaemon.cpp
@@ -51,6 +51,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/base/loggers/OwnSplitChannel.cpp b/base/loggers/OwnSplitChannel.cpp
index 2ae1e65729c..2267b8f425d 100644
--- a/base/loggers/OwnSplitChannel.cpp
+++ b/base/loggers/OwnSplitChannel.cpp
@@ -10,6 +10,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -57,7 +59,7 @@ void OwnSplitChannel::tryLogSplit(const Poco::Message & msg)
/// but let's log it into the stderr at least.
catch (...)
{
- MemoryTracker::LockExceptionInThread lock_memory_tracker(VariableContext::Global);
+ LockMemoryExceptionInThread lock_memory_tracker(VariableContext::Global);
const std::string & exception_message = getCurrentExceptionMessage(true);
const std::string & message = msg.getText();
diff --git a/debian/.pbuilderrc b/debian/.pbuilderrc
index 9449be7c7d4..485906f6198 100644
--- a/debian/.pbuilderrc
+++ b/debian/.pbuilderrc
@@ -104,8 +104,7 @@ ALLOWUNTRUSTED=${SET_ALLOWUNTRUSTED:=${ALLOWUNTRUSTED}}
if $(echo ${DEBIAN_SUITES[@]} | grep -q $DIST); then
# Debian configuration
OSNAME=debian
- #MIRRORSITE=${SET_MIRRORSITE="http://deb.debian.org/$OSNAME/"}
- MIRRORSITE=${SET_MIRRORSITE="http://mirror.yandex.ru/$OSNAME/"}
+ MIRRORSITE=${SET_MIRRORSITE="http://deb.debian.org/$OSNAME/"}
COMPONENTS="main contrib non-free"
if $(echo "$STABLE_CODENAME stable" | grep -q $DIST); then
OTHERMIRROR="$OTHERMIRROR | deb $MIRRORSITE $STABLE_BACKPORTS_SUITE $COMPONENTS"
@@ -125,8 +124,7 @@ elif $(echo ${UBUNTU_SUITES[@]} | grep -q $DIST); then
OSNAME=ubuntu
if [[ "$ARCH" == "amd64" || "$ARCH" == "i386" ]]; then
- #MIRRORSITE=${SET_MIRRORSITE="http://archive.ubuntu.com/$OSNAME/"}
- MIRRORSITE=${SET_MIRRORSITE="http://mirror.yandex.ru/$OSNAME/"}
+ MIRRORSITE=${SET_MIRRORSITE="http://archive.ubuntu.com/$OSNAME/"}
else
MIRRORSITE=${SET_MIRRORSITE="http://ports.ubuntu.com/ubuntu-ports/"}
fi
diff --git a/debian/clickhouse-server.init b/debian/clickhouse-server.init
index 1dd87fe80ae..1695f6286b8 100755
--- a/debian/clickhouse-server.init
+++ b/debian/clickhouse-server.init
@@ -5,7 +5,7 @@
# Default-Stop: 0 1 6
# Should-Start: $time $network
# Should-Stop: $network
-# Short-Description: Yandex clickhouse-server daemon
+# Short-Description: clickhouse-server daemon
### END INIT INFO
#
# NOTES:
diff --git a/debian/control b/debian/control
index ac75b00df22..f22980fdbc4 100644
--- a/debian/control
+++ b/debian/control
@@ -18,7 +18,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, clickhouse-common-static (= ${binar
Replaces: clickhouse-compressor
Conflicts: clickhouse-compressor
Description: Client binary for ClickHouse
- Yandex ClickHouse is a column-oriented database management system
+ ClickHouse is a column-oriented database management system
that allows generating analytical data reports in real time.
.
This package provides clickhouse-client , clickhouse-local and clickhouse-benchmark
@@ -30,7 +30,7 @@ Suggests: clickhouse-common-static-dbg
Replaces: clickhouse-common, clickhouse-server-base
Provides: clickhouse-common, clickhouse-server-base
Description: Common files for ClickHouse
- Yandex ClickHouse is a column-oriented database management system
+ ClickHouse is a column-oriented database management system
that allows generating analytical data reports in real time.
.
This package provides common files for both clickhouse server and client
@@ -42,7 +42,7 @@ Recommends: libcap2-bin
Replaces: clickhouse-server-common, clickhouse-server-base
Provides: clickhouse-server-common
Description: Server binary for ClickHouse
- Yandex ClickHouse is a column-oriented database management system
+ ClickHouse is a column-oriented database management system
that allows generating analytical data reports in real time.
.
This package provides clickhouse common configuration files
diff --git a/docs/en/sql-reference/statements/use.md b/docs/en/sql-reference/statements/use.md
index 841c23d333d..41cba58bb9d 100644
--- a/docs/en/sql-reference/statements/use.md
+++ b/docs/en/sql-reference/statements/use.md
@@ -3,14 +3,14 @@ toc_priority: 53
toc_title: USE
---
-# USE Statement {#use}
+# USE 语句 {#use}
``` sql
USE db
```
-Lets you set the current database for the session.
+用于设置会话的当前数据库。
-The current database is used for searching for tables if the database is not explicitly defined in the query with a dot before the table name.
+如果查询语句中没有在表名前面以加点的方式指明数据库名, 则用当前数据库进行搜索。
-This query can’t be made when using the HTTP protocol, since there is no concept of a session.
+使用 HTTP 协议时无法进行此查询,因为没有会话的概念。
diff --git a/docs/en/whats-new/changelog/2021.md b/docs/en/whats-new/changelog/2021.md
index 1c3ceca08a7..2e81d981990 100644
--- a/docs/en/whats-new/changelog/2021.md
+++ b/docs/en/whats-new/changelog/2021.md
@@ -1018,6 +1018,9 @@ toc_title: '2021'
### ClickHouse release 21.6, 2021-06-05
+#### Backward Incompatible Change
+* uniqState / uniqHLL12State / uniqCombinedState / uniqCombined64State produce incompatible states with `UUID` type. [#33607](https://github.com/ClickHouse/ClickHouse/issues/33607).
+
#### Upgrade Notes
* `zstd` compression library is updated to v1.5.0. You may get messages about "checksum does not match" in replication. These messages are expected due to update of compression algorithm and you can ignore them. These messages are informational and do not indicate any kinds of undesired behaviour.
diff --git a/docs/zh/sql-reference/statements/index.md b/docs/zh/sql-reference/statements/index.md
index ab080584c66..385639fde0b 100644
--- a/docs/zh/sql-reference/statements/index.md
+++ b/docs/zh/sql-reference/statements/index.md
@@ -1,8 +1,32 @@
---
-machine_translated: true
-machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
-toc_folder_title: "\u8BED\u53E5"
+toc_folder_title: SQL 语句
+toc_hidden: true
toc_priority: 31
---
+# ClickHouse SQL 语句 {#clickhouse-sql-statements}
+语句表示可以使用 SQL 查询执行的各种操作。每种类型的语句都有自己的语法和用法详细信息,这些语法和用法详细信息单独描述如下所示:
+
+- [SELECT](../../sql-reference/statements/select/index.md)
+- [INSERT INTO](../../sql-reference/statements/insert-into.md)
+- [CREATE](../../sql-reference/statements/create/index.md)
+- [ALTER](../../sql-reference/statements/alter/index.md)
+- [SYSTEM](../../sql-reference/statements/system.md)
+- [SHOW](../../sql-reference/statements/show.md)
+- [GRANT](../../sql-reference/statements/grant.md)
+- [REVOKE](../../sql-reference/statements/revoke.md)
+- [ATTACH](../../sql-reference/statements/attach.md)
+- [CHECK TABLE](../../sql-reference/statements/check-table.md)
+- [DESCRIBE TABLE](../../sql-reference/statements/describe-table.md)
+- [DETACH](../../sql-reference/statements/detach.md)
+- [DROP](../../sql-reference/statements/drop.md)
+- [EXISTS](../../sql-reference/statements/exists.md)
+- [KILL](../../sql-reference/statements/kill.md)
+- [OPTIMIZE](../../sql-reference/statements/optimize.md)
+- [RENAME](../../sql-reference/statements/rename.md)
+- [SET](../../sql-reference/statements/set.md)
+- [SET ROLE](../../sql-reference/statements/set-role.md)
+- [TRUNCATE](../../sql-reference/statements/truncate.md)
+- [USE](../../sql-reference/statements/use.md)
+- [EXPLAIN](../../sql-reference/statements/explain.md)
diff --git a/programs/local/LocalServer.cpp b/programs/local/LocalServer.cpp
index aa4747636c9..a294857ace8 100644
--- a/programs/local/LocalServer.cpp
+++ b/programs/local/LocalServer.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 62767e02a64..c06635cbaa9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -584,7 +584,6 @@ if (ENABLE_TESTS AND USE_GTEST)
dbms
clickhouse_common_config
clickhouse_common_zookeeper
- clickhouse_common_config
string_utils)
add_check(unit_tests_dbms)
diff --git a/src/Common/Config/CMakeLists.txt b/src/Common/Config/CMakeLists.txt
index 4d72960f727..cc41a8b2bb2 100644
--- a/src/Common/Config/CMakeLists.txt
+++ b/src/Common/Config/CMakeLists.txt
@@ -8,7 +8,6 @@ set (SRCS
)
add_library(clickhouse_common_config ${SRCS})
-
target_link_libraries(clickhouse_common_config
PUBLIC
clickhouse_common_zookeeper
@@ -18,9 +17,17 @@ target_link_libraries(clickhouse_common_config
string_utils
)
-if (USE_YAML_CPP)
-target_link_libraries(clickhouse_common_config
+add_library(clickhouse_common_config_no_zookeeper_log ${SRCS})
+target_link_libraries(clickhouse_common_config_no_zookeeper_log
+ PUBLIC
+ clickhouse_common_zookeeper_no_log
+ common
+ Poco::XML
PRIVATE
- yaml-cpp
+ string_utils
)
+
+if (USE_YAML_CPP)
+ target_link_libraries(clickhouse_common_config PRIVATE yaml-cpp)
+ target_link_libraries(clickhouse_common_config_no_zookeeper_log PRIVATE yaml-cpp)
endif()
diff --git a/src/Common/Exception.cpp b/src/Common/Exception.cpp
index cdf5816237c..b2987cbd73f 100644
--- a/src/Common/Exception.cpp
+++ b/src/Common/Exception.cpp
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
@@ -175,7 +176,7 @@ void tryLogCurrentException(const char * log_name, const std::string & start_of_
///
/// And in this case the exception will not be logged, so let's block the
/// MemoryTracker until the exception will be logged.
- MemoryTracker::LockExceptionInThread lock_memory_tracker(VariableContext::Global);
+ LockMemoryExceptionInThread lock_memory_tracker(VariableContext::Global);
/// Poco::Logger::get can allocate memory too
tryLogCurrentExceptionImpl(&Poco::Logger::get(log_name), start_of_message);
@@ -188,7 +189,7 @@ void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_
///
/// And in this case the exception will not be logged, so let's block the
/// MemoryTracker until the exception will be logged.
- MemoryTracker::LockExceptionInThread lock_memory_tracker(VariableContext::Global);
+ LockMemoryExceptionInThread lock_memory_tracker(VariableContext::Global);
tryLogCurrentExceptionImpl(logger, start_of_message);
}
diff --git a/src/Common/LockMemoryExceptionInThread.cpp b/src/Common/LockMemoryExceptionInThread.cpp
new file mode 100644
index 00000000000..606f02abcb0
--- /dev/null
+++ b/src/Common/LockMemoryExceptionInThread.cpp
@@ -0,0 +1,20 @@
+#include
+
+/// LockMemoryExceptionInThread
+thread_local uint64_t LockMemoryExceptionInThread::counter = 0;
+thread_local VariableContext LockMemoryExceptionInThread::level = VariableContext::Global;
+thread_local bool LockMemoryExceptionInThread::block_fault_injections = false;
+LockMemoryExceptionInThread::LockMemoryExceptionInThread(VariableContext level_, bool block_fault_injections_)
+ : previous_level(level)
+ , previous_block_fault_injections(block_fault_injections)
+{
+ ++counter;
+ level = level_;
+ block_fault_injections = block_fault_injections_;
+}
+LockMemoryExceptionInThread::~LockMemoryExceptionInThread()
+{
+ --counter;
+ level = previous_level;
+ block_fault_injections = previous_block_fault_injections;
+}
diff --git a/src/Common/LockMemoryExceptionInThread.h b/src/Common/LockMemoryExceptionInThread.h
new file mode 100644
index 00000000000..dc2bccf257b
--- /dev/null
+++ b/src/Common/LockMemoryExceptionInThread.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include
+
+/// To be able to avoid MEMORY_LIMIT_EXCEEDED Exception in destructors:
+/// - either configured memory limit reached
+/// - or fault injected
+///
+/// So this will simply ignore the configured memory limit (and avoid fault injection).
+///
+/// NOTE: exception will be silently ignored, no message in log
+/// (since logging from MemoryTracker::alloc() is tricky)
+///
+/// NOTE: MEMORY_LIMIT_EXCEEDED Exception implicitly blocked if
+/// stack unwinding is currently in progress in this thread (to avoid
+/// std::terminate()), so you don't need to use it in this case explicitly.
+struct LockMemoryExceptionInThread
+{
+private:
+ static thread_local uint64_t counter;
+ static thread_local VariableContext level;
+ static thread_local bool block_fault_injections;
+
+ VariableContext previous_level;
+ bool previous_block_fault_injections;
+public:
+ /// level_ - block in level and above
+ /// block_fault_injections_ - block in fault injection too
+ explicit LockMemoryExceptionInThread(VariableContext level_ = VariableContext::User, bool block_fault_injections_ = true);
+ ~LockMemoryExceptionInThread();
+
+ LockMemoryExceptionInThread(const LockMemoryExceptionInThread &) = delete;
+ LockMemoryExceptionInThread & operator=(const LockMemoryExceptionInThread &) = delete;
+
+ static bool isBlocked(VariableContext current_level, bool fault_injection)
+ {
+ return counter > 0 && current_level >= level && (!fault_injection || block_fault_injections);
+ }
+};
diff --git a/src/Common/MemoryTracker.cpp b/src/Common/MemoryTracker.cpp
index 013005442be..ba98ede221a 100644
--- a/src/Common/MemoryTracker.cpp
+++ b/src/Common/MemoryTracker.cpp
@@ -1,12 +1,14 @@
#include "MemoryTracker.h"
#include
-#include "Common/TraceCollector.h"
+#include
#include
+#include
+#include
#include
-#include
#include
#include
+#include
#include
#include
@@ -34,7 +36,7 @@ namespace
/// noexcept(false)) will cause std::terminate()
bool inline memoryTrackerCanThrow(VariableContext level, bool fault_injection)
{
- return !MemoryTracker::LockExceptionInThread::isBlocked(level, fault_injection) && !std::uncaught_exceptions();
+ return !LockMemoryExceptionInThread::isBlocked(level, fault_injection) && !std::uncaught_exceptions();
}
}
@@ -55,41 +57,6 @@ namespace ProfileEvents
static constexpr size_t log_peak_memory_usage_every = 1ULL << 30;
-// BlockerInThread
-thread_local uint64_t MemoryTracker::BlockerInThread::counter = 0;
-thread_local VariableContext MemoryTracker::BlockerInThread::level = VariableContext::Global;
-MemoryTracker::BlockerInThread::BlockerInThread(VariableContext level_)
- : previous_level(level)
-{
- ++counter;
- level = level_;
-}
-MemoryTracker::BlockerInThread::~BlockerInThread()
-{
- --counter;
- level = previous_level;
-}
-
-/// LockExceptionInThread
-thread_local uint64_t MemoryTracker::LockExceptionInThread::counter = 0;
-thread_local VariableContext MemoryTracker::LockExceptionInThread::level = VariableContext::Global;
-thread_local bool MemoryTracker::LockExceptionInThread::block_fault_injections = false;
-MemoryTracker::LockExceptionInThread::LockExceptionInThread(VariableContext level_, bool block_fault_injections_)
- : previous_level(level)
- , previous_block_fault_injections(block_fault_injections)
-{
- ++counter;
- level = level_;
- block_fault_injections = block_fault_injections_;
-}
-MemoryTracker::LockExceptionInThread::~LockExceptionInThread()
-{
- --counter;
- level = previous_level;
- block_fault_injections = previous_block_fault_injections;
-}
-
-
MemoryTracker total_memory_tracker(nullptr, VariableContext::Global);
@@ -133,9 +100,9 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
if (size < 0)
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Negative size ({}) is passed to MemoryTracker. It is a bug.", size);
- if (BlockerInThread::isBlocked(level))
+ if (MemoryTrackerBlockerInThread::isBlocked(level))
{
- /// Since the BlockerInThread should respect the level, we should go to the next parent.
+ /// Since the MemoryTrackerBlockerInThread should respect the level, we should go to the next parent.
if (auto * loaded_next = parent.load(std::memory_order_relaxed))
loaded_next->allocImpl(size, throw_if_memory_exceeded);
return;
@@ -184,7 +151,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
if (unlikely(fault_probability && fault(thread_local_rng)) && memoryTrackerCanThrow(level, true) && throw_if_memory_exceeded)
{
/// Prevent recursion. Exception::ctor -> std::string -> new[] -> MemoryTracker::alloc
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
ProfileEvents::increment(ProfileEvents::QueryMemoryLimitExceeded);
const auto * description = description_ptr.load(std::memory_order_relaxed);
@@ -203,7 +170,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
bool allocation_traced = false;
if (unlikely(current_profiler_limit && will_be > current_profiler_limit))
{
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
DB::TraceCollector::collect(DB::TraceType::Memory, StackTrace(), size);
setOrRaiseProfilerLimit((will_be + profiler_step - 1) / profiler_step * profiler_step);
allocation_traced = true;
@@ -212,7 +179,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
std::bernoulli_distribution sample(sample_probability);
if (unlikely(sample_probability && sample(thread_local_rng)))
{
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
DB::TraceCollector::collect(DB::TraceType::MemorySample, StackTrace(), size);
allocation_traced = true;
}
@@ -220,7 +187,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
if (unlikely(current_hard_limit && will_be > current_hard_limit) && memoryTrackerCanThrow(level, false) && throw_if_memory_exceeded)
{
/// Prevent recursion. Exception::ctor -> std::string -> new[] -> MemoryTracker::alloc
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
ProfileEvents::increment(ProfileEvents::QueryMemoryLimitExceeded);
const auto * description = description_ptr.load(std::memory_order_relaxed);
throw DB::Exception(
@@ -237,7 +204,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
if (throw_if_memory_exceeded)
{
/// Prevent recursion. Exception::ctor -> std::string -> new[] -> MemoryTracker::alloc
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
bool log_memory_usage = true;
peak_updated = updatePeak(will_be, log_memory_usage);
}
@@ -249,7 +216,7 @@ void MemoryTracker::allocImpl(Int64 size, bool throw_if_memory_exceeded)
if (peak_updated && allocation_traced)
{
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
DB::TraceCollector::collect(DB::TraceType::MemoryPeak, StackTrace(), will_be);
}
@@ -288,9 +255,9 @@ bool MemoryTracker::updatePeak(Int64 will_be, bool log_memory_usage)
void MemoryTracker::free(Int64 size)
{
- if (BlockerInThread::isBlocked(level))
+ if (MemoryTrackerBlockerInThread::isBlocked(level))
{
- /// Since the BlockerInThread should respect the level, we should go to the next parent.
+ /// Since the MemoryTrackerBlockerInThread should respect the level, we should go to the next parent.
if (auto * loaded_next = parent.load(std::memory_order_relaxed))
loaded_next->free(size);
return;
@@ -299,7 +266,7 @@ void MemoryTracker::free(Int64 size)
std::bernoulli_distribution sample(sample_probability);
if (unlikely(sample_probability && sample(thread_local_rng)))
{
- BlockerInThread untrack_lock(VariableContext::Global);
+ MemoryTrackerBlockerInThread untrack_lock(VariableContext::Global);
DB::TraceCollector::collect(DB::TraceType::MemorySample, StackTrace(), -size);
}
diff --git a/src/Common/MemoryTracker.h b/src/Common/MemoryTracker.h
index ce0eef52e17..a0138b25b5f 100644
--- a/src/Common/MemoryTracker.h
+++ b/src/Common/MemoryTracker.h
@@ -31,6 +31,9 @@ extern thread_local bool memory_tracker_always_throw_logical_error_on_allocation
/** Tracks memory consumption.
* It throws an exception if amount of consumed memory become greater than certain limit.
* The same memory tracker could be simultaneously used in different threads.
+ *
+ * @see LockMemoryExceptionInThread
+ * @see MemoryTrackerBlockerInThread
*/
class MemoryTracker
{
@@ -167,64 +170,6 @@ public:
/// Prints info about peak memory consumption into log.
void logPeakMemoryUsage() const;
-
- /// To be able to temporarily stop memory tracking from current thread.
- struct BlockerInThread
- {
- private:
- static thread_local uint64_t counter;
- static thread_local VariableContext level;
-
- VariableContext previous_level;
- public:
- /// level_ - block in level and above
- explicit BlockerInThread(VariableContext level_ = VariableContext::User);
- ~BlockerInThread();
-
- BlockerInThread(const BlockerInThread &) = delete;
- BlockerInThread & operator=(const BlockerInThread &) = delete;
-
- static bool isBlocked(VariableContext current_level)
- {
- return counter > 0 && current_level >= level;
- }
- };
-
- /// To be able to avoid MEMORY_LIMIT_EXCEEDED Exception in destructors:
- /// - either configured memory limit reached
- /// - or fault injected
- ///
- /// So this will simply ignore the configured memory limit (and avoid fault injection).
- ///
- /// NOTE: exception will be silently ignored, no message in log
- /// (since logging from MemoryTracker::alloc() is tricky)
- ///
- /// NOTE: MEMORY_LIMIT_EXCEEDED Exception implicitly blocked if
- /// stack unwinding is currently in progress in this thread (to avoid
- /// std::terminate()), so you don't need to use it in this case explicitly.
- struct LockExceptionInThread
- {
- private:
- static thread_local uint64_t counter;
- static thread_local VariableContext level;
- static thread_local bool block_fault_injections;
-
- VariableContext previous_level;
- bool previous_block_fault_injections;
- public:
- /// level_ - block in level and above
- /// block_fault_injections_ - block in fault injection too
- explicit LockExceptionInThread(VariableContext level_ = VariableContext::User, bool block_fault_injections_ = true);
- ~LockExceptionInThread();
-
- LockExceptionInThread(const LockExceptionInThread &) = delete;
- LockExceptionInThread & operator=(const LockExceptionInThread &) = delete;
-
- static bool isBlocked(VariableContext current_level, bool fault_injection)
- {
- return counter > 0 && current_level >= level && (!fault_injection || block_fault_injections);
- }
- };
};
extern MemoryTracker total_memory_tracker;
diff --git a/src/Common/MemoryTrackerBlockerInThread.cpp b/src/Common/MemoryTrackerBlockerInThread.cpp
new file mode 100644
index 00000000000..8eb119b2fe5
--- /dev/null
+++ b/src/Common/MemoryTrackerBlockerInThread.cpp
@@ -0,0 +1,16 @@
+#include
+
+// MemoryTrackerBlockerInThread
+thread_local uint64_t MemoryTrackerBlockerInThread::counter = 0;
+thread_local VariableContext MemoryTrackerBlockerInThread::level = VariableContext::Global;
+MemoryTrackerBlockerInThread::MemoryTrackerBlockerInThread(VariableContext level_)
+ : previous_level(level)
+{
+ ++counter;
+ level = level_;
+}
+MemoryTrackerBlockerInThread::~MemoryTrackerBlockerInThread()
+{
+ --counter;
+ level = previous_level;
+}
diff --git a/src/Common/MemoryTrackerBlockerInThread.h b/src/Common/MemoryTrackerBlockerInThread.h
new file mode 100644
index 00000000000..caad28f636e
--- /dev/null
+++ b/src/Common/MemoryTrackerBlockerInThread.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+
+/// To be able to temporarily stop memory tracking from current thread.
+struct MemoryTrackerBlockerInThread
+{
+private:
+ static thread_local uint64_t counter;
+ static thread_local VariableContext level;
+
+ VariableContext previous_level;
+public:
+ /// level_ - block in level and above
+ explicit MemoryTrackerBlockerInThread(VariableContext level_ = VariableContext::User);
+ ~MemoryTrackerBlockerInThread();
+
+ MemoryTrackerBlockerInThread(const MemoryTrackerBlockerInThread &) = delete;
+ MemoryTrackerBlockerInThread & operator=(const MemoryTrackerBlockerInThread &) = delete;
+
+ static bool isBlocked(VariableContext current_level)
+ {
+ return counter > 0 && current_level >= level;
+ }
+};
diff --git a/src/Common/QueryProfiler.cpp b/src/Common/QueryProfiler.cpp
index 0b2cd602b38..9718d15c072 100644
--- a/src/Common/QueryProfiler.cpp
+++ b/src/Common/QueryProfiler.cpp
@@ -1,9 +1,9 @@
#include "QueryProfiler.h"
#include
+#include
#include
#include
-#include
#include
#include
#include
diff --git a/src/Common/ThreadStatus.cpp b/src/Common/ThreadStatus.cpp
index 411f725f2db..ad42468de68 100644
--- a/src/Common/ThreadStatus.cpp
+++ b/src/Common/ThreadStatus.cpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
@@ -11,6 +12,7 @@
#include
#include
+#include
namespace DB
diff --git a/src/Common/TraceCollector.cpp b/src/Common/TraceCollector.cpp
deleted file mode 100644
index 523251fa2a2..00000000000
--- a/src/Common/TraceCollector.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-#include "TraceCollector.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-namespace DB
-{
-
-namespace
-{
- /// Normally query_id is a UUID (string with a fixed length) but user can provide custom query_id.
- /// Thus upper bound on query_id length should be introduced to avoid buffer overflow in signal handler.
- ///
- /// And it cannot be large, since otherwise it will not fit into PIPE_BUF.
- /// The performance test query ids can be surprisingly long like
- /// `aggregating_merge_tree_simple_aggregate_function_string.query100.profile100`,
- /// so make some allowance for them as well.
- constexpr size_t QUERY_ID_MAX_LEN = 128;
- static_assert(QUERY_ID_MAX_LEN <= std::numeric_limits::max());
-}
-
-LazyPipeFDs pipe;
-
-
-TraceCollector::TraceCollector(std::shared_ptr trace_log_)
- : trace_log(std::move(trace_log_))
-{
- pipe.open();
-
- /** Turn write end of pipe to non-blocking mode to avoid deadlocks
- * when QueryProfiler is invoked under locks and TraceCollector cannot pull data from pipe.
- */
- pipe.setNonBlockingWrite();
- pipe.tryIncreaseSize(1 << 20);
-
- thread = ThreadFromGlobalPool(&TraceCollector::run, this);
-}
-
-
-TraceCollector::~TraceCollector()
-{
- if (!thread.joinable())
- LOG_ERROR(&Poco::Logger::get("TraceCollector"), "TraceCollector thread is malformed and cannot be joined");
- else
- stop();
-
- pipe.close();
-}
-
-
-void TraceCollector::collect(TraceType trace_type, const StackTrace & stack_trace, Int64 size)
-{
- constexpr size_t buf_size = sizeof(char) /// TraceCollector stop flag
- + sizeof(UInt8) /// String size
- + QUERY_ID_MAX_LEN /// Maximum query_id length
- + sizeof(UInt8) /// Number of stack frames
- + sizeof(StackTrace::FramePointers) /// Collected stack trace, maximum capacity
- + sizeof(TraceType) /// trace type
- + sizeof(UInt64) /// thread_id
- + sizeof(Int64); /// size
-
- /// Write should be atomic to avoid overlaps
- /// (since recursive collect() is possible)
- static_assert(PIPE_BUF >= 512);
- static_assert(buf_size <= 512, "Only write of PIPE_BUF to pipe is atomic and the minimal known PIPE_BUF across supported platforms is 512");
-
- char buffer[buf_size];
- WriteBufferFromFileDescriptorDiscardOnFailure out(pipe.fds_rw[1], buf_size, buffer);
-
- StringRef query_id;
- UInt64 thread_id;
-
- if (CurrentThread::isInitialized())
- {
- query_id = CurrentThread::getQueryId();
- query_id.size = std::min(query_id.size, QUERY_ID_MAX_LEN);
-
- thread_id = CurrentThread::get().thread_id;
- }
- else
- {
- thread_id = MainThreadStatus::get()->thread_id;
- }
-
- writeChar(false, out); /// true if requested to stop the collecting thread.
-
- writeBinary(static_cast(query_id.size), out);
- out.write(query_id.data, query_id.size);
-
- size_t stack_trace_size = stack_trace.getSize();
- size_t stack_trace_offset = stack_trace.getOffset();
- writeIntBinary(UInt8(stack_trace_size - stack_trace_offset), out);
- for (size_t i = stack_trace_offset; i < stack_trace_size; ++i)
- writePODBinary(stack_trace.getFramePointers()[i], out);
-
- writePODBinary(trace_type, out);
- writePODBinary(thread_id, out);
- writePODBinary(size, out);
-
- out.next();
-}
-
-
-/** Sends TraceCollector stop message
- *
- * Each sequence of data for TraceCollector thread starts with a boolean flag.
- * If this flag is true, TraceCollector must stop reading trace_pipe and exit.
- * This function sends flag with a true value to stop TraceCollector gracefully.
- */
-void TraceCollector::stop()
-{
- WriteBufferFromFileDescriptor out(pipe.fds_rw[1]);
- writeChar(true, out);
- out.next();
- thread.join();
-}
-
-
-void TraceCollector::run()
-{
- setThreadName("TraceCollector");
-
- ReadBufferFromFileDescriptor in(pipe.fds_rw[0]);
-
- while (true)
- {
- char is_last;
- readChar(is_last, in);
- if (is_last)
- break;
-
- std::string query_id;
- UInt8 query_id_size = 0;
- readBinary(query_id_size, in);
- query_id.resize(query_id_size);
- in.read(query_id.data(), query_id_size);
-
- UInt8 trace_size = 0;
- readIntBinary(trace_size, in);
-
- Array trace;
- trace.reserve(trace_size);
-
- for (size_t i = 0; i < trace_size; ++i)
- {
- uintptr_t addr = 0;
- readPODBinary(addr, in);
- trace.emplace_back(UInt64(addr));
- }
-
- TraceType trace_type;
- readPODBinary(trace_type, in);
-
- UInt64 thread_id;
- readPODBinary(thread_id, in);
-
- Int64 size;
- readPODBinary(size, in);
-
- if (trace_log)
- {
- // time and time_in_microseconds are both being constructed from the same timespec so that the
- // times will be equal up to the precision of a second.
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- UInt64 time = UInt64(ts.tv_sec * 1000000000LL + ts.tv_nsec);
- UInt64 time_in_microseconds = UInt64((ts.tv_sec * 1000000LL) + (ts.tv_nsec / 1000));
- TraceLogElement element{time_t(time / 1000000000), time_in_microseconds, time, trace_type, thread_id, query_id, trace, size};
- trace_log->add(element);
- }
- }
-}
-
-}
diff --git a/src/Common/TraceCollector.h b/src/Common/TraceCollector.h
deleted file mode 100644
index d3bbc74726e..00000000000
--- a/src/Common/TraceCollector.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#pragma once
-
-#include "Common/PipeFDs.h"
-#include
-
-class StackTrace;
-
-namespace Poco
-{
- class Logger;
-}
-
-namespace DB
-{
-
-class TraceLog;
-
-enum class TraceType : uint8_t
-{
- Real,
- CPU,
- Memory,
- MemorySample,
- MemoryPeak,
-};
-
-class TraceCollector
-{
-public:
- TraceCollector(std::shared_ptr trace_log_);
- ~TraceCollector();
-
- /// Collect a stack trace. This method is signal safe.
- /// Precondition: the TraceCollector object must be created.
- /// size - for memory tracing is the amount of memory allocated; for other trace types it is 0.
- static void collect(TraceType trace_type, const StackTrace & stack_trace, Int64 size);
-
-private:
- std::shared_ptr trace_log;
- ThreadFromGlobalPool thread;
-
- void run();
- void stop();
-};
-
-}
diff --git a/src/Common/TraceSender.cpp b/src/Common/TraceSender.cpp
new file mode 100644
index 00000000000..57ab3df8f96
--- /dev/null
+++ b/src/Common/TraceSender.cpp
@@ -0,0 +1,78 @@
+#include
+
+#include
+#include
+#include
+#include
+
+namespace
+{
+ /// Normally query_id is a UUID (string with a fixed length) but user can provide custom query_id.
+ /// Thus upper bound on query_id length should be introduced to avoid buffer overflow in signal handler.
+ ///
+ /// And it cannot be large, since otherwise it will not fit into PIPE_BUF.
+ /// The performance test query ids can be surprisingly long like
+ /// `aggregating_merge_tree_simple_aggregate_function_string.query100.profile100`,
+ /// so make some allowance for them as well.
+ constexpr size_t QUERY_ID_MAX_LEN = 128;
+ static_assert(QUERY_ID_MAX_LEN <= std::numeric_limits::max());
+}
+
+namespace DB
+{
+
+LazyPipeFDs TraceSender::pipe;
+
+void TraceSender::send(TraceType trace_type, const StackTrace & stack_trace, Int64 size)
+{
+ constexpr size_t buf_size = sizeof(char) /// TraceCollector stop flag
+ + sizeof(UInt8) /// String size
+ + QUERY_ID_MAX_LEN /// Maximum query_id length
+ + sizeof(UInt8) /// Number of stack frames
+ + sizeof(StackTrace::FramePointers) /// Collected stack trace, maximum capacity
+ + sizeof(TraceType) /// trace type
+ + sizeof(UInt64) /// thread_id
+ + sizeof(Int64); /// size
+
+ /// Write should be atomic to avoid overlaps
+ /// (since recursive collect() is possible)
+ static_assert(PIPE_BUF >= 512);
+ static_assert(buf_size <= 512, "Only write of PIPE_BUF to pipe is atomic and the minimal known PIPE_BUF across supported platforms is 512");
+
+ char buffer[buf_size];
+ WriteBufferFromFileDescriptorDiscardOnFailure out(pipe.fds_rw[1], buf_size, buffer);
+
+ StringRef query_id;
+ UInt64 thread_id;
+
+ if (CurrentThread::isInitialized())
+ {
+ query_id = CurrentThread::getQueryId();
+ query_id.size = std::min(query_id.size, QUERY_ID_MAX_LEN);
+
+ thread_id = CurrentThread::get().thread_id;
+ }
+ else
+ {
+ thread_id = MainThreadStatus::get()->thread_id;
+ }
+
+ writeChar(false, out); /// true if requested to stop the collecting thread.
+
+ writeBinary(static_cast(query_id.size), out);
+ out.write(query_id.data, query_id.size);
+
+ size_t stack_trace_size = stack_trace.getSize();
+ size_t stack_trace_offset = stack_trace.getOffset();
+ writeIntBinary(UInt8(stack_trace_size - stack_trace_offset), out);
+ for (size_t i = stack_trace_offset; i < stack_trace_size; ++i)
+ writePODBinary(stack_trace.getFramePointers()[i], out);
+
+ writePODBinary(trace_type, out);
+ writePODBinary(thread_id, out);
+ writePODBinary(size, out);
+
+ out.next();
+}
+
+}
diff --git a/src/Common/TraceSender.h b/src/Common/TraceSender.h
new file mode 100644
index 00000000000..04c9286ad39
--- /dev/null
+++ b/src/Common/TraceSender.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include
+#include
+
+class StackTrace;
+class TraceCollector;
+
+namespace DB
+{
+
+enum class TraceType : uint8_t
+{
+ Real,
+ CPU,
+ Memory,
+ MemorySample,
+ MemoryPeak,
+};
+
+/// This is the second part of TraceCollector, that sends stacktrace to the pipe.
+/// It has been split out to avoid dependency from interpreters part.
+class TraceSender
+{
+public:
+ /// Collect a stack trace. This method is signal safe.
+ /// Precondition: the TraceCollector object must be created.
+ /// size - for memory tracing is the amount of memory allocated; for other trace types it is 0.
+ static void send(TraceType trace_type, const StackTrace & stack_trace, Int64 size);
+
+private:
+ friend class TraceCollector;
+ static LazyPipeFDs pipe;
+};
+
+}
diff --git a/src/Common/ZooKeeper/CMakeLists.txt b/src/Common/ZooKeeper/CMakeLists.txt
index d29fba53277..7e0558dd575 100644
--- a/src/Common/ZooKeeper/CMakeLists.txt
+++ b/src/Common/ZooKeeper/CMakeLists.txt
@@ -2,9 +2,32 @@ include("${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake")
add_headers_and_sources(clickhouse_common_zookeeper .)
+# for clickhouse server
add_library(clickhouse_common_zookeeper ${clickhouse_common_zookeeper_headers} ${clickhouse_common_zookeeper_sources})
+target_compile_definitions (clickhouse_common_zookeeper PRIVATE -DZOOKEEPER_LOG)
+target_link_libraries (clickhouse_common_zookeeper
+ PUBLIC
+ clickhouse_common_io
+ common
+ PRIVATE
+ string_utils
+)
+# To avoid circular dependency from interpreters.
+if (OS_DARWIN)
+ target_link_libraries (clickhouse_common_zookeeper PRIVATE -Wl,-undefined,dynamic_lookup)
+else()
+ target_link_libraries (clickhouse_common_zookeeper PRIVATE -Wl,--unresolved-symbols=ignore-all)
+endif()
-target_link_libraries (clickhouse_common_zookeeper PUBLIC clickhouse_common_io common PRIVATE string_utils)
+# for examples -- no logging (to avoid extra dependencies)
+add_library(clickhouse_common_zookeeper_no_log ${clickhouse_common_zookeeper_headers} ${clickhouse_common_zookeeper_sources})
+target_link_libraries (clickhouse_common_zookeeper_no_log
+ PUBLIC
+ clickhouse_common_io
+ common
+ PRIVATE
+ string_utils
+)
if (ENABLE_EXAMPLES)
add_subdirectory(examples)
diff --git a/src/Common/ZooKeeper/ZooKeeperCommon.cpp b/src/Common/ZooKeeper/ZooKeeperCommon.cpp
index 6a449cf0122..f6c9a3d3ca0 100644
--- a/src/Common/ZooKeeper/ZooKeeperCommon.cpp
+++ b/src/Common/ZooKeeper/ZooKeeperCommon.cpp
@@ -1,5 +1,6 @@
#include
#include
+#include
#include
#include
#include
diff --git a/src/Common/ZooKeeper/ZooKeeperImpl.cpp b/src/Common/ZooKeeper/ZooKeeperImpl.cpp
index f2603cc267f..0627a70193f 100644
--- a/src/Common/ZooKeeper/ZooKeeperImpl.cpp
+++ b/src/Common/ZooKeeper/ZooKeeperImpl.cpp
@@ -1230,6 +1230,7 @@ void ZooKeeper::setZooKeeperLog(std::shared_ptr zk_log_)
std::atomic_store(&zk_log, std::move(zk_log_));
}
+#ifdef ZOOKEEPER_LOG
void ZooKeeper::logOperationIfNeeded(const ZooKeeperRequestPtr & request, const ZooKeeperResponsePtr & response, bool finalize)
{
auto maybe_zk_log = std::atomic_load(&zk_log);
@@ -1271,5 +1272,9 @@ void ZooKeeper::logOperationIfNeeded(const ZooKeeperRequestPtr & request, const
maybe_zk_log->add(elem);
}
}
+#else
+void ZooKeeper::logOperationIfNeeded(const ZooKeeperRequestPtr &, const ZooKeeperResponsePtr &, bool)
+{}
+#endif
}
diff --git a/src/Common/ZooKeeper/ZooKeeperLock.cpp b/src/Common/ZooKeeper/ZooKeeperLock.cpp
new file mode 100644
index 00000000000..1200dcdb533
--- /dev/null
+++ b/src/Common/ZooKeeper/ZooKeeperLock.cpp
@@ -0,0 +1,93 @@
+#include
+#include
+
+namespace DB
+{
+
+namespace ErrorCodes
+{
+ extern const int LOGICAL_ERROR;
+}
+
+}
+
+namespace fs = std::filesystem;
+
+namespace zkutil
+{
+
+ZooKeeperLock::ZooKeeperLock(
+ const ZooKeeperPtr & zookeeper_,
+ const std::string & lock_prefix_,
+ const std::string & lock_name_,
+ const std::string & lock_message_)
+ : zookeeper(zookeeper_)
+ , lock_path(fs::path(lock_prefix_) / lock_name_)
+ , lock_message(lock_message_)
+ , log(&Poco::Logger::get("zkutil::Lock"))
+{
+ zookeeper->createIfNotExists(lock_prefix_, "");
+}
+
+ZooKeeperLock::~ZooKeeperLock()
+{
+ try
+ {
+ unlock();
+ }
+ catch (...)
+ {
+ DB::tryLogCurrentException(__PRETTY_FUNCTION__);
+ }
+}
+
+void ZooKeeperLock::unlock()
+{
+ if (!locked)
+ return;
+
+ locked = false;
+
+ if (zookeeper->expired())
+ {
+ LOG_WARNING(log, "Lock is lost, because session was expired. Path: {}, message: {}", lock_path, lock_message);
+ return;
+ }
+
+ Coordination::Stat stat;
+ /// NOTE It will throw if session expired after we checked it above
+ bool result = zookeeper->exists(lock_path, &stat);
+
+ if (result && stat.ephemeralOwner == zookeeper->getClientID())
+ zookeeper->remove(lock_path, -1);
+ else if (result)
+ throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Lock is lost, it has another owner. Path: {}, message: {}, owner: {}, our id: {}",
+ lock_path, lock_message, stat.ephemeralOwner, zookeeper->getClientID());
+ else
+ throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Lock is lost, node does not exist. Path: {}, message: {}", lock_path, lock_message);
+}
+
+bool ZooKeeperLock::tryLock()
+{
+ Coordination::Error code = zookeeper->tryCreate(lock_path, lock_message, zkutil::CreateMode::Ephemeral);
+
+ if (code == Coordination::Error::ZOK)
+ {
+ locked = true;
+ }
+ else if (code != Coordination::Error::ZNODEEXISTS)
+ {
+ throw Coordination::Exception(code);
+ }
+
+ return locked;
+}
+
+std::unique_ptr createSimpleZooKeeperLock(
+ const ZooKeeperPtr & zookeeper, const String & lock_prefix, const String & lock_name, const String & lock_message)
+{
+ return std::make_unique(zookeeper, lock_prefix, lock_name, lock_message);
+}
+
+
+}
diff --git a/src/Common/ZooKeeper/ZooKeeperLock.h b/src/Common/ZooKeeper/ZooKeeperLock.h
new file mode 100644
index 00000000000..218f14ef132
--- /dev/null
+++ b/src/Common/ZooKeeper/ZooKeeperLock.h
@@ -0,0 +1,54 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+namespace zkutil
+{
+
+/** Caveats: usage of locks in ZooKeeper is incorrect in 99% of cases,
+ * and highlights your poor understanding of distributed systems.
+ *
+ * It's only correct if all the operations that are performed under lock
+ * are atomically checking that the lock still holds
+ * or if we ensure that these operations will be undone if lock is lost
+ * (due to ZooKeeper session loss) that's very difficult to achieve.
+ *
+ * It's Ok if every operation that we perform under lock is actually operation in ZooKeeper.
+ *
+ * In 1% of cases when you can correctly use Lock, the logic is complex enough, so you don't need this class.
+ *
+ * TLDR: Don't use this code if you are not sure. We only have a few cases of it's usage.
+ */
+class ZooKeeperLock
+{
+public:
+ /// lock_prefix - path where the ephemeral lock node will be created
+ /// lock_name - the name of the ephemeral lock node
+ ZooKeeperLock(
+ const ZooKeeperPtr & zookeeper_,
+ const std::string & lock_prefix_,
+ const std::string & lock_name_,
+ const std::string & lock_message_ = "");
+
+ ~ZooKeeperLock();
+
+ void unlock();
+ bool tryLock();
+
+private:
+ zkutil::ZooKeeperPtr zookeeper;
+
+ std::string lock_path;
+ std::string lock_message;
+ Poco::Logger * log;
+ bool locked = false;
+
+};
+
+std::unique_ptr createSimpleZooKeeperLock(
+ const ZooKeeperPtr & zookeeper, const String & lock_prefix, const String & lock_name, const String & lock_message);
+
+}
diff --git a/src/Common/ZooKeeper/examples/CMakeLists.txt b/src/Common/ZooKeeper/examples/CMakeLists.txt
index bbfa3e1f137..8bec951e24f 100644
--- a/src/Common/ZooKeeper/examples/CMakeLists.txt
+++ b/src/Common/ZooKeeper/examples/CMakeLists.txt
@@ -1,14 +1,14 @@
add_executable(zkutil_test_commands zkutil_test_commands.cpp)
-target_link_libraries(zkutil_test_commands PRIVATE clickhouse_common_zookeeper)
+target_link_libraries(zkutil_test_commands PRIVATE clickhouse_common_zookeeper_no_log)
add_executable(zkutil_test_commands_new_lib zkutil_test_commands_new_lib.cpp)
-target_link_libraries(zkutil_test_commands_new_lib PRIVATE clickhouse_common_zookeeper string_utils)
+target_link_libraries(zkutil_test_commands_new_lib PRIVATE clickhouse_common_zookeeper_no_log string_utils)
add_executable(zkutil_test_async zkutil_test_async.cpp)
-target_link_libraries(zkutil_test_async PRIVATE clickhouse_common_zookeeper)
+target_link_libraries(zkutil_test_async PRIVATE clickhouse_common_zookeeper_no_log)
add_executable (zk_many_watches_reconnect zk_many_watches_reconnect.cpp)
-target_link_libraries (zk_many_watches_reconnect PRIVATE clickhouse_common_zookeeper clickhouse_common_config)
+target_link_libraries (zk_many_watches_reconnect PRIVATE clickhouse_common_zookeeper_no_log clickhouse_common_config)
add_executable (zookeeper_impl zookeeper_impl.cpp)
-target_link_libraries (zookeeper_impl PRIVATE clickhouse_common_zookeeper)
+target_link_libraries (zookeeper_impl PRIVATE clickhouse_common_zookeeper_no_log)
diff --git a/src/Coordination/FourLetterCommand.cpp b/src/Coordination/FourLetterCommand.cpp
index 294e623d803..3d0ebe86bf3 100644
--- a/src/Coordination/FourLetterCommand.cpp
+++ b/src/Coordination/FourLetterCommand.cpp
@@ -9,6 +9,8 @@
#include
#include
#include
+#include
+#include
#include
diff --git a/src/Coordination/KeeperStorage.cpp b/src/Coordination/KeeperStorage.cpp
index a64a7d425f6..4f174e4e803 100644
--- a/src/Coordination/KeeperStorage.cpp
+++ b/src/Coordination/KeeperStorage.cpp
@@ -1,16 +1,18 @@
#include
#include
#include
-#include
-#include
-#include
#include
-#include
-#include
+#include
+#include
+#include
#include
#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
namespace DB
{
diff --git a/src/Coordination/KeeperStorage.h b/src/Coordination/KeeperStorage.h
index f61b17a88a6..11d191b7f50 100644
--- a/src/Coordination/KeeperStorage.h
+++ b/src/Coordination/KeeperStorage.h
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/Dictionaries/CacheDictionary.cpp b/src/Dictionaries/CacheDictionary.cpp
index 102421e8721..c21ea763ac3 100644
--- a/src/Dictionaries/CacheDictionary.cpp
+++ b/src/Dictionaries/CacheDictionary.cpp
@@ -69,7 +69,7 @@ CacheDictionary::CacheDictionary(
, rnd_engine(randomSeed())
{
if (!source_ptr->supportsSelectiveLoad())
- throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "{}: source cannot be used with CacheDictionary", full_name);
+ throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "{}: source cannot be used with CacheDictionary", getFullName());
}
template
diff --git a/src/Dictionaries/DirectDictionary.cpp b/src/Dictionaries/DirectDictionary.cpp
index 19bbcb6ca98..9a65d916022 100644
--- a/src/Dictionaries/DirectDictionary.cpp
+++ b/src/Dictionaries/DirectDictionary.cpp
@@ -28,7 +28,7 @@ DirectDictionary::DirectDictionary(
, source_ptr{std::move(source_ptr_)}
{
if (!source_ptr->supportsSelectiveLoad())
- throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "{}: source cannot be used with DirectDictionary", full_name);
+ throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "{}: source cannot be used with DirectDictionary", getFullName());
}
template
diff --git a/src/Dictionaries/FlatDictionary.cpp b/src/Dictionaries/FlatDictionary.cpp
index d9c6b04b593..5d26ad3ebc2 100644
--- a/src/Dictionaries/FlatDictionary.cpp
+++ b/src/Dictionaries/FlatDictionary.cpp
@@ -370,7 +370,7 @@ void FlatDictionary::loadData()
updateData();
if (configuration.require_nonempty && 0 == element_count)
- throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY, "{}: dictionary source is empty and 'require_nonempty' property is set.", full_name);
+ throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY, "{}: dictionary source is empty and 'require_nonempty' property is set.", getFullName());
}
void FlatDictionary::calculateBytesAllocated()
@@ -478,7 +478,7 @@ void FlatDictionary::resize(Attribute & attribute, UInt64 key)
if (key >= configuration.max_array_size)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND,
"{}: identifier should be less than {}",
- full_name,
+ getFullName(),
toString(configuration.max_array_size));
auto & container = std::get>(attribute.container);
diff --git a/src/Dictionaries/HashedArrayDictionary.cpp b/src/Dictionaries/HashedArrayDictionary.cpp
index 8d16f453328..148aaafb160 100644
--- a/src/Dictionaries/HashedArrayDictionary.cpp
+++ b/src/Dictionaries/HashedArrayDictionary.cpp
@@ -695,7 +695,7 @@ void HashedArrayDictionary::loadData()
if (configuration.require_nonempty && 0 == element_count)
throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY,
"{}: dictionary source is empty and 'require_nonempty' property is set.",
- full_name);
+ getFullName());
}
template
diff --git a/src/Dictionaries/HashedDictionary.cpp b/src/Dictionaries/HashedDictionary.cpp
index bcc93a34d1e..7025c771e8f 100644
--- a/src/Dictionaries/HashedDictionary.cpp
+++ b/src/Dictionaries/HashedDictionary.cpp
@@ -583,7 +583,7 @@ void HashedDictionary::loadData()
if (configuration.require_nonempty && 0 == element_count)
throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY,
"{}: dictionary source is empty and 'require_nonempty' property is set.",
- full_name);
+ getFullName());
}
template
diff --git a/src/Dictionaries/IDictionary.h b/src/Dictionaries/IDictionary.h
index 022fecab03f..042153f0971 100644
--- a/src/Dictionaries/IDictionary.h
+++ b/src/Dictionaries/IDictionary.h
@@ -54,11 +54,14 @@ class IDictionary : public IExternalLoadable
public:
explicit IDictionary(const StorageID & dictionary_id_)
: dictionary_id(dictionary_id_)
- , full_name(dictionary_id.getInternalDictionaryName())
{
}
- const std::string & getFullName() const{ return full_name; }
+ std::string getFullName() const
+ {
+ std::lock_guard lock{name_mutex};
+ return dictionary_id.getInternalDictionaryName();
+ }
StorageID getDictionaryID() const
{
@@ -73,7 +76,11 @@ public:
dictionary_id = new_name;
}
- const std::string & getLoadableName() const override final { return getFullName(); }
+ std::string getLoadableName() const override final
+ {
+ std::lock_guard lock{name_mutex};
+ return dictionary_id.getInternalDictionaryName();
+ }
/// Specifies that no database is used.
/// Sometimes we cannot simply use an empty string for that because an empty string is
@@ -270,7 +277,6 @@ private:
mutable StorageID dictionary_id;
protected:
- const String full_name;
String dictionary_comment;
};
diff --git a/src/Dictionaries/IPAddressDictionary.cpp b/src/Dictionaries/IPAddressDictionary.cpp
index c1f244e3b81..9945ee1d4b3 100644
--- a/src/Dictionaries/IPAddressDictionary.cpp
+++ b/src/Dictionaries/IPAddressDictionary.cpp
@@ -336,7 +336,7 @@ void IPAddressDictionary::createAttributes()
if (attribute.is_nullable)
throw Exception(ErrorCodes::UNSUPPORTED_METHOD,
"{}: array or nullable attributes not supported for dictionary of type {}",
- full_name,
+ getFullName(),
getTypeName());
attribute_index_by_name.emplace(attribute.name, attributes.size());
@@ -345,7 +345,7 @@ void IPAddressDictionary::createAttributes()
if (attribute.hierarchical)
throw Exception(ErrorCodes::TYPE_MISMATCH,
"{}: hierarchical attributes not supported for dictionary of type {}",
- full_name,
+ getFullName(),
getTypeName());
}
};
@@ -520,7 +520,7 @@ void IPAddressDictionary::loadData()
LOG_TRACE(logger, "{} ip records are read", ip_records.size());
if (require_nonempty && 0 == element_count)
- throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY, "{}: dictionary source is empty and 'require_nonempty' property is set.", full_name);
+ throw Exception(ErrorCodes::DICTIONARY_IS_EMPTY, "{}: dictionary source is empty and 'require_nonempty' property is set.", getFullName());
}
template
@@ -781,7 +781,7 @@ const IPAddressDictionary::Attribute & IPAddressDictionary::getAttribute(const s
{
const auto it = attribute_index_by_name.find(attribute_name);
if (it == std::end(attribute_index_by_name))
- throw Exception(ErrorCodes::BAD_ARGUMENTS, "{}: no such attribute '{}'", full_name, attribute_name);
+ throw Exception(ErrorCodes::BAD_ARGUMENTS, "{}: no such attribute '{}'", getFullName(), attribute_name);
return attributes[it->second];
}
diff --git a/src/Dictionaries/SSDCacheDictionaryStorage.h b/src/Dictionaries/SSDCacheDictionaryStorage.h
index e30b0a257d9..7c7dc838436 100644
--- a/src/Dictionaries/SSDCacheDictionaryStorage.h
+++ b/src/Dictionaries/SSDCacheDictionaryStorage.h
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/Functions/FunctionBinaryArithmetic.h b/src/Functions/FunctionBinaryArithmetic.h
index 69d65bfcf66..a1c3320f88a 100644
--- a/src/Functions/FunctionBinaryArithmetic.h
+++ b/src/Functions/FunctionBinaryArithmetic.h
@@ -7,39 +7,38 @@
#include
#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
-#include
-#include
+#include
#include
+#include
#include
+#include
+#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "Core/DecimalFunctions.h"
-#include "IFunction.h"
-#include "FunctionHelpers.h"
-#include "IsOperation.h"
-#include "DivisionUtils.h"
-#include "castTypeToEither.h"
-#include "FunctionFactory.h"
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
-
-#include
+#include
+#include
+#include
#if USE_EMBEDDED_COMPILER
# pragma GCC diagnostic push
@@ -134,11 +133,11 @@ public:
Case && IsIntegralOrExtended, LeftDataType>,
Case && IsIntegralOrExtended, RightDataType>,
- /// e.g Decimal * Float64 = Float64
- Case::multiply && IsDataTypeDecimal && IsFloatingPoint,
- RightDataType>,
- Case::multiply && IsDataTypeDecimal && IsFloatingPoint,
- LeftDataType>,
+ /// e.g Decimal +-*/ Float, least(Decimal, Float), greatest(Decimal, Float) = Float64
+ Case::allow_decimal && IsDataTypeDecimal && IsFloatingPoint,
+ DataTypeFloat64>,
+ Case::allow_decimal && IsDataTypeDecimal && IsFloatingPoint,
+ DataTypeFloat64>,
/// Decimal Real is not supported (traditional DBs convert Decimal Real to Real)
Case && !IsIntegralOrExtendedOrDecimal, InvalidType>,
@@ -959,25 +958,16 @@ class FunctionBinaryArithmetic : public IFunction
static constexpr const bool left_is_decimal = is_decimal;
static constexpr const bool right_is_decimal = is_decimal;
- static constexpr const bool result_is_decimal = IsDataTypeDecimal;
typename ColVecResult::MutablePtr col_res = nullptr;
- const ResultDataType type = [&]
- {
- if constexpr (left_is_decimal && IsFloatingPoint)
- return RightDataType();
- else if constexpr (right_is_decimal && IsFloatingPoint)
- return LeftDataType();
- else
- return decimalResultType(left, right);
- }();
+ const ResultDataType type = decimalResultType(left, right);
const ResultType scale_a = [&]
{
if constexpr (IsDataTypeDecimal && is_division)
return right.getScaleMultiplier(); // the division impl uses only the scale_a
- else if constexpr (result_is_decimal)
+ else
{
if constexpr (is_multiply)
// the decimal impl uses scales, but if the result is decimal, both of the arguments are decimal,
@@ -988,37 +978,14 @@ class FunctionBinaryArithmetic : public IFunction
else
return type.scaleFactorFor(left, false);
}
- else if constexpr (left_is_decimal)
- {
- if (col_left_const)
- // the column will be converted to native type later, no need to scale it twice.
- // the explicit type is needed to specify lambda return type
- return ResultType{1};
-
- return 1 / DecimalUtils::convertTo(left.getScaleMultiplier(), 0);
- }
- else
- return 1; // the default value which won't cause any re-scale
}();
const ResultType scale_b = [&]
{
- if constexpr (result_is_decimal)
- {
if constexpr (is_multiply)
return ResultType{1};
else
return type.scaleFactorFor(right, is_division);
- }
- else if constexpr (right_is_decimal)
- {
- if (col_right_const)
- return ResultType{1};
-
- return 1 / DecimalUtils::convertTo(right.getScaleMultiplier(), 0);
- }
- else
- return 1;
}();
/// non-vector result
@@ -1029,20 +996,15 @@ class FunctionBinaryArithmetic : public IFunction
ResultType res = {};
if (!right_nullmap || !(*right_nullmap)[0])
- res = check_decimal_overflow ? OpImplCheck::template process(const_a, const_b, scale_a, scale_b)
+ res = check_decimal_overflow
+ ? OpImplCheck::template process(const_a, const_b, scale_a, scale_b)
: OpImpl::template process(const_a, const_b, scale_a, scale_b);
- if constexpr (result_is_decimal)
- return ResultDataType(type.getPrecision(), type.getScale()).createColumnConst(
- col_left_const->size(), toField(res, type.getScale()));
- else
- return ResultDataType().createColumnConst(col_left_const->size(), toField(res));
+ return ResultDataType(type.getPrecision(), type.getScale())
+ .createColumnConst(col_left_const->size(), toField(res, type.getScale()));
}
- if constexpr (result_is_decimal)
- col_res = ColVecResult::create(0, type.getScale());
- else
- col_res = ColVecResult::create(0);
+ col_res = ColVecResult::create(0, type.getScale());
auto & vec_res = col_res->getData();
vec_res.resize(col_left_size);
@@ -1219,8 +1181,7 @@ public:
}
else if constexpr ((IsDataTypeDecimal && IsFloatingPoint) ||
(IsDataTypeDecimal && IsFloatingPoint))
- type_res = std::make_shared,
- LeftDataType, RightDataType>>();
+ type_res = std::make_shared();
else if constexpr (IsDataTypeDecimal)
type_res = std::make_shared(left.getPrecision(), left.getScale());
else if constexpr (IsDataTypeDecimal)
@@ -1453,15 +1414,33 @@ public:
else // we can't avoid the else because otherwise the compiler may assume the ResultDataType may be Invalid
// and that would produce the compile error.
{
- using T0 = typename LeftDataType::FieldType;
- using T1 = typename RightDataType::FieldType;
+ constexpr bool decimal_with_float = (IsDataTypeDecimal && IsFloatingPoint)
+ || (IsFloatingPoint && IsDataTypeDecimal);
+
+ using T0 = std::conditional_t;
+ using T1 = std::conditional_t;
using ResultType = typename ResultDataType::FieldType;
using ColVecT0 = ColumnVectorOrDecimal;
using ColVecT1 = ColumnVectorOrDecimal;
using ColVecResult = ColumnVectorOrDecimal;
- const auto * const col_left_raw = arguments[0].column.get();
- const auto * const col_right_raw = arguments[1].column.get();
+ ColumnPtr left_col = nullptr;
+ ColumnPtr right_col = nullptr;
+
+ /// When Decimal op Float32/64, convert both of them into Float64
+ if constexpr (decimal_with_float)
+ {
+ const auto converted_type = std::make_shared();
+ left_col = castColumn(arguments[0], converted_type);
+ right_col = castColumn(arguments[1], converted_type);
+ }
+ else
+ {
+ left_col = arguments[0].column;
+ right_col = arguments[1].column;
+ }
+ const auto * const col_left_raw = left_col.get();
+ const auto * const col_right_raw = right_col.get();
const size_t col_left_size = col_left_raw->size();
@@ -1471,7 +1450,7 @@ public:
const ColVecT0 * const col_left = checkAndGetColumn(col_left_raw);
const ColVecT1 * const col_right = checkAndGetColumn(col_right_raw);
- if constexpr (IsDataTypeDecimal || IsDataTypeDecimal)
+ if constexpr (IsDataTypeDecimal)
{
return executeNumericWithDecimal(
left, right,
@@ -1525,11 +1504,7 @@ public:
const T1 value = col_right_const->template getValue();
OpImpl::template process(
- col_left->getData().data(),
- &value,
- vec_res.data(),
- vec_res.size(),
- right_nullmap);
+ col_left->getData().data(), &value, vec_res.data(), vec_res.size(), right_nullmap);
}
else
return nullptr;
diff --git a/src/Functions/IsOperation.h b/src/Functions/IsOperation.h
index 369978fe271..5af8ae77727 100644
--- a/src/Functions/IsOperation.h
+++ b/src/Functions/IsOperation.h
@@ -57,10 +57,7 @@ struct IsOperation
static constexpr bool division = div_floating || div_int || div_int_or_zero;
- static constexpr bool allow_decimal =
- plus || minus || multiply ||
- div_floating || div_int || div_int_or_zero ||
- least || greatest;
+ static constexpr bool allow_decimal = plus || minus || multiply || division || least || greatest;
};
}
diff --git a/src/IO/WriteBuffer.h b/src/IO/WriteBuffer.h
index 4d7f300a504..9440ac0a855 100644
--- a/src/IO/WriteBuffer.h
+++ b/src/IO/WriteBuffer.h
@@ -8,7 +8,7 @@
#include
#include
-#include