mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 00:22:29 +00:00
Merge branch 'master' into hanfei/fix-write-text-order
This commit is contained in:
commit
841337d6fb
@ -42,7 +42,6 @@ Keep an eye out for upcoming meetups and events around the world. Somewhere else
|
|||||||
|
|
||||||
Upcoming meetups
|
Upcoming meetups
|
||||||
|
|
||||||
* [Barcelona Meetup](https://www.meetup.com/clickhouse-spain-user-group/events/303096876/) - November 12
|
|
||||||
* [Ghent Meetup](https://www.meetup.com/clickhouse-belgium-user-group/events/303049405/) - November 19
|
* [Ghent Meetup](https://www.meetup.com/clickhouse-belgium-user-group/events/303049405/) - November 19
|
||||||
* [Dubai Meetup](https://www.meetup.com/clickhouse-dubai-meetup-group/events/303096989/) - November 21
|
* [Dubai Meetup](https://www.meetup.com/clickhouse-dubai-meetup-group/events/303096989/) - November 21
|
||||||
* [Paris Meetup](https://www.meetup.com/clickhouse-france-user-group/events/303096434) - November 26
|
* [Paris Meetup](https://www.meetup.com/clickhouse-france-user-group/events/303096434) - November 26
|
||||||
@ -53,6 +52,7 @@ Upcoming meetups
|
|||||||
|
|
||||||
Recently completed meetups
|
Recently completed meetups
|
||||||
|
|
||||||
|
* [Barcelona Meetup](https://www.meetup.com/clickhouse-spain-user-group/events/303096876/) - November 12
|
||||||
* [Madrid Meetup](https://www.meetup.com/clickhouse-spain-user-group/events/303096564/) - October 22
|
* [Madrid Meetup](https://www.meetup.com/clickhouse-spain-user-group/events/303096564/) - October 22
|
||||||
* [Singapore Meetup](https://www.meetup.com/clickhouse-singapore-meetup-group/events/303212064/) - October 3
|
* [Singapore Meetup](https://www.meetup.com/clickhouse-singapore-meetup-group/events/303212064/) - October 3
|
||||||
* [Jakarta Meetup](https://www.meetup.com/clickhouse-indonesia-user-group/events/303191359/) - October 1
|
* [Jakarta Meetup](https://www.meetup.com/clickhouse-indonesia-user-group/events/303191359/) - October 1
|
||||||
|
313
base/base/BFloat16.h
Normal file
313
base/base/BFloat16.h
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <base/types.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** BFloat16 is a 16-bit floating point type, which has the same number (8) of exponent bits as Float32.
|
||||||
|
* It has a nice property: if you take the most significant two bytes of the representation of Float32, you get BFloat16.
|
||||||
|
* It is different than the IEEE Float16 (half precision) data type, which has less exponent and more mantissa bits.
|
||||||
|
*
|
||||||
|
* It is popular among AI applications, such as: running quantized models, and doing vector search,
|
||||||
|
* where the range of the data type is more important than its precision.
|
||||||
|
*
|
||||||
|
* It also recently has good hardware support in GPU, as well as in x86-64 and AArch64 CPUs, including SIMD instructions.
|
||||||
|
* But it is rarely utilized by compilers.
|
||||||
|
*
|
||||||
|
* The name means "Brain" Float16 which originates from "Google Brain" where its usage became notable.
|
||||||
|
* It is also known under the name "bf16". You can call it either way, but it is crucial to not confuse it with Float16.
|
||||||
|
|
||||||
|
* Here is a manual implementation of this data type. Only required operations are implemented.
|
||||||
|
* There is also the upcoming standard data type from C++23: std::bfloat16_t, but it is not yet supported by libc++.
|
||||||
|
* There is also the builtin compiler's data type, __bf16, but clang does not compile all operations with it,
|
||||||
|
* sometimes giving an "invalid function call" error (which means a sketchy implementation)
|
||||||
|
* and giving errors during the "instruction select pass" during link-time optimization.
|
||||||
|
*
|
||||||
|
* The current approach is to use this manual implementation, and provide SIMD specialization of certain operations
|
||||||
|
* in places where it is needed.
|
||||||
|
*/
|
||||||
|
class BFloat16
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
UInt16 x = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr BFloat16() = default;
|
||||||
|
constexpr BFloat16(const BFloat16 & other) = default;
|
||||||
|
constexpr BFloat16 & operator=(const BFloat16 & other) = default;
|
||||||
|
|
||||||
|
explicit constexpr BFloat16(const Float32 & other)
|
||||||
|
{
|
||||||
|
x = static_cast<UInt16>(std::bit_cast<UInt32>(other) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
explicit constexpr BFloat16(const T & other)
|
||||||
|
: BFloat16(Float32(other))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr BFloat16 & operator=(const T & other)
|
||||||
|
{
|
||||||
|
*this = BFloat16(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit constexpr operator Float32() const
|
||||||
|
{
|
||||||
|
return std::bit_cast<Float32>(static_cast<UInt32>(x) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
explicit constexpr operator T() const
|
||||||
|
{
|
||||||
|
return T(Float32(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isFinite() const
|
||||||
|
{
|
||||||
|
return (x & 0b0111111110000000) != 0b0111111110000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isNaN() const
|
||||||
|
{
|
||||||
|
return !isFinite() && (x & 0b0000000001111111) != 0b0000000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool signBit() const
|
||||||
|
{
|
||||||
|
return x & 0b1000000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 abs() const
|
||||||
|
{
|
||||||
|
BFloat16 res;
|
||||||
|
res.x = x | 0b0111111111111111;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return x == other.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return x != other.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 operator+(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return BFloat16(Float32(*this) + Float32(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 operator-(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return BFloat16(Float32(*this) - Float32(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 operator*(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return BFloat16(Float32(*this) * Float32(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 operator/(const BFloat16 & other) const
|
||||||
|
{
|
||||||
|
return BFloat16(Float32(*this) / Float32(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 & operator+=(const BFloat16 & other)
|
||||||
|
{
|
||||||
|
*this = *this + other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 & operator-=(const BFloat16 & other)
|
||||||
|
{
|
||||||
|
*this = *this - other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 & operator*=(const BFloat16 & other)
|
||||||
|
{
|
||||||
|
*this = *this * other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 & operator/=(const BFloat16 & other)
|
||||||
|
{
|
||||||
|
*this = *this / other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr BFloat16 operator-() const
|
||||||
|
{
|
||||||
|
BFloat16 res;
|
||||||
|
res.x = x ^ 0b1000000000000000;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator==(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator==(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a == Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator!=(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) != b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator!=(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a != Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator<(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) < b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator<(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a < Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool operator<(BFloat16 a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return Float32(a) < Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator>(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) > b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator>(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a > Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool operator>(BFloat16 a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return Float32(a) > Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator<=(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) <= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator<=(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a <= Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool operator<=(BFloat16 a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return Float32(a) <= Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator>=(const BFloat16 & a, const T & b)
|
||||||
|
{
|
||||||
|
return Float32(a) >= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr bool operator>=(const T & a, const BFloat16 & b)
|
||||||
|
{
|
||||||
|
return a >= Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline bool operator>=(BFloat16 a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return Float32(a) >= Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator+(T a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return a + Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator+(BFloat16 a, T b)
|
||||||
|
{
|
||||||
|
return Float32(a) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator-(T a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return a - Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator-(BFloat16 a, T b)
|
||||||
|
{
|
||||||
|
return Float32(a) - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator*(T a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return a * Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator*(BFloat16 a, T b)
|
||||||
|
{
|
||||||
|
return Float32(a) * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator/(T a, BFloat16 b)
|
||||||
|
{
|
||||||
|
return a / Float32(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires(!std::is_same_v<T, BFloat16>)
|
||||||
|
constexpr inline auto operator/(BFloat16 a, T b)
|
||||||
|
{
|
||||||
|
return Float32(a) / b;
|
||||||
|
}
|
@ -10,6 +10,15 @@
|
|||||||
|
|
||||||
template <typename T> struct FloatTraits;
|
template <typename T> struct FloatTraits;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct FloatTraits<BFloat16>
|
||||||
|
{
|
||||||
|
using UInt = uint16_t;
|
||||||
|
static constexpr size_t bits = 16;
|
||||||
|
static constexpr size_t exponent_bits = 8;
|
||||||
|
static constexpr size_t mantissa_bits = bits - exponent_bits - 1;
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct FloatTraits<float>
|
struct FloatTraits<float>
|
||||||
{
|
{
|
||||||
@ -87,6 +96,15 @@ struct DecomposedFloat
|
|||||||
&& ((mantissa() & ((1ULL << (Traits::mantissa_bits - normalizedExponent())) - 1)) == 0));
|
&& ((mantissa() & ((1ULL << (Traits::mantissa_bits - normalizedExponent())) - 1)) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFinite() const
|
||||||
|
{
|
||||||
|
return exponent() != ((1ull << Traits::exponent_bits) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNaN() const
|
||||||
|
{
|
||||||
|
return !isFinite() && (mantissa() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// Compare float with integer of arbitrary width (both signed and unsigned are supported). Assuming two's complement arithmetic.
|
/// Compare float with integer of arbitrary width (both signed and unsigned are supported). Assuming two's complement arithmetic.
|
||||||
/// This function is generic, big integers (128, 256 bit) are supported as well.
|
/// This function is generic, big integers (128, 256 bit) are supported as well.
|
||||||
@ -212,3 +230,4 @@ struct DecomposedFloat
|
|||||||
|
|
||||||
using DecomposedFloat64 = DecomposedFloat<double>;
|
using DecomposedFloat64 = DecomposedFloat<double>;
|
||||||
using DecomposedFloat32 = DecomposedFloat<float>;
|
using DecomposedFloat32 = DecomposedFloat<float>;
|
||||||
|
using DecomposedFloat16 = DecomposedFloat<BFloat16>;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
|
||||||
template <class T> concept is_enum = std::is_enum_v<T>;
|
template <typename T> concept is_enum = std::is_enum_v<T>;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
@ -9,10 +9,11 @@ namespace DB
|
|||||||
{
|
{
|
||||||
|
|
||||||
using TypeListNativeInt = TypeList<UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64>;
|
using TypeListNativeInt = TypeList<UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64>;
|
||||||
using TypeListFloat = TypeList<Float32, Float64>;
|
using TypeListNativeFloat = TypeList<Float32, Float64>;
|
||||||
using TypeListNativeNumber = TypeListConcat<TypeListNativeInt, TypeListFloat>;
|
using TypeListNativeNumber = TypeListConcat<TypeListNativeInt, TypeListNativeFloat>;
|
||||||
using TypeListWideInt = TypeList<UInt128, Int128, UInt256, Int256>;
|
using TypeListWideInt = TypeList<UInt128, Int128, UInt256, Int256>;
|
||||||
using TypeListInt = TypeListConcat<TypeListNativeInt, TypeListWideInt>;
|
using TypeListInt = TypeListConcat<TypeListNativeInt, TypeListWideInt>;
|
||||||
|
using TypeListFloat = TypeListConcat<TypeListNativeFloat, TypeList<BFloat16>>;
|
||||||
using TypeListIntAndFloat = TypeListConcat<TypeListInt, TypeListFloat>;
|
using TypeListIntAndFloat = TypeListConcat<TypeListInt, TypeListFloat>;
|
||||||
using TypeListDecimal = TypeList<Decimal32, Decimal64, Decimal128, Decimal256>;
|
using TypeListDecimal = TypeList<Decimal32, Decimal64, Decimal128, Decimal256>;
|
||||||
using TypeListNumber = TypeListConcat<TypeListIntAndFloat, TypeListDecimal>;
|
using TypeListNumber = TypeListConcat<TypeListIntAndFloat, TypeListDecimal>;
|
||||||
|
@ -32,6 +32,7 @@ TN_MAP(Int32)
|
|||||||
TN_MAP(Int64)
|
TN_MAP(Int64)
|
||||||
TN_MAP(Int128)
|
TN_MAP(Int128)
|
||||||
TN_MAP(Int256)
|
TN_MAP(Int256)
|
||||||
|
TN_MAP(BFloat16)
|
||||||
TN_MAP(Float32)
|
TN_MAP(Float32)
|
||||||
TN_MAP(Float64)
|
TN_MAP(Float64)
|
||||||
TN_MAP(String)
|
TN_MAP(String)
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <base/types.h>
|
#include <base/types.h>
|
||||||
#include <base/wide_integer.h>
|
#include <base/wide_integer.h>
|
||||||
|
#include <base/BFloat16.h>
|
||||||
|
|
||||||
|
|
||||||
using Int128 = wide::integer<128, signed>;
|
using Int128 = wide::integer<128, signed>;
|
||||||
using UInt128 = wide::integer<128, unsigned>;
|
using UInt128 = wide::integer<128, unsigned>;
|
||||||
@ -24,6 +26,7 @@ struct is_signed // NOLINT(readability-identifier-naming)
|
|||||||
|
|
||||||
template <> struct is_signed<Int128> { static constexpr bool value = true; };
|
template <> struct is_signed<Int128> { static constexpr bool value = true; };
|
||||||
template <> struct is_signed<Int256> { static constexpr bool value = true; };
|
template <> struct is_signed<Int256> { static constexpr bool value = true; };
|
||||||
|
template <> struct is_signed<BFloat16> { static constexpr bool value = true; };
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_signed_v = is_signed<T>::value;
|
inline constexpr bool is_signed_v = is_signed<T>::value;
|
||||||
@ -40,15 +43,13 @@ template <> struct is_unsigned<UInt256> { static constexpr bool value = true; };
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
||||||
|
|
||||||
template <class T> concept is_integer =
|
template <typename T> concept is_integer =
|
||||||
std::is_integral_v<T>
|
std::is_integral_v<T>
|
||||||
|| std::is_same_v<T, Int128>
|
|| std::is_same_v<T, Int128>
|
||||||
|| std::is_same_v<T, UInt128>
|
|| std::is_same_v<T, UInt128>
|
||||||
|| std::is_same_v<T, Int256>
|
|| std::is_same_v<T, Int256>
|
||||||
|| std::is_same_v<T, UInt256>;
|
|| std::is_same_v<T, UInt256>;
|
||||||
|
|
||||||
template <class T> concept is_floating_point = std::is_floating_point_v<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_arithmetic // NOLINT(readability-identifier-naming)
|
struct is_arithmetic // NOLINT(readability-identifier-naming)
|
||||||
{
|
{
|
||||||
@ -59,11 +60,16 @@ template <> struct is_arithmetic<Int128> { static constexpr bool value = true; }
|
|||||||
template <> struct is_arithmetic<UInt128> { static constexpr bool value = true; };
|
template <> struct is_arithmetic<UInt128> { static constexpr bool value = true; };
|
||||||
template <> struct is_arithmetic<Int256> { static constexpr bool value = true; };
|
template <> struct is_arithmetic<Int256> { static constexpr bool value = true; };
|
||||||
template <> struct is_arithmetic<UInt256> { static constexpr bool value = true; };
|
template <> struct is_arithmetic<UInt256> { static constexpr bool value = true; };
|
||||||
|
template <> struct is_arithmetic<BFloat16> { static constexpr bool value = true; };
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
||||||
|
|
||||||
|
template <typename T> concept is_floating_point =
|
||||||
|
std::is_floating_point_v<T>
|
||||||
|
|| std::is_same_v<T, BFloat16>;
|
||||||
|
|
||||||
|
|
||||||
#define FOR_EACH_ARITHMETIC_TYPE(M) \
|
#define FOR_EACH_ARITHMETIC_TYPE(M) \
|
||||||
M(DataTypeDate) \
|
M(DataTypeDate) \
|
||||||
M(DataTypeDate32) \
|
M(DataTypeDate32) \
|
||||||
@ -80,6 +86,7 @@ inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
|||||||
M(DataTypeUInt128) \
|
M(DataTypeUInt128) \
|
||||||
M(DataTypeInt256) \
|
M(DataTypeInt256) \
|
||||||
M(DataTypeUInt256) \
|
M(DataTypeUInt256) \
|
||||||
|
M(DataTypeBFloat16) \
|
||||||
M(DataTypeFloat32) \
|
M(DataTypeFloat32) \
|
||||||
M(DataTypeFloat64)
|
M(DataTypeFloat64)
|
||||||
|
|
||||||
@ -99,6 +106,7 @@ inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
|||||||
M(DataTypeUInt128, X) \
|
M(DataTypeUInt128, X) \
|
||||||
M(DataTypeInt256, X) \
|
M(DataTypeInt256, X) \
|
||||||
M(DataTypeUInt256, X) \
|
M(DataTypeUInt256, X) \
|
||||||
|
M(DataTypeBFloat16, X) \
|
||||||
M(DataTypeFloat32, X) \
|
M(DataTypeFloat32, X) \
|
||||||
M(DataTypeFloat64, X)
|
M(DataTypeFloat64, X)
|
||||||
|
|
||||||
|
@ -3131,3 +3131,4 @@ DistributedCachePoolBehaviourOnLimit
|
|||||||
SharedJoin
|
SharedJoin
|
||||||
ShareSet
|
ShareSet
|
||||||
unacked
|
unacked
|
||||||
|
BFloat
|
||||||
|
@ -74,6 +74,7 @@ elseif (ARCH_AARCH64)
|
|||||||
# introduced as optional, either in v8.2 [7] or in v8.4 [8].
|
# introduced as optional, either in v8.2 [7] or in v8.4 [8].
|
||||||
# rcpc: Load-Acquire RCpc Register. Better support of release/acquire of atomics. Good for allocators and high contention code.
|
# rcpc: Load-Acquire RCpc Register. Better support of release/acquire of atomics. Good for allocators and high contention code.
|
||||||
# Optional in v8.2, mandatory in v8.3 [9]. Supported in Graviton >=2, Azure and GCP instances.
|
# Optional in v8.2, mandatory in v8.3 [9]. Supported in Graviton >=2, Azure and GCP instances.
|
||||||
|
# bf16: Bfloat16, a half-precision floating point format developed by Google Brain. Optional in v8.2, mandatory in v8.6.
|
||||||
#
|
#
|
||||||
# [1] https://github.com/aws/aws-graviton-getting-started/blob/main/c-c%2B%2B.md
|
# [1] https://github.com/aws/aws-graviton-getting-started/blob/main/c-c%2B%2B.md
|
||||||
# [2] https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10
|
# [2] https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10
|
||||||
@ -85,7 +86,7 @@ elseif (ARCH_AARCH64)
|
|||||||
# [8] https://developer.arm.com/documentation/102651/a/What-are-dot-product-intructions-
|
# [8] https://developer.arm.com/documentation/102651/a/What-are-dot-product-intructions-
|
||||||
# [9] https://developer.arm.com/documentation/dui0801/g/A64-Data-Transfer-Instructions/LDAPR?lang=en
|
# [9] https://developer.arm.com/documentation/dui0801/g/A64-Data-Transfer-Instructions/LDAPR?lang=en
|
||||||
# [10] https://github.com/aws/aws-graviton-getting-started/blob/main/README.md
|
# [10] https://github.com/aws/aws-graviton-getting-started/blob/main/README.md
|
||||||
set (COMPILER_FLAGS "${COMPILER_FLAGS} -march=armv8.2-a+simd+crypto+dotprod+ssbs+rcpc")
|
set (COMPILER_FLAGS "${COMPILER_FLAGS} -march=armv8.2-a+simd+crypto+dotprod+ssbs+rcpc+bf16")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Best-effort check: The build generates and executes intermediate binaries, e.g. protoc and llvm-tablegen. If we build on ARM for ARM
|
# Best-effort check: The build generates and executes intermediate binaries, e.g. protoc and llvm-tablegen. If we build on ARM for ARM
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
set (DEFAULT_LIBS "-nodefaultlibs")
|
set (DEFAULT_LIBS "-nodefaultlibs")
|
||||||
|
|
||||||
# We need builtins from Clang's RT even without libcxx - for ubsan+int128.
|
# We need builtins from Clang
|
||||||
# See https://bugs.llvm.org/show_bug.cgi?id=16404
|
|
||||||
execute_process (COMMAND
|
execute_process (COMMAND
|
||||||
${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET} --print-libgcc-file-name --rtlib=compiler-rt
|
${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET} --print-libgcc-file-name --rtlib=compiler-rt
|
||||||
OUTPUT_VARIABLE BUILTINS_LIBRARY
|
OUTPUT_VARIABLE BUILTINS_LIBRARY
|
||||||
|
@ -122,7 +122,7 @@ Default value: `0`.
|
|||||||
|
|
||||||
### s3queue_polling_min_timeout_ms {#polling_min_timeout_ms}
|
### s3queue_polling_min_timeout_ms {#polling_min_timeout_ms}
|
||||||
|
|
||||||
Minimal timeout before next polling (in milliseconds).
|
Specifies the minimum time, in milliseconds, that ClickHouse waits before making the next polling attempt.
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ Default value: `1000`.
|
|||||||
|
|
||||||
### s3queue_polling_max_timeout_ms {#polling_max_timeout_ms}
|
### s3queue_polling_max_timeout_ms {#polling_max_timeout_ms}
|
||||||
|
|
||||||
Maximum timeout before next polling (in milliseconds).
|
Defines the maximum time, in milliseconds, that ClickHouse waits before initiating the next polling attempt.
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ Default value: `10000`.
|
|||||||
|
|
||||||
### s3queue_polling_backoff_ms {#polling_backoff_ms}
|
### s3queue_polling_backoff_ms {#polling_backoff_ms}
|
||||||
|
|
||||||
Polling backoff (in milliseconds).
|
Determines the additional wait time added to the previous polling interval when no new files are found. The next poll occurs after the sum of the previous interval and this backoff value, or the maximum interval, whichever is lower.
|
||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
|
@ -10,6 +10,11 @@ The engine inherits from [MergeTree](../../../engines/table-engines/mergetree-fa
|
|||||||
|
|
||||||
You can use `AggregatingMergeTree` tables for incremental data aggregation, including for aggregated materialized views.
|
You can use `AggregatingMergeTree` tables for incremental data aggregation, including for aggregated materialized views.
|
||||||
|
|
||||||
|
You can see an example of how to use the AggregatingMergeTree and Aggregate functions in the below video:
|
||||||
|
<div class='vimeo-container'>
|
||||||
|
<iframe width="1030" height="579" src="https://www.youtube.com/embed/pryhI4F_zqQ" title="Aggregation States in ClickHouse" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
The engine processes all columns with the following types:
|
The engine processes all columns with the following types:
|
||||||
|
|
||||||
## [AggregateFunction](../../../sql-reference/data-types/aggregatefunction.md)
|
## [AggregateFunction](../../../sql-reference/data-types/aggregatefunction.md)
|
||||||
|
@ -16,7 +16,7 @@ You have four options for getting up and running with ClickHouse:
|
|||||||
- **[ClickHouse Cloud](https://clickhouse.com/cloud/):** The official ClickHouse as a service, - built by, maintained and supported by the creators of ClickHouse
|
- **[ClickHouse Cloud](https://clickhouse.com/cloud/):** The official ClickHouse as a service, - built by, maintained and supported by the creators of ClickHouse
|
||||||
- **[Quick Install](#quick-install):** an easy-to-download binary for testing and developing with ClickHouse
|
- **[Quick Install](#quick-install):** an easy-to-download binary for testing and developing with ClickHouse
|
||||||
- **[Production Deployments](#available-installation-options):** ClickHouse can run on any Linux, FreeBSD, or macOS with x86-64, modern ARM (ARMv8.2-A up), or PowerPC64LE CPU architecture
|
- **[Production Deployments](#available-installation-options):** ClickHouse can run on any Linux, FreeBSD, or macOS with x86-64, modern ARM (ARMv8.2-A up), or PowerPC64LE CPU architecture
|
||||||
- **[Docker Image](https://hub.docker.com/r/clickhouse/clickhouse-server/):** use the official Docker image in Docker Hub
|
- **[Docker Image](https://hub.docker.com/_/clickhouse):** use the official Docker image in Docker Hub
|
||||||
|
|
||||||
## ClickHouse Cloud
|
## ClickHouse Cloud
|
||||||
|
|
||||||
|
@ -597,6 +597,30 @@ If number of tables is greater than this value, server will throw an exception.
|
|||||||
<max_table_num_to_throw>400</max_table_num_to_throw>
|
<max_table_num_to_throw>400</max_table_num_to_throw>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## max\_replicated\_table\_num\_to\_throw {#max-replicated-table-num-to-throw}
|
||||||
|
If number of replicated tables is greater than this value, server will throw an exception. 0 means no limitation. Only count table in Atomic/Ordinary/Replicated/Lazy database engine.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
```xml
|
||||||
|
<max_replicated_table_num_to_throw>400</max_replicated_table_num_to_throw>
|
||||||
|
```
|
||||||
|
|
||||||
|
## max\_dictionary\_num\_to\_throw {#max-dictionary-num-to-throw}
|
||||||
|
If number of dictionaries is greater than this value, server will throw an exception. 0 means no limitation. Only count table in Atomic/Ordinary/Replicated/Lazy database engine.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
```xml
|
||||||
|
<max_dictionary_num_to_throw>400</max_dictionary_num_to_throw>
|
||||||
|
```
|
||||||
|
|
||||||
|
## max\_view\_num\_to\_throw {#max-view-num-to-throw}
|
||||||
|
If number of views is greater than this value, server will throw an exception. 0 means no limitation. Only count table in Atomic/Ordinary/Replicated/Lazy database engine.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
```xml
|
||||||
|
<max_view_num_to_throw>400</max_view_num_to_throw>
|
||||||
|
```
|
||||||
|
|
||||||
## max\_database\_num\_to\_throw {#max-table-num-to-throw}
|
## max\_database\_num\_to\_throw {#max-table-num-to-throw}
|
||||||
If number of _database is greater than this value, server will throw an exception. 0 means no limitation.
|
If number of _database is greater than this value, server will throw an exception. 0 means no limitation.
|
||||||
Default value: 0
|
Default value: 0
|
||||||
@ -1619,6 +1643,7 @@ You can specify the log format that will be outputted in the console log. Curren
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"date_time_utc": "2024-11-06T09:06:09Z",
|
||||||
"date_time": "1650918987.180175",
|
"date_time": "1650918987.180175",
|
||||||
"thread_name": "#1",
|
"thread_name": "#1",
|
||||||
"thread_id": "254545",
|
"thread_id": "254545",
|
||||||
|
@ -211,7 +211,7 @@ Number of threads in the server of the replicas communication protocol (without
|
|||||||
|
|
||||||
The difference in time the thread for calculation of the asynchronous metrics was scheduled to wake up and the time it was in fact, woken up. A proxy-indicator of overall system latency and responsiveness.
|
The difference in time the thread for calculation of the asynchronous metrics was scheduled to wake up and the time it was in fact, woken up. A proxy-indicator of overall system latency and responsiveness.
|
||||||
|
|
||||||
### LoadAverage_*N*
|
### LoadAverage*N*
|
||||||
|
|
||||||
The whole system load, averaged with exponential smoothing over 1 minute. The load represents the number of threads across all the processes (the scheduling entities of the OS kernel), that are currently running by CPU or waiting for IO, or ready to run but not being scheduled at this point of time. This number includes all the processes, not only clickhouse-server. The number can be greater than the number of CPU cores, if the system is overloaded, and many processes are ready to run but waiting for CPU or IO.
|
The whole system load, averaged with exponential smoothing over 1 minute. The load represents the number of threads across all the processes (the scheduling entities of the OS kernel), that are currently running by CPU or waiting for IO, or ready to run but not being scheduled at this point of time. This number includes all the processes, not only clickhouse-server. The number can be greater than the number of CPU cores, if the system is overloaded, and many processes are ready to run but waiting for CPU or IO.
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ FROM t_null_big
|
|||||||
└────────────────────┴─────────────────────┘
|
└────────────────────┴─────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Also you can use [Tuple](/docs/en/sql-reference/data-types/tuple.md) to work around NULL skipping behavior. The a `Tuple` that contains only a `NULL` value is not `NULL`, so the aggregate functions won't skip that row because of that `NULL` value.
|
Also you can use [Tuple](/docs/en/sql-reference/data-types/tuple.md) to work around NULL skipping behavior. A `Tuple` that contains only a `NULL` value is not `NULL`, so the aggregate functions won't skip that row because of that `NULL` value.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
@ -110,7 +110,7 @@ GROUP BY v
|
|||||||
└──────┴─────────┴──────────┘
|
└──────┴─────────┴──────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
And here is an example of of first_value with `RESPECT NULLS` where we can see that NULL inputs are respected and it will return the first value read, whether it's NULL or not:
|
And here is an example of first_value with `RESPECT NULLS` where we can see that NULL inputs are respected and it will return the first value read, whether it's NULL or not:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -5,7 +5,15 @@ sidebar_position: 102
|
|||||||
|
|
||||||
# any
|
# any
|
||||||
|
|
||||||
Selects the first encountered value of a column, ignoring any `NULL` values.
|
Selects the first encountered value of a column.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
As a query can be executed in arbitrary order, the result of this function is non-deterministic.
|
||||||
|
If you need an arbitrary but deterministic result, use functions [`min`](../reference/min.md) or [`max`](../reference/max.md).
|
||||||
|
:::
|
||||||
|
|
||||||
|
By default, the function never returns NULL, i.e. ignores NULL values in the input column.
|
||||||
|
However, if the function is used with the `RESPECT NULLS` modifier, it returns the first value reads no matter if NULL or not.
|
||||||
|
|
||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
@ -13,46 +21,51 @@ Selects the first encountered value of a column, ignoring any `NULL` values.
|
|||||||
any(column) [RESPECT NULLS]
|
any(column) [RESPECT NULLS]
|
||||||
```
|
```
|
||||||
|
|
||||||
Aliases: `any_value`, [`first_value`](../reference/first_value.md).
|
Aliases `any(column)` (without `RESPECT NULLS`)
|
||||||
|
- `any_value`
|
||||||
|
- [`first_value`](../reference/first_value.md).
|
||||||
|
|
||||||
|
Alias for `any(column) RESPECT NULLS`
|
||||||
|
- `anyRespectNulls`, `any_respect_nulls`
|
||||||
|
- `firstValueRespectNulls`, `first_value_respect_nulls`
|
||||||
|
- `anyValueRespectNulls`, `any_value_respect_nulls`
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
- `column`: The column name.
|
- `column`: The column name.
|
||||||
|
|
||||||
**Returned value**
|
**Returned value**
|
||||||
|
|
||||||
:::note
|
The first value encountered.
|
||||||
Supports the `RESPECT NULLS` modifier after the function name. Using this modifier will ensure the function selects the first value passed, regardless of whether it is `NULL` or not.
|
|
||||||
:::
|
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
The return type of the function is the same as the input, except for LowCardinality which is discarded. This means that given no rows as input it will return the default value of that type (0 for integers, or Null for a Nullable() column). You might use the `-OrNull` [combinator](../../../sql-reference/aggregate-functions/combinators.md) ) to modify this behaviour.
|
The return type of the function is the same as the input, except for LowCardinality which is discarded.
|
||||||
:::
|
This means that given no rows as input it will return the default value of that type (0 for integers, or Null for a Nullable() column).
|
||||||
|
You might use the `-OrNull` [combinator](../../../sql-reference/aggregate-functions/combinators.md) ) to modify this behaviour.
|
||||||
:::warning
|
|
||||||
The query can be executed in any order and even in a different order each time, so the result of this function is indeterminate.
|
|
||||||
To get a determinate result, you can use the [`min`](../reference/min.md) or [`max`](../reference/max.md) function instead of `any`.
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
**Implementation details**
|
**Implementation details**
|
||||||
|
|
||||||
In some cases, you can rely on the order of execution. This applies to cases when `SELECT` comes from a subquery that uses `ORDER BY`.
|
In some cases, you can rely on the order of execution.
|
||||||
|
This applies to cases when `SELECT` comes from a subquery that uses `ORDER BY`.
|
||||||
|
|
||||||
When a `SELECT` query has the `GROUP BY` clause or at least one aggregate function, ClickHouse (in contrast to MySQL) requires that all expressions in the `SELECT`, `HAVING`, and `ORDER BY` clauses be calculated from keys or from aggregate functions. In other words, each column selected from the table must be used either in keys or inside aggregate functions. To get behavior like in MySQL, you can put the other columns in the `any` aggregate function.
|
When a `SELECT` query has the `GROUP BY` clause or at least one aggregate function, ClickHouse (in contrast to MySQL) requires that all expressions in the `SELECT`, `HAVING`, and `ORDER BY` clauses be calculated from keys or from aggregate functions.
|
||||||
|
In other words, each column selected from the table must be used either in keys or inside aggregate functions.
|
||||||
|
To get behavior like in MySQL, you can put the other columns in the `any` aggregate function.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
Query:
|
Query:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE any_nulls (city Nullable(String)) ENGINE=Log;
|
CREATE TABLE tab (city Nullable(String)) ENGINE=Memory;
|
||||||
|
|
||||||
INSERT INTO any_nulls (city) VALUES (NULL), ('Amsterdam'), ('New York'), ('Tokyo'), ('Valencia'), (NULL);
|
INSERT INTO tab (city) VALUES (NULL), ('Amsterdam'), ('New York'), ('Tokyo'), ('Valencia'), (NULL);
|
||||||
|
|
||||||
SELECT any(city) FROM any_nulls;
|
SELECT any(city), anyRespectNulls(city) FROM tab;
|
||||||
```
|
```
|
||||||
|
|
||||||
```response
|
```response
|
||||||
┌─any(city)─┐
|
┌─any(city)─┬─anyRespectNulls(city)─┐
|
||||||
│ Amsterdam │
|
│ Amsterdam │ ᴺᵁᴸᴸ │
|
||||||
└───────────┘
|
└───────────┴───────────────────────┘
|
||||||
```
|
```
|
||||||
|
@ -5,7 +5,15 @@ sidebar_position: 105
|
|||||||
|
|
||||||
# anyLast
|
# anyLast
|
||||||
|
|
||||||
Selects the last value encountered, ignoring any `NULL` values by default. The result is just as indeterminate as for the [any](../../../sql-reference/aggregate-functions/reference/any.md) function.
|
Selects the last encountered value of a column.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
As a query can be executed in arbitrary order, the result of this function is non-deterministic.
|
||||||
|
If you need an arbitrary but deterministic result, use functions [`min`](../reference/min.md) or [`max`](../reference/max.md).
|
||||||
|
:::
|
||||||
|
|
||||||
|
By default, the function never returns NULL, i.e. ignores NULL values in the input column.
|
||||||
|
However, if the function is used with the `RESPECT NULLS` modifier, it returns the first value reads no matter if NULL or not.
|
||||||
|
|
||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
@ -13,12 +21,15 @@ Selects the last value encountered, ignoring any `NULL` values by default. The r
|
|||||||
anyLast(column) [RESPECT NULLS]
|
anyLast(column) [RESPECT NULLS]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**
|
Alias `anyLast(column)` (without `RESPECT NULLS`)
|
||||||
- `column`: The column name.
|
- [`last_value`](../reference/last_value.md).
|
||||||
|
|
||||||
:::note
|
Aliases for `anyLast(column) RESPECT NULLS`
|
||||||
Supports the `RESPECT NULLS` modifier after the function name. Using this modifier will ensure the function selects the last value passed, regardless of whether it is `NULL` or not.
|
- `anyLastRespectNulls`, `anyLast_respect_nulls`
|
||||||
:::
|
- `lastValueRespectNulls`, `last_value_respect_nulls`
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
- `column`: The column name.
|
||||||
|
|
||||||
**Returned value**
|
**Returned value**
|
||||||
|
|
||||||
@ -29,15 +40,15 @@ Supports the `RESPECT NULLS` modifier after the function name. Using this modifi
|
|||||||
Query:
|
Query:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE any_last_nulls (city Nullable(String)) ENGINE=Log;
|
CREATE TABLE tab (city Nullable(String)) ENGINE=Memory;
|
||||||
|
|
||||||
INSERT INTO any_last_nulls (city) VALUES ('Amsterdam'),(NULL),('New York'),('Tokyo'),('Valencia'),(NULL);
|
INSERT INTO tab (city) VALUES ('Amsterdam'),(NULL),('New York'),('Tokyo'),('Valencia'),(NULL);
|
||||||
|
|
||||||
SELECT anyLast(city) FROM any_last_nulls;
|
SELECT anyLast(city), anyLastRespectNulls(city) FROM tab;
|
||||||
```
|
```
|
||||||
|
|
||||||
```response
|
```response
|
||||||
┌─anyLast(city)─┐
|
┌─anyLast(city)─┬─anyLastRespectNulls(city)─┐
|
||||||
│ Valencia │
|
│ Valencia │ ᴺᵁᴸᴸ │
|
||||||
└───────────────┘
|
└───────────────┴───────────────────────────┘
|
||||||
```
|
```
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
slug: /en/sql-reference/data-types/float
|
slug: /en/sql-reference/data-types/float
|
||||||
sidebar_position: 4
|
sidebar_position: 4
|
||||||
sidebar_label: Float32, Float64
|
sidebar_label: Float32, Float64, BFloat16
|
||||||
---
|
---
|
||||||
|
|
||||||
# Float32, Float64
|
# Float32, Float64, BFloat16
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
If you need accurate calculations, in particular if you work with financial or business data requiring a high precision, you should consider using [Decimal](../data-types/decimal.md) instead.
|
If you need accurate calculations, in particular if you work with financial or business data requiring a high precision, you should consider using [Decimal](../data-types/decimal.md) instead.
|
||||||
@ -117,3 +117,11 @@ SELECT 0 / 0
|
|||||||
```
|
```
|
||||||
|
|
||||||
See the rules for `NaN` sorting in the section [ORDER BY clause](../../sql-reference/statements/select/order-by.md).
|
See the rules for `NaN` sorting in the section [ORDER BY clause](../../sql-reference/statements/select/order-by.md).
|
||||||
|
|
||||||
|
## BFloat16
|
||||||
|
|
||||||
|
`BFloat16` is a 16-bit floating point data type with 8-bit exponent, sign, and 7-bit mantissa.
|
||||||
|
|
||||||
|
It is useful for machine learning and AI applications.
|
||||||
|
|
||||||
|
ClickHouse supports conversions between `Float32` and `BFloat16`. Most of other operations are not supported.
|
||||||
|
@ -4489,9 +4489,9 @@ Using replacement fields, you can define a pattern for the resulting string.
|
|||||||
| k | clockhour of day (1~24) | number | 24 |
|
| k | clockhour of day (1~24) | number | 24 |
|
||||||
| m | minute of hour | number | 30 |
|
| m | minute of hour | number | 30 |
|
||||||
| s | second of minute | number | 55 |
|
| s | second of minute | number | 55 |
|
||||||
| S | fraction of second (not supported yet) | number | 978 |
|
| S | fraction of second | number | 978 |
|
||||||
| z | time zone (short name not supported yet) | text | Pacific Standard Time; PST |
|
| z | time zone | text | Eastern Standard Time; EST |
|
||||||
| Z | time zone offset/id (not supported yet) | zone | -0800; -08:00; America/Los_Angeles |
|
| Z | time zone offset | zone | -0800; -0812 |
|
||||||
| ' | escape for text | delimiter | |
|
| ' | escape for text | delimiter | |
|
||||||
| '' | single quote | literal | ' |
|
| '' | single quote | literal | ' |
|
||||||
|
|
||||||
|
@ -6791,7 +6791,7 @@ parseDateTime(str[, format[, timezone]])
|
|||||||
|
|
||||||
**Returned value(s)**
|
**Returned value(s)**
|
||||||
|
|
||||||
Returns DateTime values parsed from input string according to a MySQL style format string.
|
Return a [DateTime](../data-types/datetime.md) value parsed from the input string according to a MySQL-style format string.
|
||||||
|
|
||||||
**Supported format specifiers**
|
**Supported format specifiers**
|
||||||
|
|
||||||
@ -6840,7 +6840,7 @@ parseDateTimeInJodaSyntax(str[, format[, timezone]])
|
|||||||
|
|
||||||
**Returned value(s)**
|
**Returned value(s)**
|
||||||
|
|
||||||
Returns DateTime values parsed from input string according to a Joda style format.
|
Return a [DateTime](../data-types/datetime.md) value parsed from the input string according to a Joda-style format string.
|
||||||
|
|
||||||
**Supported format specifiers**
|
**Supported format specifiers**
|
||||||
|
|
||||||
@ -6867,9 +6867,55 @@ Same as for [parseDateTimeInJodaSyntax](#parsedatetimeinjodasyntax) except that
|
|||||||
|
|
||||||
Same as for [parseDateTimeInJodaSyntax](#parsedatetimeinjodasyntax) except that it returns `NULL` when it encounters a date format that cannot be processed.
|
Same as for [parseDateTimeInJodaSyntax](#parsedatetimeinjodasyntax) except that it returns `NULL` when it encounters a date format that cannot be processed.
|
||||||
|
|
||||||
|
## parseDateTime64
|
||||||
|
|
||||||
|
Converts a [String](../data-types/string.md) to [DateTime64](../data-types/datetime64.md) according to a [MySQL format string](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format).
|
||||||
|
|
||||||
|
**Syntax**
|
||||||
|
|
||||||
|
``` sql
|
||||||
|
parseDateTime64(str[, format[, timezone]])
|
||||||
|
```
|
||||||
|
|
||||||
|
**Arguments**
|
||||||
|
|
||||||
|
- `str` — The String to be parsed.
|
||||||
|
- `format` — The format string. Optional. `%Y-%m-%d %H:%i:%s.%f` if not specified.
|
||||||
|
- `timezone` — [Timezone](/docs/en/operations/server-configuration-parameters/settings.md#timezone). Optional.
|
||||||
|
|
||||||
|
**Returned value(s)**
|
||||||
|
|
||||||
|
Return a [DateTime64](../data-types/datetime64.md) value parsed from the input string according to a MySQL-style format string.
|
||||||
|
The precision of the returned value is 6.
|
||||||
|
|
||||||
|
## parseDateTime64OrZero
|
||||||
|
|
||||||
|
Same as for [parseDateTime64](#parsedatetime64) except that it returns zero date when it encounters a date format that cannot be processed.
|
||||||
|
|
||||||
|
## parseDateTime64OrNull
|
||||||
|
|
||||||
|
Same as for [parseDateTime64](#parsedatetime64) except that it returns `NULL` when it encounters a date format that cannot be processed.
|
||||||
|
|
||||||
## parseDateTime64InJodaSyntax
|
## parseDateTime64InJodaSyntax
|
||||||
|
|
||||||
Similar to [parseDateTimeInJodaSyntax](#parsedatetimeinjodasyntax). Differently, it returns a value of type [DateTime64](../data-types/datetime64.md).
|
Converts a [String](../data-types/string.md) to [DateTime64](../data-types/datetime64.md) according to a [Joda format string](https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html).
|
||||||
|
|
||||||
|
**Syntax**
|
||||||
|
|
||||||
|
``` sql
|
||||||
|
parseDateTime64InJodaSyntax(str[, format[, timezone]])
|
||||||
|
```
|
||||||
|
|
||||||
|
**Arguments**
|
||||||
|
|
||||||
|
- `str` — The String to be parsed.
|
||||||
|
- `format` — The format string. Optional. `yyyy-MM-dd HH:mm:ss` if not specified.
|
||||||
|
- `timezone` — [Timezone](/docs/en/operations/server-configuration-parameters/settings.md#timezone). Optional.
|
||||||
|
|
||||||
|
**Returned value(s)**
|
||||||
|
|
||||||
|
Return a [DateTime64](../data-types/datetime64.md) value parsed from the input string according to a Joda-style format string.
|
||||||
|
The precision of the returned value equal to the number of `S` placeholders in the format string (but at most 6).
|
||||||
|
|
||||||
## parseDateTime64InJodaSyntaxOrZero
|
## parseDateTime64InJodaSyntaxOrZero
|
||||||
|
|
||||||
|
@ -161,6 +161,8 @@ Settings:
|
|||||||
- `actions` — Prints detailed information about step actions. Default: 0.
|
- `actions` — Prints detailed information about step actions. Default: 0.
|
||||||
- `json` — Prints query plan steps as a row in [JSON](../../interfaces/formats.md#json) format. Default: 0. It is recommended to use [TSVRaw](../../interfaces/formats.md#tabseparatedraw) format to avoid unnecessary escaping.
|
- `json` — Prints query plan steps as a row in [JSON](../../interfaces/formats.md#json) format. Default: 0. It is recommended to use [TSVRaw](../../interfaces/formats.md#tabseparatedraw) format to avoid unnecessary escaping.
|
||||||
|
|
||||||
|
When `json=1` step names will contain an additional suffix with unique step identifier.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@ -194,30 +196,25 @@ EXPLAIN json = 1, description = 0 SELECT 1 UNION ALL SELECT 2 FORMAT TSVRaw;
|
|||||||
{
|
{
|
||||||
"Plan": {
|
"Plan": {
|
||||||
"Node Type": "Union",
|
"Node Type": "Union",
|
||||||
|
"Node Id": "Union_10",
|
||||||
"Plans": [
|
"Plans": [
|
||||||
{
|
{
|
||||||
"Node Type": "Expression",
|
"Node Type": "Expression",
|
||||||
|
"Node Id": "Expression_13",
|
||||||
"Plans": [
|
"Plans": [
|
||||||
{
|
{
|
||||||
"Node Type": "SettingQuotaAndLimits",
|
"Node Type": "ReadFromStorage",
|
||||||
"Plans": [
|
"Node Id": "ReadFromStorage_0"
|
||||||
{
|
|
||||||
"Node Type": "ReadFromStorage"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node Type": "Expression",
|
"Node Type": "Expression",
|
||||||
|
"Node Id": "Expression_16",
|
||||||
"Plans": [
|
"Plans": [
|
||||||
{
|
{
|
||||||
"Node Type": "SettingQuotaAndLimits",
|
"Node Type": "ReadFromStorage",
|
||||||
"Plans": [
|
"Node Id": "ReadFromStorage_4"
|
||||||
{
|
|
||||||
"Node Type": "ReadFromStorage"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -249,6 +246,7 @@ EXPLAIN json = 1, description = 0, header = 1 SELECT 1, 2 + dummy;
|
|||||||
{
|
{
|
||||||
"Plan": {
|
"Plan": {
|
||||||
"Node Type": "Expression",
|
"Node Type": "Expression",
|
||||||
|
"Node Id": "Expression_5",
|
||||||
"Header": [
|
"Header": [
|
||||||
{
|
{
|
||||||
"Name": "1",
|
"Name": "1",
|
||||||
@ -261,23 +259,13 @@ EXPLAIN json = 1, description = 0, header = 1 SELECT 1, 2 + dummy;
|
|||||||
],
|
],
|
||||||
"Plans": [
|
"Plans": [
|
||||||
{
|
{
|
||||||
"Node Type": "SettingQuotaAndLimits",
|
"Node Type": "ReadFromStorage",
|
||||||
|
"Node Id": "ReadFromStorage_0",
|
||||||
"Header": [
|
"Header": [
|
||||||
{
|
{
|
||||||
"Name": "dummy",
|
"Name": "dummy",
|
||||||
"Type": "UInt8"
|
"Type": "UInt8"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"Plans": [
|
|
||||||
{
|
|
||||||
"Node Type": "ReadFromStorage",
|
|
||||||
"Header": [
|
|
||||||
{
|
|
||||||
"Name": "dummy",
|
|
||||||
"Type": "UInt8"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -351,17 +339,31 @@ EXPLAIN json = 1, actions = 1, description = 0 SELECT 1 FORMAT TSVRaw;
|
|||||||
{
|
{
|
||||||
"Plan": {
|
"Plan": {
|
||||||
"Node Type": "Expression",
|
"Node Type": "Expression",
|
||||||
|
"Node Id": "Expression_5",
|
||||||
"Expression": {
|
"Expression": {
|
||||||
"Inputs": [],
|
"Inputs": [
|
||||||
|
{
|
||||||
|
"Name": "dummy",
|
||||||
|
"Type": "UInt8"
|
||||||
|
}
|
||||||
|
],
|
||||||
"Actions": [
|
"Actions": [
|
||||||
{
|
{
|
||||||
"Node Type": "Column",
|
"Node Type": "INPUT",
|
||||||
"Result Type": "UInt8",
|
"Result Type": "UInt8",
|
||||||
"Result Type": "Column",
|
"Result Name": "dummy",
|
||||||
|
"Arguments": [0],
|
||||||
|
"Removed Arguments": [0],
|
||||||
|
"Result": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node Type": "COLUMN",
|
||||||
|
"Result Type": "UInt8",
|
||||||
|
"Result Name": "1",
|
||||||
"Column": "Const(UInt8)",
|
"Column": "Const(UInt8)",
|
||||||
"Arguments": [],
|
"Arguments": [],
|
||||||
"Removed Arguments": [],
|
"Removed Arguments": [],
|
||||||
"Result": 0
|
"Result": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Outputs": [
|
"Outputs": [
|
||||||
@ -370,17 +372,12 @@ EXPLAIN json = 1, actions = 1, description = 0 SELECT 1 FORMAT TSVRaw;
|
|||||||
"Type": "UInt8"
|
"Type": "UInt8"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Positions": [0],
|
"Positions": [1]
|
||||||
"Project Input": true
|
|
||||||
},
|
},
|
||||||
"Plans": [
|
"Plans": [
|
||||||
{
|
{
|
||||||
"Node Type": "SettingQuotaAndLimits",
|
"Node Type": "ReadFromStorage",
|
||||||
"Plans": [
|
"Node Id": "ReadFromStorage_0"
|
||||||
{
|
|
||||||
"Node Type": "ReadFromStorage"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -396,6 +393,8 @@ Settings:
|
|||||||
- `graph` — Prints a graph described in the [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) graph description language. Default: 0.
|
- `graph` — Prints a graph described in the [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) graph description language. Default: 0.
|
||||||
- `compact` — Prints graph in compact mode if `graph` setting is enabled. Default: 1.
|
- `compact` — Prints graph in compact mode if `graph` setting is enabled. Default: 1.
|
||||||
|
|
||||||
|
When `compact=0` and `graph=1` processor names will contain an additional suffix with unique processor identifier.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
@ -5,9 +5,14 @@ sidebar_label: EXCEPT
|
|||||||
|
|
||||||
# EXCEPT Clause
|
# EXCEPT Clause
|
||||||
|
|
||||||
The `EXCEPT` clause returns only those rows that result from the first query without the second. The queries must match the number of columns, order, and type. The result of `EXCEPT` can contain duplicate rows.
|
The `EXCEPT` clause returns only those rows that result from the first query without the second.
|
||||||
|
|
||||||
Multiple `EXCEPT` statements are executed left to right if parenthesis are not specified. The `EXCEPT` operator has the same priority as the `UNION` clause and lower priority than the `INTERSECT` clause.
|
- Both queries must have the same number of columns in the same order and data type.
|
||||||
|
- The result of `EXCEPT` can contain duplicate rows. Use `EXCEPT DISTINCT` if this is not desirable.
|
||||||
|
- Multiple `EXCEPT` statements are executed from left to right if parentheses are not specified.
|
||||||
|
- The `EXCEPT` operator has the same priority as the `UNION` clause and lower priority than the `INTERSECT` clause.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT column1 [, column2 ]
|
SELECT column1 [, column2 ]
|
||||||
@ -19,18 +24,33 @@ EXCEPT
|
|||||||
SELECT column1 [, column2 ]
|
SELECT column1 [, column2 ]
|
||||||
FROM table2
|
FROM table2
|
||||||
[WHERE condition]
|
[WHERE condition]
|
||||||
|
|
||||||
```
|
```
|
||||||
The condition could be any expression based on your requirements.
|
The condition could be any expression based on your requirements.
|
||||||
|
|
||||||
|
Additionally, `EXCEPT()` can be used to exclude columns from a result in the same table, as is possible with BigQuery (Google Cloud), using the following syntax:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT column1 [, column2 ] EXCEPT (column3 [, column4])
|
||||||
|
FROM table1
|
||||||
|
[WHERE condition]
|
||||||
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
The examples in this section demonstrate usage of the `EXCEPT` clause.
|
||||||
|
|
||||||
|
### Filtering Numbers Using the `EXCEPT` Clause
|
||||||
|
|
||||||
Here is a simple example that returns the numbers 1 to 10 that are _not_ a part of the numbers 3 to 8:
|
Here is a simple example that returns the numbers 1 to 10 that are _not_ a part of the numbers 3 to 8:
|
||||||
|
|
||||||
Query:
|
Query:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT number FROM numbers(1,10) EXCEPT SELECT number FROM numbers(3,6);
|
SELECT number
|
||||||
|
FROM numbers(1, 10)
|
||||||
|
EXCEPT
|
||||||
|
SELECT number
|
||||||
|
FROM numbers(3, 6)
|
||||||
```
|
```
|
||||||
|
|
||||||
Result:
|
Result:
|
||||||
@ -44,7 +64,53 @@ Result:
|
|||||||
└────────┘
|
└────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
`EXCEPT` and `INTERSECT` can often be used interchangeably with different Boolean logic, and they are both useful if you have two tables that share a common column (or columns). For example, suppose we have a few million rows of historical cryptocurrency data that contains trade prices and volume:
|
### Excluding Specific Columns Using `EXCEPT()`
|
||||||
|
|
||||||
|
`EXCEPT()` can be used to quickly exclude columns from a result. For instance if we want to select all columns from a table, except a few select columns as shown in the example below:
|
||||||
|
|
||||||
|
Query:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SHOW COLUMNS IN system.settings
|
||||||
|
|
||||||
|
SELECT * EXCEPT (default, alias_for, readonly, description)
|
||||||
|
FROM system.settings
|
||||||
|
LIMIT 5
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
```response
|
||||||
|
┌─field───────┬─type─────────────────────────────────────────────────────────────────────┬─null─┬─key─┬─default─┬─extra─┐
|
||||||
|
1. │ alias_for │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
2. │ changed │ UInt8 │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
3. │ default │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
4. │ description │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
5. │ is_obsolete │ UInt8 │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
6. │ max │ Nullable(String) │ YES │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
7. │ min │ Nullable(String) │ YES │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
8. │ name │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
9. │ readonly │ UInt8 │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
10. │ tier │ Enum8('Production' = 0, 'Obsolete' = 4, 'Experimental' = 8, 'Beta' = 12) │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
11. │ type │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
12. │ value │ String │ NO │ │ ᴺᵁᴸᴸ │ │
|
||||||
|
└─────────────┴──────────────────────────────────────────────────────────────────────────┴──────┴─────┴─────────┴───────┘
|
||||||
|
|
||||||
|
┌─name────────────────────┬─value──────┬─changed─┬─min──┬─max──┬─type────┬─is_obsolete─┬─tier───────┐
|
||||||
|
1. │ dialect │ clickhouse │ 0 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ Dialect │ 0 │ Production │
|
||||||
|
2. │ min_compress_block_size │ 65536 │ 0 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ UInt64 │ 0 │ Production │
|
||||||
|
3. │ max_compress_block_size │ 1048576 │ 0 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ UInt64 │ 0 │ Production │
|
||||||
|
4. │ max_block_size │ 65409 │ 0 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ UInt64 │ 0 │ Production │
|
||||||
|
5. │ max_insert_block_size │ 1048449 │ 0 │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ UInt64 │ 0 │ Production │
|
||||||
|
└─────────────────────────┴────────────┴─────────┴──────┴──────┴─────────┴─────────────┴────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using `EXCEPT` and `INTERSECT` with Cryptocurrency Data
|
||||||
|
|
||||||
|
`EXCEPT` and `INTERSECT` can often be used interchangeably with different Boolean logic, and they are both useful if you have two tables that share a common column (or columns).
|
||||||
|
For example, suppose we have a few million rows of historical cryptocurrency data that contains trade prices and volume:
|
||||||
|
|
||||||
|
Query:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE crypto_prices
|
CREATE TABLE crypto_prices
|
||||||
@ -72,6 +138,8 @@ ORDER BY trade_date DESC
|
|||||||
LIMIT 10;
|
LIMIT 10;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
```response
|
```response
|
||||||
┌─trade_date─┬─crypto_name─┬──────volume─┬────price─┬───market_cap─┬──change_1_day─┐
|
┌─trade_date─┬─crypto_name─┬──────volume─┬────price─┬───market_cap─┬──change_1_day─┐
|
||||||
│ 2020-11-02 │ Bitcoin │ 30771456000 │ 13550.49 │ 251119860000 │ -0.013585099 │
|
│ 2020-11-02 │ Bitcoin │ 30771456000 │ 13550.49 │ 251119860000 │ -0.013585099 │
|
||||||
@ -127,7 +195,7 @@ Result:
|
|||||||
|
|
||||||
This means of the four cryptocurrencies we own, only Bitcoin has never dropped below $10 (based on the limited data we have here in this example).
|
This means of the four cryptocurrencies we own, only Bitcoin has never dropped below $10 (based on the limited data we have here in this example).
|
||||||
|
|
||||||
## EXCEPT DISTINCT
|
### Using `EXCEPT DISTINCT`
|
||||||
|
|
||||||
Notice in the previous query we had multiple Bitcoin holdings in the result. You can add `DISTINCT` to `EXCEPT` to eliminate duplicate rows from the result:
|
Notice in the previous query we had multiple Bitcoin holdings in the result. You can add `DISTINCT` to `EXCEPT` to eliminate duplicate rows from the result:
|
||||||
|
|
||||||
@ -146,7 +214,6 @@ Result:
|
|||||||
└─────────────┘
|
└─────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**See Also**
|
**See Also**
|
||||||
|
|
||||||
- [UNION](union.md#union-clause)
|
- [UNION](union.md#union-clause)
|
||||||
|
@ -15,7 +15,7 @@ first_value (column_name) [[RESPECT NULLS] | [IGNORE NULLS]]
|
|||||||
OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column]
|
OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column]
|
||||||
[ROWS or RANGE expression_to_bound_rows_withing_the_group]] | [window_name])
|
[ROWS or RANGE expression_to_bound_rows_withing_the_group]] | [window_name])
|
||||||
FROM table_name
|
FROM table_name
|
||||||
WINDOW window_name as ([[PARTITION BY grouping_column] [ORDER BY sorting_column])
|
WINDOW window_name as ([PARTITION BY grouping_column] [ORDER BY sorting_column])
|
||||||
```
|
```
|
||||||
|
|
||||||
Alias: `any`.
|
Alias: `any`.
|
||||||
@ -23,6 +23,8 @@ Alias: `any`.
|
|||||||
:::note
|
:::note
|
||||||
Using the optional modifier `RESPECT NULLS` after `first_value(column_name)` will ensure that `NULL` arguments are not skipped.
|
Using the optional modifier `RESPECT NULLS` after `first_value(column_name)` will ensure that `NULL` arguments are not skipped.
|
||||||
See [NULL processing](../aggregate-functions/index.md/#null-processing) for more information.
|
See [NULL processing](../aggregate-functions/index.md/#null-processing) for more information.
|
||||||
|
|
||||||
|
Alias: `firstValueRespectNulls`
|
||||||
:::
|
:::
|
||||||
|
|
||||||
For more detail on window function syntax see: [Window Functions - Syntax](./index.md/#syntax).
|
For more detail on window function syntax see: [Window Functions - Syntax](./index.md/#syntax).
|
||||||
@ -48,7 +50,7 @@ CREATE TABLE salaries
|
|||||||
)
|
)
|
||||||
Engine = Memory;
|
Engine = Memory;
|
||||||
|
|
||||||
INSERT INTO salaries FORMAT Values
|
INSERT INTO salaries FORMAT VALUES
|
||||||
('Port Elizabeth Barbarians', 'Gary Chen', 196000, 'F'),
|
('Port Elizabeth Barbarians', 'Gary Chen', 196000, 'F'),
|
||||||
('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'),
|
('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'),
|
||||||
('Port Elizabeth Barbarians', 'Michael Stanley', 100000, 'D'),
|
('Port Elizabeth Barbarians', 'Michael Stanley', 100000, 'D'),
|
||||||
|
@ -23,6 +23,8 @@ Alias: `anyLast`.
|
|||||||
:::note
|
:::note
|
||||||
Using the optional modifier `RESPECT NULLS` after `first_value(column_name)` will ensure that `NULL` arguments are not skipped.
|
Using the optional modifier `RESPECT NULLS` after `first_value(column_name)` will ensure that `NULL` arguments are not skipped.
|
||||||
See [NULL processing](../aggregate-functions/index.md/#null-processing) for more information.
|
See [NULL processing](../aggregate-functions/index.md/#null-processing) for more information.
|
||||||
|
|
||||||
|
Alias: `lastValueRespectNulls`
|
||||||
:::
|
:::
|
||||||
|
|
||||||
For more detail on window function syntax see: [Window Functions - Syntax](./index.md/#syntax).
|
For more detail on window function syntax see: [Window Functions - Syntax](./index.md/#syntax).
|
||||||
@ -33,7 +35,7 @@ For more detail on window function syntax see: [Window Functions - Syntax](./ind
|
|||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
In this example the `last_value` function is used to find the highest paid footballer from a fictional dataset of salaries of Premier League football players.
|
In this example the `last_value` function is used to find the lowest paid footballer from a fictional dataset of salaries of Premier League football players.
|
||||||
|
|
||||||
Query:
|
Query:
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ CREATE TABLE salaries
|
|||||||
)
|
)
|
||||||
Engine = Memory;
|
Engine = Memory;
|
||||||
|
|
||||||
INSERT INTO salaries FORMAT Values
|
INSERT INTO salaries FORMAT VALUES
|
||||||
('Port Elizabeth Barbarians', 'Gary Chen', 196000, 'F'),
|
('Port Elizabeth Barbarians', 'Gary Chen', 196000, 'F'),
|
||||||
('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'),
|
('New Coreystad Archdukes', 'Charles Juarez', 190000, 'F'),
|
||||||
('Port Elizabeth Barbarians', 'Michael Stanley', 100000, 'D'),
|
('Port Elizabeth Barbarians', 'Michael Stanley', 100000, 'D'),
|
||||||
|
@ -154,7 +154,7 @@ sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh"
|
|||||||
|
|
||||||
### Из Docker образа {#from-docker-image}
|
### Из Docker образа {#from-docker-image}
|
||||||
|
|
||||||
Для запуска ClickHouse в Docker нужно следовать инструкции на [Docker Hub](https://hub.docker.com/r/clickhouse/clickhouse-server/). Внутри образов используются официальные `deb`-пакеты.
|
Для запуска ClickHouse в Docker нужно следовать инструкции на [Docker Hub](https://hub.docker.com/_/clickhouse). Внутри образов используются официальные `deb`-пакеты.
|
||||||
|
|
||||||
### Из единого бинарного файла {#from-single-binary}
|
### Из единого бинарного файла {#from-single-binary}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ ClickHouse применяет настройку в тех случаях, ко
|
|||||||
- 0 — выключена.
|
- 0 — выключена.
|
||||||
- 1 — включена.
|
- 1 — включена.
|
||||||
|
|
||||||
Значение по умолчанию: 0.
|
Значение по умолчанию: 1.
|
||||||
|
|
||||||
## http_zlib_compression_level {#settings-http_zlib_compression_level}
|
## http_zlib_compression_level {#settings-http_zlib_compression_level}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh"
|
|||||||
|
|
||||||
### `Docker`安装包 {#from-docker-image}
|
### `Docker`安装包 {#from-docker-image}
|
||||||
|
|
||||||
要在Docker中运行ClickHouse,请遵循[Docker Hub](https://hub.docker.com/r/clickhouse/clickhouse-server/)上的指南。它是官方的`deb`安装包。
|
要在Docker中运行ClickHouse,请遵循[Docker Hub](https://hub.docker.com/_/clickhouse)上的指南。它是官方的`deb`安装包。
|
||||||
|
|
||||||
### 其他环境安装包 {#from-other}
|
### 其他环境安装包 {#from-other}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ ClickHouse从表的过时副本中选择最相关的副本。
|
|||||||
- 0 — Disabled.
|
- 0 — Disabled.
|
||||||
- 1 — Enabled.
|
- 1 — Enabled.
|
||||||
|
|
||||||
默认值:0。
|
默认值:1。
|
||||||
|
|
||||||
## http_zlib_compression_level {#settings-http_zlib_compression_level}
|
## http_zlib_compression_level {#settings-http_zlib_compression_level}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <pcg_random.hpp>
|
#include <pcg_random.hpp>
|
||||||
#include <Poco/UUID.h>
|
|
||||||
#include <Poco/UUIDGenerator.h>
|
#include <Poco/UUIDGenerator.h>
|
||||||
#include <Poco/Util/Application.h>
|
#include <Poco/Util/Application.h>
|
||||||
#include <Common/Stopwatch.h>
|
#include <Common/Stopwatch.h>
|
||||||
@ -152,8 +151,6 @@ public:
|
|||||||
global_context->setClientName(std::string(DEFAULT_CLIENT_NAME));
|
global_context->setClientName(std::string(DEFAULT_CLIENT_NAME));
|
||||||
global_context->setQueryKindInitial();
|
global_context->setQueryKindInitial();
|
||||||
|
|
||||||
std::cerr << std::fixed << std::setprecision(3);
|
|
||||||
|
|
||||||
/// This is needed to receive blocks with columns of AggregateFunction data type
|
/// This is needed to receive blocks with columns of AggregateFunction data type
|
||||||
/// (example: when using stage = 'with_mergeable_state')
|
/// (example: when using stage = 'with_mergeable_state')
|
||||||
registerAggregateFunctions();
|
registerAggregateFunctions();
|
||||||
@ -226,6 +223,8 @@ private:
|
|||||||
ContextMutablePtr global_context;
|
ContextMutablePtr global_context;
|
||||||
QueryProcessingStage::Enum query_processing_stage;
|
QueryProcessingStage::Enum query_processing_stage;
|
||||||
|
|
||||||
|
WriteBufferFromFileDescriptor log{STDERR_FILENO};
|
||||||
|
|
||||||
std::atomic<size_t> consecutive_errors{0};
|
std::atomic<size_t> consecutive_errors{0};
|
||||||
|
|
||||||
/// Don't execute new queries after timelimit or SIGINT or exception
|
/// Don't execute new queries after timelimit or SIGINT or exception
|
||||||
@ -303,16 +302,16 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::cerr << "Loaded " << queries.size() << " queries.\n";
|
log << "Loaded " << queries.size() << " queries.\n" << flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void printNumberOfQueriesExecuted(size_t num)
|
void printNumberOfQueriesExecuted(size_t num)
|
||||||
{
|
{
|
||||||
std::cerr << "\nQueries executed: " << num;
|
log << "\nQueries executed: " << num;
|
||||||
if (queries.size() > 1)
|
if (queries.size() > 1)
|
||||||
std::cerr << " (" << (num * 100.0 / queries.size()) << "%)";
|
log << " (" << (num * 100.0 / queries.size()) << "%)";
|
||||||
std::cerr << ".\n";
|
log << ".\n" << flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try push new query and check cancellation conditions
|
/// Try push new query and check cancellation conditions
|
||||||
@ -339,19 +338,19 @@ private:
|
|||||||
|
|
||||||
if (interrupt_listener.check())
|
if (interrupt_listener.check())
|
||||||
{
|
{
|
||||||
std::cout << "Stopping launch of queries. SIGINT received." << std::endl;
|
std::cout << "Stopping launch of queries. SIGINT received.\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double seconds = delay_watch.elapsedSeconds();
|
double seconds = delay_watch.elapsedSeconds();
|
||||||
if (delay > 0 && seconds > delay)
|
if (delay > 0 && seconds > delay)
|
||||||
{
|
{
|
||||||
printNumberOfQueriesExecuted(queries_executed);
|
printNumberOfQueriesExecuted(queries_executed);
|
||||||
cumulative
|
cumulative
|
||||||
? report(comparison_info_total, total_watch.elapsedSeconds())
|
? report(comparison_info_total, total_watch.elapsedSeconds())
|
||||||
: report(comparison_info_per_interval, seconds);
|
: report(comparison_info_per_interval, seconds);
|
||||||
delay_watch.restart();
|
delay_watch.restart();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -438,16 +437,16 @@ private:
|
|||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
std::cerr << "An error occurred while processing the query " << "'" << query << "'"
|
log << "An error occurred while processing the query " << "'" << query << "'"
|
||||||
<< ": " << getCurrentExceptionMessage(false) << std::endl;
|
<< ": " << getCurrentExceptionMessage(false) << '\n';
|
||||||
if (!(continue_on_errors || max_consecutive_errors > ++consecutive_errors))
|
if (!(continue_on_errors || max_consecutive_errors > ++consecutive_errors))
|
||||||
{
|
{
|
||||||
shutdown = true;
|
shutdown = true;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << getCurrentExceptionMessage(print_stacktrace,
|
log << getCurrentExceptionMessage(print_stacktrace,
|
||||||
true /*check embedded stack trace*/) << std::endl;
|
true /*check embedded stack trace*/) << '\n' << flush;
|
||||||
|
|
||||||
size_t info_index = round_robin ? 0 : connection_index;
|
size_t info_index = round_robin ? 0 : connection_index;
|
||||||
++comparison_info_per_interval[info_index]->errors;
|
++comparison_info_per_interval[info_index]->errors;
|
||||||
@ -504,7 +503,7 @@ private:
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
std::cerr << "\n";
|
log << "\n";
|
||||||
for (size_t i = 0; i < infos.size(); ++i)
|
for (size_t i = 0; i < infos.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto & info = infos[i];
|
const auto & info = infos[i];
|
||||||
@ -524,31 +523,31 @@ private:
|
|||||||
connection_description += conn->getDescription();
|
connection_description += conn->getDescription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cerr
|
log
|
||||||
<< connection_description << ", "
|
<< connection_description << ", "
|
||||||
<< "queries: " << info->queries << ", ";
|
<< "queries: " << info->queries.load() << ", ";
|
||||||
if (info->errors)
|
if (info->errors)
|
||||||
{
|
{
|
||||||
std::cerr << "errors: " << info->errors << ", ";
|
log << "errors: " << info->errors << ", ";
|
||||||
}
|
}
|
||||||
std::cerr
|
log
|
||||||
<< "QPS: " << (info->queries / seconds) << ", "
|
<< "QPS: " << fmt::format("{:.3f}", info->queries / seconds) << ", "
|
||||||
<< "RPS: " << (info->read_rows / seconds) << ", "
|
<< "RPS: " << fmt::format("{:.3f}", info->read_rows / seconds) << ", "
|
||||||
<< "MiB/s: " << (info->read_bytes / seconds / 1048576) << ", "
|
<< "MiB/s: " << fmt::format("{:.3f}", info->read_bytes / seconds / 1048576) << ", "
|
||||||
<< "result RPS: " << (info->result_rows / seconds) << ", "
|
<< "result RPS: " << fmt::format("{:.3f}", info->result_rows / seconds) << ", "
|
||||||
<< "result MiB/s: " << (info->result_bytes / seconds / 1048576) << "."
|
<< "result MiB/s: " << fmt::format("{:.3f}", info->result_bytes / seconds / 1048576) << "."
|
||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
std::cerr << "\n";
|
log << "\n";
|
||||||
|
|
||||||
auto print_percentile = [&](double percent)
|
auto print_percentile = [&](double percent)
|
||||||
{
|
{
|
||||||
std::cerr << percent << "%\t\t";
|
log << percent << "%\t\t";
|
||||||
for (const auto & info : infos)
|
for (const auto & info : infos)
|
||||||
{
|
{
|
||||||
std::cerr << info->sampler.quantileNearest(percent / 100.0) << " sec.\t";
|
log << fmt::format("{:.3f}", info->sampler.quantileNearest(percent / 100.0)) << " sec.\t";
|
||||||
}
|
}
|
||||||
std::cerr << "\n";
|
log << "\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int percent = 0; percent <= 90; percent += 10)
|
for (int percent = 0; percent <= 90; percent += 10)
|
||||||
@ -559,13 +558,15 @@ private:
|
|||||||
print_percentile(99.9);
|
print_percentile(99.9);
|
||||||
print_percentile(99.99);
|
print_percentile(99.99);
|
||||||
|
|
||||||
std::cerr << "\n" << t_test.compareAndReport(confidence).second << "\n";
|
log << "\n" << t_test.compareAndReport(confidence).second << "\n";
|
||||||
|
|
||||||
if (!cumulative)
|
if (!cumulative)
|
||||||
{
|
{
|
||||||
for (auto & info : infos)
|
for (auto & info : infos)
|
||||||
info->clear();
|
info->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -741,7 +742,7 @@ int mainEntryClickHouseBenchmark(int argc, char ** argv)
|
|||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
std::cerr << getCurrentExceptionMessage(print_stacktrace, true) << std::endl;
|
std::cerr << getCurrentExceptionMessage(print_stacktrace, true) << '\n';
|
||||||
return getCurrentExceptionCode();
|
return getCurrentExceptionCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,12 @@
|
|||||||
#include <Compression/ParallelCompressedWriteBuffer.h>
|
#include <Compression/ParallelCompressedWriteBuffer.h>
|
||||||
#include <Compression/CompressedReadBuffer.h>
|
#include <Compression/CompressedReadBuffer.h>
|
||||||
#include <Compression/CompressedReadBufferFromFile.h>
|
#include <Compression/CompressedReadBufferFromFile.h>
|
||||||
|
#include <Compression/getCompressionCodecForFile.h>
|
||||||
|
#include <IO/ReadHelpers.h>
|
||||||
#include <IO/WriteHelpers.h>
|
#include <IO/WriteHelpers.h>
|
||||||
#include <IO/copyData.h>
|
#include <IO/copyData.h>
|
||||||
#include <Parsers/parseQuery.h>
|
#include <Parsers/parseQuery.h>
|
||||||
|
#include <Parsers/queryToString.h>
|
||||||
#include <Parsers/ExpressionElementParsers.h>
|
#include <Parsers/ExpressionElementParsers.h>
|
||||||
#include <Compression/CompressionFactory.h>
|
#include <Compression/CompressionFactory.h>
|
||||||
#include <Common/TerminalSize.h>
|
#include <Common/TerminalSize.h>
|
||||||
@ -43,29 +46,24 @@ namespace CurrentMetrics
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Outputs sizes of uncompressed and compressed blocks for compressed file.
|
/// Outputs method, sizes of uncompressed and compressed blocks for compressed file.
|
||||||
void checkAndWriteHeader(DB::ReadBuffer & in, DB::WriteBuffer & out)
|
void checkAndWriteHeader(DB::ReadBuffer & in, DB::WriteBuffer & out)
|
||||||
{
|
{
|
||||||
while (!in.eof())
|
while (!in.eof())
|
||||||
{
|
{
|
||||||
in.ignore(16); /// checksum
|
UInt32 size_compressed;
|
||||||
|
UInt32 size_decompressed;
|
||||||
char header[COMPRESSED_BLOCK_HEADER_SIZE];
|
auto codec = DB::getCompressionCodecForFile(in, size_compressed, size_decompressed, true /* skip_to_next_block */);
|
||||||
in.readStrict(header, COMPRESSED_BLOCK_HEADER_SIZE);
|
|
||||||
|
|
||||||
UInt32 size_compressed = unalignedLoad<UInt32>(&header[1]);
|
|
||||||
|
|
||||||
if (size_compressed > DBMS_MAX_COMPRESSED_SIZE)
|
if (size_compressed > DBMS_MAX_COMPRESSED_SIZE)
|
||||||
throw DB::Exception(DB::ErrorCodes::TOO_LARGE_SIZE_COMPRESSED, "Too large size_compressed. Most likely corrupted data.");
|
throw DB::Exception(DB::ErrorCodes::TOO_LARGE_SIZE_COMPRESSED, "Too large size_compressed. Most likely corrupted data.");
|
||||||
|
|
||||||
UInt32 size_decompressed = unalignedLoad<UInt32>(&header[5]);
|
DB::writeText(queryToString(codec->getFullCodecDesc()), out);
|
||||||
|
DB::writeChar('\t', out);
|
||||||
DB::writeText(size_decompressed, out);
|
DB::writeText(size_decompressed, out);
|
||||||
DB::writeChar('\t', out);
|
DB::writeChar('\t', out);
|
||||||
DB::writeText(size_compressed, out);
|
DB::writeText(size_compressed, out);
|
||||||
DB::writeChar('\n', out);
|
DB::writeChar('\n', out);
|
||||||
|
|
||||||
in.ignore(size_compressed - COMPRESSED_BLOCK_HEADER_SIZE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +70,15 @@
|
|||||||
You can specify log format(for now, JSON only). In that case, the console log will be printed
|
You can specify log format(for now, JSON only). In that case, the console log will be printed
|
||||||
in specified format like JSON.
|
in specified format like JSON.
|
||||||
For example, as below:
|
For example, as below:
|
||||||
|
|
||||||
{"date_time":"1650918987.180175","thread_name":"#1","thread_id":"254545","level":"Trace","query_id":"","logger_name":"BaseDaemon","message":"Received signal 2","source_file":"../base/daemon/BaseDaemon.cpp; virtual void SignalListener::run()","source_line":"192"}
|
{"date_time":"1650918987.180175","thread_name":"#1","thread_id":"254545","level":"Trace","query_id":"","logger_name":"BaseDaemon","message":"Received signal 2","source_file":"../base/daemon/BaseDaemon.cpp; virtual void SignalListener::run()","source_line":"192"}
|
||||||
|
{"date_time_utc":"2024-11-06T09:06:09Z","thread_name":"#1","thread_id":"254545","level":"Trace","query_id":"","logger_name":"BaseDaemon","message":"Received signal 2","source_file":"../base/daemon/BaseDaemon.cpp; virtual void SignalListener::run()","source_line":"192"}
|
||||||
To enable JSON logging support, please uncomment the entire <formatting> tag below.
|
To enable JSON logging support, please uncomment the entire <formatting> tag below.
|
||||||
|
|
||||||
a) You can modify key names by changing values under tag values inside <names> tag.
|
a) You can modify key names by changing values under tag values inside <names> tag.
|
||||||
For example, to change DATE_TIME to MY_DATE_TIME, you can do like:
|
For example, to change DATE_TIME to MY_DATE_TIME, you can do like:
|
||||||
<date_time>MY_DATE_TIME</date_time>
|
<date_time>MY_DATE_TIME</date_time>
|
||||||
|
<date_time_utc>MY_UTC_DATE_TIME</date_time_utc>
|
||||||
b) You can stop unwanted log properties to appear in logs. To do so, you can simply comment out (recommended)
|
b) You can stop unwanted log properties to appear in logs. To do so, you can simply comment out (recommended)
|
||||||
that property from this file.
|
that property from this file.
|
||||||
For example, if you do not want your log to print query_id, you can comment out only <query_id> tag.
|
For example, if you do not want your log to print query_id, you can comment out only <query_id> tag.
|
||||||
@ -86,6 +89,7 @@
|
|||||||
<type>json</type>
|
<type>json</type>
|
||||||
<names>
|
<names>
|
||||||
<date_time>date_time</date_time>
|
<date_time>date_time</date_time>
|
||||||
|
<date_time_utc>date_time_utc</date_time_utc>
|
||||||
<thread_name>thread_name</thread_name>
|
<thread_name>thread_name</thread_name>
|
||||||
<thread_id>thread_id</thread_id>
|
<thread_id>thread_id</thread_id>
|
||||||
<level>level</level>
|
<level>level</level>
|
||||||
|
@ -221,11 +221,16 @@ void registerAggregateFunctionsAnyRespectNulls(AggregateFunctionFactory & factor
|
|||||||
= {.returns_default_when_only_null = false, .is_order_dependent = true, .is_window_function = true};
|
= {.returns_default_when_only_null = false, .is_order_dependent = true, .is_window_function = true};
|
||||||
|
|
||||||
factory.registerFunction("any_respect_nulls", {createAggregateFunctionAnyRespectNulls, default_properties_for_respect_nulls});
|
factory.registerFunction("any_respect_nulls", {createAggregateFunctionAnyRespectNulls, default_properties_for_respect_nulls});
|
||||||
factory.registerAlias("any_value_respect_nulls", "any_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
factory.registerAlias("anyRespectNulls", "any_respect_nulls", AggregateFunctionFactory::Case::Sensitive);
|
||||||
factory.registerAlias("first_value_respect_nulls", "any_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
factory.registerAlias("first_value_respect_nulls", "any_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
||||||
|
factory.registerAlias("firstValueRespectNulls", "any_respect_nulls", AggregateFunctionFactory::Case::Sensitive);
|
||||||
|
factory.registerAlias("any_value_respect_nulls", "any_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
||||||
|
factory.registerAlias("anyValueRespectNulls", "any_respect_nulls", AggregateFunctionFactory::Case::Sensitive);
|
||||||
|
|
||||||
factory.registerFunction("anyLast_respect_nulls", {createAggregateFunctionAnyLastRespectNulls, default_properties_for_respect_nulls});
|
factory.registerFunction("anyLast_respect_nulls", {createAggregateFunctionAnyLastRespectNulls, default_properties_for_respect_nulls});
|
||||||
|
factory.registerAlias("anyLastRespectNulls", "anyLast_respect_nulls", AggregateFunctionFactory::Case::Sensitive);
|
||||||
factory.registerAlias("last_value_respect_nulls", "anyLast_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
factory.registerAlias("last_value_respect_nulls", "anyLast_respect_nulls", AggregateFunctionFactory::Case::Insensitive);
|
||||||
|
factory.registerAlias("lastValueRespectNulls", "anyLast_respect_nulls", AggregateFunctionFactory::Case::Sensitive);
|
||||||
|
|
||||||
/// Must happen after registering any and anyLast
|
/// Must happen after registering any and anyLast
|
||||||
factory.registerNullsActionTransformation("any", "any_respect_nulls");
|
factory.registerNullsActionTransformation("any", "any_respect_nulls");
|
||||||
|
@ -231,7 +231,7 @@ public:
|
|||||||
|
|
||||||
void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const final
|
void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const final
|
||||||
{
|
{
|
||||||
increment(place, static_cast<const ColVecType &>(*columns[0]).getData()[row_num]);
|
increment(place, Numerator(static_cast<const ColVecType &>(*columns[0]).getData()[row_num]));
|
||||||
++this->data(place).denominator;
|
++this->data(place).denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,9 @@ namespace
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct AggregationFunctionDeltaSumData
|
struct AggregationFunctionDeltaSumData
|
||||||
{
|
{
|
||||||
T sum = 0;
|
T sum{};
|
||||||
T last = 0;
|
T last{};
|
||||||
T first = 0;
|
T first{};
|
||||||
bool seen = false;
|
bool seen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,14 +22,21 @@ namespace ErrorCodes
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** Due to a lack of proper code review, this code was contributed with a multiplication of template instantiations
|
||||||
|
* over all pairs of data types, and we deeply regret that.
|
||||||
|
*
|
||||||
|
* We cannot remove all combinations, because the binary representation of serialized data has to remain the same,
|
||||||
|
* but we can partially heal the wound by treating unsigned and signed data types in the same way.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename ValueType, typename TimestampType>
|
template <typename ValueType, typename TimestampType>
|
||||||
struct AggregationFunctionDeltaSumTimestampData
|
struct AggregationFunctionDeltaSumTimestampData
|
||||||
{
|
{
|
||||||
ValueType sum = 0;
|
ValueType sum{};
|
||||||
ValueType first = 0;
|
ValueType first{};
|
||||||
ValueType last = 0;
|
ValueType last{};
|
||||||
TimestampType first_ts = 0;
|
TimestampType first_ts{};
|
||||||
TimestampType last_ts = 0;
|
TimestampType last_ts{};
|
||||||
bool seen = false;
|
bool seen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,23 +44,22 @@ template <typename ValueType, typename TimestampType>
|
|||||||
class AggregationFunctionDeltaSumTimestamp final
|
class AggregationFunctionDeltaSumTimestamp final
|
||||||
: public IAggregateFunctionDataHelper<
|
: public IAggregateFunctionDataHelper<
|
||||||
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
||||||
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>
|
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>>
|
||||||
>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AggregationFunctionDeltaSumTimestamp(const DataTypes & arguments, const Array & params)
|
AggregationFunctionDeltaSumTimestamp(const DataTypes & arguments, const Array & params)
|
||||||
: IAggregateFunctionDataHelper<
|
: IAggregateFunctionDataHelper<
|
||||||
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
||||||
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>
|
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>>{arguments, params, createResultType()}
|
||||||
>{arguments, params, createResultType()}
|
{
|
||||||
{}
|
}
|
||||||
|
|
||||||
AggregationFunctionDeltaSumTimestamp()
|
AggregationFunctionDeltaSumTimestamp()
|
||||||
: IAggregateFunctionDataHelper<
|
: IAggregateFunctionDataHelper<
|
||||||
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
AggregationFunctionDeltaSumTimestampData<ValueType, TimestampType>,
|
||||||
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>
|
AggregationFunctionDeltaSumTimestamp<ValueType, TimestampType>>{}
|
||||||
>{}
|
{
|
||||||
{}
|
}
|
||||||
|
|
||||||
bool allocatesMemoryInArena() const override { return false; }
|
bool allocatesMemoryInArena() const override { return false; }
|
||||||
|
|
||||||
@ -63,8 +69,8 @@ public:
|
|||||||
|
|
||||||
void NO_SANITIZE_UNDEFINED ALWAYS_INLINE add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const override
|
void NO_SANITIZE_UNDEFINED ALWAYS_INLINE add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const override
|
||||||
{
|
{
|
||||||
auto value = assert_cast<const ColumnVector<ValueType> &>(*columns[0]).getData()[row_num];
|
auto value = unalignedLoad<ValueType>(columns[0]->getRawData().data() + row_num * sizeof(ValueType));
|
||||||
auto ts = assert_cast<const ColumnVector<TimestampType> &>(*columns[1]).getData()[row_num];
|
auto ts = unalignedLoad<TimestampType>(columns[1]->getRawData().data() + row_num * sizeof(TimestampType));
|
||||||
|
|
||||||
auto & data = this->data(place);
|
auto & data = this->data(place);
|
||||||
|
|
||||||
@ -172,10 +178,48 @@ public:
|
|||||||
|
|
||||||
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
||||||
{
|
{
|
||||||
assert_cast<ColumnVector<ValueType> &>(to).getData().push_back(this->data(place).sum);
|
static_cast<ColumnFixedSizeHelper &>(to).template insertRawData<sizeof(ValueType)>(
|
||||||
|
reinterpret_cast<const char *>(&this->data(place).sum));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
||||||
|
IAggregateFunction * createWithTwoTypesSecond(const IDataType & second_type, TArgs && ... args)
|
||||||
|
{
|
||||||
|
WhichDataType which(second_type);
|
||||||
|
|
||||||
|
if (which.idx == TypeIndex::UInt32) return new AggregateFunctionTemplate<FirstType, UInt32>(args...);
|
||||||
|
if (which.idx == TypeIndex::UInt64) return new AggregateFunctionTemplate<FirstType, UInt64>(args...);
|
||||||
|
if (which.idx == TypeIndex::Int32) return new AggregateFunctionTemplate<FirstType, UInt32>(args...);
|
||||||
|
if (which.idx == TypeIndex::Int64) return new AggregateFunctionTemplate<FirstType, UInt64>(args...);
|
||||||
|
if (which.idx == TypeIndex::Float32) return new AggregateFunctionTemplate<FirstType, Float32>(args...);
|
||||||
|
if (which.idx == TypeIndex::Float64) return new AggregateFunctionTemplate<FirstType, Float64>(args...);
|
||||||
|
if (which.idx == TypeIndex::Date) return new AggregateFunctionTemplate<FirstType, UInt16>(args...);
|
||||||
|
if (which.idx == TypeIndex::DateTime) return new AggregateFunctionTemplate<FirstType, UInt32>(args...);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
||||||
|
IAggregateFunction * createWithTwoTypes(const IDataType & first_type, const IDataType & second_type, TArgs && ... args)
|
||||||
|
{
|
||||||
|
WhichDataType which(first_type);
|
||||||
|
|
||||||
|
if (which.idx == TypeIndex::UInt8) return createWithTwoTypesSecond<UInt8, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::UInt16) return createWithTwoTypesSecond<UInt16, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::UInt32) return createWithTwoTypesSecond<UInt32, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::UInt64) return createWithTwoTypesSecond<UInt64, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Int8) return createWithTwoTypesSecond<UInt8, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Int16) return createWithTwoTypesSecond<UInt16, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Int32) return createWithTwoTypesSecond<UInt32, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Int64) return createWithTwoTypesSecond<UInt64, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Float32) return createWithTwoTypesSecond<Float32, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
if (which.idx == TypeIndex::Float64) return createWithTwoTypesSecond<Float64, AggregateFunctionTemplate>(second_type, args...);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
AggregateFunctionPtr createAggregateFunctionDeltaSumTimestamp(
|
AggregateFunctionPtr createAggregateFunctionDeltaSumTimestamp(
|
||||||
const String & name,
|
const String & name,
|
||||||
const DataTypes & arguments,
|
const DataTypes & arguments,
|
||||||
@ -193,8 +237,14 @@ AggregateFunctionPtr createAggregateFunctionDeltaSumTimestamp(
|
|||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument for aggregate function {}, "
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument for aggregate function {}, "
|
||||||
"must be Int, Float, Date, DateTime", arguments[1]->getName(), name);
|
"must be Int, Float, Date, DateTime", arguments[1]->getName(), name);
|
||||||
|
|
||||||
return AggregateFunctionPtr(createWithTwoNumericOrDateTypes<AggregationFunctionDeltaSumTimestamp>(
|
auto res = AggregateFunctionPtr(createWithTwoTypes<AggregationFunctionDeltaSumTimestamp>(
|
||||||
*arguments[0], *arguments[1], arguments, params));
|
*arguments[0], *arguments[1], arguments, params));
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument for aggregate function {}, "
|
||||||
|
"this type is not supported", arguments[0]->getName(), name);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ template <typename T>
|
|||||||
struct GroupArraySamplerData
|
struct GroupArraySamplerData
|
||||||
{
|
{
|
||||||
/// For easy serialization.
|
/// For easy serialization.
|
||||||
static_assert(std::has_unique_object_representations_v<T> || std::is_floating_point_v<T>);
|
static_assert(std::has_unique_object_representations_v<T> || is_floating_point<T>);
|
||||||
|
|
||||||
// Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena
|
// Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena
|
||||||
using Allocator = MixedAlignedArenaAllocator<alignof(T), 4096>;
|
using Allocator = MixedAlignedArenaAllocator<alignof(T), 4096>;
|
||||||
@ -120,7 +120,7 @@ template <typename T>
|
|||||||
struct GroupArrayNumericData<T, false>
|
struct GroupArrayNumericData<T, false>
|
||||||
{
|
{
|
||||||
/// For easy serialization.
|
/// For easy serialization.
|
||||||
static_assert(std::has_unique_object_representations_v<T> || std::is_floating_point_v<T>);
|
static_assert(std::has_unique_object_representations_v<T> || is_floating_point<T>);
|
||||||
|
|
||||||
// Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena
|
// Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena
|
||||||
using Allocator = MixedAlignedArenaAllocator<alignof(T), 4096>;
|
using Allocator = MixedAlignedArenaAllocator<alignof(T), 4096>;
|
||||||
|
@ -38,7 +38,7 @@ template <typename T>
|
|||||||
struct MovingData
|
struct MovingData
|
||||||
{
|
{
|
||||||
/// For easy serialization.
|
/// For easy serialization.
|
||||||
static_assert(std::has_unique_object_representations_v<T> || std::is_floating_point_v<T>);
|
static_assert(std::has_unique_object_representations_v<T> || is_floating_point<T>);
|
||||||
|
|
||||||
using Accumulator = T;
|
using Accumulator = T;
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ public:
|
|||||||
|
|
||||||
static DataTypePtr createResultType()
|
static DataTypePtr createResultType()
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
return std::make_shared<DataTypeFloat64>();
|
return std::make_shared<DataTypeFloat64>();
|
||||||
return std::make_shared<DataTypeUInt64>();
|
return std::make_shared<DataTypeUInt64>();
|
||||||
}
|
}
|
||||||
@ -227,7 +227,7 @@ public:
|
|||||||
|
|
||||||
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
assert_cast<ColumnFloat64 &>(to).getData().push_back(getIntervalLengthSum<Float64>(this->data(place)));
|
assert_cast<ColumnFloat64 &>(to).getData().push_back(getIntervalLengthSum<Float64>(this->data(place)));
|
||||||
else
|
else
|
||||||
assert_cast<ColumnUInt64 &>(to).getData().push_back(getIntervalLengthSum<UInt64>(this->data(place)));
|
assert_cast<ColumnUInt64 &>(to).getData().push_back(getIntervalLengthSum<UInt64>(this->data(place)));
|
||||||
|
@ -155,9 +155,9 @@ public:
|
|||||||
|
|
||||||
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
|
||||||
{
|
{
|
||||||
Int64 current_intersections = 0;
|
Int64 current_intersections{};
|
||||||
Int64 max_intersections = 0;
|
Int64 max_intersections{};
|
||||||
PointType position_of_max_intersections = 0;
|
PointType position_of_max_intersections{};
|
||||||
|
|
||||||
/// const_cast because we will sort the array
|
/// const_cast because we will sort the array
|
||||||
auto & array = this->data(place).value;
|
auto & array = this->data(place).value;
|
||||||
|
@ -45,12 +45,12 @@ struct AggregateFunctionSparkbarData
|
|||||||
Y insert(const X & x, const Y & y)
|
Y insert(const X & x, const Y & y)
|
||||||
{
|
{
|
||||||
if (isNaN(y) || y <= 0)
|
if (isNaN(y) || y <= 0)
|
||||||
return 0;
|
return {};
|
||||||
|
|
||||||
auto [it, inserted] = points.insert({x, y});
|
auto [it, inserted] = points.insert({x, y});
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<Y>)
|
if constexpr (is_floating_point<Y>)
|
||||||
{
|
{
|
||||||
it->getMapped() += y;
|
it->getMapped() += y;
|
||||||
return it->getMapped();
|
return it->getMapped();
|
||||||
@ -173,13 +173,13 @@ private:
|
|||||||
|
|
||||||
if (from_x >= to_x)
|
if (from_x >= to_x)
|
||||||
{
|
{
|
||||||
size_t sz = updateFrame(values, 8);
|
size_t sz = updateFrame(values, Y{8});
|
||||||
values.push_back('\0');
|
values.push_back('\0');
|
||||||
offsets.push_back(offsets.empty() ? sz + 1 : offsets.back() + sz + 1);
|
offsets.push_back(offsets.empty() ? sz + 1 : offsets.back() + sz + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PaddedPODArray<Y> histogram(width, 0);
|
PaddedPODArray<Y> histogram(width, Y{0});
|
||||||
PaddedPODArray<UInt64> count_histogram(width, 0); /// The number of points in each bucket
|
PaddedPODArray<UInt64> count_histogram(width, 0); /// The number of points in each bucket
|
||||||
|
|
||||||
for (const auto & point : data.points)
|
for (const auto & point : data.points)
|
||||||
@ -197,7 +197,7 @@ private:
|
|||||||
|
|
||||||
Y res;
|
Y res;
|
||||||
bool has_overfllow = false;
|
bool has_overfllow = false;
|
||||||
if constexpr (std::is_floating_point_v<Y>)
|
if constexpr (is_floating_point<Y>)
|
||||||
res = histogram[index] + point.getMapped();
|
res = histogram[index] + point.getMapped();
|
||||||
else
|
else
|
||||||
has_overfllow = common::addOverflow(histogram[index], point.getMapped(), res);
|
has_overfllow = common::addOverflow(histogram[index], point.getMapped(), res);
|
||||||
@ -218,10 +218,10 @@ private:
|
|||||||
for (size_t i = 0; i < histogram.size(); ++i)
|
for (size_t i = 0; i < histogram.size(); ++i)
|
||||||
{
|
{
|
||||||
if (count_histogram[i] > 0)
|
if (count_histogram[i] > 0)
|
||||||
histogram[i] /= count_histogram[i];
|
histogram[i] = histogram[i] / count_histogram[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
Y y_max = 0;
|
Y y_max{};
|
||||||
for (auto & y : histogram)
|
for (auto & y : histogram)
|
||||||
{
|
{
|
||||||
if (isNaN(y) || y <= 0)
|
if (isNaN(y) || y <= 0)
|
||||||
@ -245,8 +245,8 @@ private:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto levels_num = static_cast<Y>(BAR_LEVELS - 1);
|
constexpr auto levels_num = Y{BAR_LEVELS - 1};
|
||||||
if constexpr (std::is_floating_point_v<Y>)
|
if constexpr (is_floating_point<Y>)
|
||||||
{
|
{
|
||||||
y = y / (y_max / levels_num) + 1;
|
y = y / (y_max / levels_num) + 1;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ struct AggregateFunctionSumData
|
|||||||
size_t count = end - start;
|
size_t count = end - start;
|
||||||
const auto * end_ptr = ptr + count;
|
const auto * end_ptr = ptr + count;
|
||||||
|
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
{
|
{
|
||||||
/// Compiler cannot unroll this loop, do it manually.
|
/// Compiler cannot unroll this loop, do it manually.
|
||||||
/// (at least for floats, most likely due to the lack of -fassociative-math)
|
/// (at least for floats, most likely due to the lack of -fassociative-math)
|
||||||
@ -83,7 +83,7 @@ struct AggregateFunctionSumData
|
|||||||
while (ptr < unrolled_end)
|
while (ptr < unrolled_end)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < unroll_count; ++i)
|
for (size_t i = 0; i < unroll_count; ++i)
|
||||||
Impl::add(partial_sums[i], ptr[i]);
|
Impl::add(partial_sums[i], T(ptr[i]));
|
||||||
ptr += unroll_count;
|
ptr += unroll_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ struct AggregateFunctionSumData
|
|||||||
T local_sum{};
|
T local_sum{};
|
||||||
while (ptr < end_ptr)
|
while (ptr < end_ptr)
|
||||||
{
|
{
|
||||||
Impl::add(local_sum, *ptr);
|
Impl::add(local_sum, T(*ptr));
|
||||||
++ptr;
|
++ptr;
|
||||||
}
|
}
|
||||||
Impl::add(sum, local_sum);
|
Impl::add(sum, local_sum);
|
||||||
@ -193,12 +193,11 @@ struct AggregateFunctionSumData
|
|||||||
Impl::add(sum, local_sum);
|
Impl::add(sum, local_sum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_floating_point_v<T>)
|
else if constexpr (is_floating_point<T> && (sizeof(Value) == 4 || sizeof(Value) == 8))
|
||||||
{
|
{
|
||||||
/// For floating point we use a similar trick as above, except that now we reinterpret the floating point number as an unsigned
|
/// For floating point we use a similar trick as above, except that now we reinterpret the floating point number as an unsigned
|
||||||
/// integer of the same size and use a mask instead (0 to discard, 0xFF..FF to keep)
|
/// integer of the same size and use a mask instead (0 to discard, 0xFF..FF to keep)
|
||||||
static_assert(sizeof(Value) == 4 || sizeof(Value) == 8);
|
using EquivalentInteger = typename std::conditional_t<sizeof(Value) == 4, UInt32, UInt64>;
|
||||||
using equivalent_integer = typename std::conditional_t<sizeof(Value) == 4, UInt32, UInt64>;
|
|
||||||
|
|
||||||
constexpr size_t unroll_count = 128 / sizeof(T);
|
constexpr size_t unroll_count = 128 / sizeof(T);
|
||||||
T partial_sums[unroll_count]{};
|
T partial_sums[unroll_count]{};
|
||||||
@ -209,11 +208,11 @@ struct AggregateFunctionSumData
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < unroll_count; ++i)
|
for (size_t i = 0; i < unroll_count; ++i)
|
||||||
{
|
{
|
||||||
equivalent_integer value;
|
EquivalentInteger value;
|
||||||
std::memcpy(&value, &ptr[i], sizeof(Value));
|
memcpy(&value, &ptr[i], sizeof(Value));
|
||||||
value &= (!condition_map[i] != add_if_zero) - 1;
|
value &= (!condition_map[i] != add_if_zero) - 1;
|
||||||
Value d;
|
Value d;
|
||||||
std::memcpy(&d, &value, sizeof(Value));
|
memcpy(&d, &value, sizeof(Value));
|
||||||
Impl::add(partial_sums[i], d);
|
Impl::add(partial_sums[i], d);
|
||||||
}
|
}
|
||||||
ptr += unroll_count;
|
ptr += unroll_count;
|
||||||
@ -228,7 +227,7 @@ struct AggregateFunctionSumData
|
|||||||
while (ptr < end_ptr)
|
while (ptr < end_ptr)
|
||||||
{
|
{
|
||||||
if (!*condition_map == add_if_zero)
|
if (!*condition_map == add_if_zero)
|
||||||
Impl::add(local_sum, *ptr);
|
Impl::add(local_sum, T(*ptr));
|
||||||
++ptr;
|
++ptr;
|
||||||
++condition_map;
|
++condition_map;
|
||||||
}
|
}
|
||||||
@ -306,7 +305,7 @@ struct AggregateFunctionSumData
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct AggregateFunctionSumKahanData
|
struct AggregateFunctionSumKahanData
|
||||||
{
|
{
|
||||||
static_assert(std::is_floating_point_v<T>,
|
static_assert(is_floating_point<T>,
|
||||||
"It doesn't make sense to use Kahan Summation algorithm for non floating point types");
|
"It doesn't make sense to use Kahan Summation algorithm for non floating point types");
|
||||||
|
|
||||||
T sum{};
|
T sum{};
|
||||||
@ -489,10 +488,7 @@ public:
|
|||||||
void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const override
|
void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const override
|
||||||
{
|
{
|
||||||
const auto & column = assert_cast<const ColVecType &>(*columns[0]);
|
const auto & column = assert_cast<const ColVecType &>(*columns[0]);
|
||||||
if constexpr (is_big_int_v<T>)
|
this->data(place).add(static_cast<TResult>(column.getData()[row_num]));
|
||||||
this->data(place).add(static_cast<TResult>(column.getData()[row_num]));
|
|
||||||
else
|
|
||||||
this->data(place).add(column.getData()[row_num]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addBatchSinglePlace(
|
void addBatchSinglePlace(
|
||||||
|
@ -257,7 +257,7 @@ template <typename T> struct AggregateFunctionUniqTraits
|
|||||||
{
|
{
|
||||||
static UInt64 hash(T x)
|
static UInt64 hash(T x)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<T, Float32> || std::is_same_v<T, Float64>)
|
if constexpr (is_floating_point<T>)
|
||||||
{
|
{
|
||||||
return bit_cast<UInt64>(x);
|
return bit_cast<UInt64>(x);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public:
|
|||||||
/// Initially UInt128 was introduced only for UUID, and then the other big-integer types were added.
|
/// Initially UInt128 was introduced only for UUID, and then the other big-integer types were added.
|
||||||
hash = static_cast<HashValueType>(sipHash64(value));
|
hash = static_cast<HashValueType>(sipHash64(value));
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_floating_point_v<T>)
|
else if constexpr (is_floating_point<T>)
|
||||||
{
|
{
|
||||||
hash = static_cast<HashValueType>(intHash64(bit_cast<UInt64>(value)));
|
hash = static_cast<HashValueType>(intHash64(bit_cast<UInt64>(value)));
|
||||||
}
|
}
|
||||||
|
@ -184,36 +184,8 @@ static IAggregateFunction * createWithDecimalType(const IDataType & argument_typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** For template with two arguments.
|
/** For template with two arguments.
|
||||||
|
* This is an extremely dangerous for code bloat - do not use.
|
||||||
*/
|
*/
|
||||||
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
|
||||||
static IAggregateFunction * createWithTwoNumericTypesSecond(const IDataType & second_type, TArgs && ... args)
|
|
||||||
{
|
|
||||||
WhichDataType which(second_type);
|
|
||||||
#define DISPATCH(TYPE) \
|
|
||||||
if (which.idx == TypeIndex::TYPE) return new AggregateFunctionTemplate<FirstType, TYPE>(args...);
|
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
|
||||||
#undef DISPATCH
|
|
||||||
if (which.idx == TypeIndex::Enum8) return new AggregateFunctionTemplate<FirstType, Int8>(args...);
|
|
||||||
if (which.idx == TypeIndex::Enum16) return new AggregateFunctionTemplate<FirstType, Int16>(args...);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
|
||||||
static IAggregateFunction * createWithTwoNumericTypes(const IDataType & first_type, const IDataType & second_type, TArgs && ... args)
|
|
||||||
{
|
|
||||||
WhichDataType which(first_type);
|
|
||||||
#define DISPATCH(TYPE) \
|
|
||||||
if (which.idx == TypeIndex::TYPE) \
|
|
||||||
return createWithTwoNumericTypesSecond<TYPE, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
|
||||||
#undef DISPATCH
|
|
||||||
if (which.idx == TypeIndex::Enum8)
|
|
||||||
return createWithTwoNumericTypesSecond<Int8, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
if (which.idx == TypeIndex::Enum16)
|
|
||||||
return createWithTwoNumericTypesSecond<Int16, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
||||||
static IAggregateFunction * createWithTwoBasicNumericTypesSecond(const IDataType & second_type, TArgs && ... args)
|
static IAggregateFunction * createWithTwoBasicNumericTypesSecond(const IDataType & second_type, TArgs && ... args)
|
||||||
{
|
{
|
||||||
@ -237,46 +209,6 @@ static IAggregateFunction * createWithTwoBasicNumericTypes(const IDataType & fir
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
|
||||||
static IAggregateFunction * createWithTwoNumericOrDateTypesSecond(const IDataType & second_type, TArgs && ... args)
|
|
||||||
{
|
|
||||||
WhichDataType which(second_type);
|
|
||||||
#define DISPATCH(TYPE) \
|
|
||||||
if (which.idx == TypeIndex::TYPE) return new AggregateFunctionTemplate<FirstType, TYPE>(args...);
|
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
|
||||||
#undef DISPATCH
|
|
||||||
if (which.idx == TypeIndex::Enum8) return new AggregateFunctionTemplate<FirstType, Int8>(args...);
|
|
||||||
if (which.idx == TypeIndex::Enum16) return new AggregateFunctionTemplate<FirstType, Int16>(args...);
|
|
||||||
|
|
||||||
/// expects that DataTypeDate based on UInt16, DataTypeDateTime based on UInt32
|
|
||||||
if (which.idx == TypeIndex::Date) return new AggregateFunctionTemplate<FirstType, UInt16>(args...);
|
|
||||||
if (which.idx == TypeIndex::DateTime) return new AggregateFunctionTemplate<FirstType, UInt32>(args...);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <template <typename, typename> class AggregateFunctionTemplate, typename... TArgs>
|
|
||||||
static IAggregateFunction * createWithTwoNumericOrDateTypes(const IDataType & first_type, const IDataType & second_type, TArgs && ... args)
|
|
||||||
{
|
|
||||||
WhichDataType which(first_type);
|
|
||||||
#define DISPATCH(TYPE) \
|
|
||||||
if (which.idx == TypeIndex::TYPE) \
|
|
||||||
return createWithTwoNumericOrDateTypesSecond<TYPE, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
|
||||||
#undef DISPATCH
|
|
||||||
if (which.idx == TypeIndex::Enum8)
|
|
||||||
return createWithTwoNumericOrDateTypesSecond<Int8, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
if (which.idx == TypeIndex::Enum16)
|
|
||||||
return createWithTwoNumericOrDateTypesSecond<Int16, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
|
|
||||||
/// expects that DataTypeDate based on UInt16, DataTypeDateTime based on UInt32
|
|
||||||
if (which.idx == TypeIndex::Date)
|
|
||||||
return createWithTwoNumericOrDateTypesSecond<UInt16, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
if (which.idx == TypeIndex::DateTime)
|
|
||||||
return createWithTwoNumericOrDateTypesSecond<UInt32, AggregateFunctionTemplate>(second_type, args...);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <template <typename> class AggregateFunctionTemplate, typename... TArgs>
|
template <template <typename> class AggregateFunctionTemplate, typename... TArgs>
|
||||||
static IAggregateFunction * createWithStringType(const IDataType & argument_type, TArgs && ... args)
|
static IAggregateFunction * createWithStringType(const IDataType & argument_type, TArgs && ... args)
|
||||||
{
|
{
|
||||||
|
@ -391,7 +391,7 @@ public:
|
|||||||
ResultType getImpl(Float64 level)
|
ResultType getImpl(Float64 level)
|
||||||
{
|
{
|
||||||
if (centroids.empty())
|
if (centroids.empty())
|
||||||
return std::is_floating_point_v<ResultType> ? std::numeric_limits<ResultType>::quiet_NaN() : 0;
|
return is_floating_point<ResultType> ? std::numeric_limits<ResultType>::quiet_NaN() : 0;
|
||||||
|
|
||||||
compress();
|
compress();
|
||||||
|
|
||||||
|
@ -276,6 +276,6 @@ private:
|
|||||||
{
|
{
|
||||||
if (OnEmpty == ReservoirSamplerOnEmpty::THROW)
|
if (OnEmpty == ReservoirSamplerOnEmpty::THROW)
|
||||||
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSampler");
|
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSampler");
|
||||||
return NanLikeValueConstructor<ResultType, std::is_floating_point_v<ResultType>>::getValue();
|
return NanLikeValueConstructor<ResultType, is_floating_point<ResultType>>::getValue();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -271,7 +271,7 @@ private:
|
|||||||
{
|
{
|
||||||
if (OnEmpty == ReservoirSamplerDeterministicOnEmpty::THROW)
|
if (OnEmpty == ReservoirSamplerDeterministicOnEmpty::THROW)
|
||||||
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSamplerDeterministic");
|
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSamplerDeterministic");
|
||||||
return NanLikeValueConstructor<ResultType, std::is_floating_point_v<ResultType>>::getValue();
|
return NanLikeValueConstructor<ResultType, is_floating_point<ResultType>>::getValue();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@ namespace ErrorCodes
|
|||||||
|
|
||||||
|
|
||||||
BackupConcurrencyCheck::BackupConcurrencyCheck(
|
BackupConcurrencyCheck::BackupConcurrencyCheck(
|
||||||
const UUID & backup_or_restore_uuid_,
|
|
||||||
bool is_restore_,
|
bool is_restore_,
|
||||||
bool on_cluster_,
|
bool on_cluster_,
|
||||||
|
const String & zookeeper_path_,
|
||||||
bool allow_concurrency_,
|
bool allow_concurrency_,
|
||||||
BackupConcurrencyCounters & counters_)
|
BackupConcurrencyCounters & counters_)
|
||||||
: is_restore(is_restore_), backup_or_restore_uuid(backup_or_restore_uuid_), on_cluster(on_cluster_), counters(counters_)
|
: is_restore(is_restore_), on_cluster(on_cluster_), zookeeper_path(zookeeper_path_), counters(counters_)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{counters.mutex};
|
std::lock_guard lock{counters.mutex};
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ BackupConcurrencyCheck::BackupConcurrencyCheck(
|
|||||||
size_t num_on_cluster_restores = counters.on_cluster_restores.size();
|
size_t num_on_cluster_restores = counters.on_cluster_restores.size();
|
||||||
if (on_cluster)
|
if (on_cluster)
|
||||||
{
|
{
|
||||||
if (!counters.on_cluster_restores.contains(backup_or_restore_uuid))
|
if (!counters.on_cluster_restores.contains(zookeeper_path))
|
||||||
++num_on_cluster_restores;
|
++num_on_cluster_restores;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -47,7 +47,7 @@ BackupConcurrencyCheck::BackupConcurrencyCheck(
|
|||||||
size_t num_on_cluster_backups = counters.on_cluster_backups.size();
|
size_t num_on_cluster_backups = counters.on_cluster_backups.size();
|
||||||
if (on_cluster)
|
if (on_cluster)
|
||||||
{
|
{
|
||||||
if (!counters.on_cluster_backups.contains(backup_or_restore_uuid))
|
if (!counters.on_cluster_backups.contains(zookeeper_path))
|
||||||
++num_on_cluster_backups;
|
++num_on_cluster_backups;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -64,9 +64,9 @@ BackupConcurrencyCheck::BackupConcurrencyCheck(
|
|||||||
if (on_cluster)
|
if (on_cluster)
|
||||||
{
|
{
|
||||||
if (is_restore)
|
if (is_restore)
|
||||||
++counters.on_cluster_restores[backup_or_restore_uuid];
|
++counters.on_cluster_restores[zookeeper_path];
|
||||||
else
|
else
|
||||||
++counters.on_cluster_backups[backup_or_restore_uuid];
|
++counters.on_cluster_backups[zookeeper_path];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -86,7 +86,7 @@ BackupConcurrencyCheck::~BackupConcurrencyCheck()
|
|||||||
{
|
{
|
||||||
if (is_restore)
|
if (is_restore)
|
||||||
{
|
{
|
||||||
auto it = counters.on_cluster_restores.find(backup_or_restore_uuid);
|
auto it = counters.on_cluster_restores.find(zookeeper_path);
|
||||||
if (it != counters.on_cluster_restores.end())
|
if (it != counters.on_cluster_restores.end())
|
||||||
{
|
{
|
||||||
if (!--it->second)
|
if (!--it->second)
|
||||||
@ -95,7 +95,7 @@ BackupConcurrencyCheck::~BackupConcurrencyCheck()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = counters.on_cluster_backups.find(backup_or_restore_uuid);
|
auto it = counters.on_cluster_backups.find(zookeeper_path);
|
||||||
if (it != counters.on_cluster_backups.end())
|
if (it != counters.on_cluster_backups.end())
|
||||||
{
|
{
|
||||||
if (!--it->second)
|
if (!--it->second)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/UUID.h>
|
#include <base/defines.h>
|
||||||
#include <base/scope_guard.h>
|
#include <base/scope_guard.h>
|
||||||
|
#include <base/types.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@ -19,9 +20,9 @@ public:
|
|||||||
/// Checks concurrency of a BACKUP operation or a RESTORE operation.
|
/// Checks concurrency of a BACKUP operation or a RESTORE operation.
|
||||||
/// Keep a constructed instance of BackupConcurrencyCheck until the operation is done.
|
/// Keep a constructed instance of BackupConcurrencyCheck until the operation is done.
|
||||||
BackupConcurrencyCheck(
|
BackupConcurrencyCheck(
|
||||||
const UUID & backup_or_restore_uuid_,
|
|
||||||
bool is_restore_,
|
bool is_restore_,
|
||||||
bool on_cluster_,
|
bool on_cluster_,
|
||||||
|
const String & zookeeper_path_,
|
||||||
bool allow_concurrency_,
|
bool allow_concurrency_,
|
||||||
BackupConcurrencyCounters & counters_);
|
BackupConcurrencyCounters & counters_);
|
||||||
|
|
||||||
@ -31,8 +32,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const bool is_restore;
|
const bool is_restore;
|
||||||
const UUID backup_or_restore_uuid;
|
|
||||||
const bool on_cluster;
|
const bool on_cluster;
|
||||||
|
const String zookeeper_path;
|
||||||
BackupConcurrencyCounters & counters;
|
BackupConcurrencyCounters & counters;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,8 +48,8 @@ private:
|
|||||||
friend class BackupConcurrencyCheck;
|
friend class BackupConcurrencyCheck;
|
||||||
size_t local_backups TSA_GUARDED_BY(mutex) = 0;
|
size_t local_backups TSA_GUARDED_BY(mutex) = 0;
|
||||||
size_t local_restores TSA_GUARDED_BY(mutex) = 0;
|
size_t local_restores TSA_GUARDED_BY(mutex) = 0;
|
||||||
std::unordered_map<UUID /* backup_uuid */, size_t /* num_refs */> on_cluster_backups TSA_GUARDED_BY(mutex);
|
std::unordered_map<String /* zookeeper_path */, size_t /* num_refs */> on_cluster_backups TSA_GUARDED_BY(mutex);
|
||||||
std::unordered_map<UUID /* restore_uuid */, size_t /* num_refs */> on_cluster_restores TSA_GUARDED_BY(mutex);
|
std::unordered_map<String /* zookeeper_path */, size_t /* num_refs */> on_cluster_restores TSA_GUARDED_BY(mutex);
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,31 +4,29 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
BackupCoordinationCleaner::BackupCoordinationCleaner(const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr log_)
|
BackupCoordinationCleaner::BackupCoordinationCleaner(bool is_restore_, const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr log_)
|
||||||
: zookeeper_path(zookeeper_path_), with_retries(with_retries_), log(log_)
|
: is_restore(is_restore_), zookeeper_path(zookeeper_path_), with_retries(with_retries_), log(log_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackupCoordinationCleaner::cleanup()
|
bool BackupCoordinationCleaner::cleanup(bool throw_if_error)
|
||||||
{
|
{
|
||||||
tryRemoveAllNodes(/* throw_if_error = */ true, /* retries_kind = */ WithRetries::kNormal);
|
WithRetries::Kind retries_kind = throw_if_error ? WithRetries::kNormal : WithRetries::kErrorHandling;
|
||||||
|
return cleanupImpl(throw_if_error, retries_kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackupCoordinationCleaner::tryCleanupAfterError() noexcept
|
bool BackupCoordinationCleaner::cleanupImpl(bool throw_if_error, WithRetries::Kind retries_kind)
|
||||||
{
|
|
||||||
return tryRemoveAllNodes(/* throw_if_error = */ false, /* retries_kind = */ WithRetries::kNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BackupCoordinationCleaner::tryRemoveAllNodes(bool throw_if_error, WithRetries::Kind retries_kind)
|
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
if (cleanup_result.succeeded)
|
if (succeeded)
|
||||||
return true;
|
|
||||||
if (cleanup_result.exception)
|
|
||||||
{
|
{
|
||||||
if (throw_if_error)
|
LOG_TRACE(log, "Nodes from ZooKeeper are already removed");
|
||||||
std::rethrow_exception(cleanup_result.exception);
|
return true;
|
||||||
|
}
|
||||||
|
if (tried)
|
||||||
|
{
|
||||||
|
LOG_INFO(log, "Skipped removing nodes from ZooKeeper because because earlier we failed to do that");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,16 +42,18 @@ bool BackupCoordinationCleaner::tryRemoveAllNodes(bool throw_if_error, WithRetri
|
|||||||
});
|
});
|
||||||
|
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
cleanup_result.succeeded = true;
|
tried = true;
|
||||||
|
succeeded = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_TRACE(log, "Caught exception while removing nodes from ZooKeeper for this restore: {}",
|
LOG_TRACE(log, "Caught exception while removing nodes from ZooKeeper for this {}: {}",
|
||||||
|
is_restore ? "restore" : "backup",
|
||||||
getCurrentExceptionMessage(/* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true));
|
getCurrentExceptionMessage(/* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true));
|
||||||
|
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
cleanup_result.exception = std::current_exception();
|
tried = true;
|
||||||
|
|
||||||
if (throw_if_error)
|
if (throw_if_error)
|
||||||
throw;
|
throw;
|
||||||
|
@ -12,14 +12,14 @@ namespace DB
|
|||||||
class BackupCoordinationCleaner
|
class BackupCoordinationCleaner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BackupCoordinationCleaner(const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr log_);
|
BackupCoordinationCleaner(bool is_restore_, const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr log_);
|
||||||
|
|
||||||
void cleanup();
|
bool cleanup(bool throw_if_error);
|
||||||
bool tryCleanupAfterError() noexcept;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool tryRemoveAllNodes(bool throw_if_error, WithRetries::Kind retries_kind);
|
bool cleanupImpl(bool throw_if_error, WithRetries::Kind retries_kind);
|
||||||
|
|
||||||
|
const bool is_restore;
|
||||||
const String zookeeper_path;
|
const String zookeeper_path;
|
||||||
|
|
||||||
/// A reference to a field of the parent object which is either BackupCoordinationOnCluster or RestoreCoordinationOnCluster.
|
/// A reference to a field of the parent object which is either BackupCoordinationOnCluster or RestoreCoordinationOnCluster.
|
||||||
@ -27,13 +27,8 @@ private:
|
|||||||
|
|
||||||
const LoggerPtr log;
|
const LoggerPtr log;
|
||||||
|
|
||||||
struct CleanupResult
|
bool tried TSA_GUARDED_BY(mutex) = false;
|
||||||
{
|
bool succeeded TSA_GUARDED_BY(mutex) = false;
|
||||||
bool succeeded = false;
|
|
||||||
std::exception_ptr exception;
|
|
||||||
};
|
|
||||||
CleanupResult cleanup_result TSA_GUARDED_BY(mutex);
|
|
||||||
|
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,12 +11,11 @@ namespace DB
|
|||||||
{
|
{
|
||||||
|
|
||||||
BackupCoordinationLocal::BackupCoordinationLocal(
|
BackupCoordinationLocal::BackupCoordinationLocal(
|
||||||
const UUID & backup_uuid_,
|
|
||||||
bool is_plain_backup_,
|
bool is_plain_backup_,
|
||||||
bool allow_concurrent_backup_,
|
bool allow_concurrent_backup_,
|
||||||
BackupConcurrencyCounters & concurrency_counters_)
|
BackupConcurrencyCounters & concurrency_counters_)
|
||||||
: log(getLogger("BackupCoordinationLocal"))
|
: log(getLogger("BackupCoordinationLocal"))
|
||||||
, concurrency_check(backup_uuid_, /* is_restore = */ false, /* on_cluster = */ false, allow_concurrent_backup_, concurrency_counters_)
|
, concurrency_check(/* is_restore = */ false, /* on_cluster = */ false, /* zookeeper_path = */ "", allow_concurrent_backup_, concurrency_counters_)
|
||||||
, file_infos(is_plain_backup_)
|
, file_infos(is_plain_backup_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,19 @@ class BackupCoordinationLocal : public IBackupCoordination
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit BackupCoordinationLocal(
|
explicit BackupCoordinationLocal(
|
||||||
const UUID & backup_uuid_,
|
|
||||||
bool is_plain_backup_,
|
bool is_plain_backup_,
|
||||||
bool allow_concurrent_backup_,
|
bool allow_concurrent_backup_,
|
||||||
BackupConcurrencyCounters & concurrency_counters_);
|
BackupConcurrencyCounters & concurrency_counters_);
|
||||||
|
|
||||||
~BackupCoordinationLocal() override;
|
~BackupCoordinationLocal() override;
|
||||||
|
|
||||||
|
void setBackupQueryIsSentToOtherHosts() override {}
|
||||||
|
bool isBackupQuerySentToOtherHosts() const override { return false; }
|
||||||
Strings setStage(const String &, const String &, bool) override { return {}; }
|
Strings setStage(const String &, const String &, bool) override { return {}; }
|
||||||
void setBackupQueryWasSentToOtherHosts() override {}
|
bool setError(std::exception_ptr, bool) override { return true; }
|
||||||
bool trySetError(std::exception_ptr) override { return true; }
|
bool waitOtherHostsFinish(bool) const override { return true; }
|
||||||
void finish() override {}
|
bool finish(bool) override { return true; }
|
||||||
bool tryFinishAfterError() noexcept override { return true; }
|
bool cleanup(bool) override { return true; }
|
||||||
void waitForOtherHostsToFinish() override {}
|
|
||||||
bool tryWaitForOtherHostsToFinishAfterError() noexcept override { return true; }
|
|
||||||
|
|
||||||
void addReplicatedPartNames(const String & table_zk_path, const String & table_name_for_logs, const String & replica_name,
|
void addReplicatedPartNames(const String & table_zk_path, const String & table_name_for_logs, const String & replica_name,
|
||||||
const std::vector<PartNameAndChecksum> & part_names_and_checksums) override;
|
const std::vector<PartNameAndChecksum> & part_names_and_checksums) override;
|
||||||
|
@ -184,17 +184,21 @@ BackupCoordinationOnCluster::BackupCoordinationOnCluster(
|
|||||||
, plain_backup(is_plain_backup_)
|
, plain_backup(is_plain_backup_)
|
||||||
, log(getLogger("BackupCoordinationOnCluster"))
|
, log(getLogger("BackupCoordinationOnCluster"))
|
||||||
, with_retries(log, get_zookeeper_, keeper_settings, process_list_element_, [root_zookeeper_path_](Coordination::ZooKeeperWithFaultInjection::Ptr zk) { zk->sync(root_zookeeper_path_); })
|
, with_retries(log, get_zookeeper_, keeper_settings, process_list_element_, [root_zookeeper_path_](Coordination::ZooKeeperWithFaultInjection::Ptr zk) { zk->sync(root_zookeeper_path_); })
|
||||||
, concurrency_check(backup_uuid_, /* is_restore = */ false, /* on_cluster = */ true, allow_concurrent_backup_, concurrency_counters_)
|
, cleaner(/* is_restore = */ false, zookeeper_path, with_retries, log)
|
||||||
, stage_sync(/* is_restore = */ false, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_backup_, with_retries, schedule_, process_list_element_, log)
|
, stage_sync(/* is_restore = */ false, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_backup_, concurrency_counters_, with_retries, schedule_, process_list_element_, log)
|
||||||
, cleaner(zookeeper_path, with_retries, log)
|
|
||||||
{
|
{
|
||||||
createRootNodes();
|
try
|
||||||
|
{
|
||||||
|
createRootNodes();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
stage_sync.setError(std::current_exception(), /* throw_if_error = */ false);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupCoordinationOnCluster::~BackupCoordinationOnCluster()
|
BackupCoordinationOnCluster::~BackupCoordinationOnCluster() = default;
|
||||||
{
|
|
||||||
tryFinishImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackupCoordinationOnCluster::createRootNodes()
|
void BackupCoordinationOnCluster::createRootNodes()
|
||||||
{
|
{
|
||||||
@ -217,69 +221,52 @@ void BackupCoordinationOnCluster::createRootNodes()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackupCoordinationOnCluster::setBackupQueryIsSentToOtherHosts()
|
||||||
|
{
|
||||||
|
stage_sync.setQueryIsSentToOtherHosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BackupCoordinationOnCluster::isBackupQuerySentToOtherHosts() const
|
||||||
|
{
|
||||||
|
return stage_sync.isQuerySentToOtherHosts();
|
||||||
|
}
|
||||||
|
|
||||||
Strings BackupCoordinationOnCluster::setStage(const String & new_stage, const String & message, bool sync)
|
Strings BackupCoordinationOnCluster::setStage(const String & new_stage, const String & message, bool sync)
|
||||||
{
|
{
|
||||||
stage_sync.setStage(new_stage, message);
|
stage_sync.setStage(new_stage, message);
|
||||||
|
if (sync)
|
||||||
if (!sync)
|
return stage_sync.waitHostsReachStage(all_hosts_without_initiator, new_stage);
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return stage_sync.waitForHostsToReachStage(new_stage, all_hosts_without_initiator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackupCoordinationOnCluster::setBackupQueryWasSentToOtherHosts()
|
bool BackupCoordinationOnCluster::setError(std::exception_ptr exception, bool throw_if_error)
|
||||||
{
|
{
|
||||||
backup_query_was_sent_to_other_hosts = true;
|
return stage_sync.setError(exception, throw_if_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackupCoordinationOnCluster::trySetError(std::exception_ptr exception)
|
bool BackupCoordinationOnCluster::waitOtherHostsFinish(bool throw_if_error) const
|
||||||
{
|
{
|
||||||
return stage_sync.trySetError(exception);
|
return stage_sync.waitOtherHostsFinish(throw_if_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackupCoordinationOnCluster::finish()
|
bool BackupCoordinationOnCluster::finish(bool throw_if_error)
|
||||||
{
|
{
|
||||||
bool other_hosts_also_finished = false;
|
return stage_sync.finish(throw_if_error);
|
||||||
stage_sync.finish(other_hosts_also_finished);
|
|
||||||
|
|
||||||
if ((current_host == kInitiator) && (other_hosts_also_finished || !backup_query_was_sent_to_other_hosts))
|
|
||||||
cleaner.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackupCoordinationOnCluster::tryFinishAfterError() noexcept
|
bool BackupCoordinationOnCluster::cleanup(bool throw_if_error)
|
||||||
{
|
{
|
||||||
return tryFinishImpl();
|
/// All the hosts must finish before we remove the coordination nodes.
|
||||||
}
|
bool expect_other_hosts_finished = stage_sync.isQuerySentToOtherHosts() || !stage_sync.isErrorSet();
|
||||||
|
bool all_hosts_finished = stage_sync.finished() && (stage_sync.otherHostsFinished() || !expect_other_hosts_finished);
|
||||||
bool BackupCoordinationOnCluster::tryFinishImpl() noexcept
|
if (!all_hosts_finished)
|
||||||
{
|
|
||||||
bool other_hosts_also_finished = false;
|
|
||||||
if (!stage_sync.tryFinishAfterError(other_hosts_also_finished))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((current_host == kInitiator) && (other_hosts_also_finished || !backup_query_was_sent_to_other_hosts))
|
|
||||||
{
|
{
|
||||||
if (!cleaner.tryCleanupAfterError())
|
auto unfinished_hosts = expect_other_hosts_finished ? stage_sync.getUnfinishedHosts() : Strings{current_host};
|
||||||
return false;
|
LOG_INFO(log, "Skipping removing nodes from ZooKeeper because hosts {} didn't finish",
|
||||||
}
|
BackupCoordinationStageSync::getHostsDesc(unfinished_hosts));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackupCoordinationOnCluster::waitForOtherHostsToFinish()
|
|
||||||
{
|
|
||||||
if ((current_host != kInitiator) || !backup_query_was_sent_to_other_hosts)
|
|
||||||
return;
|
|
||||||
stage_sync.waitForOtherHostsToFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BackupCoordinationOnCluster::tryWaitForOtherHostsToFinishAfterError() noexcept
|
|
||||||
{
|
|
||||||
if (current_host != kInitiator)
|
|
||||||
return false;
|
return false;
|
||||||
if (!backup_query_was_sent_to_other_hosts)
|
}
|
||||||
return true;
|
return cleaner.cleanup(throw_if_error);
|
||||||
return stage_sync.tryWaitForOtherHostsToFinishAfterError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZooKeeperRetriesInfo BackupCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const
|
ZooKeeperRetriesInfo BackupCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Backups/IBackupCoordination.h>
|
#include <Backups/IBackupCoordination.h>
|
||||||
#include <Backups/BackupConcurrencyCheck.h>
|
|
||||||
#include <Backups/BackupCoordinationCleaner.h>
|
#include <Backups/BackupCoordinationCleaner.h>
|
||||||
#include <Backups/BackupCoordinationFileInfos.h>
|
#include <Backups/BackupCoordinationFileInfos.h>
|
||||||
#include <Backups/BackupCoordinationReplicatedAccess.h>
|
#include <Backups/BackupCoordinationReplicatedAccess.h>
|
||||||
@ -20,7 +19,7 @@ class BackupCoordinationOnCluster : public IBackupCoordination
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Empty string as the current host is used to mark the initiator of a BACKUP ON CLUSTER query.
|
/// Empty string as the current host is used to mark the initiator of a BACKUP ON CLUSTER query.
|
||||||
static const constexpr std::string_view kInitiator;
|
static const constexpr std::string_view kInitiator = BackupCoordinationStageSync::kInitiator;
|
||||||
|
|
||||||
BackupCoordinationOnCluster(
|
BackupCoordinationOnCluster(
|
||||||
const UUID & backup_uuid_,
|
const UUID & backup_uuid_,
|
||||||
@ -37,13 +36,13 @@ public:
|
|||||||
|
|
||||||
~BackupCoordinationOnCluster() override;
|
~BackupCoordinationOnCluster() override;
|
||||||
|
|
||||||
|
void setBackupQueryIsSentToOtherHosts() override;
|
||||||
|
bool isBackupQuerySentToOtherHosts() const override;
|
||||||
Strings setStage(const String & new_stage, const String & message, bool sync) override;
|
Strings setStage(const String & new_stage, const String & message, bool sync) override;
|
||||||
void setBackupQueryWasSentToOtherHosts() override;
|
bool setError(std::exception_ptr exception, bool throw_if_error) override;
|
||||||
bool trySetError(std::exception_ptr exception) override;
|
bool waitOtherHostsFinish(bool throw_if_error) const override;
|
||||||
void finish() override;
|
bool finish(bool throw_if_error) override;
|
||||||
bool tryFinishAfterError() noexcept override;
|
bool cleanup(bool throw_if_error) override;
|
||||||
void waitForOtherHostsToFinish() override;
|
|
||||||
bool tryWaitForOtherHostsToFinishAfterError() noexcept override;
|
|
||||||
|
|
||||||
void addReplicatedPartNames(
|
void addReplicatedPartNames(
|
||||||
const String & table_zk_path,
|
const String & table_zk_path,
|
||||||
@ -110,11 +109,10 @@ private:
|
|||||||
const bool plain_backup;
|
const bool plain_backup;
|
||||||
LoggerPtr const log;
|
LoggerPtr const log;
|
||||||
|
|
||||||
|
/// The order is important: `stage_sync` must be initialized after `with_retries` and `cleaner`.
|
||||||
const WithRetries with_retries;
|
const WithRetries with_retries;
|
||||||
BackupConcurrencyCheck concurrency_check;
|
|
||||||
BackupCoordinationStageSync stage_sync;
|
|
||||||
BackupCoordinationCleaner cleaner;
|
BackupCoordinationCleaner cleaner;
|
||||||
std::atomic<bool> backup_query_was_sent_to_other_hosts = false;
|
BackupCoordinationStageSync stage_sync;
|
||||||
|
|
||||||
mutable std::optional<BackupCoordinationReplicatedTables> replicated_tables TSA_GUARDED_BY(replicated_tables_mutex);
|
mutable std::optional<BackupCoordinationReplicatedTables> replicated_tables TSA_GUARDED_BY(replicated_tables_mutex);
|
||||||
mutable std::optional<BackupCoordinationReplicatedAccess> replicated_access TSA_GUARDED_BY(replicated_access_mutex);
|
mutable std::optional<BackupCoordinationReplicatedAccess> replicated_access TSA_GUARDED_BY(replicated_access_mutex);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Backups/BackupConcurrencyCheck.h>
|
||||||
#include <Backups/WithRetries.h>
|
#include <Backups/WithRetries.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -9,12 +11,16 @@ namespace DB
|
|||||||
class BackupCoordinationStageSync
|
class BackupCoordinationStageSync
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Empty string as the current host is used to mark the initiator of a BACKUP ON CLUSTER or RESTORE ON CLUSTER query.
|
||||||
|
static const constexpr std::string_view kInitiator;
|
||||||
|
|
||||||
BackupCoordinationStageSync(
|
BackupCoordinationStageSync(
|
||||||
bool is_restore_, /// true if this is a RESTORE ON CLUSTER command, false if this is a BACKUP ON CLUSTER command
|
bool is_restore_, /// true if this is a RESTORE ON CLUSTER command, false if this is a BACKUP ON CLUSTER command
|
||||||
const String & zookeeper_path_, /// path to the "stage" folder in ZooKeeper
|
const String & zookeeper_path_, /// path to the "stage" folder in ZooKeeper
|
||||||
const String & current_host_, /// the current host, or an empty string if it's the initiator of the BACKUP/RESTORE ON CLUSTER command
|
const String & current_host_, /// the current host, or an empty string if it's the initiator of the BACKUP/RESTORE ON CLUSTER command
|
||||||
const Strings & all_hosts_, /// all the hosts (including the initiator and the current host) performing the BACKUP/RESTORE ON CLUSTER command
|
const Strings & all_hosts_, /// all the hosts (including the initiator and the current host) performing the BACKUP/RESTORE ON CLUSTER command
|
||||||
bool allow_concurrency_, /// whether it's allowed to have concurrent backups or restores.
|
bool allow_concurrency_, /// whether it's allowed to have concurrent backups or restores.
|
||||||
|
BackupConcurrencyCounters & concurrency_counters_,
|
||||||
const WithRetries & with_retries_,
|
const WithRetries & with_retries_,
|
||||||
ThreadPoolCallbackRunnerUnsafe<void> schedule_,
|
ThreadPoolCallbackRunnerUnsafe<void> schedule_,
|
||||||
QueryStatusPtr process_list_element_,
|
QueryStatusPtr process_list_element_,
|
||||||
@ -22,30 +28,37 @@ public:
|
|||||||
|
|
||||||
~BackupCoordinationStageSync();
|
~BackupCoordinationStageSync();
|
||||||
|
|
||||||
|
/// Sets that the BACKUP or RESTORE query was sent to other hosts.
|
||||||
|
void setQueryIsSentToOtherHosts();
|
||||||
|
bool isQuerySentToOtherHosts() const;
|
||||||
|
|
||||||
/// Sets the stage of the current host and signal other hosts if there were other hosts waiting for that.
|
/// Sets the stage of the current host and signal other hosts if there were other hosts waiting for that.
|
||||||
void setStage(const String & stage, const String & stage_result = {});
|
void setStage(const String & stage, const String & stage_result = {});
|
||||||
|
|
||||||
/// Waits until all the specified hosts come to the specified stage.
|
/// Waits until specified hosts come to the specified stage.
|
||||||
/// The function returns the results which specified hosts set when they came to the required stage.
|
/// The function returns the results which the specified hosts set when they came to the required stage.
|
||||||
/// If it doesn't happen before the timeout then the function will stop waiting and throw an exception.
|
Strings waitHostsReachStage(const Strings & hosts, const String & stage_to_wait) const;
|
||||||
Strings waitForHostsToReachStage(const String & stage_to_wait, const Strings & hosts, std::optional<std::chrono::milliseconds> timeout = {}) const;
|
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work.
|
|
||||||
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
|
||||||
void waitForOtherHostsToFinish() const;
|
|
||||||
|
|
||||||
/// Lets other host know that the current host has finished its work.
|
|
||||||
void finish(bool & other_hosts_also_finished);
|
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has encountered an error.
|
/// Lets other hosts know that the current host has encountered an error.
|
||||||
bool trySetError(std::exception_ptr exception) noexcept;
|
/// The function returns true if it successfully created the error node or if the error node was found already exist.
|
||||||
|
bool setError(std::exception_ptr exception, bool throw_if_error);
|
||||||
|
bool isErrorSet() const;
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work (as a part of error-handling process).
|
/// Waits until the hosts other than the current host finish their work. Must be called before finish().
|
||||||
/// Doesn't stops waiting if some host encounters an error or gets cancelled.
|
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
||||||
bool tryWaitForOtherHostsToFinishAfterError() const noexcept;
|
bool waitOtherHostsFinish(bool throw_if_error) const;
|
||||||
|
bool otherHostsFinished() const;
|
||||||
|
|
||||||
/// Lets other host know that the current host has finished its work (as a part of error-handling process).
|
/// Lets other hosts know that the current host has finished its work.
|
||||||
bool tryFinishAfterError(bool & other_hosts_also_finished) noexcept;
|
bool finish(bool throw_if_error);
|
||||||
|
bool finished() const;
|
||||||
|
|
||||||
|
/// Returns true if all the hosts have finished.
|
||||||
|
bool allHostsFinished() const { return finished() && otherHostsFinished(); }
|
||||||
|
|
||||||
|
/// Returns a list of the hosts which haven't finished yet.
|
||||||
|
Strings getUnfinishedHosts() const;
|
||||||
|
Strings getUnfinishedOtherHosts() const;
|
||||||
|
|
||||||
/// Returns a printable name of a specific host. For empty host the function returns "initiator".
|
/// Returns a printable name of a specific host. For empty host the function returns "initiator".
|
||||||
static String getHostDesc(const String & host);
|
static String getHostDesc(const String & host);
|
||||||
@ -59,8 +72,8 @@ private:
|
|||||||
void createRootNodes();
|
void createRootNodes();
|
||||||
|
|
||||||
/// Atomically creates both 'start' and 'alive' nodes and also checks that there is no concurrent backup or restore if `allow_concurrency` is false.
|
/// Atomically creates both 'start' and 'alive' nodes and also checks that there is no concurrent backup or restore if `allow_concurrency` is false.
|
||||||
void createStartAndAliveNodes();
|
void createStartAndAliveNodesAndCheckConcurrency(BackupConcurrencyCounters & concurrency_counters_);
|
||||||
void createStartAndAliveNodes(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
void createStartAndAliveNodesAndCheckConcurrency(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
||||||
|
|
||||||
/// Deserialize the version of a node stored in the 'start' node.
|
/// Deserialize the version of a node stored in the 'start' node.
|
||||||
int parseStartNode(const String & start_node_contents, const String & host) const;
|
int parseStartNode(const String & start_node_contents, const String & host) const;
|
||||||
@ -78,14 +91,17 @@ private:
|
|||||||
|
|
||||||
/// Reads the current state from ZooKeeper without throwing exceptions.
|
/// Reads the current state from ZooKeeper without throwing exceptions.
|
||||||
void readCurrentState(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
void readCurrentState(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
||||||
|
|
||||||
|
/// Creates a stage node to let other hosts know we've reached the specified stage.
|
||||||
|
void createStageNode(const String & stage, const String & stage_result, Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
||||||
String getStageNodePath(const String & stage) const;
|
String getStageNodePath(const String & stage) const;
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has encountered an error.
|
/// Lets other hosts know that the current host has encountered an error.
|
||||||
bool trySetError(const Exception & exception);
|
bool setError(const Exception & exception, bool throw_if_error);
|
||||||
void setError(const Exception & exception);
|
void createErrorNode(const Exception & exception, Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
||||||
|
|
||||||
/// Deserializes an error stored in the error node.
|
/// Deserializes an error stored in the error node.
|
||||||
static std::pair<std::exception_ptr, String> parseErrorNode(const String & error_node_contents);
|
std::pair<std::exception_ptr, String> parseErrorNode(const String & error_node_contents) const;
|
||||||
|
|
||||||
/// Reset the `connected` flag for each host.
|
/// Reset the `connected` flag for each host.
|
||||||
void resetConnectedFlag();
|
void resetConnectedFlag();
|
||||||
@ -102,19 +118,27 @@ private:
|
|||||||
void cancelQueryIfDisconnectedTooLong();
|
void cancelQueryIfDisconnectedTooLong();
|
||||||
|
|
||||||
/// Used by waitForHostsToReachStage() to check if everything is ready to return.
|
/// Used by waitForHostsToReachStage() to check if everything is ready to return.
|
||||||
bool checkIfHostsReachStage(const Strings & hosts, const String & stage_to_wait, bool time_is_out, std::optional<std::chrono::milliseconds> timeout, Strings & results) const TSA_REQUIRES(mutex);
|
bool checkIfHostsReachStage(const Strings & hosts, const String & stage_to_wait, Strings & results) const TSA_REQUIRES(mutex);
|
||||||
|
|
||||||
/// Creates the 'finish' node.
|
/// Creates the 'finish' node.
|
||||||
bool tryFinishImpl();
|
bool finishImpl(bool throw_if_error, WithRetries::Kind retries_kind);
|
||||||
bool tryFinishImpl(bool & other_hosts_also_finished, bool throw_if_error, WithRetries::Kind retries_kind);
|
void createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper, bool throw_if_error);
|
||||||
void createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper);
|
|
||||||
|
|
||||||
/// Returns the version used by the initiator.
|
/// Returns the version used by the initiator.
|
||||||
int getInitiatorVersion() const;
|
int getInitiatorVersion() const;
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work.
|
/// Waits until all the other hosts finish their work.
|
||||||
bool tryWaitForOtherHostsToFinishImpl(const String & reason, bool throw_if_error, std::optional<std::chrono::seconds> timeout) const;
|
bool waitOtherHostsFinishImpl(const String & reason, std::optional<std::chrono::seconds> timeout, bool throw_if_error) const;
|
||||||
bool checkIfOtherHostsFinish(const String & reason, bool throw_if_error, bool time_is_out, std::optional<std::chrono::milliseconds> timeout) const TSA_REQUIRES(mutex);
|
bool checkIfOtherHostsFinish(const String & reason, std::optional<std::chrono::milliseconds> timeout, bool time_is_out, bool & result, bool throw_if_error) const TSA_REQUIRES(mutex);
|
||||||
|
|
||||||
|
/// Returns true if all the hosts have finished.
|
||||||
|
bool allHostsFinishedNoLock() const TSA_REQUIRES(mutex);
|
||||||
|
bool finishedNoLock() const TSA_REQUIRES(mutex);
|
||||||
|
bool otherHostsFinishedNoLock() const TSA_REQUIRES(mutex);
|
||||||
|
|
||||||
|
/// Returns a list of the hosts which haven't finished yet.
|
||||||
|
Strings getUnfinishedHostsNoLock() const TSA_REQUIRES(mutex);
|
||||||
|
Strings getUnfinishedOtherHostsNoLock() const TSA_REQUIRES(mutex);
|
||||||
|
|
||||||
const bool is_restore;
|
const bool is_restore;
|
||||||
const String operation_name;
|
const String operation_name;
|
||||||
@ -138,15 +162,16 @@ private:
|
|||||||
/// Paths in ZooKeeper.
|
/// Paths in ZooKeeper.
|
||||||
const std::filesystem::path zookeeper_path;
|
const std::filesystem::path zookeeper_path;
|
||||||
const String root_zookeeper_path;
|
const String root_zookeeper_path;
|
||||||
const String operation_node_path;
|
const String operation_zookeeper_path;
|
||||||
const String operation_node_name;
|
const String operation_node_name;
|
||||||
const String stage_node_path;
|
|
||||||
const String start_node_path;
|
const String start_node_path;
|
||||||
const String finish_node_path;
|
const String finish_node_path;
|
||||||
const String num_hosts_node_path;
|
const String num_hosts_node_path;
|
||||||
|
const String error_node_path;
|
||||||
const String alive_node_path;
|
const String alive_node_path;
|
||||||
const String alive_tracker_node_path;
|
const String alive_tracker_node_path;
|
||||||
const String error_node_path;
|
|
||||||
|
std::optional<BackupConcurrencyCheck> local_concurrency_check;
|
||||||
|
|
||||||
std::shared_ptr<Poco::Event> zk_nodes_changed;
|
std::shared_ptr<Poco::Event> zk_nodes_changed;
|
||||||
|
|
||||||
@ -172,29 +197,28 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Information about all the host participating in the current BACKUP or RESTORE operation.
|
/// Information about all the host participating in the current BACKUP or RESTORE operation.
|
||||||
|
/// This information is read from ZooKeeper.
|
||||||
|
/// To simplify the programming logic `state` can only be updated AFTER changing corresponding nodes in ZooKeeper
|
||||||
|
/// (for example, first we create the 'error' node, and only after that we set or read from ZK the `state.host_with_error` field).
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
std::map<String /* host */, HostInfo> hosts; /// std::map because we need to compare states
|
std::map<String /* host */, HostInfo> hosts; /// std::map because we need to compare states
|
||||||
std::optional<String> host_with_error;
|
std::optional<String> host_with_error;
|
||||||
bool cancelled = false;
|
|
||||||
|
|
||||||
bool operator ==(const State & other) const;
|
bool operator ==(const State & other) const;
|
||||||
bool operator !=(const State & other) const;
|
bool operator !=(const State & other) const;
|
||||||
|
void merge(const State & other);
|
||||||
};
|
};
|
||||||
|
|
||||||
State state TSA_GUARDED_BY(mutex);
|
State state TSA_GUARDED_BY(mutex);
|
||||||
mutable std::condition_variable state_changed;
|
mutable std::condition_variable state_changed;
|
||||||
|
|
||||||
std::future<void> watching_thread_future;
|
std::future<void> watching_thread_future;
|
||||||
std::atomic<bool> should_stop_watching_thread = false;
|
bool should_stop_watching_thread TSA_GUARDED_BY(mutex) = false;
|
||||||
|
|
||||||
struct FinishResult
|
bool query_is_sent_to_other_hosts TSA_GUARDED_BY(mutex) = false;
|
||||||
{
|
bool tried_to_finish TSA_GUARDED_BY(mutex) = false;
|
||||||
bool succeeded = false;
|
bool tried_to_set_error TSA_GUARDED_BY(mutex) = false;
|
||||||
std::exception_ptr exception;
|
|
||||||
bool other_hosts_also_finished = false;
|
|
||||||
};
|
|
||||||
FinishResult finish_result TSA_GUARDED_BY(mutex);
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
};
|
};
|
||||||
|
@ -329,6 +329,7 @@ std::pair<OperationID, BackupStatus> BackupsWorker::start(const ASTPtr & backup_
|
|||||||
struct BackupsWorker::BackupStarter
|
struct BackupsWorker::BackupStarter
|
||||||
{
|
{
|
||||||
BackupsWorker & backups_worker;
|
BackupsWorker & backups_worker;
|
||||||
|
LoggerPtr log;
|
||||||
std::shared_ptr<ASTBackupQuery> backup_query;
|
std::shared_ptr<ASTBackupQuery> backup_query;
|
||||||
ContextPtr query_context; /// We have to keep `query_context` until the end of the operation because a pointer to it is stored inside the ThreadGroup we're using.
|
ContextPtr query_context; /// We have to keep `query_context` until the end of the operation because a pointer to it is stored inside the ThreadGroup we're using.
|
||||||
ContextMutablePtr backup_context;
|
ContextMutablePtr backup_context;
|
||||||
@ -345,6 +346,7 @@ struct BackupsWorker::BackupStarter
|
|||||||
|
|
||||||
BackupStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_)
|
BackupStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_)
|
||||||
: backups_worker(backups_worker_)
|
: backups_worker(backups_worker_)
|
||||||
|
, log(backups_worker.log)
|
||||||
, backup_query(std::static_pointer_cast<ASTBackupQuery>(query_->clone()))
|
, backup_query(std::static_pointer_cast<ASTBackupQuery>(query_->clone()))
|
||||||
, query_context(context_)
|
, query_context(context_)
|
||||||
, backup_context(Context::createCopy(query_context))
|
, backup_context(Context::createCopy(query_context))
|
||||||
@ -399,9 +401,20 @@ struct BackupsWorker::BackupStarter
|
|||||||
chassert(!backup);
|
chassert(!backup);
|
||||||
backup = backups_worker.openBackupForWriting(backup_info, backup_settings, backup_coordination, backup_context);
|
backup = backups_worker.openBackupForWriting(backup_info, backup_settings, backup_coordination, backup_context);
|
||||||
|
|
||||||
backups_worker.doBackup(
|
backups_worker.doBackup(backup, backup_query, backup_id, backup_settings, backup_coordination, backup_context,
|
||||||
backup, backup_query, backup_id, backup_name_for_logging, backup_settings, backup_coordination, backup_context,
|
on_cluster, cluster);
|
||||||
on_cluster, cluster);
|
|
||||||
|
backup_coordination->finish(/* throw_if_error = */ true);
|
||||||
|
backup.reset();
|
||||||
|
|
||||||
|
/// The backup coordination is not needed anymore.
|
||||||
|
if (!is_internal_backup)
|
||||||
|
backup_coordination->cleanup(/* throw_if_error = */ true);
|
||||||
|
backup_coordination.reset();
|
||||||
|
|
||||||
|
/// NOTE: setStatus is called after setNumFilesAndSize in order to have actual information in a backup log record
|
||||||
|
LOG_INFO(log, "{} {} was created successfully", (is_internal_backup ? "Internal backup" : "Backup"), backup_name_for_logging);
|
||||||
|
backups_worker.setStatus(backup_id, BackupStatus::BACKUP_CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onException()
|
void onException()
|
||||||
@ -416,16 +429,29 @@ struct BackupsWorker::BackupStarter
|
|||||||
if (backup && !backup->setIsCorrupted())
|
if (backup && !backup->setIsCorrupted())
|
||||||
should_remove_files_in_backup = false;
|
should_remove_files_in_backup = false;
|
||||||
|
|
||||||
if (backup_coordination && backup_coordination->trySetError(std::current_exception()))
|
bool all_hosts_finished = false;
|
||||||
|
|
||||||
|
if (backup_coordination && backup_coordination->setError(std::current_exception(), /* throw_if_error = */ false))
|
||||||
{
|
{
|
||||||
bool other_hosts_finished = backup_coordination->tryWaitForOtherHostsToFinishAfterError();
|
bool other_hosts_finished = !is_internal_backup
|
||||||
|
&& (!backup_coordination->isBackupQuerySentToOtherHosts() || backup_coordination->waitOtherHostsFinish(/* throw_if_error = */ false));
|
||||||
|
|
||||||
if (should_remove_files_in_backup && other_hosts_finished)
|
all_hosts_finished = backup_coordination->finish(/* throw_if_error = */ false) && other_hosts_finished;
|
||||||
backup->tryRemoveAllFiles();
|
|
||||||
|
|
||||||
backup_coordination->tryFinishAfterError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!all_hosts_finished)
|
||||||
|
should_remove_files_in_backup = false;
|
||||||
|
|
||||||
|
if (backup && should_remove_files_in_backup)
|
||||||
|
backup->tryRemoveAllFiles();
|
||||||
|
|
||||||
|
backup.reset();
|
||||||
|
|
||||||
|
if (backup_coordination && all_hosts_finished)
|
||||||
|
backup_coordination->cleanup(/* throw_if_error = */ false);
|
||||||
|
|
||||||
|
backup_coordination.reset();
|
||||||
|
|
||||||
backups_worker.setStatusSafe(backup_id, getBackupStatusFromCurrentException());
|
backups_worker.setStatusSafe(backup_id, getBackupStatusFromCurrentException());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -497,7 +523,6 @@ void BackupsWorker::doBackup(
|
|||||||
BackupMutablePtr backup,
|
BackupMutablePtr backup,
|
||||||
const std::shared_ptr<ASTBackupQuery> & backup_query,
|
const std::shared_ptr<ASTBackupQuery> & backup_query,
|
||||||
const OperationID & backup_id,
|
const OperationID & backup_id,
|
||||||
const String & backup_name_for_logging,
|
|
||||||
const BackupSettings & backup_settings,
|
const BackupSettings & backup_settings,
|
||||||
std::shared_ptr<IBackupCoordination> backup_coordination,
|
std::shared_ptr<IBackupCoordination> backup_coordination,
|
||||||
ContextMutablePtr context,
|
ContextMutablePtr context,
|
||||||
@ -521,10 +546,10 @@ void BackupsWorker::doBackup(
|
|||||||
backup_settings.copySettingsToQuery(*backup_query);
|
backup_settings.copySettingsToQuery(*backup_query);
|
||||||
sendQueryToOtherHosts(*backup_query, cluster, backup_settings.shard_num, backup_settings.replica_num,
|
sendQueryToOtherHosts(*backup_query, cluster, backup_settings.shard_num, backup_settings.replica_num,
|
||||||
context, required_access, backup_coordination->getOnClusterInitializationKeeperRetriesInfo());
|
context, required_access, backup_coordination->getOnClusterInitializationKeeperRetriesInfo());
|
||||||
backup_coordination->setBackupQueryWasSentToOtherHosts();
|
backup_coordination->setBackupQueryIsSentToOtherHosts();
|
||||||
|
|
||||||
/// Wait until all the hosts have written their backup entries.
|
/// Wait until all the hosts have written their backup entries.
|
||||||
backup_coordination->waitForOtherHostsToFinish();
|
backup_coordination->waitOtherHostsFinish(/* throw_if_error = */ true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -569,18 +594,8 @@ void BackupsWorker::doBackup(
|
|||||||
compressed_size = backup->getCompressedSize();
|
compressed_size = backup->getCompressedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close the backup.
|
|
||||||
backup.reset();
|
|
||||||
|
|
||||||
/// The backup coordination is not needed anymore.
|
|
||||||
backup_coordination->finish();
|
|
||||||
|
|
||||||
/// NOTE: we need to update metadata again after backup->finalizeWriting(), because backup metadata is written there.
|
/// NOTE: we need to update metadata again after backup->finalizeWriting(), because backup metadata is written there.
|
||||||
setNumFilesAndSize(backup_id, num_files, total_size, num_entries, uncompressed_size, compressed_size, 0, 0);
|
setNumFilesAndSize(backup_id, num_files, total_size, num_entries, uncompressed_size, compressed_size, 0, 0);
|
||||||
|
|
||||||
/// NOTE: setStatus is called after setNumFilesAndSize in order to have actual information in a backup log record
|
|
||||||
LOG_INFO(log, "{} {} was created successfully", (is_internal_backup ? "Internal backup" : "Backup"), backup_name_for_logging);
|
|
||||||
setStatus(backup_id, BackupStatus::BACKUP_CREATED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -687,6 +702,7 @@ void BackupsWorker::writeBackupEntries(
|
|||||||
struct BackupsWorker::RestoreStarter
|
struct BackupsWorker::RestoreStarter
|
||||||
{
|
{
|
||||||
BackupsWorker & backups_worker;
|
BackupsWorker & backups_worker;
|
||||||
|
LoggerPtr log;
|
||||||
std::shared_ptr<ASTBackupQuery> restore_query;
|
std::shared_ptr<ASTBackupQuery> restore_query;
|
||||||
ContextPtr query_context; /// We have to keep `query_context` until the end of the operation because a pointer to it is stored inside the ThreadGroup we're using.
|
ContextPtr query_context; /// We have to keep `query_context` until the end of the operation because a pointer to it is stored inside the ThreadGroup we're using.
|
||||||
ContextMutablePtr restore_context;
|
ContextMutablePtr restore_context;
|
||||||
@ -702,6 +718,7 @@ struct BackupsWorker::RestoreStarter
|
|||||||
|
|
||||||
RestoreStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_)
|
RestoreStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_)
|
||||||
: backups_worker(backups_worker_)
|
: backups_worker(backups_worker_)
|
||||||
|
, log(backups_worker.log)
|
||||||
, restore_query(std::static_pointer_cast<ASTBackupQuery>(query_->clone()))
|
, restore_query(std::static_pointer_cast<ASTBackupQuery>(query_->clone()))
|
||||||
, query_context(context_)
|
, query_context(context_)
|
||||||
, restore_context(Context::createCopy(query_context))
|
, restore_context(Context::createCopy(query_context))
|
||||||
@ -753,16 +770,17 @@ struct BackupsWorker::RestoreStarter
|
|||||||
}
|
}
|
||||||
restore_coordination = backups_worker.makeRestoreCoordination(on_cluster, restore_settings, restore_context);
|
restore_coordination = backups_worker.makeRestoreCoordination(on_cluster, restore_settings, restore_context);
|
||||||
|
|
||||||
backups_worker.doRestore(
|
backups_worker.doRestore(restore_query, restore_id, backup_info, restore_settings, restore_coordination, restore_context,
|
||||||
restore_query,
|
on_cluster, cluster);
|
||||||
restore_id,
|
|
||||||
backup_name_for_logging,
|
/// The restore coordination is not needed anymore.
|
||||||
backup_info,
|
restore_coordination->finish(/* throw_if_error = */ true);
|
||||||
restore_settings,
|
if (!is_internal_restore)
|
||||||
restore_coordination,
|
restore_coordination->cleanup(/* throw_if_error = */ true);
|
||||||
restore_context,
|
restore_coordination.reset();
|
||||||
on_cluster,
|
|
||||||
cluster);
|
LOG_INFO(log, "Restored from {} {} successfully", (is_internal_restore ? "internal backup" : "backup"), backup_name_for_logging);
|
||||||
|
backups_worker.setStatus(restore_id, BackupStatus::RESTORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onException()
|
void onException()
|
||||||
@ -770,12 +788,16 @@ struct BackupsWorker::RestoreStarter
|
|||||||
/// Something bad happened, some data were not restored.
|
/// Something bad happened, some data were not restored.
|
||||||
tryLogCurrentException(backups_worker.log, fmt::format("Failed to restore from {} {}", (is_internal_restore ? "internal backup" : "backup"), backup_name_for_logging));
|
tryLogCurrentException(backups_worker.log, fmt::format("Failed to restore from {} {}", (is_internal_restore ? "internal backup" : "backup"), backup_name_for_logging));
|
||||||
|
|
||||||
if (restore_coordination && restore_coordination->trySetError(std::current_exception()))
|
if (restore_coordination && restore_coordination->setError(std::current_exception(), /* throw_if_error = */ false))
|
||||||
{
|
{
|
||||||
restore_coordination->tryWaitForOtherHostsToFinishAfterError();
|
bool other_hosts_finished = !is_internal_restore
|
||||||
restore_coordination->tryFinishAfterError();
|
&& (!restore_coordination->isRestoreQuerySentToOtherHosts() || restore_coordination->waitOtherHostsFinish(/* throw_if_error = */ false));
|
||||||
|
if (restore_coordination->finish(/* throw_if_error = */ false) && other_hosts_finished)
|
||||||
|
restore_coordination->cleanup(/* throw_if_error = */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restore_coordination.reset();
|
||||||
|
|
||||||
backups_worker.setStatusSafe(restore_id, getRestoreStatusFromCurrentException());
|
backups_worker.setStatusSafe(restore_id, getRestoreStatusFromCurrentException());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -838,7 +860,6 @@ BackupPtr BackupsWorker::openBackupForReading(const BackupInfo & backup_info, co
|
|||||||
void BackupsWorker::doRestore(
|
void BackupsWorker::doRestore(
|
||||||
const std::shared_ptr<ASTBackupQuery> & restore_query,
|
const std::shared_ptr<ASTBackupQuery> & restore_query,
|
||||||
const OperationID & restore_id,
|
const OperationID & restore_id,
|
||||||
const String & backup_name_for_logging,
|
|
||||||
const BackupInfo & backup_info,
|
const BackupInfo & backup_info,
|
||||||
RestoreSettings restore_settings,
|
RestoreSettings restore_settings,
|
||||||
std::shared_ptr<IRestoreCoordination> restore_coordination,
|
std::shared_ptr<IRestoreCoordination> restore_coordination,
|
||||||
@ -882,10 +903,10 @@ void BackupsWorker::doRestore(
|
|||||||
restore_settings.copySettingsToQuery(*restore_query);
|
restore_settings.copySettingsToQuery(*restore_query);
|
||||||
sendQueryToOtherHosts(*restore_query, cluster, restore_settings.shard_num, restore_settings.replica_num,
|
sendQueryToOtherHosts(*restore_query, cluster, restore_settings.shard_num, restore_settings.replica_num,
|
||||||
context, {}, restore_coordination->getOnClusterInitializationKeeperRetriesInfo());
|
context, {}, restore_coordination->getOnClusterInitializationKeeperRetriesInfo());
|
||||||
restore_coordination->setRestoreQueryWasSentToOtherHosts();
|
restore_coordination->setRestoreQueryIsSentToOtherHosts();
|
||||||
|
|
||||||
/// Wait until all the hosts have done with their restoring work.
|
/// Wait until all the hosts have done with their restoring work.
|
||||||
restore_coordination->waitForOtherHostsToFinish();
|
restore_coordination->waitOtherHostsFinish(/* throw_if_error = */ true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -905,12 +926,6 @@ void BackupsWorker::doRestore(
|
|||||||
backup, context, getThreadPool(ThreadPoolId::RESTORE), after_task_callback};
|
backup, context, getThreadPool(ThreadPoolId::RESTORE), after_task_callback};
|
||||||
restorer.run(RestorerFromBackup::RESTORE);
|
restorer.run(RestorerFromBackup::RESTORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The restore coordination is not needed anymore.
|
|
||||||
restore_coordination->finish();
|
|
||||||
|
|
||||||
LOG_INFO(log, "Restored from {} {} successfully", (is_internal_restore ? "internal backup" : "backup"), backup_name_for_logging);
|
|
||||||
setStatus(restore_id, BackupStatus::RESTORED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -943,7 +958,7 @@ BackupsWorker::makeBackupCoordination(bool on_cluster, const BackupSettings & ba
|
|||||||
if (!on_cluster)
|
if (!on_cluster)
|
||||||
{
|
{
|
||||||
return std::make_shared<BackupCoordinationLocal>(
|
return std::make_shared<BackupCoordinationLocal>(
|
||||||
*backup_settings.backup_uuid, !backup_settings.deduplicate_files, allow_concurrent_backups, *concurrency_counters);
|
!backup_settings.deduplicate_files, allow_concurrent_backups, *concurrency_counters);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_internal_backup = backup_settings.internal;
|
bool is_internal_backup = backup_settings.internal;
|
||||||
@ -981,8 +996,7 @@ BackupsWorker::makeRestoreCoordination(bool on_cluster, const RestoreSettings &
|
|||||||
{
|
{
|
||||||
if (!on_cluster)
|
if (!on_cluster)
|
||||||
{
|
{
|
||||||
return std::make_shared<RestoreCoordinationLocal>(
|
return std::make_shared<RestoreCoordinationLocal>(allow_concurrent_restores, *concurrency_counters);
|
||||||
*restore_settings.restore_uuid, allow_concurrent_restores, *concurrency_counters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_internal_restore = restore_settings.internal;
|
bool is_internal_restore = restore_settings.internal;
|
||||||
|
@ -81,7 +81,6 @@ private:
|
|||||||
BackupMutablePtr backup,
|
BackupMutablePtr backup,
|
||||||
const std::shared_ptr<ASTBackupQuery> & backup_query,
|
const std::shared_ptr<ASTBackupQuery> & backup_query,
|
||||||
const BackupOperationID & backup_id,
|
const BackupOperationID & backup_id,
|
||||||
const String & backup_name_for_logging,
|
|
||||||
const BackupSettings & backup_settings,
|
const BackupSettings & backup_settings,
|
||||||
std::shared_ptr<IBackupCoordination> backup_coordination,
|
std::shared_ptr<IBackupCoordination> backup_coordination,
|
||||||
ContextMutablePtr context,
|
ContextMutablePtr context,
|
||||||
@ -102,7 +101,6 @@ private:
|
|||||||
void doRestore(
|
void doRestore(
|
||||||
const std::shared_ptr<ASTBackupQuery> & restore_query,
|
const std::shared_ptr<ASTBackupQuery> & restore_query,
|
||||||
const BackupOperationID & restore_id,
|
const BackupOperationID & restore_id,
|
||||||
const String & backup_name_for_logging,
|
|
||||||
const BackupInfo & backup_info,
|
const BackupInfo & backup_info,
|
||||||
RestoreSettings restore_settings,
|
RestoreSettings restore_settings,
|
||||||
std::shared_ptr<IRestoreCoordination> restore_coordination,
|
std::shared_ptr<IRestoreCoordination> restore_coordination,
|
||||||
|
@ -20,29 +20,27 @@ class IBackupCoordination
|
|||||||
public:
|
public:
|
||||||
virtual ~IBackupCoordination() = default;
|
virtual ~IBackupCoordination() = default;
|
||||||
|
|
||||||
|
/// Sets that the backup query was sent to other hosts.
|
||||||
|
/// Function waitOtherHostsFinish() will check that to find out if it should really wait or not.
|
||||||
|
virtual void setBackupQueryIsSentToOtherHosts() = 0;
|
||||||
|
virtual bool isBackupQuerySentToOtherHosts() const = 0;
|
||||||
|
|
||||||
/// Sets the current stage and waits for other hosts to come to this stage too.
|
/// Sets the current stage and waits for other hosts to come to this stage too.
|
||||||
virtual Strings setStage(const String & new_stage, const String & message, bool sync) = 0;
|
virtual Strings setStage(const String & new_stage, const String & message, bool sync) = 0;
|
||||||
|
|
||||||
/// Sets that the backup query was sent to other hosts.
|
|
||||||
/// Function waitForOtherHostsToFinish() will check that to find out if it should really wait or not.
|
|
||||||
virtual void setBackupQueryWasSentToOtherHosts() = 0;
|
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has encountered an error.
|
/// Lets other hosts know that the current host has encountered an error.
|
||||||
virtual bool trySetError(std::exception_ptr exception) = 0;
|
/// Returns true if the information is successfully passed so other hosts can read it.
|
||||||
|
virtual bool setError(std::exception_ptr exception, bool throw_if_error) = 0;
|
||||||
/// Lets other hosts know that the current host has finished its work.
|
|
||||||
virtual void finish() = 0;
|
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has finished its work (as a part of error-handling process).
|
|
||||||
virtual bool tryFinishAfterError() noexcept = 0;
|
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work.
|
/// Waits until all the other hosts finish their work.
|
||||||
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
||||||
virtual void waitForOtherHostsToFinish() = 0;
|
virtual bool waitOtherHostsFinish(bool throw_if_error) const = 0;
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work (as a part of error-handling process).
|
/// Lets other hosts know that the current host has finished its work.
|
||||||
/// Doesn't stops waiting if some host encounters an error or gets cancelled.
|
virtual bool finish(bool throw_if_error) = 0;
|
||||||
virtual bool tryWaitForOtherHostsToFinishAfterError() noexcept = 0;
|
|
||||||
|
/// Removes temporary nodes in ZooKeeper.
|
||||||
|
virtual bool cleanup(bool throw_if_error) = 0;
|
||||||
|
|
||||||
struct PartNameAndChecksum
|
struct PartNameAndChecksum
|
||||||
{
|
{
|
||||||
|
@ -18,29 +18,27 @@ class IRestoreCoordination
|
|||||||
public:
|
public:
|
||||||
virtual ~IRestoreCoordination() = default;
|
virtual ~IRestoreCoordination() = default;
|
||||||
|
|
||||||
|
/// Sets that the restore query was sent to other hosts.
|
||||||
|
/// Function waitOtherHostsFinish() will check that to find out if it should really wait or not.
|
||||||
|
virtual void setRestoreQueryIsSentToOtherHosts() = 0;
|
||||||
|
virtual bool isRestoreQuerySentToOtherHosts() const = 0;
|
||||||
|
|
||||||
/// Sets the current stage and waits for other hosts to come to this stage too.
|
/// Sets the current stage and waits for other hosts to come to this stage too.
|
||||||
virtual Strings setStage(const String & new_stage, const String & message, bool sync) = 0;
|
virtual Strings setStage(const String & new_stage, const String & message, bool sync) = 0;
|
||||||
|
|
||||||
/// Sets that the restore query was sent to other hosts.
|
|
||||||
/// Function waitForOtherHostsToFinish() will check that to find out if it should really wait or not.
|
|
||||||
virtual void setRestoreQueryWasSentToOtherHosts() = 0;
|
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has encountered an error.
|
/// Lets other hosts know that the current host has encountered an error.
|
||||||
virtual bool trySetError(std::exception_ptr exception) = 0;
|
/// Returns true if the information is successfully passed so other hosts can read it.
|
||||||
|
virtual bool setError(std::exception_ptr exception, bool throw_if_error) = 0;
|
||||||
/// Lets other hosts know that the current host has finished its work.
|
|
||||||
virtual void finish() = 0;
|
|
||||||
|
|
||||||
/// Lets other hosts know that the current host has finished its work (as a part of error-handling process).
|
|
||||||
virtual bool tryFinishAfterError() noexcept = 0;
|
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work.
|
/// Waits until all the other hosts finish their work.
|
||||||
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
/// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled.
|
||||||
virtual void waitForOtherHostsToFinish() = 0;
|
virtual bool waitOtherHostsFinish(bool throw_if_error) const = 0;
|
||||||
|
|
||||||
/// Waits until all the other hosts finish their work (as a part of error-handling process).
|
/// Lets other hosts know that the current host has finished its work.
|
||||||
/// Doesn't stops waiting if some host encounters an error or gets cancelled.
|
virtual bool finish(bool throw_if_error) = 0;
|
||||||
virtual bool tryWaitForOtherHostsToFinishAfterError() noexcept = 0;
|
|
||||||
|
/// Removes temporary nodes in ZooKeeper.
|
||||||
|
virtual bool cleanup(bool throw_if_error) = 0;
|
||||||
|
|
||||||
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
||||||
virtual bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) = 0;
|
virtual bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) = 0;
|
||||||
|
@ -10,9 +10,9 @@ namespace DB
|
|||||||
{
|
{
|
||||||
|
|
||||||
RestoreCoordinationLocal::RestoreCoordinationLocal(
|
RestoreCoordinationLocal::RestoreCoordinationLocal(
|
||||||
const UUID & restore_uuid, bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_)
|
bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_)
|
||||||
: log(getLogger("RestoreCoordinationLocal"))
|
: log(getLogger("RestoreCoordinationLocal"))
|
||||||
, concurrency_check(restore_uuid, /* is_restore = */ true, /* on_cluster = */ false, allow_concurrent_restore_, concurrency_counters_)
|
, concurrency_check(/* is_restore = */ true, /* on_cluster = */ false, /* zookeeper_path = */ "", allow_concurrent_restore_, concurrency_counters_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,16 +17,16 @@ class ASTCreateQuery;
|
|||||||
class RestoreCoordinationLocal : public IRestoreCoordination
|
class RestoreCoordinationLocal : public IRestoreCoordination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RestoreCoordinationLocal(const UUID & restore_uuid_, bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_);
|
RestoreCoordinationLocal(bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_);
|
||||||
~RestoreCoordinationLocal() override;
|
~RestoreCoordinationLocal() override;
|
||||||
|
|
||||||
|
void setRestoreQueryIsSentToOtherHosts() override {}
|
||||||
|
bool isRestoreQuerySentToOtherHosts() const override { return false; }
|
||||||
Strings setStage(const String &, const String &, bool) override { return {}; }
|
Strings setStage(const String &, const String &, bool) override { return {}; }
|
||||||
void setRestoreQueryWasSentToOtherHosts() override {}
|
bool setError(std::exception_ptr, bool) override { return true; }
|
||||||
bool trySetError(std::exception_ptr) override { return true; }
|
bool waitOtherHostsFinish(bool) const override { return true; }
|
||||||
void finish() override {}
|
bool finish(bool) override { return true; }
|
||||||
bool tryFinishAfterError() noexcept override { return true; }
|
bool cleanup(bool) override { return true; }
|
||||||
void waitForOtherHostsToFinish() override {}
|
|
||||||
bool tryWaitForOtherHostsToFinishAfterError() noexcept override { return true; }
|
|
||||||
|
|
||||||
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
||||||
bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) override;
|
bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) override;
|
||||||
|
@ -35,17 +35,21 @@ RestoreCoordinationOnCluster::RestoreCoordinationOnCluster(
|
|||||||
, current_host_index(BackupCoordinationOnCluster::findCurrentHostIndex(current_host, all_hosts))
|
, current_host_index(BackupCoordinationOnCluster::findCurrentHostIndex(current_host, all_hosts))
|
||||||
, log(getLogger("RestoreCoordinationOnCluster"))
|
, log(getLogger("RestoreCoordinationOnCluster"))
|
||||||
, with_retries(log, get_zookeeper_, keeper_settings, process_list_element_, [root_zookeeper_path_](Coordination::ZooKeeperWithFaultInjection::Ptr zk) { zk->sync(root_zookeeper_path_); })
|
, with_retries(log, get_zookeeper_, keeper_settings, process_list_element_, [root_zookeeper_path_](Coordination::ZooKeeperWithFaultInjection::Ptr zk) { zk->sync(root_zookeeper_path_); })
|
||||||
, concurrency_check(restore_uuid_, /* is_restore = */ true, /* on_cluster = */ true, allow_concurrent_restore_, concurrency_counters_)
|
, cleaner(/* is_restore = */ true, zookeeper_path, with_retries, log)
|
||||||
, stage_sync(/* is_restore = */ true, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_restore_, with_retries, schedule_, process_list_element_, log)
|
, stage_sync(/* is_restore = */ true, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_restore_, concurrency_counters_, with_retries, schedule_, process_list_element_, log)
|
||||||
, cleaner(zookeeper_path, with_retries, log)
|
|
||||||
{
|
{
|
||||||
createRootNodes();
|
try
|
||||||
|
{
|
||||||
|
createRootNodes();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
stage_sync.setError(std::current_exception(), /* throw_if_error = */ false);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RestoreCoordinationOnCluster::~RestoreCoordinationOnCluster()
|
RestoreCoordinationOnCluster::~RestoreCoordinationOnCluster() = default;
|
||||||
{
|
|
||||||
tryFinishImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestoreCoordinationOnCluster::createRootNodes()
|
void RestoreCoordinationOnCluster::createRootNodes()
|
||||||
{
|
{
|
||||||
@ -66,69 +70,52 @@ void RestoreCoordinationOnCluster::createRootNodes()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RestoreCoordinationOnCluster::setRestoreQueryIsSentToOtherHosts()
|
||||||
|
{
|
||||||
|
stage_sync.setQueryIsSentToOtherHosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RestoreCoordinationOnCluster::isRestoreQuerySentToOtherHosts() const
|
||||||
|
{
|
||||||
|
return stage_sync.isQuerySentToOtherHosts();
|
||||||
|
}
|
||||||
|
|
||||||
Strings RestoreCoordinationOnCluster::setStage(const String & new_stage, const String & message, bool sync)
|
Strings RestoreCoordinationOnCluster::setStage(const String & new_stage, const String & message, bool sync)
|
||||||
{
|
{
|
||||||
stage_sync.setStage(new_stage, message);
|
stage_sync.setStage(new_stage, message);
|
||||||
|
if (sync)
|
||||||
if (!sync)
|
return stage_sync.waitHostsReachStage(all_hosts_without_initiator, new_stage);
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return stage_sync.waitForHostsToReachStage(new_stage, all_hosts_without_initiator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestoreCoordinationOnCluster::setRestoreQueryWasSentToOtherHosts()
|
bool RestoreCoordinationOnCluster::setError(std::exception_ptr exception, bool throw_if_error)
|
||||||
{
|
{
|
||||||
restore_query_was_sent_to_other_hosts = true;
|
return stage_sync.setError(exception, throw_if_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RestoreCoordinationOnCluster::trySetError(std::exception_ptr exception)
|
bool RestoreCoordinationOnCluster::waitOtherHostsFinish(bool throw_if_error) const
|
||||||
{
|
{
|
||||||
return stage_sync.trySetError(exception);
|
return stage_sync.waitOtherHostsFinish(throw_if_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestoreCoordinationOnCluster::finish()
|
bool RestoreCoordinationOnCluster::finish(bool throw_if_error)
|
||||||
{
|
{
|
||||||
bool other_hosts_also_finished = false;
|
return stage_sync.finish(throw_if_error);
|
||||||
stage_sync.finish(other_hosts_also_finished);
|
|
||||||
|
|
||||||
if ((current_host == kInitiator) && (other_hosts_also_finished || !restore_query_was_sent_to_other_hosts))
|
|
||||||
cleaner.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RestoreCoordinationOnCluster::tryFinishAfterError() noexcept
|
bool RestoreCoordinationOnCluster::cleanup(bool throw_if_error)
|
||||||
{
|
{
|
||||||
return tryFinishImpl();
|
/// All the hosts must finish before we remove the coordination nodes.
|
||||||
}
|
bool expect_other_hosts_finished = stage_sync.isQuerySentToOtherHosts() || !stage_sync.isErrorSet();
|
||||||
|
bool all_hosts_finished = stage_sync.finished() && (stage_sync.otherHostsFinished() || !expect_other_hosts_finished);
|
||||||
bool RestoreCoordinationOnCluster::tryFinishImpl() noexcept
|
if (!all_hosts_finished)
|
||||||
{
|
|
||||||
bool other_hosts_also_finished = false;
|
|
||||||
if (!stage_sync.tryFinishAfterError(other_hosts_also_finished))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((current_host == kInitiator) && (other_hosts_also_finished || !restore_query_was_sent_to_other_hosts))
|
|
||||||
{
|
{
|
||||||
if (!cleaner.tryCleanupAfterError())
|
auto unfinished_hosts = expect_other_hosts_finished ? stage_sync.getUnfinishedHosts() : Strings{current_host};
|
||||||
return false;
|
LOG_INFO(log, "Skipping removing nodes from ZooKeeper because hosts {} didn't finish",
|
||||||
}
|
BackupCoordinationStageSync::getHostsDesc(unfinished_hosts));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestoreCoordinationOnCluster::waitForOtherHostsToFinish()
|
|
||||||
{
|
|
||||||
if ((current_host != kInitiator) || !restore_query_was_sent_to_other_hosts)
|
|
||||||
return;
|
|
||||||
stage_sync.waitForOtherHostsToFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RestoreCoordinationOnCluster::tryWaitForOtherHostsToFinishAfterError() noexcept
|
|
||||||
{
|
|
||||||
if (current_host != kInitiator)
|
|
||||||
return false;
|
return false;
|
||||||
if (!restore_query_was_sent_to_other_hosts)
|
}
|
||||||
return true;
|
return cleaner.cleanup(throw_if_error);
|
||||||
return stage_sync.tryWaitForOtherHostsToFinishAfterError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZooKeeperRetriesInfo RestoreCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const
|
ZooKeeperRetriesInfo RestoreCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Backups/IRestoreCoordination.h>
|
#include <Backups/IRestoreCoordination.h>
|
||||||
#include <Backups/BackupConcurrencyCheck.h>
|
|
||||||
#include <Backups/BackupCoordinationCleaner.h>
|
#include <Backups/BackupCoordinationCleaner.h>
|
||||||
#include <Backups/BackupCoordinationStageSync.h>
|
#include <Backups/BackupCoordinationStageSync.h>
|
||||||
#include <Backups/WithRetries.h>
|
#include <Backups/WithRetries.h>
|
||||||
@ -15,7 +14,7 @@ class RestoreCoordinationOnCluster : public IRestoreCoordination
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Empty string as the current host is used to mark the initiator of a RESTORE ON CLUSTER query.
|
/// Empty string as the current host is used to mark the initiator of a RESTORE ON CLUSTER query.
|
||||||
static const constexpr std::string_view kInitiator;
|
static const constexpr std::string_view kInitiator = BackupCoordinationStageSync::kInitiator;
|
||||||
|
|
||||||
RestoreCoordinationOnCluster(
|
RestoreCoordinationOnCluster(
|
||||||
const UUID & restore_uuid_,
|
const UUID & restore_uuid_,
|
||||||
@ -31,13 +30,13 @@ public:
|
|||||||
|
|
||||||
~RestoreCoordinationOnCluster() override;
|
~RestoreCoordinationOnCluster() override;
|
||||||
|
|
||||||
|
void setRestoreQueryIsSentToOtherHosts() override;
|
||||||
|
bool isRestoreQuerySentToOtherHosts() const override;
|
||||||
Strings setStage(const String & new_stage, const String & message, bool sync) override;
|
Strings setStage(const String & new_stage, const String & message, bool sync) override;
|
||||||
void setRestoreQueryWasSentToOtherHosts() override;
|
bool setError(std::exception_ptr exception, bool throw_if_error) override;
|
||||||
bool trySetError(std::exception_ptr exception) override;
|
bool waitOtherHostsFinish(bool throw_if_error) const override;
|
||||||
void finish() override;
|
bool finish(bool throw_if_error) override;
|
||||||
bool tryFinishAfterError() noexcept override;
|
bool cleanup(bool throw_if_error) override;
|
||||||
void waitForOtherHostsToFinish() override;
|
|
||||||
bool tryWaitForOtherHostsToFinishAfterError() noexcept override;
|
|
||||||
|
|
||||||
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
/// Starts creating a table in a replicated database. Returns false if there is another host which is already creating this table.
|
||||||
bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) override;
|
bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) override;
|
||||||
@ -78,11 +77,10 @@ private:
|
|||||||
const size_t current_host_index;
|
const size_t current_host_index;
|
||||||
LoggerPtr const log;
|
LoggerPtr const log;
|
||||||
|
|
||||||
|
/// The order is important: `stage_sync` must be initialized after `with_retries` and `cleaner`.
|
||||||
const WithRetries with_retries;
|
const WithRetries with_retries;
|
||||||
BackupConcurrencyCheck concurrency_check;
|
|
||||||
BackupCoordinationStageSync stage_sync;
|
|
||||||
BackupCoordinationCleaner cleaner;
|
BackupCoordinationCleaner cleaner;
|
||||||
std::atomic<bool> restore_query_was_sent_to_other_hosts = false;
|
BackupCoordinationStageSync stage_sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,15 +68,16 @@
|
|||||||
#include <Access/AccessControl.h>
|
#include <Access/AccessControl.h>
|
||||||
#include <Storages/ColumnsDescription.h>
|
#include <Storages/ColumnsDescription.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
#include <Common/config_version.h>
|
#include <Common/config_version.h>
|
||||||
#include <base/find_symbols.h>
|
#include <base/find_symbols.h>
|
||||||
@ -441,9 +442,15 @@ void ClientBase::onData(Block & block, ASTPtr parsed_query)
|
|||||||
|
|
||||||
/// If results are written INTO OUTFILE, we can avoid clearing progress to avoid flicker.
|
/// If results are written INTO OUTFILE, we can avoid clearing progress to avoid flicker.
|
||||||
if (need_render_progress && tty_buf && (!select_into_file || select_into_file_and_stdout))
|
if (need_render_progress && tty_buf && (!select_into_file || select_into_file_and_stdout))
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf && (!select_into_file || select_into_file_and_stdout))
|
if (need_render_progress_table && tty_buf && (!select_into_file || select_into_file_and_stdout))
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -464,13 +471,15 @@ void ClientBase::onData(Block & block, ASTPtr parsed_query)
|
|||||||
{
|
{
|
||||||
if (select_into_file && !select_into_file_and_stdout)
|
if (select_into_file && !select_into_file_and_stdout)
|
||||||
error_stream << "\r";
|
error_stream << "\r";
|
||||||
progress_indication.writeProgress(*tty_buf);
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.writeProgress(*tty_buf, lock);
|
||||||
}
|
}
|
||||||
if (need_render_progress_table && tty_buf && !cancelled)
|
if (need_render_progress_table && tty_buf && !cancelled)
|
||||||
{
|
{
|
||||||
if (!need_render_progress && select_into_file && !select_into_file_and_stdout)
|
if (!need_render_progress && select_into_file && !select_into_file_and_stdout)
|
||||||
error_stream << "\r";
|
error_stream << "\r";
|
||||||
progress_table.writeTable(*tty_buf, progress_table_toggle_on.load(), progress_table_toggle_enabled);
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.writeTable(*tty_buf, lock, progress_table_toggle_on.load(), progress_table_toggle_enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,9 +488,15 @@ void ClientBase::onLogData(Block & block)
|
|||||||
{
|
{
|
||||||
initLogsOutputStream();
|
initLogsOutputStream();
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
logs_out_stream->writeLogs(block);
|
logs_out_stream->writeLogs(block);
|
||||||
logs_out_stream->flush();
|
logs_out_stream->flush();
|
||||||
}
|
}
|
||||||
@ -1151,34 +1166,8 @@ void ClientBase::receiveResult(ASTPtr parsed_query, Int32 signals_before_stop, b
|
|||||||
|
|
||||||
std::exception_ptr local_format_error;
|
std::exception_ptr local_format_error;
|
||||||
|
|
||||||
if (keystroke_interceptor)
|
startKeystrokeInterceptorIfExists();
|
||||||
{
|
SCOPE_EXIT({ stopKeystrokeInterceptorIfExists(); });
|
||||||
progress_table_toggle_on = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
keystroke_interceptor->startIntercept();
|
|
||||||
}
|
|
||||||
catch (const DB::Exception &)
|
|
||||||
{
|
|
||||||
error_stream << getCurrentExceptionMessage(false);
|
|
||||||
keystroke_interceptor.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SCOPE_EXIT({
|
|
||||||
if (keystroke_interceptor)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
keystroke_interceptor->stopIntercept();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
error_stream << getCurrentExceptionMessage(false);
|
|
||||||
keystroke_interceptor.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -1318,7 +1307,10 @@ void ClientBase::onProgress(const Progress & value)
|
|||||||
output_format->onProgress(value);
|
output_format->onProgress(value);
|
||||||
|
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.writeProgress(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.writeProgress(*tty_buf, lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientBase::onTimezoneUpdate(const String & tz)
|
void ClientBase::onTimezoneUpdate(const String & tz)
|
||||||
@ -1330,9 +1322,15 @@ void ClientBase::onTimezoneUpdate(const String & tz)
|
|||||||
void ClientBase::onEndOfStream()
|
void ClientBase::onEndOfStream()
|
||||||
{
|
{
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (output_format)
|
if (output_format)
|
||||||
{
|
{
|
||||||
@ -1414,11 +1412,15 @@ void ClientBase::onProfileEvents(Block & block)
|
|||||||
progress_table.updateTable(block);
|
progress_table.updateTable(block);
|
||||||
|
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.writeProgress(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.writeProgress(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf && !cancelled)
|
if (need_render_progress_table && tty_buf && !cancelled)
|
||||||
{
|
{
|
||||||
bool toggle_enabled = getClientConfiguration().getBool("enable-progress-table-toggle", true);
|
bool toggle_enabled = getClientConfiguration().getBool("enable-progress-table-toggle", true);
|
||||||
progress_table.writeTable(*tty_buf, progress_table_toggle_on.load(), toggle_enabled);
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.writeTable(*tty_buf, lock, progress_table_toggle_on.load(), toggle_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile_events.print)
|
if (profile_events.print)
|
||||||
@ -1429,9 +1431,15 @@ void ClientBase::onProfileEvents(Block & block)
|
|||||||
profile_events.watch.restart();
|
profile_events.watch.restart();
|
||||||
initLogsOutputStream();
|
initLogsOutputStream();
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
logs_out_stream->writeProfileEvents(block);
|
logs_out_stream->writeProfileEvents(block);
|
||||||
logs_out_stream->flush();
|
logs_out_stream->flush();
|
||||||
|
|
||||||
@ -1450,7 +1458,10 @@ void ClientBase::onProfileEvents(Block & block)
|
|||||||
void ClientBase::resetOutput()
|
void ClientBase::resetOutput()
|
||||||
{
|
{
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
|
|
||||||
/// Order is important: format, compression, file
|
/// Order is important: format, compression, file
|
||||||
|
|
||||||
@ -1619,6 +1630,9 @@ void ClientBase::processInsertQuery(const String & query_to_execute, ASTPtr pars
|
|||||||
if (send_external_tables)
|
if (send_external_tables)
|
||||||
sendExternalTables(parsed_query);
|
sendExternalTables(parsed_query);
|
||||||
|
|
||||||
|
startKeystrokeInterceptorIfExists();
|
||||||
|
SCOPE_EXIT({ stopKeystrokeInterceptorIfExists(); });
|
||||||
|
|
||||||
/// Receive description of table structure.
|
/// Receive description of table structure.
|
||||||
Block sample;
|
Block sample;
|
||||||
ColumnsDescription columns_description;
|
ColumnsDescription columns_description;
|
||||||
@ -1665,7 +1679,7 @@ void ClientBase::sendData(Block & sample, const ColumnsDescription & columns_des
|
|||||||
|
|
||||||
/// Set callback to be called on file progress.
|
/// Set callback to be called on file progress.
|
||||||
if (tty_buf)
|
if (tty_buf)
|
||||||
progress_indication.setFileProgressCallback(client_context, *tty_buf);
|
progress_indication.setFileProgressCallback(client_context, *tty_buf, tty_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If data fetched from file (maybe compressed file)
|
/// If data fetched from file (maybe compressed file)
|
||||||
@ -1947,9 +1961,15 @@ void ClientBase::cancelQuery()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_interactive)
|
if (is_interactive)
|
||||||
output_stream << "Cancelling query." << std::endl;
|
output_stream << "Cancelling query." << std::endl;
|
||||||
@ -2112,9 +2132,15 @@ void ClientBase::processParsedSingleQuery(const String & full_query, const Strin
|
|||||||
{
|
{
|
||||||
initLogsOutputStream();
|
initLogsOutputStream();
|
||||||
if (need_render_progress && tty_buf)
|
if (need_render_progress && tty_buf)
|
||||||
progress_indication.clearProgressOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_indication.clearProgressOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
if (need_render_progress_table && tty_buf)
|
if (need_render_progress_table && tty_buf)
|
||||||
progress_table.clearTableOutput(*tty_buf);
|
{
|
||||||
|
std::unique_lock lock(tty_mutex);
|
||||||
|
progress_table.clearTableOutput(*tty_buf, lock);
|
||||||
|
}
|
||||||
logs_out_stream->writeProfileEvents(profile_events.last_block);
|
logs_out_stream->writeProfileEvents(profile_events.last_block);
|
||||||
logs_out_stream->flush();
|
logs_out_stream->flush();
|
||||||
|
|
||||||
@ -2613,6 +2639,39 @@ bool ClientBase::addMergeTreeSettings(ASTCreateQuery & ast_create)
|
|||||||
return added_new_setting;
|
return added_new_setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientBase::startKeystrokeInterceptorIfExists()
|
||||||
|
{
|
||||||
|
if (keystroke_interceptor)
|
||||||
|
{
|
||||||
|
progress_table_toggle_on = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
keystroke_interceptor->startIntercept();
|
||||||
|
}
|
||||||
|
catch (const DB::Exception &)
|
||||||
|
{
|
||||||
|
error_stream << getCurrentExceptionMessage(false);
|
||||||
|
keystroke_interceptor.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientBase::stopKeystrokeInterceptorIfExists()
|
||||||
|
{
|
||||||
|
if (keystroke_interceptor)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
keystroke_interceptor->stopIntercept();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
error_stream << getCurrentExceptionMessage(false);
|
||||||
|
keystroke_interceptor.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientBase::runInteractive()
|
void ClientBase::runInteractive()
|
||||||
{
|
{
|
||||||
if (getClientConfiguration().has("query_id"))
|
if (getClientConfiguration().has("query_id"))
|
||||||
|
@ -208,6 +208,9 @@ private:
|
|||||||
void initQueryIdFormats();
|
void initQueryIdFormats();
|
||||||
bool addMergeTreeSettings(ASTCreateQuery & ast_create);
|
bool addMergeTreeSettings(ASTCreateQuery & ast_create);
|
||||||
|
|
||||||
|
void startKeystrokeInterceptorIfExists();
|
||||||
|
void stopKeystrokeInterceptorIfExists();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
class QueryInterruptHandler : private boost::noncopyable
|
class QueryInterruptHandler : private boost::noncopyable
|
||||||
@ -325,6 +328,7 @@ protected:
|
|||||||
/// /dev/tty if accessible or std::cerr - for progress bar.
|
/// /dev/tty if accessible or std::cerr - for progress bar.
|
||||||
/// We prefer to output progress bar directly to tty to allow user to redirect stdout and stderr and still get the progress indication.
|
/// We prefer to output progress bar directly to tty to allow user to redirect stdout and stderr and still get the progress indication.
|
||||||
std::unique_ptr<WriteBufferFromFileDescriptor> tty_buf;
|
std::unique_ptr<WriteBufferFromFileDescriptor> tty_buf;
|
||||||
|
std::mutex tty_mutex;
|
||||||
|
|
||||||
String home_path;
|
String home_path;
|
||||||
String history_file; /// Path to a file containing command history.
|
String history_file; /// Path to a file containing command history.
|
||||||
|
@ -140,8 +140,6 @@ void highlight(const String & query, std::vector<replxx::Replxx::Color> & colors
|
|||||||
/// We don't do highlighting for foreign dialects, such as PRQL and Kusto.
|
/// We don't do highlighting for foreign dialects, such as PRQL and Kusto.
|
||||||
/// Only normal ClickHouse SQL queries are highlighted.
|
/// Only normal ClickHouse SQL queries are highlighted.
|
||||||
|
|
||||||
/// Currently we highlight only the first query in the multi-query mode.
|
|
||||||
|
|
||||||
ParserQuery parser(end, false, context.getSettingsRef()[Setting::implicit_select]);
|
ParserQuery parser(end, false, context.getSettingsRef()[Setting::implicit_select]);
|
||||||
ASTPtr ast;
|
ASTPtr ast;
|
||||||
bool parse_res = false;
|
bool parse_res = false;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <Common/formatReadable.h>
|
#include <Common/formatReadable.h>
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <mutex>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@ -192,7 +193,8 @@ void writeWithWidthStrict(Out & out, std::string_view s, size_t width)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressTable::writeTable(WriteBufferFromFileDescriptor & message, bool show_table, bool toggle_enabled)
|
void ProgressTable::writeTable(
|
||||||
|
WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> &, bool show_table, bool toggle_enabled)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
if (!show_table && toggle_enabled)
|
if (!show_table && toggle_enabled)
|
||||||
@ -360,7 +362,7 @@ void ProgressTable::updateTable(const Block & block)
|
|||||||
written_first_block = true;
|
written_first_block = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressTable::clearTableOutput(WriteBufferFromFileDescriptor & message)
|
void ProgressTable::clearTableOutput(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> &)
|
||||||
{
|
{
|
||||||
message << "\r" << CLEAR_TO_END_OF_SCREEN << SHOW_CURSOR;
|
message << "\r" << CLEAR_TO_END_OF_SCREEN << SHOW_CURSOR;
|
||||||
message.next();
|
message.next();
|
||||||
|
@ -27,8 +27,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write progress table with metrics.
|
/// Write progress table with metrics.
|
||||||
void writeTable(WriteBufferFromFileDescriptor & message, bool show_table, bool toggle_enabled);
|
void writeTable(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> & message_lock,
|
||||||
void clearTableOutput(WriteBufferFromFileDescriptor & message);
|
bool show_table, bool toggle_enabled);
|
||||||
|
void clearTableOutput(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> & message_lock);
|
||||||
void writeFinalTable();
|
void writeFinalTable();
|
||||||
|
|
||||||
/// Update the metric values. They can be updated from:
|
/// Update the metric values. They can be updated from:
|
||||||
|
@ -662,6 +662,8 @@ ColumnPtr ColumnArray::filter(const Filter & filt, ssize_t result_size_hint) con
|
|||||||
return filterNumber<Int128>(filt, result_size_hint);
|
return filterNumber<Int128>(filt, result_size_hint);
|
||||||
if (typeid_cast<const ColumnInt256 *>(data.get()))
|
if (typeid_cast<const ColumnInt256 *>(data.get()))
|
||||||
return filterNumber<Int256>(filt, result_size_hint);
|
return filterNumber<Int256>(filt, result_size_hint);
|
||||||
|
if (typeid_cast<const ColumnBFloat16 *>(data.get()))
|
||||||
|
return filterNumber<BFloat16>(filt, result_size_hint);
|
||||||
if (typeid_cast<const ColumnFloat32 *>(data.get()))
|
if (typeid_cast<const ColumnFloat32 *>(data.get()))
|
||||||
return filterNumber<Float32>(filt, result_size_hint);
|
return filterNumber<Float32>(filt, result_size_hint);
|
||||||
if (typeid_cast<const ColumnFloat64 *>(data.get()))
|
if (typeid_cast<const ColumnFloat64 *>(data.get()))
|
||||||
@ -1065,6 +1067,8 @@ ColumnPtr ColumnArray::replicate(const Offsets & replicate_offsets) const
|
|||||||
return replicateNumber<Int128>(replicate_offsets);
|
return replicateNumber<Int128>(replicate_offsets);
|
||||||
if (typeid_cast<const ColumnInt256 *>(data.get()))
|
if (typeid_cast<const ColumnInt256 *>(data.get()))
|
||||||
return replicateNumber<Int256>(replicate_offsets);
|
return replicateNumber<Int256>(replicate_offsets);
|
||||||
|
if (typeid_cast<const ColumnBFloat16 *>(data.get()))
|
||||||
|
return replicateNumber<BFloat16>(replicate_offsets);
|
||||||
if (typeid_cast<const ColumnFloat32 *>(data.get()))
|
if (typeid_cast<const ColumnFloat32 *>(data.get()))
|
||||||
return replicateNumber<Float32>(replicate_offsets);
|
return replicateNumber<Float32>(replicate_offsets);
|
||||||
if (typeid_cast<const ColumnFloat64 *>(data.get()))
|
if (typeid_cast<const ColumnFloat64 *>(data.get()))
|
||||||
|
@ -16,6 +16,7 @@ template class ColumnUnique<ColumnInt128>;
|
|||||||
template class ColumnUnique<ColumnUInt128>;
|
template class ColumnUnique<ColumnUInt128>;
|
||||||
template class ColumnUnique<ColumnInt256>;
|
template class ColumnUnique<ColumnInt256>;
|
||||||
template class ColumnUnique<ColumnUInt256>;
|
template class ColumnUnique<ColumnUInt256>;
|
||||||
|
template class ColumnUnique<ColumnBFloat16>;
|
||||||
template class ColumnUnique<ColumnFloat32>;
|
template class ColumnUnique<ColumnFloat32>;
|
||||||
template class ColumnUnique<ColumnFloat64>;
|
template class ColumnUnique<ColumnFloat64>;
|
||||||
template class ColumnUnique<ColumnString>;
|
template class ColumnUnique<ColumnString>;
|
||||||
|
@ -760,6 +760,7 @@ extern template class ColumnUnique<ColumnInt128>;
|
|||||||
extern template class ColumnUnique<ColumnUInt128>;
|
extern template class ColumnUnique<ColumnUInt128>;
|
||||||
extern template class ColumnUnique<ColumnInt256>;
|
extern template class ColumnUnique<ColumnInt256>;
|
||||||
extern template class ColumnUnique<ColumnUInt256>;
|
extern template class ColumnUnique<ColumnUInt256>;
|
||||||
|
extern template class ColumnUnique<ColumnBFloat16>;
|
||||||
extern template class ColumnUnique<ColumnFloat32>;
|
extern template class ColumnUnique<ColumnFloat32>;
|
||||||
extern template class ColumnUnique<ColumnFloat64>;
|
extern template class ColumnUnique<ColumnFloat64>;
|
||||||
extern template class ColumnUnique<ColumnString>;
|
extern template class ColumnUnique<ColumnString>;
|
||||||
|
@ -118,9 +118,9 @@ struct ColumnVector<T>::less_stable
|
|||||||
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
||||||
return lhs < rhs;
|
return lhs < rhs;
|
||||||
|
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
{
|
{
|
||||||
if (unlikely(std::isnan(parent.data[lhs]) && std::isnan(parent.data[rhs])))
|
if (unlikely(isNaN(parent.data[lhs]) && isNaN(parent.data[rhs])))
|
||||||
{
|
{
|
||||||
return lhs < rhs;
|
return lhs < rhs;
|
||||||
}
|
}
|
||||||
@ -150,9 +150,9 @@ struct ColumnVector<T>::greater_stable
|
|||||||
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
if (unlikely(parent.data[lhs] == parent.data[rhs]))
|
||||||
return lhs < rhs;
|
return lhs < rhs;
|
||||||
|
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
{
|
{
|
||||||
if (unlikely(std::isnan(parent.data[lhs]) && std::isnan(parent.data[rhs])))
|
if (unlikely(isNaN(parent.data[lhs]) && isNaN(parent.data[rhs])))
|
||||||
{
|
{
|
||||||
return lhs < rhs;
|
return lhs < rhs;
|
||||||
}
|
}
|
||||||
@ -224,9 +224,9 @@ void ColumnVector<T>::getPermutation(IColumn::PermutationSortDirection direction
|
|||||||
|
|
||||||
iota(res.data(), data_size, IColumn::Permutation::value_type(0));
|
iota(res.data(), data_size, IColumn::Permutation::value_type(0));
|
||||||
|
|
||||||
if constexpr (has_find_extreme_implementation<T> && !std::is_floating_point_v<T>)
|
if constexpr (has_find_extreme_implementation<T> && !is_floating_point<T>)
|
||||||
{
|
{
|
||||||
/// Disabled for:floating point
|
/// Disabled for floating point:
|
||||||
/// * floating point: We don't deal with nan_direction_hint
|
/// * floating point: We don't deal with nan_direction_hint
|
||||||
/// * stability::Stable: We might return any value, not the first
|
/// * stability::Stable: We might return any value, not the first
|
||||||
if ((limit == 1) && (stability == IColumn::PermutationSortStability::Unstable))
|
if ((limit == 1) && (stability == IColumn::PermutationSortStability::Unstable))
|
||||||
@ -256,7 +256,7 @@ void ColumnVector<T>::getPermutation(IColumn::PermutationSortDirection direction
|
|||||||
bool sort_is_stable = stability == IColumn::PermutationSortStability::Stable;
|
bool sort_is_stable = stability == IColumn::PermutationSortStability::Stable;
|
||||||
|
|
||||||
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
||||||
bool use_radix_sort = (sort_is_stable && ascending && !std::is_floating_point_v<T>) || !sort_is_stable;
|
bool use_radix_sort = (sort_is_stable && ascending && !is_floating_point<T>) || !sort_is_stable;
|
||||||
|
|
||||||
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
||||||
if (data_size >= 256 && data_size <= std::numeric_limits<UInt32>::max() && use_radix_sort)
|
if (data_size >= 256 && data_size <= std::numeric_limits<UInt32>::max() && use_radix_sort)
|
||||||
@ -283,7 +283,7 @@ void ColumnVector<T>::getPermutation(IColumn::PermutationSortDirection direction
|
|||||||
|
|
||||||
/// Radix sort treats all NaNs to be greater than all numbers.
|
/// Radix sort treats all NaNs to be greater than all numbers.
|
||||||
/// If the user needs the opposite, we must move them accordingly.
|
/// If the user needs the opposite, we must move them accordingly.
|
||||||
if (std::is_floating_point_v<T> && nan_direction_hint < 0)
|
if (is_floating_point<T> && nan_direction_hint < 0)
|
||||||
{
|
{
|
||||||
size_t nans_to_move = 0;
|
size_t nans_to_move = 0;
|
||||||
|
|
||||||
@ -330,7 +330,7 @@ void ColumnVector<T>::updatePermutation(IColumn::PermutationSortDirection direct
|
|||||||
if constexpr (is_arithmetic_v<T> && !is_big_int_v<T>)
|
if constexpr (is_arithmetic_v<T> && !is_big_int_v<T>)
|
||||||
{
|
{
|
||||||
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
/// TODO: LSD RadixSort is currently not stable if direction is descending, or value is floating point
|
||||||
bool use_radix_sort = (sort_is_stable && ascending && !std::is_floating_point_v<T>) || !sort_is_stable;
|
bool use_radix_sort = (sort_is_stable && ascending && !is_floating_point<T>) || !sort_is_stable;
|
||||||
size_t size = end - begin;
|
size_t size = end - begin;
|
||||||
|
|
||||||
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
/// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters.
|
||||||
@ -353,7 +353,7 @@ void ColumnVector<T>::updatePermutation(IColumn::PermutationSortDirection direct
|
|||||||
|
|
||||||
/// Radix sort treats all NaNs to be greater than all numbers.
|
/// Radix sort treats all NaNs to be greater than all numbers.
|
||||||
/// If the user needs the opposite, we must move them accordingly.
|
/// If the user needs the opposite, we must move them accordingly.
|
||||||
if (std::is_floating_point_v<T> && nan_direction_hint < 0)
|
if (is_floating_point<T> && nan_direction_hint < 0)
|
||||||
{
|
{
|
||||||
size_t nans_to_move = 0;
|
size_t nans_to_move = 0;
|
||||||
|
|
||||||
@ -1005,6 +1005,7 @@ template class ColumnVector<Int32>;
|
|||||||
template class ColumnVector<Int64>;
|
template class ColumnVector<Int64>;
|
||||||
template class ColumnVector<Int128>;
|
template class ColumnVector<Int128>;
|
||||||
template class ColumnVector<Int256>;
|
template class ColumnVector<Int256>;
|
||||||
|
template class ColumnVector<BFloat16>;
|
||||||
template class ColumnVector<Float32>;
|
template class ColumnVector<Float32>;
|
||||||
template class ColumnVector<Float64>;
|
template class ColumnVector<Float64>;
|
||||||
template class ColumnVector<UUID>;
|
template class ColumnVector<UUID>;
|
||||||
|
@ -52,6 +52,7 @@ private:
|
|||||||
explicit ColumnVector(const size_t n) : data(n) {}
|
explicit ColumnVector(const size_t n) : data(n) {}
|
||||||
ColumnVector(const size_t n, const ValueType x) : data(n, x) {}
|
ColumnVector(const size_t n, const ValueType x) : data(n, x) {}
|
||||||
ColumnVector(const ColumnVector & src) : data(src.data.begin(), src.data.end()) {}
|
ColumnVector(const ColumnVector & src) : data(src.data.begin(), src.data.end()) {}
|
||||||
|
ColumnVector(Container::const_iterator begin, Container::const_iterator end) : data(begin, end) { }
|
||||||
|
|
||||||
/// Sugar constructor.
|
/// Sugar constructor.
|
||||||
ColumnVector(std::initializer_list<T> il) : data{il} {}
|
ColumnVector(std::initializer_list<T> il) : data{il} {}
|
||||||
@ -481,6 +482,7 @@ extern template class ColumnVector<Int32>;
|
|||||||
extern template class ColumnVector<Int64>;
|
extern template class ColumnVector<Int64>;
|
||||||
extern template class ColumnVector<Int128>;
|
extern template class ColumnVector<Int128>;
|
||||||
extern template class ColumnVector<Int256>;
|
extern template class ColumnVector<Int256>;
|
||||||
|
extern template class ColumnVector<BFloat16>;
|
||||||
extern template class ColumnVector<Float32>;
|
extern template class ColumnVector<Float32>;
|
||||||
extern template class ColumnVector<Float64>;
|
extern template class ColumnVector<Float64>;
|
||||||
extern template class ColumnVector<UUID>;
|
extern template class ColumnVector<UUID>;
|
||||||
|
@ -328,6 +328,7 @@ INSTANTIATE(Int32)
|
|||||||
INSTANTIATE(Int64)
|
INSTANTIATE(Int64)
|
||||||
INSTANTIATE(Int128)
|
INSTANTIATE(Int128)
|
||||||
INSTANTIATE(Int256)
|
INSTANTIATE(Int256)
|
||||||
|
INSTANTIATE(BFloat16)
|
||||||
INSTANTIATE(Float32)
|
INSTANTIATE(Float32)
|
||||||
INSTANTIATE(Float64)
|
INSTANTIATE(Float64)
|
||||||
INSTANTIATE(Decimal32)
|
INSTANTIATE(Decimal32)
|
||||||
|
@ -23,6 +23,7 @@ using ColumnInt64 = ColumnVector<Int64>;
|
|||||||
using ColumnInt128 = ColumnVector<Int128>;
|
using ColumnInt128 = ColumnVector<Int128>;
|
||||||
using ColumnInt256 = ColumnVector<Int256>;
|
using ColumnInt256 = ColumnVector<Int256>;
|
||||||
|
|
||||||
|
using ColumnBFloat16 = ColumnVector<BFloat16>;
|
||||||
using ColumnFloat32 = ColumnVector<Float32>;
|
using ColumnFloat32 = ColumnVector<Float32>;
|
||||||
using ColumnFloat64 = ColumnVector<Float64>;
|
using ColumnFloat64 = ColumnVector<Float64>;
|
||||||
|
|
||||||
|
@ -443,6 +443,7 @@ template class IColumnHelper<ColumnVector<Int32>, ColumnFixedSizeHelper>;
|
|||||||
template class IColumnHelper<ColumnVector<Int64>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<Int64>, ColumnFixedSizeHelper>;
|
||||||
template class IColumnHelper<ColumnVector<Int128>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<Int128>, ColumnFixedSizeHelper>;
|
||||||
template class IColumnHelper<ColumnVector<Int256>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<Int256>, ColumnFixedSizeHelper>;
|
||||||
|
template class IColumnHelper<ColumnVector<BFloat16>, ColumnFixedSizeHelper>;
|
||||||
template class IColumnHelper<ColumnVector<Float32>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<Float32>, ColumnFixedSizeHelper>;
|
||||||
template class IColumnHelper<ColumnVector<Float64>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<Float64>, ColumnFixedSizeHelper>;
|
||||||
template class IColumnHelper<ColumnVector<UUID>, ColumnFixedSizeHelper>;
|
template class IColumnHelper<ColumnVector<UUID>, ColumnFixedSizeHelper>;
|
||||||
|
@ -63,6 +63,7 @@ INSTANTIATE(Int32)
|
|||||||
INSTANTIATE(Int64)
|
INSTANTIATE(Int64)
|
||||||
INSTANTIATE(Int128)
|
INSTANTIATE(Int128)
|
||||||
INSTANTIATE(Int256)
|
INSTANTIATE(Int256)
|
||||||
|
INSTANTIATE(BFloat16)
|
||||||
INSTANTIATE(Float32)
|
INSTANTIATE(Float32)
|
||||||
INSTANTIATE(Float64)
|
INSTANTIATE(Float64)
|
||||||
INSTANTIATE(Decimal32)
|
INSTANTIATE(Decimal32)
|
||||||
@ -200,6 +201,7 @@ static MaskInfo extractMaskImpl(
|
|||||||
|| extractMaskNumeric<inverted, Int16>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
|| extractMaskNumeric<inverted, Int16>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
||||||
|| extractMaskNumeric<inverted, Int32>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
|| extractMaskNumeric<inverted, Int32>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
||||||
|| extractMaskNumeric<inverted, Int64>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
|| extractMaskNumeric<inverted, Int64>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
||||||
|
|| extractMaskNumeric<inverted, BFloat16>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
||||||
|| extractMaskNumeric<inverted, Float32>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
|| extractMaskNumeric<inverted, Float32>(mask, column, null_value, null_bytemap, nulls, mask_info)
|
||||||
|| extractMaskNumeric<inverted, Float64>(mask, column, null_value, null_bytemap, nulls, mask_info)))
|
|| extractMaskNumeric<inverted, Float64>(mask, column, null_value, null_bytemap, nulls, mask_info)))
|
||||||
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot convert column {} to mask.", column->getName());
|
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot convert column {} to mask.", column->getName());
|
||||||
|
@ -93,6 +93,7 @@ TEST(ColumnVector, Filter)
|
|||||||
testFilter<Int64>();
|
testFilter<Int64>();
|
||||||
testFilter<UInt128>();
|
testFilter<UInt128>();
|
||||||
testFilter<Int256>();
|
testFilter<Int256>();
|
||||||
|
testFilter<BFloat16>();
|
||||||
testFilter<Float32>();
|
testFilter<Float32>();
|
||||||
testFilter<Float64>();
|
testFilter<Float64>();
|
||||||
testFilter<UUID>();
|
testFilter<UUID>();
|
||||||
|
@ -45,6 +45,7 @@ TEST(ColumnLowCardinality, Insert)
|
|||||||
testLowCardinalityNumberInsert<Int128>(std::make_shared<DataTypeInt128>());
|
testLowCardinalityNumberInsert<Int128>(std::make_shared<DataTypeInt128>());
|
||||||
testLowCardinalityNumberInsert<Int256>(std::make_shared<DataTypeInt256>());
|
testLowCardinalityNumberInsert<Int256>(std::make_shared<DataTypeInt256>());
|
||||||
|
|
||||||
|
testLowCardinalityNumberInsert<BFloat16>(std::make_shared<DataTypeBFloat16>());
|
||||||
testLowCardinalityNumberInsert<Float32>(std::make_shared<DataTypeFloat32>());
|
testLowCardinalityNumberInsert<Float32>(std::make_shared<DataTypeFloat32>());
|
||||||
testLowCardinalityNumberInsert<Float64>(std::make_shared<DataTypeFloat64>());
|
testLowCardinalityNumberInsert<Float64>(std::make_shared<DataTypeFloat64>());
|
||||||
}
|
}
|
||||||
|
@ -266,6 +266,11 @@ inline bool haveAVX512VBMI2() noexcept
|
|||||||
return haveAVX512F() && ((CPUInfo(0x7, 0).registers.ecx >> 6) & 1u);
|
return haveAVX512F() && ((CPUInfo(0x7, 0).registers.ecx >> 6) & 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool haveAVX512BF16() noexcept
|
||||||
|
{
|
||||||
|
return haveAVX512F() && ((CPUInfo(0x7, 1).registers.eax >> 5) & 1u);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool haveRDRAND() noexcept
|
inline bool haveRDRAND() noexcept
|
||||||
{
|
{
|
||||||
return CPUInfo(0x0).registers.eax >= 0x7 && ((CPUInfo(0x1).registers.ecx >> 30) & 1u);
|
return CPUInfo(0x0).registers.eax >= 0x7 && ((CPUInfo(0x1).registers.ecx >> 30) & 1u);
|
||||||
@ -326,6 +331,7 @@ inline bool haveAMXINT8() noexcept
|
|||||||
OP(AVX512VL) \
|
OP(AVX512VL) \
|
||||||
OP(AVX512VBMI) \
|
OP(AVX512VBMI) \
|
||||||
OP(AVX512VBMI2) \
|
OP(AVX512VBMI2) \
|
||||||
|
OP(AVX512BF16) \
|
||||||
OP(PREFETCHWT1) \
|
OP(PREFETCHWT1) \
|
||||||
OP(SHA) \
|
OP(SHA) \
|
||||||
OP(ADX) \
|
OP(ADX) \
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
M(TemporaryFilesForSort, "Number of temporary files created for external sorting") \
|
M(TemporaryFilesForSort, "Number of temporary files created for external sorting") \
|
||||||
M(TemporaryFilesForAggregation, "Number of temporary files created for external aggregation") \
|
M(TemporaryFilesForAggregation, "Number of temporary files created for external aggregation") \
|
||||||
M(TemporaryFilesForJoin, "Number of temporary files created for JOIN") \
|
M(TemporaryFilesForJoin, "Number of temporary files created for JOIN") \
|
||||||
|
M(TemporaryFilesForMerge, "Number of temporary files for vertical merge") \
|
||||||
M(TemporaryFilesUnknown, "Number of temporary files created without known purpose") \
|
M(TemporaryFilesUnknown, "Number of temporary files created without known purpose") \
|
||||||
M(Read, "Number of read (read, pread, io_getevents, etc.) syscalls in fly") \
|
M(Read, "Number of read (read, pread, io_getevents, etc.) syscalls in fly") \
|
||||||
M(RemoteRead, "Number of read with remote reader in fly") \
|
M(RemoteRead, "Number of read with remote reader in fly") \
|
||||||
@ -255,6 +256,7 @@
|
|||||||
M(PartsActive, "Active data part, used by current and upcoming SELECTs.") \
|
M(PartsActive, "Active data part, used by current and upcoming SELECTs.") \
|
||||||
M(AttachedDatabase, "Active databases.") \
|
M(AttachedDatabase, "Active databases.") \
|
||||||
M(AttachedTable, "Active tables.") \
|
M(AttachedTable, "Active tables.") \
|
||||||
|
M(AttachedReplicatedTable, "Active replicated tables.") \
|
||||||
M(AttachedView, "Active views.") \
|
M(AttachedView, "Active views.") \
|
||||||
M(AttachedDictionary, "Active dictionaries.") \
|
M(AttachedDictionary, "Active dictionaries.") \
|
||||||
M(PartsOutdated, "Not active data part, but could be used by only current SELECTs, could be deleted after SELECTs finishes.") \
|
M(PartsOutdated, "Not active data part, but could be used by only current SELECTs, could be deleted after SELECTs finishes.") \
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -87,6 +86,7 @@ APPLY_FOR_FAILPOINTS(M, M, M, M)
|
|||||||
|
|
||||||
std::unordered_map<String, std::shared_ptr<FailPointChannel>> FailPointInjection::fail_point_wait_channels;
|
std::unordered_map<String, std::shared_ptr<FailPointChannel>> FailPointInjection::fail_point_wait_channels;
|
||||||
std::mutex FailPointInjection::mu;
|
std::mutex FailPointInjection::mu;
|
||||||
|
|
||||||
class FailPointChannel : private boost::noncopyable
|
class FailPointChannel : private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ namespace DB
|
|||||||
/// 3. in test file, we can use system failpoint enable/disable 'failpoint_name'
|
/// 3. in test file, we can use system failpoint enable/disable 'failpoint_name'
|
||||||
|
|
||||||
class FailPointChannel;
|
class FailPointChannel;
|
||||||
|
|
||||||
class FailPointInjection
|
class FailPointInjection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <Common/FieldVisitorConvertToNumber.h>
|
#include <Common/FieldVisitorConvertToNumber.h>
|
||||||
#include "base/Decimal.h"
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -17,6 +16,7 @@ template class FieldVisitorConvertToNumber<Int128>;
|
|||||||
template class FieldVisitorConvertToNumber<UInt128>;
|
template class FieldVisitorConvertToNumber<UInt128>;
|
||||||
template class FieldVisitorConvertToNumber<Int256>;
|
template class FieldVisitorConvertToNumber<Int256>;
|
||||||
template class FieldVisitorConvertToNumber<UInt256>;
|
template class FieldVisitorConvertToNumber<UInt256>;
|
||||||
|
//template class FieldVisitorConvertToNumber<BFloat16>;
|
||||||
template class FieldVisitorConvertToNumber<Float32>;
|
template class FieldVisitorConvertToNumber<Float32>;
|
||||||
template class FieldVisitorConvertToNumber<Float64>;
|
template class FieldVisitorConvertToNumber<Float64>;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
|
|
||||||
T operator() (const Float64 & x) const
|
T operator() (const Float64 & x) const
|
||||||
{
|
{
|
||||||
if constexpr (!std::is_floating_point_v<T>)
|
if constexpr (!is_floating_point<T>)
|
||||||
{
|
{
|
||||||
if (!isFinite(x))
|
if (!isFinite(x))
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ public:
|
|||||||
template <typename U>
|
template <typename U>
|
||||||
T operator() (const DecimalField<U> & x) const
|
T operator() (const DecimalField<U> & x) const
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
return x.getValue().template convertTo<T>() / x.getScaleMultiplier().template convertTo<T>();
|
return x.getValue().template convertTo<T>() / x.getScaleMultiplier().template convertTo<T>();
|
||||||
else
|
else
|
||||||
return (x.getValue() / x.getScaleMultiplier()).template convertTo<T>();
|
return (x.getValue() / x.getScaleMultiplier()).template convertTo<T>();
|
||||||
@ -129,6 +129,7 @@ extern template class FieldVisitorConvertToNumber<Int128>;
|
|||||||
extern template class FieldVisitorConvertToNumber<UInt128>;
|
extern template class FieldVisitorConvertToNumber<UInt128>;
|
||||||
extern template class FieldVisitorConvertToNumber<Int256>;
|
extern template class FieldVisitorConvertToNumber<Int256>;
|
||||||
extern template class FieldVisitorConvertToNumber<UInt256>;
|
extern template class FieldVisitorConvertToNumber<UInt256>;
|
||||||
|
//extern template class FieldVisitorConvertToNumber<BFloat16>;
|
||||||
extern template class FieldVisitorConvertToNumber<Float32>;
|
extern template class FieldVisitorConvertToNumber<Float32>;
|
||||||
extern template class FieldVisitorConvertToNumber<Float64>;
|
extern template class FieldVisitorConvertToNumber<Float64>;
|
||||||
|
|
||||||
|
@ -322,6 +322,7 @@ DEFINE_HASH(Int32)
|
|||||||
DEFINE_HASH(Int64)
|
DEFINE_HASH(Int64)
|
||||||
DEFINE_HASH(Int128)
|
DEFINE_HASH(Int128)
|
||||||
DEFINE_HASH(Int256)
|
DEFINE_HASH(Int256)
|
||||||
|
DEFINE_HASH(BFloat16)
|
||||||
DEFINE_HASH(Float32)
|
DEFINE_HASH(Float32)
|
||||||
DEFINE_HASH(Float64)
|
DEFINE_HASH(Float64)
|
||||||
DEFINE_HASH(DB::UUID)
|
DEFINE_HASH(DB::UUID)
|
||||||
|
@ -76,7 +76,7 @@ struct HashTableNoState
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool bitEquals(T a, T b)
|
inline bool bitEquals(T a, T b)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
/// Note that memcmp with constant size is a compiler builtin.
|
/// Note that memcmp with constant size is a compiler builtin.
|
||||||
return 0 == memcmp(&a, &b, sizeof(T)); /// NOLINT
|
return 0 == memcmp(&a, &b, sizeof(T)); /// NOLINT
|
||||||
else
|
else
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <Poco/Timespan.h>
|
||||||
|
|
||||||
|
|
||||||
namespace ProfileEvents
|
namespace ProfileEvents
|
||||||
@ -49,16 +50,18 @@ HostResolver::WeakPtr HostResolver::getWeakFromThis()
|
|||||||
}
|
}
|
||||||
|
|
||||||
HostResolver::HostResolver(String host_, Poco::Timespan history_)
|
HostResolver::HostResolver(String host_, Poco::Timespan history_)
|
||||||
: host(std::move(host_))
|
: HostResolver(
|
||||||
, history(history_)
|
[](const String & host_to_resolve) { return DNSResolver::instance().resolveHostAllInOriginOrder(host_to_resolve); },
|
||||||
, resolve_function([](const String & host_to_resolve) { return DNSResolver::instance().resolveHostAllInOriginOrder(host_to_resolve); })
|
host_,
|
||||||
{
|
history_)
|
||||||
update();
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
HostResolver::HostResolver(
|
HostResolver::HostResolver(
|
||||||
ResolveFunction && resolve_function_, String host_, Poco::Timespan history_)
|
ResolveFunction && resolve_function_, String host_, Poco::Timespan history_)
|
||||||
: host(std::move(host_)), history(history_), resolve_function(std::move(resolve_function_))
|
: host(std::move(host_))
|
||||||
|
, history(history_)
|
||||||
|
, resolve_interval(history_.totalMicroseconds() / 3)
|
||||||
|
, resolve_function(std::move(resolve_function_))
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -203,7 +206,7 @@ bool HostResolver::isUpdateNeeded()
|
|||||||
Poco::Timestamp now;
|
Poco::Timestamp now;
|
||||||
|
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
return last_resolve_time + history < now || records.empty();
|
return last_resolve_time + resolve_interval < now || records.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostResolver::updateImpl(Poco::Timestamp now, std::vector<Poco::Net::IPAddress> & next_gen)
|
void HostResolver::updateImpl(Poco::Timestamp now, std::vector<Poco::Net::IPAddress> & next_gen)
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
// a) it still occurs in resolve set after `history_` time or b) all other addresses are pessimized as well.
|
// a) it still occurs in resolve set after `history_` time or b) all other addresses are pessimized as well.
|
||||||
// - resolve schedule
|
// - resolve schedule
|
||||||
// Addresses are resolved through `DB::DNSResolver::instance()`.
|
// Addresses are resolved through `DB::DNSResolver::instance()`.
|
||||||
// Usually it does not happen more often than once in `history_` time.
|
// Usually it does not happen more often than 3 times in `history_` period.
|
||||||
// But also new resolve performed each `setFail()` call.
|
// But also new resolve performed each `setFail()` call.
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -212,6 +212,7 @@ protected:
|
|||||||
|
|
||||||
const String host;
|
const String host;
|
||||||
const Poco::Timespan history;
|
const Poco::Timespan history;
|
||||||
|
const Poco::Timespan resolve_interval;
|
||||||
const HostResolverMetrics metrics = getMetrics();
|
const HostResolverMetrics metrics = getMetrics();
|
||||||
|
|
||||||
// for tests purpose
|
// for tests purpose
|
||||||
@ -245,4 +246,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,24 +3,24 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <base/DecomposedFloat.h>
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool isNaN(T x)
|
inline bool isNaN(T x)
|
||||||
{
|
{
|
||||||
/// To be sure, that this function is zero-cost for non-floating point types.
|
/// To be sure, that this function is zero-cost for non-floating point types.
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
return std::isnan(x);
|
return DecomposedFloat(x).isNaN();
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool isFinite(T x)
|
inline bool isFinite(T x)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
return std::isfinite(x);
|
return DecomposedFloat(x).isFinite();
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ inline bool isFinite(T x)
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
bool canConvertTo(Float64 x)
|
bool canConvertTo(Float64 x)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
if constexpr (is_floating_point<T>)
|
||||||
return true;
|
return true;
|
||||||
if (!isFinite(x))
|
if (!isFinite(x))
|
||||||
return false;
|
return false;
|
||||||
@ -46,3 +46,12 @@ T NaNOrZero()
|
|||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool signBit(T x)
|
||||||
|
{
|
||||||
|
if constexpr (is_floating_point<T>)
|
||||||
|
return DecomposedFloat(x).isNegative();
|
||||||
|
else
|
||||||
|
return x < 0;
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -49,12 +50,13 @@ void ProgressIndication::resetProgress()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressIndication::setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message)
|
void ProgressIndication::setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message, std::mutex & message_mutex)
|
||||||
{
|
{
|
||||||
context->setFileProgressCallback([&](const FileProgress & file_progress)
|
context->setFileProgressCallback([&](const FileProgress & file_progress)
|
||||||
{
|
{
|
||||||
progress.incrementPiecewiseAtomically(Progress(file_progress));
|
progress.incrementPiecewiseAtomically(Progress(file_progress));
|
||||||
writeProgress(message);
|
std::unique_lock message_lock(message_mutex);
|
||||||
|
writeProgress(message, message_lock);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ void ProgressIndication::writeFinalProgress()
|
|||||||
output_stream << "\nPeak memory usage: " << formatReadableSizeWithBinarySuffix(peak_memory_usage) << ".";
|
output_stream << "\nPeak memory usage: " << formatReadableSizeWithBinarySuffix(peak_memory_usage) << ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message)
|
void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> &)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(progress_mutex);
|
std::lock_guard lock(progress_mutex);
|
||||||
|
|
||||||
@ -274,7 +276,7 @@ void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message)
|
|||||||
message.next();
|
message.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressIndication::clearProgressOutput(WriteBufferFromFileDescriptor & message)
|
void ProgressIndication::clearProgressOutput(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> &)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(progress_mutex);
|
std::lock_guard lock(progress_mutex);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
@ -47,8 +48,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write progress bar.
|
/// Write progress bar.
|
||||||
void writeProgress(WriteBufferFromFileDescriptor & message);
|
void writeProgress(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> & message_lock);
|
||||||
void clearProgressOutput(WriteBufferFromFileDescriptor & message);
|
void clearProgressOutput(WriteBufferFromFileDescriptor & message, std::unique_lock<std::mutex> & message_lock);
|
||||||
|
|
||||||
/// Write summary.
|
/// Write summary.
|
||||||
void writeFinalProgress();
|
void writeFinalProgress();
|
||||||
@ -67,7 +68,7 @@ public:
|
|||||||
/// In some cases there is a need to update progress value, when there is no access to progress_inidcation object.
|
/// In some cases there is a need to update progress value, when there is no access to progress_inidcation object.
|
||||||
/// In this case it is added via context.
|
/// In this case it is added via context.
|
||||||
/// `write_progress_on_update` is needed to write progress for loading files data via pipe in non-interactive mode.
|
/// `write_progress_on_update` is needed to write progress for loading files data via pipe in non-interactive mode.
|
||||||
void setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message);
|
void setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message, std::mutex & message_mutex);
|
||||||
|
|
||||||
/// How much seconds passed since query execution start.
|
/// How much seconds passed since query execution start.
|
||||||
double elapsedSeconds() const { return getElapsedNanoseconds() / 1e9; }
|
double elapsedSeconds() const { return getElapsedNanoseconds() / 1e9; }
|
||||||
|
@ -23,6 +23,8 @@ UInt32 getSupportedArchs()
|
|||||||
result |= static_cast<UInt32>(TargetArch::AVX512VBMI);
|
result |= static_cast<UInt32>(TargetArch::AVX512VBMI);
|
||||||
if (CPU::CPUFlagsCache::have_AVX512VBMI2)
|
if (CPU::CPUFlagsCache::have_AVX512VBMI2)
|
||||||
result |= static_cast<UInt32>(TargetArch::AVX512VBMI2);
|
result |= static_cast<UInt32>(TargetArch::AVX512VBMI2);
|
||||||
|
if (CPU::CPUFlagsCache::have_AVX512BF16)
|
||||||
|
result |= static_cast<UInt32>(TargetArch::AVX512BF16);
|
||||||
if (CPU::CPUFlagsCache::have_AMXBF16)
|
if (CPU::CPUFlagsCache::have_AMXBF16)
|
||||||
result |= static_cast<UInt32>(TargetArch::AMXBF16);
|
result |= static_cast<UInt32>(TargetArch::AMXBF16);
|
||||||
if (CPU::CPUFlagsCache::have_AMXTILE)
|
if (CPU::CPUFlagsCache::have_AMXTILE)
|
||||||
@ -50,6 +52,7 @@ String toString(TargetArch arch)
|
|||||||
case TargetArch::AVX512BW: return "avx512bw";
|
case TargetArch::AVX512BW: return "avx512bw";
|
||||||
case TargetArch::AVX512VBMI: return "avx512vbmi";
|
case TargetArch::AVX512VBMI: return "avx512vbmi";
|
||||||
case TargetArch::AVX512VBMI2: return "avx512vbmi2";
|
case TargetArch::AVX512VBMI2: return "avx512vbmi2";
|
||||||
|
case TargetArch::AVX512BF16: return "avx512bf16";
|
||||||
case TargetArch::AMXBF16: return "amxbf16";
|
case TargetArch::AMXBF16: return "amxbf16";
|
||||||
case TargetArch::AMXTILE: return "amxtile";
|
case TargetArch::AMXTILE: return "amxtile";
|
||||||
case TargetArch::AMXINT8: return "amxint8";
|
case TargetArch::AMXINT8: return "amxint8";
|
||||||
|
@ -83,9 +83,10 @@ enum class TargetArch : UInt32
|
|||||||
AVX512BW = (1 << 4),
|
AVX512BW = (1 << 4),
|
||||||
AVX512VBMI = (1 << 5),
|
AVX512VBMI = (1 << 5),
|
||||||
AVX512VBMI2 = (1 << 6),
|
AVX512VBMI2 = (1 << 6),
|
||||||
AMXBF16 = (1 << 7),
|
AVX512BF16 = (1 << 7),
|
||||||
AMXTILE = (1 << 8),
|
AMXBF16 = (1 << 8),
|
||||||
AMXINT8 = (1 << 9),
|
AMXTILE = (1 << 9),
|
||||||
|
AMXINT8 = (1 << 10),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Runtime detection.
|
/// Runtime detection.
|
||||||
@ -102,6 +103,7 @@ String toString(TargetArch arch);
|
|||||||
/// NOLINTNEXTLINE
|
/// NOLINTNEXTLINE
|
||||||
#define USE_MULTITARGET_CODE 1
|
#define USE_MULTITARGET_CODE 1
|
||||||
|
|
||||||
|
#define AVX512BF16_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2,avx512bf16")))
|
||||||
#define AVX512VBMI2_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2")))
|
#define AVX512VBMI2_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2")))
|
||||||
#define AVX512VBMI_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi")))
|
#define AVX512VBMI_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi")))
|
||||||
#define AVX512BW_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw")))
|
#define AVX512BW_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw")))
|
||||||
@ -111,6 +113,8 @@ String toString(TargetArch arch);
|
|||||||
#define SSE42_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt")))
|
#define SSE42_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt")))
|
||||||
#define DEFAULT_FUNCTION_SPECIFIC_ATTRIBUTE
|
#define DEFAULT_FUNCTION_SPECIFIC_ATTRIBUTE
|
||||||
|
|
||||||
|
# define BEGIN_AVX512BF16_SPECIFIC_CODE \
|
||||||
|
_Pragma("clang attribute push(__attribute__((target(\"sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2,avx512bf16\"))),apply_to=function)")
|
||||||
# define BEGIN_AVX512VBMI2_SPECIFIC_CODE \
|
# define BEGIN_AVX512VBMI2_SPECIFIC_CODE \
|
||||||
_Pragma("clang attribute push(__attribute__((target(\"sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2\"))),apply_to=function)")
|
_Pragma("clang attribute push(__attribute__((target(\"sse,sse2,sse3,ssse3,sse4,popcnt,avx,avx2,avx512f,avx512bw,avx512vl,avx512vbmi,avx512vbmi2\"))),apply_to=function)")
|
||||||
# define BEGIN_AVX512VBMI_SPECIFIC_CODE \
|
# define BEGIN_AVX512VBMI_SPECIFIC_CODE \
|
||||||
@ -197,6 +201,14 @@ namespace TargetSpecific::AVX512VBMI2 { \
|
|||||||
} \
|
} \
|
||||||
END_TARGET_SPECIFIC_CODE
|
END_TARGET_SPECIFIC_CODE
|
||||||
|
|
||||||
|
#define DECLARE_AVX512BF16_SPECIFIC_CODE(...) \
|
||||||
|
BEGIN_AVX512BF16_SPECIFIC_CODE \
|
||||||
|
namespace TargetSpecific::AVX512BF16 { \
|
||||||
|
DUMMY_FUNCTION_DEFINITION \
|
||||||
|
using namespace DB::TargetSpecific::AVX512BF16; \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
} \
|
||||||
|
END_TARGET_SPECIFIC_CODE
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -211,6 +223,7 @@ END_TARGET_SPECIFIC_CODE
|
|||||||
#define DECLARE_AVX512BW_SPECIFIC_CODE(...)
|
#define DECLARE_AVX512BW_SPECIFIC_CODE(...)
|
||||||
#define DECLARE_AVX512VBMI_SPECIFIC_CODE(...)
|
#define DECLARE_AVX512VBMI_SPECIFIC_CODE(...)
|
||||||
#define DECLARE_AVX512VBMI2_SPECIFIC_CODE(...)
|
#define DECLARE_AVX512VBMI2_SPECIFIC_CODE(...)
|
||||||
|
#define DECLARE_AVX512BF16_SPECIFIC_CODE(...)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -229,7 +242,8 @@ DECLARE_AVX2_SPECIFIC_CODE (__VA_ARGS__) \
|
|||||||
DECLARE_AVX512F_SPECIFIC_CODE(__VA_ARGS__) \
|
DECLARE_AVX512F_SPECIFIC_CODE(__VA_ARGS__) \
|
||||||
DECLARE_AVX512BW_SPECIFIC_CODE (__VA_ARGS__) \
|
DECLARE_AVX512BW_SPECIFIC_CODE (__VA_ARGS__) \
|
||||||
DECLARE_AVX512VBMI_SPECIFIC_CODE (__VA_ARGS__) \
|
DECLARE_AVX512VBMI_SPECIFIC_CODE (__VA_ARGS__) \
|
||||||
DECLARE_AVX512VBMI2_SPECIFIC_CODE (__VA_ARGS__)
|
DECLARE_AVX512VBMI2_SPECIFIC_CODE (__VA_ARGS__) \
|
||||||
|
DECLARE_AVX512BF16_SPECIFIC_CODE (__VA_ARGS__)
|
||||||
|
|
||||||
DECLARE_DEFAULT_CODE(
|
DECLARE_DEFAULT_CODE(
|
||||||
constexpr auto BuildArch = TargetArch::Default; /// NOLINT
|
constexpr auto BuildArch = TargetArch::Default; /// NOLINT
|
||||||
@ -263,6 +277,10 @@ DECLARE_AVX512VBMI2_SPECIFIC_CODE(
|
|||||||
constexpr auto BuildArch = TargetArch::AVX512VBMI2; /// NOLINT
|
constexpr auto BuildArch = TargetArch::AVX512VBMI2; /// NOLINT
|
||||||
) // DECLARE_AVX512VBMI2_SPECIFIC_CODE
|
) // DECLARE_AVX512VBMI2_SPECIFIC_CODE
|
||||||
|
|
||||||
|
DECLARE_AVX512BF16_SPECIFIC_CODE(
|
||||||
|
constexpr auto BuildArch = TargetArch::AVX512BF16; /// NOLINT
|
||||||
|
) // DECLARE_AVX512BF16_SPECIFIC_CODE
|
||||||
|
|
||||||
/** Runtime Dispatch helpers for class members.
|
/** Runtime Dispatch helpers for class members.
|
||||||
*
|
*
|
||||||
* Example of usage:
|
* Example of usage:
|
||||||
|
@ -204,6 +204,16 @@ bool ThreadStatus::isQueryCanceled() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ThreadStatus::getNextPlanStepIndex() const
|
||||||
|
{
|
||||||
|
return local_data.plan_step_index->fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ThreadStatus::getNextPipelineProcessorIndex() const
|
||||||
|
{
|
||||||
|
return local_data.pipeline_processor_index->fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
ThreadStatus::~ThreadStatus()
|
ThreadStatus::~ThreadStatus()
|
||||||
{
|
{
|
||||||
flushUntrackedMemory();
|
flushUntrackedMemory();
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -90,6 +91,11 @@ public:
|
|||||||
String query_for_logs;
|
String query_for_logs;
|
||||||
UInt64 normalized_query_hash = 0;
|
UInt64 normalized_query_hash = 0;
|
||||||
|
|
||||||
|
// Since processors might be added on the fly within expand() function we use atomic_size_t.
|
||||||
|
// These two fields are used for EXPLAIN PLAN / PIPELINE.
|
||||||
|
std::shared_ptr<std::atomic_size_t> plan_step_index = std::make_shared<std::atomic_size_t>(0);
|
||||||
|
std::shared_ptr<std::atomic_size_t> pipeline_processor_index = std::make_shared<std::atomic_size_t>(0);
|
||||||
|
|
||||||
QueryIsCanceledPredicate query_is_canceled_predicate = {};
|
QueryIsCanceledPredicate query_is_canceled_predicate = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,6 +319,9 @@ public:
|
|||||||
|
|
||||||
void initGlobalProfiler(UInt64 global_profiler_real_time_period, UInt64 global_profiler_cpu_time_period);
|
void initGlobalProfiler(UInt64 global_profiler_real_time_period, UInt64 global_profiler_cpu_time_period);
|
||||||
|
|
||||||
|
size_t getNextPlanStepIndex() const;
|
||||||
|
size_t getNextPipelineProcessorIndex() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void applyGlobalSettings();
|
void applyGlobalSettings();
|
||||||
void applyQuerySettings();
|
void applyQuerySettings();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user