diff --git a/README.md b/README.md index abaf27abf11..3270cd19671 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,6 @@ Keep an eye out for upcoming meetups and events around the world. Somewhere else 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 * [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 @@ -53,6 +52,7 @@ Upcoming 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 * [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 diff --git a/base/base/BFloat16.h b/base/base/BFloat16.h new file mode 100644 index 00000000000..00848038fe9 --- /dev/null +++ b/base/base/BFloat16.h @@ -0,0 +1,313 @@ +#pragma once + +#include +#include + + +/** 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(std::bit_cast(other) >> 16); + } + + template + explicit constexpr BFloat16(const T & other) + : BFloat16(Float32(other)) + { + } + + template + constexpr BFloat16 & operator=(const T & other) + { + *this = BFloat16(other); + return *this; + } + + explicit constexpr operator Float32() const + { + return std::bit_cast(static_cast(x) << 16); + } + + template + 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 +requires(!std::is_same_v) +constexpr bool operator==(const BFloat16 & a, const T & b) +{ + return Float32(a) == b; +} + +template +requires(!std::is_same_v) +constexpr bool operator==(const T & a, const BFloat16 & b) +{ + return a == Float32(b); +} + +template +requires(!std::is_same_v) +constexpr bool operator!=(const BFloat16 & a, const T & b) +{ + return Float32(a) != b; +} + +template +requires(!std::is_same_v) +constexpr bool operator!=(const T & a, const BFloat16 & b) +{ + return a != Float32(b); +} + +template +requires(!std::is_same_v) +constexpr bool operator<(const BFloat16 & a, const T & b) +{ + return Float32(a) < b; +} + +template +requires(!std::is_same_v) +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 +requires(!std::is_same_v) +constexpr bool operator>(const BFloat16 & a, const T & b) +{ + return Float32(a) > b; +} + +template +requires(!std::is_same_v) +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 +requires(!std::is_same_v) +constexpr bool operator<=(const BFloat16 & a, const T & b) +{ + return Float32(a) <= b; +} + +template +requires(!std::is_same_v) +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 +requires(!std::is_same_v) +constexpr bool operator>=(const BFloat16 & a, const T & b) +{ + return Float32(a) >= b; +} + +template +requires(!std::is_same_v) +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 +requires(!std::is_same_v) +constexpr inline auto operator+(T a, BFloat16 b) +{ + return a + Float32(b); +} + +template +requires(!std::is_same_v) +constexpr inline auto operator+(BFloat16 a, T b) +{ + return Float32(a) + b; +} + +template +requires(!std::is_same_v) +constexpr inline auto operator-(T a, BFloat16 b) +{ + return a - Float32(b); +} + +template +requires(!std::is_same_v) +constexpr inline auto operator-(BFloat16 a, T b) +{ + return Float32(a) - b; +} + +template +requires(!std::is_same_v) +constexpr inline auto operator*(T a, BFloat16 b) +{ + return a * Float32(b); +} + +template +requires(!std::is_same_v) +constexpr inline auto operator*(BFloat16 a, T b) +{ + return Float32(a) * b; +} + +template +requires(!std::is_same_v) +constexpr inline auto operator/(T a, BFloat16 b) +{ + return a / Float32(b); +} + +template +requires(!std::is_same_v) +constexpr inline auto operator/(BFloat16 a, T b) +{ + return Float32(a) / b; +} diff --git a/base/base/DecomposedFloat.h b/base/base/DecomposedFloat.h index 28dc3004240..fef91adefb0 100644 --- a/base/base/DecomposedFloat.h +++ b/base/base/DecomposedFloat.h @@ -10,6 +10,15 @@ template struct FloatTraits; +template <> +struct FloatTraits +{ + 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 <> struct FloatTraits { @@ -87,6 +96,15 @@ struct DecomposedFloat && ((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. /// This function is generic, big integers (128, 256 bit) are supported as well. @@ -212,3 +230,4 @@ struct DecomposedFloat using DecomposedFloat64 = DecomposedFloat; using DecomposedFloat32 = DecomposedFloat; +using DecomposedFloat16 = DecomposedFloat; diff --git a/base/base/EnumReflection.h b/base/base/EnumReflection.h index e4e0ef672fd..2ad704f8ca8 100644 --- a/base/base/EnumReflection.h +++ b/base/base/EnumReflection.h @@ -4,7 +4,7 @@ #include -template concept is_enum = std::is_enum_v; +template concept is_enum = std::is_enum_v; namespace detail { diff --git a/base/base/TypeLists.h b/base/base/TypeLists.h index 6c1283d054c..375ea94b5ea 100644 --- a/base/base/TypeLists.h +++ b/base/base/TypeLists.h @@ -9,10 +9,11 @@ namespace DB { using TypeListNativeInt = TypeList; -using TypeListFloat = TypeList; -using TypeListNativeNumber = TypeListConcat; +using TypeListNativeFloat = TypeList; +using TypeListNativeNumber = TypeListConcat; using TypeListWideInt = TypeList; using TypeListInt = TypeListConcat; +using TypeListFloat = TypeListConcat>; using TypeListIntAndFloat = TypeListConcat; using TypeListDecimal = TypeList; using TypeListNumber = TypeListConcat; diff --git a/base/base/TypeName.h b/base/base/TypeName.h index 9005b5a2bf4..1f4b475d653 100644 --- a/base/base/TypeName.h +++ b/base/base/TypeName.h @@ -32,6 +32,7 @@ TN_MAP(Int32) TN_MAP(Int64) TN_MAP(Int128) TN_MAP(Int256) +TN_MAP(BFloat16) TN_MAP(Float32) TN_MAP(Float64) TN_MAP(String) diff --git a/base/base/extended_types.h b/base/base/extended_types.h index 3bf3f4ed31d..ef36a5385a0 100644 --- a/base/base/extended_types.h +++ b/base/base/extended_types.h @@ -4,6 +4,8 @@ #include #include +#include + using Int128 = wide::integer<128, signed>; using UInt128 = wide::integer<128, unsigned>; @@ -24,6 +26,7 @@ struct is_signed // NOLINT(readability-identifier-naming) template <> struct is_signed { static constexpr bool value = true; }; template <> struct is_signed { static constexpr bool value = true; }; +template <> struct is_signed { static constexpr bool value = true; }; template inline constexpr bool is_signed_v = is_signed::value; @@ -40,15 +43,13 @@ template <> struct is_unsigned { static constexpr bool value = true; }; template inline constexpr bool is_unsigned_v = is_unsigned::value; -template concept is_integer = +template concept is_integer = std::is_integral_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; -template concept is_floating_point = std::is_floating_point_v; - template struct is_arithmetic // NOLINT(readability-identifier-naming) { @@ -59,11 +60,16 @@ template <> struct is_arithmetic { static constexpr bool value = true; } template <> struct is_arithmetic { static constexpr bool value = true; }; template <> struct is_arithmetic { static constexpr bool value = true; }; template <> struct is_arithmetic { static constexpr bool value = true; }; - +template <> struct is_arithmetic { static constexpr bool value = true; }; template inline constexpr bool is_arithmetic_v = is_arithmetic::value; +template concept is_floating_point = + std::is_floating_point_v + || std::is_same_v; + + #define FOR_EACH_ARITHMETIC_TYPE(M) \ M(DataTypeDate) \ M(DataTypeDate32) \ @@ -80,6 +86,7 @@ inline constexpr bool is_arithmetic_v = is_arithmetic::value; M(DataTypeUInt128) \ M(DataTypeInt256) \ M(DataTypeUInt256) \ + M(DataTypeBFloat16) \ M(DataTypeFloat32) \ M(DataTypeFloat64) @@ -99,6 +106,7 @@ inline constexpr bool is_arithmetic_v = is_arithmetic::value; M(DataTypeUInt128, X) \ M(DataTypeInt256, X) \ M(DataTypeUInt256, X) \ + M(DataTypeBFloat16, X) \ M(DataTypeFloat32, X) \ M(DataTypeFloat64, X) diff --git a/ci/jobs/scripts/check_style/aspell-ignore/en/aspell-dict.txt b/ci/jobs/scripts/check_style/aspell-ignore/en/aspell-dict.txt index e2966898be2..7cae8509b83 100644 --- a/ci/jobs/scripts/check_style/aspell-ignore/en/aspell-dict.txt +++ b/ci/jobs/scripts/check_style/aspell-ignore/en/aspell-dict.txt @@ -3131,3 +3131,4 @@ DistributedCachePoolBehaviourOnLimit SharedJoin ShareSet unacked +BFloat diff --git a/cmake/cpu_features.cmake b/cmake/cpu_features.cmake index 2bb6deb4847..dbc77d835be 100644 --- a/cmake/cpu_features.cmake +++ b/cmake/cpu_features.cmake @@ -85,7 +85,7 @@ elseif (ARCH_AARCH64) # [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 # [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 () # Best-effort check: The build generates and executes intermediate binaries, e.g. protoc and llvm-tablegen. If we build on ARM for ARM diff --git a/cmake/linux/default_libs.cmake b/cmake/linux/default_libs.cmake index 51620bc9f33..79875e1ed6b 100644 --- a/cmake/linux/default_libs.cmake +++ b/cmake/linux/default_libs.cmake @@ -3,8 +3,7 @@ set (DEFAULT_LIBS "-nodefaultlibs") -# We need builtins from Clang's RT even without libcxx - for ubsan+int128. -# See https://bugs.llvm.org/show_bug.cgi?id=16404 +# We need builtins from Clang execute_process (COMMAND ${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET} --print-libgcc-file-name --rtlib=compiler-rt OUTPUT_VARIABLE BUILTINS_LIBRARY diff --git a/docs/en/operations/server-configuration-parameters/settings.md b/docs/en/operations/server-configuration-parameters/settings.md index c5f92ccdf68..ca4938b1a47 100644 --- a/docs/en/operations/server-configuration-parameters/settings.md +++ b/docs/en/operations/server-configuration-parameters/settings.md @@ -597,6 +597,30 @@ If number of tables is greater than this value, server will throw an exception. 400 ``` +## 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 +400 +``` + +## 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 +400 +``` + +## 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 +400 +``` + ## 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. Default value: 0 diff --git a/docs/en/sql-reference/data-types/float.md b/docs/en/sql-reference/data-types/float.md index 3c789076c1e..7185308bdce 100644 --- a/docs/en/sql-reference/data-types/float.md +++ b/docs/en/sql-reference/data-types/float.md @@ -1,10 +1,10 @@ --- slug: /en/sql-reference/data-types/float sidebar_position: 4 -sidebar_label: Float32, Float64 +sidebar_label: Float32, Float64, BFloat16 --- -# Float32, Float64 +# Float32, Float64, BFloat16 :::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. @@ -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). + +## 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. diff --git a/programs/benchmark/Benchmark.cpp b/programs/benchmark/Benchmark.cpp index eb60888df14..86cc2ebe92f 100644 --- a/programs/benchmark/Benchmark.cpp +++ b/programs/benchmark/Benchmark.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -152,8 +151,6 @@ public: global_context->setClientName(std::string(DEFAULT_CLIENT_NAME)); global_context->setQueryKindInitial(); - std::cerr << std::fixed << std::setprecision(3); - /// This is needed to receive blocks with columns of AggregateFunction data type /// (example: when using stage = 'with_mergeable_state') registerAggregateFunctions(); @@ -226,6 +223,8 @@ private: ContextMutablePtr global_context; QueryProcessingStage::Enum query_processing_stage; + WriteBufferFromFileDescriptor log{STDERR_FILENO}; + std::atomic consecutive_errors{0}; /// 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) { - std::cerr << "\nQueries executed: " << num; + log << "\nQueries executed: " << num; if (queries.size() > 1) - std::cerr << " (" << (num * 100.0 / queries.size()) << "%)"; - std::cerr << ".\n"; + log << " (" << (num * 100.0 / queries.size()) << "%)"; + log << ".\n" << flush; } /// Try push new query and check cancellation conditions @@ -339,19 +338,19 @@ private: 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; } + } - double seconds = delay_watch.elapsedSeconds(); - if (delay > 0 && seconds > delay) - { - printNumberOfQueriesExecuted(queries_executed); - cumulative - ? report(comparison_info_total, total_watch.elapsedSeconds()) - : report(comparison_info_per_interval, seconds); - delay_watch.restart(); - } + double seconds = delay_watch.elapsedSeconds(); + if (delay > 0 && seconds > delay) + { + printNumberOfQueriesExecuted(queries_executed); + cumulative + ? report(comparison_info_total, total_watch.elapsedSeconds()) + : report(comparison_info_per_interval, seconds); + delay_watch.restart(); } return true; @@ -438,16 +437,16 @@ private: catch (...) { std::lock_guard lock(mutex); - std::cerr << "An error occurred while processing the query " << "'" << query << "'" - << ": " << getCurrentExceptionMessage(false) << std::endl; + log << "An error occurred while processing the query " << "'" << query << "'" + << ": " << getCurrentExceptionMessage(false) << '\n'; if (!(continue_on_errors || max_consecutive_errors > ++consecutive_errors)) { shutdown = true; throw; } - std::cerr << getCurrentExceptionMessage(print_stacktrace, - true /*check embedded stack trace*/) << std::endl; + log << getCurrentExceptionMessage(print_stacktrace, + true /*check embedded stack trace*/) << '\n' << flush; size_t info_index = round_robin ? 0 : connection_index; ++comparison_info_per_interval[info_index]->errors; @@ -504,7 +503,7 @@ private: { std::lock_guard lock(mutex); - std::cerr << "\n"; + log << "\n"; for (size_t i = 0; i < infos.size(); ++i) { const auto & info = infos[i]; @@ -524,31 +523,31 @@ private: connection_description += conn->getDescription(); } } - std::cerr - << connection_description << ", " - << "queries: " << info->queries << ", "; + log + << connection_description << ", " + << "queries: " << info->queries.load() << ", "; if (info->errors) { - std::cerr << "errors: " << info->errors << ", "; + log << "errors: " << info->errors << ", "; } - std::cerr - << "QPS: " << (info->queries / seconds) << ", " - << "RPS: " << (info->read_rows / seconds) << ", " - << "MiB/s: " << (info->read_bytes / seconds / 1048576) << ", " - << "result RPS: " << (info->result_rows / seconds) << ", " - << "result MiB/s: " << (info->result_bytes / seconds / 1048576) << "." - << "\n"; + log + << "QPS: " << fmt::format("{:.3f}", info->queries / seconds) << ", " + << "RPS: " << fmt::format("{:.3f}", info->read_rows / seconds) << ", " + << "MiB/s: " << fmt::format("{:.3f}", info->read_bytes / seconds / 1048576) << ", " + << "result RPS: " << fmt::format("{:.3f}", info->result_rows / seconds) << ", " + << "result MiB/s: " << fmt::format("{:.3f}", info->result_bytes / seconds / 1048576) << "." + << "\n"; } - std::cerr << "\n"; + log << "\n"; auto print_percentile = [&](double percent) { - std::cerr << percent << "%\t\t"; + log << percent << "%\t\t"; 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) @@ -559,13 +558,15 @@ private: print_percentile(99.9); print_percentile(99.99); - std::cerr << "\n" << t_test.compareAndReport(confidence).second << "\n"; + log << "\n" << t_test.compareAndReport(confidence).second << "\n"; if (!cumulative) { for (auto & info : infos) info->clear(); } + + log.next(); } public: @@ -741,7 +742,7 @@ int mainEntryClickHouseBenchmark(int argc, char ** argv) } catch (...) { - std::cerr << getCurrentExceptionMessage(print_stacktrace, true) << std::endl; + std::cerr << getCurrentExceptionMessage(print_stacktrace, true) << '\n'; return getCurrentExceptionCode(); } } diff --git a/programs/compressor/Compressor.cpp b/programs/compressor/Compressor.cpp index bf67db8ff2e..e73f61dde83 100644 --- a/programs/compressor/Compressor.cpp +++ b/programs/compressor/Compressor.cpp @@ -12,9 +12,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -43,29 +46,24 @@ namespace CurrentMetrics 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) { while (!in.eof()) { - in.ignore(16); /// checksum - - char header[COMPRESSED_BLOCK_HEADER_SIZE]; - in.readStrict(header, COMPRESSED_BLOCK_HEADER_SIZE); - - UInt32 size_compressed = unalignedLoad(&header[1]); + UInt32 size_compressed; + UInt32 size_decompressed; + auto codec = DB::getCompressionCodecForFile(in, size_compressed, size_decompressed, true /* skip_to_next_block */); if (size_compressed > DBMS_MAX_COMPRESSED_SIZE) throw DB::Exception(DB::ErrorCodes::TOO_LARGE_SIZE_COMPRESSED, "Too large size_compressed. Most likely corrupted data."); - UInt32 size_decompressed = unalignedLoad(&header[5]); - + DB::writeText(queryToString(codec->getFullCodecDesc()), out); + DB::writeChar('\t', out); DB::writeText(size_decompressed, out); DB::writeChar('\t', out); DB::writeText(size_compressed, out); DB::writeChar('\n', out); - - in.ignore(size_compressed - COMPRESSED_BLOCK_HEADER_SIZE); } } diff --git a/src/AggregateFunctions/AggregateFunctionAvg.h b/src/AggregateFunctions/AggregateFunctionAvg.h index 6e1e9289565..8d53a081ee0 100644 --- a/src/AggregateFunctions/AggregateFunctionAvg.h +++ b/src/AggregateFunctions/AggregateFunctionAvg.h @@ -231,7 +231,7 @@ public: void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const final { - increment(place, static_cast(*columns[0]).getData()[row_num]); + increment(place, Numerator(static_cast(*columns[0]).getData()[row_num])); ++this->data(place).denominator; } diff --git a/src/AggregateFunctions/AggregateFunctionDeltaSum.cpp b/src/AggregateFunctions/AggregateFunctionDeltaSum.cpp index 42169c34c25..c61b9918a35 100644 --- a/src/AggregateFunctions/AggregateFunctionDeltaSum.cpp +++ b/src/AggregateFunctions/AggregateFunctionDeltaSum.cpp @@ -27,9 +27,9 @@ namespace template struct AggregationFunctionDeltaSumData { - T sum = 0; - T last = 0; - T first = 0; + T sum{}; + T last{}; + T first{}; bool seen = false; }; diff --git a/src/AggregateFunctions/AggregateFunctionDeltaSumTimestamp.cpp b/src/AggregateFunctions/AggregateFunctionDeltaSumTimestamp.cpp index 5819c533fd9..dc1adead87c 100644 --- a/src/AggregateFunctions/AggregateFunctionDeltaSumTimestamp.cpp +++ b/src/AggregateFunctions/AggregateFunctionDeltaSumTimestamp.cpp @@ -25,11 +25,11 @@ namespace template struct AggregationFunctionDeltaSumTimestampData { - ValueType sum = 0; - ValueType first = 0; - ValueType last = 0; - TimestampType first_ts = 0; - TimestampType last_ts = 0; + ValueType sum{}; + ValueType first{}; + ValueType last{}; + TimestampType first_ts{}; + TimestampType last_ts{}; bool seen = false; }; diff --git a/src/AggregateFunctions/AggregateFunctionGroupArray.cpp b/src/AggregateFunctions/AggregateFunctionGroupArray.cpp index fb730306c0d..7dc5a4b86b3 100644 --- a/src/AggregateFunctions/AggregateFunctionGroupArray.cpp +++ b/src/AggregateFunctions/AggregateFunctionGroupArray.cpp @@ -79,7 +79,7 @@ template struct GroupArraySamplerData { /// For easy serialization. - static_assert(std::has_unique_object_representations_v || std::is_floating_point_v); + static_assert(std::has_unique_object_representations_v || is_floating_point); // Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena using Allocator = MixedAlignedArenaAllocator; @@ -120,7 +120,7 @@ template struct GroupArrayNumericData { /// For easy serialization. - static_assert(std::has_unique_object_representations_v || std::is_floating_point_v); + static_assert(std::has_unique_object_representations_v || is_floating_point); // Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena using Allocator = MixedAlignedArenaAllocator; diff --git a/src/AggregateFunctions/AggregateFunctionGroupArrayMoving.cpp b/src/AggregateFunctions/AggregateFunctionGroupArrayMoving.cpp index 43aad8ac3ba..a6e73729b6a 100644 --- a/src/AggregateFunctions/AggregateFunctionGroupArrayMoving.cpp +++ b/src/AggregateFunctions/AggregateFunctionGroupArrayMoving.cpp @@ -38,7 +38,7 @@ template struct MovingData { /// For easy serialization. - static_assert(std::has_unique_object_representations_v || std::is_floating_point_v); + static_assert(std::has_unique_object_representations_v || is_floating_point); using Accumulator = T; diff --git a/src/AggregateFunctions/AggregateFunctionIntervalLengthSum.cpp b/src/AggregateFunctions/AggregateFunctionIntervalLengthSum.cpp index eacd0596757..e5404add820 100644 --- a/src/AggregateFunctions/AggregateFunctionIntervalLengthSum.cpp +++ b/src/AggregateFunctions/AggregateFunctionIntervalLengthSum.cpp @@ -187,7 +187,7 @@ public: static DataTypePtr createResultType() { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) return std::make_shared(); return std::make_shared(); } @@ -227,7 +227,7 @@ public: void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) assert_cast(to).getData().push_back(getIntervalLengthSum(this->data(place))); else assert_cast(to).getData().push_back(getIntervalLengthSum(this->data(place))); diff --git a/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp b/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp index ca91f960dab..f4edec7f528 100644 --- a/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp +++ b/src/AggregateFunctions/AggregateFunctionMaxIntersections.cpp @@ -155,9 +155,9 @@ public: void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override { - Int64 current_intersections = 0; - Int64 max_intersections = 0; - PointType position_of_max_intersections = 0; + Int64 current_intersections{}; + Int64 max_intersections{}; + PointType position_of_max_intersections{}; /// const_cast because we will sort the array auto & array = this->data(place).value; diff --git a/src/AggregateFunctions/AggregateFunctionSparkbar.cpp b/src/AggregateFunctions/AggregateFunctionSparkbar.cpp index 362ffbe20d2..de2a741e105 100644 --- a/src/AggregateFunctions/AggregateFunctionSparkbar.cpp +++ b/src/AggregateFunctions/AggregateFunctionSparkbar.cpp @@ -45,12 +45,12 @@ struct AggregateFunctionSparkbarData Y insert(const X & x, const Y & y) { if (isNaN(y) || y <= 0) - return 0; + return {}; auto [it, inserted] = points.insert({x, y}); if (!inserted) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { it->getMapped() += y; return it->getMapped(); @@ -173,13 +173,13 @@ private: if (from_x >= to_x) { - size_t sz = updateFrame(values, 8); + size_t sz = updateFrame(values, Y{8}); values.push_back('\0'); offsets.push_back(offsets.empty() ? sz + 1 : offsets.back() + sz + 1); return; } - PaddedPODArray histogram(width, 0); + PaddedPODArray histogram(width, Y{0}); PaddedPODArray count_histogram(width, 0); /// The number of points in each bucket for (const auto & point : data.points) @@ -197,7 +197,7 @@ private: Y res; bool has_overfllow = false; - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) res = histogram[index] + point.getMapped(); else has_overfllow = common::addOverflow(histogram[index], point.getMapped(), res); @@ -218,10 +218,10 @@ private: for (size_t i = 0; i < histogram.size(); ++i) { 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) { if (isNaN(y) || y <= 0) @@ -245,8 +245,8 @@ private: continue; } - constexpr auto levels_num = static_cast(BAR_LEVELS - 1); - if constexpr (std::is_floating_point_v) + constexpr auto levels_num = Y{BAR_LEVELS - 1}; + if constexpr (is_floating_point) { y = y / (y_max / levels_num) + 1; } diff --git a/src/AggregateFunctions/AggregateFunctionSum.h b/src/AggregateFunctions/AggregateFunctionSum.h index 2ce03c530c2..7c7fb6338a2 100644 --- a/src/AggregateFunctions/AggregateFunctionSum.h +++ b/src/AggregateFunctions/AggregateFunctionSum.h @@ -69,7 +69,7 @@ struct AggregateFunctionSumData size_t count = end - start; const auto * end_ptr = ptr + count; - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { /// Compiler cannot unroll this loop, do it manually. /// (at least for floats, most likely due to the lack of -fassociative-math) @@ -83,7 +83,7 @@ struct AggregateFunctionSumData while (ptr < unrolled_end) { 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; } @@ -95,7 +95,7 @@ struct AggregateFunctionSumData T local_sum{}; while (ptr < end_ptr) { - Impl::add(local_sum, *ptr); + Impl::add(local_sum, T(*ptr)); ++ptr; } Impl::add(sum, local_sum); @@ -193,12 +193,11 @@ struct AggregateFunctionSumData Impl::add(sum, local_sum); return; } - else if constexpr (std::is_floating_point_v) + else if constexpr (is_floating_point && (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) - static_assert(sizeof(Value) == 4 || sizeof(Value) == 8); - using equivalent_integer = typename std::conditional_t; + using EquivalentInteger = typename std::conditional_t; constexpr size_t unroll_count = 128 / sizeof(T); T partial_sums[unroll_count]{}; @@ -209,11 +208,11 @@ struct AggregateFunctionSumData { for (size_t i = 0; i < unroll_count; ++i) { - equivalent_integer value; - std::memcpy(&value, &ptr[i], sizeof(Value)); + EquivalentInteger value; + memcpy(&value, &ptr[i], sizeof(Value)); value &= (!condition_map[i] != add_if_zero) - 1; Value d; - std::memcpy(&d, &value, sizeof(Value)); + memcpy(&d, &value, sizeof(Value)); Impl::add(partial_sums[i], d); } ptr += unroll_count; @@ -228,7 +227,7 @@ struct AggregateFunctionSumData while (ptr < end_ptr) { if (!*condition_map == add_if_zero) - Impl::add(local_sum, *ptr); + Impl::add(local_sum, T(*ptr)); ++ptr; ++condition_map; } @@ -306,7 +305,7 @@ struct AggregateFunctionSumData template struct AggregateFunctionSumKahanData { - static_assert(std::is_floating_point_v, + static_assert(is_floating_point, "It doesn't make sense to use Kahan Summation algorithm for non floating point types"); T sum{}; @@ -489,10 +488,7 @@ public: void add(AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const override { const auto & column = assert_cast(*columns[0]); - if constexpr (is_big_int_v) - this->data(place).add(static_cast(column.getData()[row_num])); - else - this->data(place).add(column.getData()[row_num]); + this->data(place).add(static_cast(column.getData()[row_num])); } void addBatchSinglePlace( diff --git a/src/AggregateFunctions/AggregateFunctionUniq.h b/src/AggregateFunctions/AggregateFunctionUniq.h index 35d6e599e38..a094ed288d6 100644 --- a/src/AggregateFunctions/AggregateFunctionUniq.h +++ b/src/AggregateFunctions/AggregateFunctionUniq.h @@ -257,7 +257,7 @@ template struct AggregateFunctionUniqTraits { static UInt64 hash(T x) { - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (is_floating_point) { return bit_cast(x); } diff --git a/src/AggregateFunctions/AggregateFunctionUniqCombined.h b/src/AggregateFunctions/AggregateFunctionUniqCombined.h index c6377a9532d..4a91991ebb5 100644 --- a/src/AggregateFunctions/AggregateFunctionUniqCombined.h +++ b/src/AggregateFunctions/AggregateFunctionUniqCombined.h @@ -111,7 +111,7 @@ public: /// Initially UInt128 was introduced only for UUID, and then the other big-integer types were added. hash = static_cast(sipHash64(value)); } - else if constexpr (std::is_floating_point_v) + else if constexpr (is_floating_point) { hash = static_cast(intHash64(bit_cast(value))); } diff --git a/src/AggregateFunctions/QuantileTDigest.h b/src/AggregateFunctions/QuantileTDigest.h index f915d6c70a3..8117b2a7fe1 100644 --- a/src/AggregateFunctions/QuantileTDigest.h +++ b/src/AggregateFunctions/QuantileTDigest.h @@ -391,7 +391,7 @@ public: ResultType getImpl(Float64 level) { if (centroids.empty()) - return std::is_floating_point_v ? std::numeric_limits::quiet_NaN() : 0; + return is_floating_point ? std::numeric_limits::quiet_NaN() : 0; compress(); diff --git a/src/AggregateFunctions/ReservoirSampler.h b/src/AggregateFunctions/ReservoirSampler.h index 2668e0dc890..870cb429fb7 100644 --- a/src/AggregateFunctions/ReservoirSampler.h +++ b/src/AggregateFunctions/ReservoirSampler.h @@ -276,6 +276,6 @@ private: { if (OnEmpty == ReservoirSamplerOnEmpty::THROW) throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSampler"); - return NanLikeValueConstructor>::getValue(); + return NanLikeValueConstructor>::getValue(); } }; diff --git a/src/AggregateFunctions/ReservoirSamplerDeterministic.h b/src/AggregateFunctions/ReservoirSamplerDeterministic.h index 0ad8e968358..f35d1eb49af 100644 --- a/src/AggregateFunctions/ReservoirSamplerDeterministic.h +++ b/src/AggregateFunctions/ReservoirSamplerDeterministic.h @@ -271,7 +271,7 @@ private: { if (OnEmpty == ReservoirSamplerDeterministicOnEmpty::THROW) throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "Quantile of empty ReservoirSamplerDeterministic"); - return NanLikeValueConstructor>::getValue(); + return NanLikeValueConstructor>::getValue(); } }; diff --git a/src/Backups/BackupConcurrencyCheck.cpp b/src/Backups/BackupConcurrencyCheck.cpp index 8b29ae41b53..a67d241845d 100644 --- a/src/Backups/BackupConcurrencyCheck.cpp +++ b/src/Backups/BackupConcurrencyCheck.cpp @@ -14,12 +14,12 @@ namespace ErrorCodes BackupConcurrencyCheck::BackupConcurrencyCheck( - const UUID & backup_or_restore_uuid_, bool is_restore_, bool on_cluster_, + const String & zookeeper_path_, bool allow_concurrency_, 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}; @@ -32,7 +32,7 @@ BackupConcurrencyCheck::BackupConcurrencyCheck( size_t num_on_cluster_restores = counters.on_cluster_restores.size(); 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; } else @@ -47,7 +47,7 @@ BackupConcurrencyCheck::BackupConcurrencyCheck( size_t num_on_cluster_backups = counters.on_cluster_backups.size(); 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; } else @@ -64,9 +64,9 @@ BackupConcurrencyCheck::BackupConcurrencyCheck( if (on_cluster) { if (is_restore) - ++counters.on_cluster_restores[backup_or_restore_uuid]; + ++counters.on_cluster_restores[zookeeper_path]; else - ++counters.on_cluster_backups[backup_or_restore_uuid]; + ++counters.on_cluster_backups[zookeeper_path]; } else { @@ -86,7 +86,7 @@ BackupConcurrencyCheck::~BackupConcurrencyCheck() { 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->second) @@ -95,7 +95,7 @@ BackupConcurrencyCheck::~BackupConcurrencyCheck() } 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->second) diff --git a/src/Backups/BackupConcurrencyCheck.h b/src/Backups/BackupConcurrencyCheck.h index 048a23a716a..a1baeff5464 100644 --- a/src/Backups/BackupConcurrencyCheck.h +++ b/src/Backups/BackupConcurrencyCheck.h @@ -1,7 +1,8 @@ #pragma once -#include +#include #include +#include #include #include @@ -19,9 +20,9 @@ public: /// Checks concurrency of a BACKUP operation or a RESTORE operation. /// Keep a constructed instance of BackupConcurrencyCheck until the operation is done. BackupConcurrencyCheck( - const UUID & backup_or_restore_uuid_, bool is_restore_, bool on_cluster_, + const String & zookeeper_path_, bool allow_concurrency_, BackupConcurrencyCounters & counters_); @@ -31,8 +32,8 @@ public: private: const bool is_restore; - const UUID backup_or_restore_uuid; const bool on_cluster; + const String zookeeper_path; BackupConcurrencyCounters & counters; }; @@ -47,8 +48,8 @@ private: friend class BackupConcurrencyCheck; size_t local_backups TSA_GUARDED_BY(mutex) = 0; size_t local_restores TSA_GUARDED_BY(mutex) = 0; - std::unordered_map on_cluster_backups TSA_GUARDED_BY(mutex); - std::unordered_map on_cluster_restores TSA_GUARDED_BY(mutex); + std::unordered_map on_cluster_backups TSA_GUARDED_BY(mutex); + std::unordered_map on_cluster_restores TSA_GUARDED_BY(mutex); std::mutex mutex; }; diff --git a/src/Backups/BackupCoordinationCleaner.cpp b/src/Backups/BackupCoordinationCleaner.cpp index 1f5068a94de..47095f27eb3 100644 --- a/src/Backups/BackupCoordinationCleaner.cpp +++ b/src/Backups/BackupCoordinationCleaner.cpp @@ -4,31 +4,29 @@ namespace DB { -BackupCoordinationCleaner::BackupCoordinationCleaner(const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr log_) - : zookeeper_path(zookeeper_path_), with_retries(with_retries_), log(log_) +BackupCoordinationCleaner::BackupCoordinationCleaner(bool is_restore_, const String & zookeeper_path_, const WithRetries & with_retries_, LoggerPtr 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 -{ - return tryRemoveAllNodes(/* throw_if_error = */ false, /* retries_kind = */ WithRetries::kNormal); -} - -bool BackupCoordinationCleaner::tryRemoveAllNodes(bool throw_if_error, WithRetries::Kind retries_kind) +bool BackupCoordinationCleaner::cleanupImpl(bool throw_if_error, WithRetries::Kind retries_kind) { { std::lock_guard lock{mutex}; - if (cleanup_result.succeeded) - return true; - if (cleanup_result.exception) + if (succeeded) { - if (throw_if_error) - std::rethrow_exception(cleanup_result.exception); + LOG_TRACE(log, "Nodes from ZooKeeper are already removed"); + return true; + } + if (tried) + { + LOG_INFO(log, "Skipped removing nodes from ZooKeeper because because earlier we failed to do that"); return false; } } @@ -44,16 +42,18 @@ bool BackupCoordinationCleaner::tryRemoveAllNodes(bool throw_if_error, WithRetri }); std::lock_guard lock{mutex}; - cleanup_result.succeeded = true; + tried = true; + succeeded = true; return true; } 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)); std::lock_guard lock{mutex}; - cleanup_result.exception = std::current_exception(); + tried = true; if (throw_if_error) throw; diff --git a/src/Backups/BackupCoordinationCleaner.h b/src/Backups/BackupCoordinationCleaner.h index 43e095d9f33..c760a3611f9 100644 --- a/src/Backups/BackupCoordinationCleaner.h +++ b/src/Backups/BackupCoordinationCleaner.h @@ -12,14 +12,14 @@ namespace DB class BackupCoordinationCleaner { 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 tryCleanupAfterError() noexcept; + bool cleanup(bool throw_if_error); 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; /// A reference to a field of the parent object which is either BackupCoordinationOnCluster or RestoreCoordinationOnCluster. @@ -27,13 +27,8 @@ private: const LoggerPtr log; - struct CleanupResult - { - bool succeeded = false; - std::exception_ptr exception; - }; - CleanupResult cleanup_result TSA_GUARDED_BY(mutex); - + bool tried TSA_GUARDED_BY(mutex) = false; + bool succeeded TSA_GUARDED_BY(mutex) = false; std::mutex mutex; }; diff --git a/src/Backups/BackupCoordinationLocal.cpp b/src/Backups/BackupCoordinationLocal.cpp index 8bd6b4d327d..402e789eacb 100644 --- a/src/Backups/BackupCoordinationLocal.cpp +++ b/src/Backups/BackupCoordinationLocal.cpp @@ -11,12 +11,11 @@ namespace DB { BackupCoordinationLocal::BackupCoordinationLocal( - const UUID & backup_uuid_, bool is_plain_backup_, bool allow_concurrent_backup_, BackupConcurrencyCounters & concurrency_counters_) : 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_) { } diff --git a/src/Backups/BackupCoordinationLocal.h b/src/Backups/BackupCoordinationLocal.h index 09991c0d301..e63fcde981a 100644 --- a/src/Backups/BackupCoordinationLocal.h +++ b/src/Backups/BackupCoordinationLocal.h @@ -23,20 +23,19 @@ class BackupCoordinationLocal : public IBackupCoordination { public: explicit BackupCoordinationLocal( - const UUID & backup_uuid_, bool is_plain_backup_, bool allow_concurrent_backup_, BackupConcurrencyCounters & concurrency_counters_); ~BackupCoordinationLocal() override; + void setBackupQueryIsSentToOtherHosts() override {} + bool isBackupQuerySentToOtherHosts() const override { return false; } Strings setStage(const String &, const String &, bool) override { return {}; } - void setBackupQueryWasSentToOtherHosts() override {} - bool trySetError(std::exception_ptr) override { return true; } - void finish() override {} - bool tryFinishAfterError() noexcept override { return true; } - void waitForOtherHostsToFinish() override {} - bool tryWaitForOtherHostsToFinishAfterError() noexcept override { return true; } + bool setError(std::exception_ptr, bool) override { return true; } + bool waitOtherHostsFinish(bool) const override { return true; } + bool finish(bool) override { return true; } + bool cleanup(bool) override { return true; } void addReplicatedPartNames(const String & table_zk_path, const String & table_name_for_logs, const String & replica_name, const std::vector & part_names_and_checksums) override; diff --git a/src/Backups/BackupCoordinationOnCluster.cpp b/src/Backups/BackupCoordinationOnCluster.cpp index dc34939f805..1b14f226eff 100644 --- a/src/Backups/BackupCoordinationOnCluster.cpp +++ b/src/Backups/BackupCoordinationOnCluster.cpp @@ -184,17 +184,21 @@ BackupCoordinationOnCluster::BackupCoordinationOnCluster( , plain_backup(is_plain_backup_) , 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_); }) - , concurrency_check(backup_uuid_, /* is_restore = */ false, /* on_cluster = */ true, allow_concurrent_backup_, concurrency_counters_) - , stage_sync(/* is_restore = */ false, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_backup_, with_retries, schedule_, process_list_element_, log) - , cleaner(zookeeper_path, with_retries, log) + , 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_, concurrency_counters_, with_retries, schedule_, process_list_element_, log) { - createRootNodes(); + try + { + createRootNodes(); + } + catch (...) + { + stage_sync.setError(std::current_exception(), /* throw_if_error = */ false); + throw; + } } -BackupCoordinationOnCluster::~BackupCoordinationOnCluster() -{ - tryFinishImpl(); -} +BackupCoordinationOnCluster::~BackupCoordinationOnCluster() = default; 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) { stage_sync.setStage(new_stage, message); - - if (!sync) - return {}; - - return stage_sync.waitForHostsToReachStage(new_stage, all_hosts_without_initiator); + if (sync) + return stage_sync.waitHostsReachStage(all_hosts_without_initiator, new_stage); + return {}; } -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; - stage_sync.finish(other_hosts_also_finished); - - if ((current_host == kInitiator) && (other_hosts_also_finished || !backup_query_was_sent_to_other_hosts)) - cleaner.cleanup(); + return stage_sync.finish(throw_if_error); } -bool BackupCoordinationOnCluster::tryFinishAfterError() noexcept +bool BackupCoordinationOnCluster::cleanup(bool throw_if_error) { - return tryFinishImpl(); -} - -bool BackupCoordinationOnCluster::tryFinishImpl() noexcept -{ - 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)) + /// 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); + if (!all_hosts_finished) { - if (!cleaner.tryCleanupAfterError()) - return false; - } - - 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) + auto unfinished_hosts = expect_other_hosts_finished ? stage_sync.getUnfinishedHosts() : Strings{current_host}; + LOG_INFO(log, "Skipping removing nodes from ZooKeeper because hosts {} didn't finish", + BackupCoordinationStageSync::getHostsDesc(unfinished_hosts)); return false; - if (!backup_query_was_sent_to_other_hosts) - return true; - return stage_sync.tryWaitForOtherHostsToFinishAfterError(); + } + return cleaner.cleanup(throw_if_error); } ZooKeeperRetriesInfo BackupCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const diff --git a/src/Backups/BackupCoordinationOnCluster.h b/src/Backups/BackupCoordinationOnCluster.h index 7369c2cc746..b439ab619d8 100644 --- a/src/Backups/BackupCoordinationOnCluster.h +++ b/src/Backups/BackupCoordinationOnCluster.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -20,7 +19,7 @@ class BackupCoordinationOnCluster : public IBackupCoordination { public: /// 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( const UUID & backup_uuid_, @@ -37,13 +36,13 @@ public: ~BackupCoordinationOnCluster() override; + void setBackupQueryIsSentToOtherHosts() override; + bool isBackupQuerySentToOtherHosts() const override; Strings setStage(const String & new_stage, const String & message, bool sync) override; - void setBackupQueryWasSentToOtherHosts() override; - bool trySetError(std::exception_ptr exception) override; - void finish() override; - bool tryFinishAfterError() noexcept override; - void waitForOtherHostsToFinish() override; - bool tryWaitForOtherHostsToFinishAfterError() noexcept override; + bool setError(std::exception_ptr exception, bool throw_if_error) override; + bool waitOtherHostsFinish(bool throw_if_error) const override; + bool finish(bool throw_if_error) override; + bool cleanup(bool throw_if_error) override; void addReplicatedPartNames( const String & table_zk_path, @@ -110,11 +109,10 @@ private: const bool plain_backup; LoggerPtr const log; + /// The order is important: `stage_sync` must be initialized after `with_retries` and `cleaner`. const WithRetries with_retries; - BackupConcurrencyCheck concurrency_check; - BackupCoordinationStageSync stage_sync; BackupCoordinationCleaner cleaner; - std::atomic backup_query_was_sent_to_other_hosts = false; + BackupCoordinationStageSync stage_sync; mutable std::optional replicated_tables TSA_GUARDED_BY(replicated_tables_mutex); mutable std::optional replicated_access TSA_GUARDED_BY(replicated_access_mutex); diff --git a/src/Backups/BackupCoordinationStageSync.cpp b/src/Backups/BackupCoordinationStageSync.cpp index 9a05f9490c2..df5f08091ba 100644 --- a/src/Backups/BackupCoordinationStageSync.cpp +++ b/src/Backups/BackupCoordinationStageSync.cpp @@ -42,9 +42,6 @@ namespace kCurrentVersion = 2, }; - - /// Empty string as the current host is used to mark the initiator of a BACKUP ON CLUSTER or RESTORE ON CLUSTER query. - const constexpr std::string_view kInitiator; } bool BackupCoordinationStageSync::HostInfo::operator ==(const HostInfo & other) const @@ -63,12 +60,32 @@ bool BackupCoordinationStageSync::State::operator ==(const State & other) const bool BackupCoordinationStageSync::State::operator !=(const State & other) const = default; +void BackupCoordinationStageSync::State::merge(const State & other) +{ + if (other.host_with_error && !host_with_error) + { + const String & host = *other.host_with_error; + host_with_error = host; + hosts.at(host).exception = other.hosts.at(host).exception; + } + + for (const auto & [host, other_host_info] : other.hosts) + { + auto & host_info = hosts.at(host); + host_info.stages.insert(other_host_info.stages.begin(), other_host_info.stages.end()); + if (other_host_info.finished) + host_info.finished = true; + } +} + + BackupCoordinationStageSync::BackupCoordinationStageSync( bool is_restore_, const String & zookeeper_path_, const String & current_host_, const Strings & all_hosts_, bool allow_concurrency_, + BackupConcurrencyCounters & concurrency_counters_, const WithRetries & with_retries_, ThreadPoolCallbackRunnerUnsafe schedule_, QueryStatusPtr process_list_element_, @@ -89,35 +106,28 @@ BackupCoordinationStageSync::BackupCoordinationStageSync( , max_attempts_after_bad_version(with_retries.getKeeperSettings().max_attempts_after_bad_version) , zookeeper_path(zookeeper_path_) , root_zookeeper_path(zookeeper_path.parent_path().parent_path()) - , operation_node_path(zookeeper_path.parent_path()) + , operation_zookeeper_path(zookeeper_path.parent_path()) , operation_node_name(zookeeper_path.parent_path().filename()) - , stage_node_path(zookeeper_path) , start_node_path(zookeeper_path / ("started|" + current_host)) , finish_node_path(zookeeper_path / ("finished|" + current_host)) , num_hosts_node_path(zookeeper_path / "num_hosts") + , error_node_path(zookeeper_path / "error") , alive_node_path(zookeeper_path / ("alive|" + current_host)) , alive_tracker_node_path(fs::path{root_zookeeper_path} / "alive_tracker") - , error_node_path(zookeeper_path / "error") , zk_nodes_changed(std::make_shared()) { - if ((zookeeper_path.filename() != "stage") || !operation_node_name.starts_with(is_restore ? "restore-" : "backup-") - || (root_zookeeper_path == operation_node_path)) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected path in ZooKeeper specified: {}", zookeeper_path); - } - initializeState(); createRootNodes(); try { - createStartAndAliveNodes(); + createStartAndAliveNodesAndCheckConcurrency(concurrency_counters_); startWatchingThread(); } catch (...) { - trySetError(std::current_exception()); - tryFinishImpl(); + if (setError(std::current_exception(), /* throw_if_error = */ false)) + finish(/* throw_if_error = */ false); throw; } } @@ -125,7 +135,26 @@ BackupCoordinationStageSync::BackupCoordinationStageSync( BackupCoordinationStageSync::~BackupCoordinationStageSync() { - tryFinishImpl(); + /// Normally either finish() or setError() must be called. + if (!tried_to_finish) + { + if (state.host_with_error) + { + /// setError() was called and succeeded. + finish(/* throw_if_error = */ false); + } + else if (!tried_to_set_error) + { + /// Neither finish() nor setError() were called, it's a bug. + chassert(false, "~BackupCoordinationStageSync() is called without finish() or setError()"); + LOG_ERROR(log, "~BackupCoordinationStageSync() is called without finish() or setError()"); + } + } + + /// Normally the watching thread should be stopped already because the finish() function stops it. + /// However if an error happened then the watching thread can be still running, + /// so here in the destructor we have to ensure that it's stopped. + stopWatchingThread(); } @@ -137,6 +166,12 @@ void BackupCoordinationStageSync::initializeState() for (const String & host : all_hosts) state.hosts.emplace(host, HostInfo{.host = host, .last_connection_time = now, .last_connection_time_monotonic = monotonic_now}); + + if (!state.hosts.contains(current_host)) + throw Exception(ErrorCodes::LOGICAL_ERROR, "List of hosts must contain the current host"); + + if (!state.hosts.contains(String{kInitiator})) + throw Exception(ErrorCodes::LOGICAL_ERROR, "List of hosts must contain the initiator"); } @@ -179,7 +214,13 @@ String BackupCoordinationStageSync::getHostsDesc(const Strings & hosts) void BackupCoordinationStageSync::createRootNodes() { - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::createRootNodes", WithRetries::kInitialization); + if ((zookeeper_path.filename() != "stage") || !operation_node_name.starts_with(is_restore ? "restore-" : "backup-") + || (root_zookeeper_path == operation_zookeeper_path)) + { + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected path in ZooKeeper specified: {}", zookeeper_path); + } + + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::createRootNodes", WithRetries::kInitialization); holder.retries_ctl.retryLoop( [&, &zookeeper = holder.faulty_zookeeper]() { @@ -190,18 +231,22 @@ void BackupCoordinationStageSync::createRootNodes() } -void BackupCoordinationStageSync::createStartAndAliveNodes() +void BackupCoordinationStageSync::createStartAndAliveNodesAndCheckConcurrency(BackupConcurrencyCounters & concurrency_counters_) { - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::createStartAndAliveNodes", WithRetries::kInitialization); + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::createStartAndAliveNodes", WithRetries::kInitialization); holder.retries_ctl.retryLoop([&, &zookeeper = holder.faulty_zookeeper]() { with_retries.renewZooKeeper(zookeeper); - createStartAndAliveNodes(zookeeper); + createStartAndAliveNodesAndCheckConcurrency(zookeeper); }); + + /// The local concurrency check should be done here after BackupCoordinationStageSync::checkConcurrency() checked that + /// there are no 'alive' nodes corresponding to other backups or restores. + local_concurrency_check.emplace(is_restore, /* on_cluster = */ true, zookeeper_path, allow_concurrency, concurrency_counters_); } -void BackupCoordinationStageSync::createStartAndAliveNodes(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper) +void BackupCoordinationStageSync::createStartAndAliveNodesAndCheckConcurrency(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper) { /// The "num_hosts" node keeps the number of hosts which started (created the "started" node) /// but not yet finished (not created the "finished" node). @@ -252,27 +297,27 @@ void BackupCoordinationStageSync::createStartAndAliveNodes(Coordination::ZooKeep Coordination::Requests requests; requests.reserve(6); - size_t operation_node_path_pos = static_cast(-1); - if (!zookeeper->exists(operation_node_path)) + size_t operation_node_pos = static_cast(-1); + if (!zookeeper->exists(operation_zookeeper_path)) { - operation_node_path_pos = requests.size(); - requests.emplace_back(zkutil::makeCreateRequest(operation_node_path, "", zkutil::CreateMode::Persistent)); + operation_node_pos = requests.size(); + requests.emplace_back(zkutil::makeCreateRequest(operation_zookeeper_path, "", zkutil::CreateMode::Persistent)); } - size_t stage_node_path_pos = static_cast(-1); - if (!zookeeper->exists(stage_node_path)) + size_t zookeeper_path_pos = static_cast(-1); + if (!zookeeper->exists(zookeeper_path)) { - stage_node_path_pos = requests.size(); - requests.emplace_back(zkutil::makeCreateRequest(stage_node_path, "", zkutil::CreateMode::Persistent)); + zookeeper_path_pos = requests.size(); + requests.emplace_back(zkutil::makeCreateRequest(zookeeper_path, "", zkutil::CreateMode::Persistent)); } - size_t num_hosts_node_path_pos = requests.size(); + size_t num_hosts_node_pos = requests.size(); if (num_hosts) requests.emplace_back(zkutil::makeSetRequest(num_hosts_node_path, toString(*num_hosts + 1), num_hosts_version)); else requests.emplace_back(zkutil::makeCreateRequest(num_hosts_node_path, "1", zkutil::CreateMode::Persistent)); - size_t alive_tracker_node_path_pos = requests.size(); + size_t alive_tracker_node_pos = requests.size(); requests.emplace_back(zkutil::makeSetRequest(alive_tracker_node_path, "", alive_tracker_version)); requests.emplace_back(zkutil::makeCreateRequest(start_node_path, std::to_string(kCurrentVersion), zkutil::CreateMode::Persistent)); @@ -284,7 +329,7 @@ void BackupCoordinationStageSync::createStartAndAliveNodes(Coordination::ZooKeep if (code == Coordination::Error::ZOK) { LOG_INFO(log, "Created start node #{} in ZooKeeper for {} (coordination version: {})", - num_hosts.value_or(0) + 1, current_host_desc, kCurrentVersion); + num_hosts.value_or(0) + 1, current_host_desc, static_cast(kCurrentVersion)); return; } @@ -294,40 +339,34 @@ void BackupCoordinationStageSync::createStartAndAliveNodes(Coordination::ZooKeep LOG_TRACE(log, "{} (attempt #{}){}", message, attempt_no, will_try_again ? ", will try again" : ""); }; - if ((responses.size() > operation_node_path_pos) && - (responses[operation_node_path_pos]->error == Coordination::Error::ZNODEEXISTS)) + if ((operation_node_pos < responses.size()) && + (responses[operation_node_pos]->error == Coordination::Error::ZNODEEXISTS)) { - show_error_before_next_attempt(fmt::format("Node {} in ZooKeeper already exists", operation_node_path)); + show_error_before_next_attempt(fmt::format("Node {} already exists", operation_zookeeper_path)); /// needs another attempt } - else if ((responses.size() > stage_node_path_pos) && - (responses[stage_node_path_pos]->error == Coordination::Error::ZNODEEXISTS)) + else if ((zookeeper_path_pos < responses.size()) && + (responses[zookeeper_path_pos]->error == Coordination::Error::ZNODEEXISTS)) { - show_error_before_next_attempt(fmt::format("Node {} in ZooKeeper already exists", stage_node_path)); + show_error_before_next_attempt(fmt::format("Node {} already exists", zookeeper_path)); /// needs another attempt } - else if ((responses.size() > num_hosts_node_path_pos) && num_hosts && - (responses[num_hosts_node_path_pos]->error == Coordination::Error::ZBADVERSION)) + else if ((num_hosts_node_pos < responses.size()) && !num_hosts && + (responses[num_hosts_node_pos]->error == Coordination::Error::ZNODEEXISTS)) { - show_error_before_next_attempt("Other host changed the 'num_hosts' node in ZooKeeper"); + show_error_before_next_attempt(fmt::format("Node {} already exists", num_hosts_node_path)); + /// needs another attempt + } + else if ((num_hosts_node_pos < responses.size()) && num_hosts && + (responses[num_hosts_node_pos]->error == Coordination::Error::ZBADVERSION)) + { + show_error_before_next_attempt(fmt::format("The version of node {} changed", num_hosts_node_path)); num_hosts.reset(); /// needs to reread 'num_hosts' again } - else if ((responses.size() > num_hosts_node_path_pos) && num_hosts && - (responses[num_hosts_node_path_pos]->error == Coordination::Error::ZNONODE)) + else if ((alive_tracker_node_pos < responses.size()) && + (responses[alive_tracker_node_pos]->error == Coordination::Error::ZBADVERSION)) { - show_error_before_next_attempt("Other host removed the 'num_hosts' node in ZooKeeper"); - num_hosts.reset(); /// needs to reread 'num_hosts' again - } - else if ((responses.size() > num_hosts_node_path_pos) && !num_hosts && - (responses[num_hosts_node_path_pos]->error == Coordination::Error::ZNODEEXISTS)) - { - show_error_before_next_attempt("Other host created the 'num_hosts' node in ZooKeeper"); - /// needs another attempt - } - else if ((responses.size() > alive_tracker_node_path_pos) && - (responses[alive_tracker_node_path_pos]->error == Coordination::Error::ZBADVERSION)) - { - show_error_before_next_attempt("Concurrent backup or restore changed some 'alive' nodes in ZooKeeper"); + show_error_before_next_attempt(fmt::format("The version of node {} changed", alive_tracker_node_path)); check_concurrency = true; /// needs to recheck for concurrency again } else @@ -337,8 +376,7 @@ void BackupCoordinationStageSync::createStartAndAliveNodes(Coordination::ZooKeep } throw Exception(ErrorCodes::FAILED_TO_SYNC_BACKUP_OR_RESTORE, - "Couldn't create the 'start' node in ZooKeeper for {} after {} attempts", - current_host_desc, max_attempts_after_bad_version); + "Couldn't create node {} in ZooKeeper after {} attempts", start_node_path, max_attempts_after_bad_version); } @@ -387,36 +425,53 @@ void BackupCoordinationStageSync::startWatchingThread() void BackupCoordinationStageSync::stopWatchingThread() { - should_stop_watching_thread = true; + { + std::lock_guard lock{mutex}; + if (should_stop_watching_thread) + return; + should_stop_watching_thread = true; - /// Wake up waiting threads. - if (zk_nodes_changed) - zk_nodes_changed->set(); - state_changed.notify_all(); + /// Wake up waiting threads. + if (zk_nodes_changed) + zk_nodes_changed->set(); + state_changed.notify_all(); + } if (watching_thread_future.valid()) watching_thread_future.wait(); + + LOG_TRACE(log, "Stopped the watching thread"); } void BackupCoordinationStageSync::watchingThread() { - while (!should_stop_watching_thread) + auto should_stop = [&] + { + std::lock_guard lock{mutex}; + return should_stop_watching_thread; + }; + + while (!should_stop()) { try { /// Check if the current BACKUP or RESTORE command is already cancelled. checkIfQueryCancelled(); + } + catch (...) + { + tryLogCurrentException(log, "Caugth exception while watching"); + } - /// Reset the `connected` flag for each host, we'll set them to true again after we find the 'alive' nodes. - resetConnectedFlag(); - + try + { /// Recreate the 'alive' node if necessary and read a new state from ZooKeeper. - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::watchingThread"); + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::watchingThread"); auto & zookeeper = holder.faulty_zookeeper; with_retries.renewZooKeeper(zookeeper); - if (should_stop_watching_thread) + if (should_stop()) return; /// Recreate the 'alive' node if it was removed. @@ -427,7 +482,10 @@ void BackupCoordinationStageSync::watchingThread() } catch (...) { - tryLogCurrentException(log, "Caugth exception while watching"); + tryLogCurrentException(log, "Caught exception while watching"); + + /// Reset the `connected` flag for each host, we'll set them to true again after we find the 'alive' nodes. + resetConnectedFlag(); } try @@ -438,9 +496,12 @@ void BackupCoordinationStageSync::watchingThread() } catch (...) { - tryLogCurrentException(log, "Caugth exception while checking if the query should be cancelled"); + tryLogCurrentException(log, "Caught exception while watching"); } + if (should_stop()) + return; + zk_nodes_changed->tryWait(sync_period_ms.count()); } } @@ -473,7 +534,7 @@ void BackupCoordinationStageSync::readCurrentState(Coordination::ZooKeeperWithFa zk_nodes_changed->reset(); /// Get zk nodes and subscribe on their changes. - Strings new_zk_nodes = zookeeper->getChildren(stage_node_path, nullptr, zk_nodes_changed); + Strings new_zk_nodes = zookeeper->getChildren(zookeeper_path, nullptr, zk_nodes_changed); std::sort(new_zk_nodes.begin(), new_zk_nodes.end()); /// Sorting is necessary because we compare the list of zk nodes with its previous versions. State new_state; @@ -492,6 +553,8 @@ void BackupCoordinationStageSync::readCurrentState(Coordination::ZooKeeperWithFa zk_nodes = new_zk_nodes; new_state = state; + for (auto & [_, host_info] : new_state.hosts) + host_info.connected = false; } auto get_host_info = [&](const String & host) -> HostInfo * @@ -514,7 +577,8 @@ void BackupCoordinationStageSync::readCurrentState(Coordination::ZooKeeperWithFa { String serialized_error = zookeeper->get(error_node_path); auto [exception, host] = parseErrorNode(serialized_error); - if (auto * host_info = get_host_info(host)) + auto * host_info = get_host_info(host); + if (exception && host_info) { host_info->exception = exception; new_state.host_with_error = host; @@ -576,6 +640,9 @@ void BackupCoordinationStageSync::readCurrentState(Coordination::ZooKeeperWithFa { std::lock_guard lock{mutex}; + /// We were reading `new_state` from ZooKeeper with `mutex` unlocked, so `state` could get more information during that reading, + /// we don't want to lose that information, that's why we use merge() here. + new_state.merge(state); was_state_changed = (new_state != state); state = std::move(new_state); } @@ -604,26 +671,10 @@ int BackupCoordinationStageSync::parseStartNode(const String & start_node_conten } -std::pair BackupCoordinationStageSync::parseErrorNode(const String & error_node_contents) -{ - ReadBufferFromOwnString buf{error_node_contents}; - String host; - readStringBinary(host, buf); - auto exception = std::make_exception_ptr(readException(buf, fmt::format("Got error from {}", getHostDesc(host)))); - return {exception, host}; -} - - void BackupCoordinationStageSync::checkIfQueryCancelled() { if (process_list_element->checkTimeLimitSoft()) return; /// Not cancelled. - - std::lock_guard lock{mutex}; - if (state.cancelled) - return; /// Already marked as cancelled. - - state.cancelled = true; state_changed.notify_all(); } @@ -634,13 +685,13 @@ void BackupCoordinationStageSync::cancelQueryIfError() { std::lock_guard lock{mutex}; - if (state.cancelled || !state.host_with_error) + if (!state.host_with_error) return; - state.cancelled = true; exception = state.hosts.at(*state.host_with_error).exception; } + chassert(exception); process_list_element->cancelQuery(false, exception); state_changed.notify_all(); } @@ -652,7 +703,7 @@ void BackupCoordinationStageSync::cancelQueryIfDisconnectedTooLong() { std::lock_guard lock{mutex}; - if (state.cancelled || state.host_with_error || ((failure_after_host_disconnected_for_seconds.count() == 0))) + if (state.host_with_error || ((failure_after_host_disconnected_for_seconds.count() == 0))) return; auto monotonic_now = std::chrono::steady_clock::now(); @@ -685,27 +736,92 @@ void BackupCoordinationStageSync::cancelQueryIfDisconnectedTooLong() } } } - - if (!exception) - return; - - state.cancelled = true; } + if (!exception) + return; + process_list_element->cancelQuery(false, exception); state_changed.notify_all(); } +void BackupCoordinationStageSync::setQueryIsSentToOtherHosts() +{ + std::lock_guard lock{mutex}; + query_is_sent_to_other_hosts = true; +} + +bool BackupCoordinationStageSync::isQuerySentToOtherHosts() const +{ + std::lock_guard lock{mutex}; + return query_is_sent_to_other_hosts; +} + + void BackupCoordinationStageSync::setStage(const String & stage, const String & stage_result) { LOG_INFO(log, "{} reached stage {}", current_host_desc, stage); - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::setStage"); + + { + std::lock_guard lock{mutex}; + if (state.hosts.at(current_host).stages.contains(stage)) + return; /// Already set. + } + + if ((getInitiatorVersion() == kVersionWithoutFinishNode) && (stage == BackupCoordinationStage::COMPLETED)) + { + LOG_TRACE(log, "Stopping the watching thread because the initiator uses outdated version {}", getInitiatorVersion()); + stopWatchingThread(); + } + + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::setStage"); holder.retries_ctl.retryLoop([&, &zookeeper = holder.faulty_zookeeper]() { with_retries.renewZooKeeper(zookeeper); - zookeeper->createIfNotExists(getStageNodePath(stage), stage_result); + createStageNode(stage, stage_result, zookeeper); }); + + /// If the initiator of the query has that old version then it doesn't expect us to create the 'finish' node and moreover + /// the initiator can start removing all the nodes immediately after all hosts report about reaching the "completed" status. + /// So to avoid weird errors in the logs we won't create the 'finish' node if the initiator of the query has that old version. + if ((getInitiatorVersion() == kVersionWithoutFinishNode) && (stage == BackupCoordinationStage::COMPLETED)) + { + LOG_INFO(log, "Skipped creating the 'finish' node because the initiator uses outdated version {}", getInitiatorVersion()); + std::lock_guard lock{mutex}; + tried_to_finish = true; + state.hosts.at(current_host).finished = true; + } +} + + +void BackupCoordinationStageSync::createStageNode(const String & stage, const String & stage_result, Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper) +{ + String serialized_error; + if (zookeeper->tryGet(error_node_path, serialized_error)) + { + auto [exception, host] = parseErrorNode(serialized_error); + if (exception) + std::rethrow_exception(exception); + } + + auto code = zookeeper->tryCreate(getStageNodePath(stage), stage_result, zkutil::CreateMode::Persistent); + if (code == Coordination::Error::ZOK) + { + std::lock_guard lock{mutex}; + state.hosts.at(current_host).stages[stage] = stage_result; + return; + } + + if (code == Coordination::Error::ZNODEEXISTS) + { + String another_result = zookeeper->get(getStageNodePath(stage)); + std::lock_guard lock{mutex}; + state.hosts.at(current_host).stages[stage] = another_result; + return; + } + + throw zkutil::KeeperException::fromPath(code, getStageNodePath(stage)); } @@ -715,71 +831,7 @@ String BackupCoordinationStageSync::getStageNodePath(const String & stage) const } -bool BackupCoordinationStageSync::trySetError(std::exception_ptr exception) noexcept -{ - try - { - std::rethrow_exception(exception); - } - catch (const Exception & e) - { - return trySetError(e); - } - catch (...) - { - return trySetError(Exception(getCurrentExceptionMessageAndPattern(true, true), getCurrentExceptionCode())); - } -} - - -bool BackupCoordinationStageSync::trySetError(const Exception & exception) -{ - try - { - setError(exception); - return true; - } - catch (...) - { - return false; - } -} - - -void BackupCoordinationStageSync::setError(const Exception & exception) -{ - /// Most likely this exception has been already logged so here we're logging it without stacktrace. - String exception_message = getExceptionMessage(exception, /* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true); - LOG_INFO(log, "Sending exception from {} to other hosts: {}", current_host_desc, exception_message); - - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::setError", WithRetries::kErrorHandling); - - holder.retries_ctl.retryLoop([&, &zookeeper = holder.faulty_zookeeper]() - { - with_retries.renewZooKeeper(zookeeper); - - WriteBufferFromOwnString buf; - writeStringBinary(current_host, buf); - writeException(exception, buf, true); - auto code = zookeeper->tryCreate(error_node_path, buf.str(), zkutil::CreateMode::Persistent); - - if (code == Coordination::Error::ZOK) - { - LOG_TRACE(log, "Sent exception from {} to other hosts", current_host_desc); - } - else if (code == Coordination::Error::ZNODEEXISTS) - { - LOG_INFO(log, "An error has been already assigned for this {}", operation_name); - } - else - { - throw zkutil::KeeperException::fromPath(code, error_node_path); - } - }); -} - - -Strings BackupCoordinationStageSync::waitForHostsToReachStage(const String & stage_to_wait, const Strings & hosts, std::optional timeout) const +Strings BackupCoordinationStageSync::waitHostsReachStage(const Strings & hosts, const String & stage_to_wait) const { Strings results; results.resize(hosts.size()); @@ -787,44 +839,28 @@ Strings BackupCoordinationStageSync::waitForHostsToReachStage(const String & sta std::unique_lock lock{mutex}; /// TSA_NO_THREAD_SAFETY_ANALYSIS is here because Clang Thread Safety Analysis doesn't understand std::unique_lock. - auto check_if_hosts_ready = [&](bool time_is_out) TSA_NO_THREAD_SAFETY_ANALYSIS + auto check_if_hosts_reach_stage = [&]() TSA_NO_THREAD_SAFETY_ANALYSIS { - return checkIfHostsReachStage(hosts, stage_to_wait, time_is_out, timeout, results); + return checkIfHostsReachStage(hosts, stage_to_wait, results); }; - if (timeout) - { - if (!state_changed.wait_for(lock, *timeout, [&] { return check_if_hosts_ready(/* time_is_out = */ false); })) - check_if_hosts_ready(/* time_is_out = */ true); - } - else - { - state_changed.wait(lock, [&] { return check_if_hosts_ready(/* time_is_out = */ false); }); - } + state_changed.wait(lock, check_if_hosts_reach_stage); return results; } -bool BackupCoordinationStageSync::checkIfHostsReachStage( - const Strings & hosts, - const String & stage_to_wait, - bool time_is_out, - std::optional timeout, - Strings & results) const +bool BackupCoordinationStageSync::checkIfHostsReachStage(const Strings & hosts, const String & stage_to_wait, Strings & results) const { - if (should_stop_watching_thread) - throw Exception(ErrorCodes::LOGICAL_ERROR, "finish() was called while waiting for a stage"); - process_list_element->checkTimeLimit(); for (size_t i = 0; i != hosts.size(); ++i) { const String & host = hosts[i]; auto it = state.hosts.find(host); - if (it == state.hosts.end()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "waitForHostsToReachStage() was called for unexpected {}, all hosts are {}", getHostDesc(host), getHostsDesc(all_hosts)); + throw Exception(ErrorCodes::LOGICAL_ERROR, + "waitHostsReachStage() was called for unexpected {}, all hosts are {}", getHostDesc(host), getHostsDesc(all_hosts)); const HostInfo & host_info = it->second; auto stage_it = host_info.stages.find(stage_to_wait); @@ -835,10 +871,11 @@ bool BackupCoordinationStageSync::checkIfHostsReachStage( } if (host_info.finished) - { throw Exception(ErrorCodes::FAILED_TO_SYNC_BACKUP_OR_RESTORE, "{} finished without coming to stage {}", getHostDesc(host), stage_to_wait); - } + + if (should_stop_watching_thread) + throw Exception(ErrorCodes::LOGICAL_ERROR, "waitHostsReachStage() can't wait for stage {} after the watching thread stopped", stage_to_wait); String host_status; if (!host_info.started) @@ -846,85 +883,73 @@ bool BackupCoordinationStageSync::checkIfHostsReachStage( else if (!host_info.connected) host_status = fmt::format(": the host is currently disconnected, last connection was at {}", host_info.last_connection_time); - if (!time_is_out) - { - LOG_TRACE(log, "Waiting for {} to reach stage {}{}", getHostDesc(host), stage_to_wait, host_status); - return false; - } - else - { - throw Exception(ErrorCodes::FAILED_TO_SYNC_BACKUP_OR_RESTORE, - "Waited longer than timeout {} for {} to reach stage {}{}", - *timeout, getHostDesc(host), stage_to_wait, host_status); - } + LOG_TRACE(log, "Waiting for {} to reach stage {}{}", getHostDesc(host), stage_to_wait, host_status); + return false; /// wait for next change of `state_changed` } LOG_INFO(log, "Hosts {} reached stage {}", getHostsDesc(hosts), stage_to_wait); - return true; + return true; /// stop waiting } -void BackupCoordinationStageSync::finish(bool & other_hosts_also_finished) +bool BackupCoordinationStageSync::finish(bool throw_if_error) { - tryFinishImpl(other_hosts_also_finished, /* throw_if_error = */ true, /* retries_kind = */ WithRetries::kNormal); + WithRetries::Kind retries_kind = WithRetries::kNormal; + if (throw_if_error) + retries_kind = WithRetries::kErrorHandling; + + return finishImpl(throw_if_error, retries_kind); } -bool BackupCoordinationStageSync::tryFinishAfterError(bool & other_hosts_also_finished) noexcept +bool BackupCoordinationStageSync::finishImpl(bool throw_if_error, WithRetries::Kind retries_kind) { - return tryFinishImpl(other_hosts_also_finished, /* throw_if_error = */ false, /* retries_kind = */ WithRetries::kErrorHandling); -} - - -bool BackupCoordinationStageSync::tryFinishImpl() -{ - bool other_hosts_also_finished; - return tryFinishAfterError(other_hosts_also_finished); -} - - -bool BackupCoordinationStageSync::tryFinishImpl(bool & other_hosts_also_finished, bool throw_if_error, WithRetries::Kind retries_kind) -{ - auto get_value_other_hosts_also_finished = [&] TSA_REQUIRES(mutex) - { - other_hosts_also_finished = true; - for (const auto & [host, host_info] : state.hosts) - { - if ((host != current_host) && !host_info.finished) - other_hosts_also_finished = false; - } - }; - { std::lock_guard lock{mutex}; - if (finish_result.succeeded) + + if (finishedNoLock()) { - get_value_other_hosts_also_finished(); + LOG_INFO(log, "The finish node for {} already exists", current_host_desc); return true; } - if (finish_result.exception) + + if (tried_to_finish) { - if (throw_if_error) - std::rethrow_exception(finish_result.exception); + /// We don't repeat creating the finish node, no matter if it was successful or not. + LOG_INFO(log, "Skipped creating the finish node for {} because earlier we failed to do that", current_host_desc); return false; } + + bool failed_to_set_error = tried_to_set_error && !state.host_with_error; + if (failed_to_set_error) + { + /// Tried to create the 'error' node, but failed. + /// Then it's better not to create the 'finish' node in this case because otherwise other hosts might think we've succeeded. + LOG_INFO(log, "Skipping creating the finish node for {} because there was an error which we were unable to send to other hosts", current_host_desc); + return false; + } + + if (current_host == kInitiator) + { + /// Normally the initiator should wait for other hosts to finish before creating its own finish node. + /// We show warning if some of the other hosts didn't finish. + bool expect_other_hosts_finished = query_is_sent_to_other_hosts || !state.host_with_error; + bool other_hosts_finished = otherHostsFinishedNoLock() || !expect_other_hosts_finished; + if (!other_hosts_finished) + LOG_WARNING(log, "Hosts {} didn't finish before the initiator", getHostsDesc(getUnfinishedOtherHostsNoLock())); + } } + stopWatchingThread(); + try { - stopWatchingThread(); - - auto holder = with_retries.createRetriesControlHolder("BackupStageSync::finish", retries_kind); + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::finish", retries_kind); holder.retries_ctl.retryLoop([&, &zookeeper = holder.faulty_zookeeper]() { with_retries.renewZooKeeper(zookeeper); - createFinishNodeAndRemoveAliveNode(zookeeper); + createFinishNodeAndRemoveAliveNode(zookeeper, throw_if_error); }); - - std::lock_guard lock{mutex}; - finish_result.succeeded = true; - get_value_other_hosts_also_finished(); - return true; } catch (...) { @@ -933,63 +958,87 @@ bool BackupCoordinationStageSync::tryFinishImpl(bool & other_hosts_also_finished getCurrentExceptionMessage(/* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true)); std::lock_guard lock{mutex}; - finish_result.exception = std::current_exception(); + tried_to_finish = true; + if (throw_if_error) throw; return false; } + + { + std::lock_guard lock{mutex}; + tried_to_finish = true; + state.hosts.at(current_host).finished = true; + } + + return true; } -void BackupCoordinationStageSync::createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper) +void BackupCoordinationStageSync::createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper, bool throw_if_error) { - if (zookeeper->exists(finish_node_path)) - return; - - /// If the initiator of the query has that old version then it doesn't expect us to create the 'finish' node and moreover - /// the initiator can start removing all the nodes immediately after all hosts report about reaching the "completed" status. - /// So to avoid weird errors in the logs we won't create the 'finish' node if the initiator of the query has that old version. - if ((getInitiatorVersion() == kVersionWithoutFinishNode) && (current_host != kInitiator)) - { - LOG_INFO(log, "Skipped creating the 'finish' node because the initiator uses outdated version {}", getInitiatorVersion()); - return; - } - std::optional num_hosts; int num_hosts_version = -1; for (size_t attempt_no = 1; attempt_no <= max_attempts_after_bad_version; ++attempt_no) { + /// The 'num_hosts' node may not exist if createStartAndAliveNodes() failed in the constructor. if (!num_hosts) { + String num_hosts_str; Coordination::Stat stat; - num_hosts = parseFromString(zookeeper->get(num_hosts_node_path, &stat)); - num_hosts_version = stat.version; + if (zookeeper->tryGet(num_hosts_node_path, num_hosts_str, &stat)) + { + num_hosts = parseFromString(num_hosts_str); + num_hosts_version = stat.version; + } } + String serialized_error; + if (throw_if_error && zookeeper->tryGet(error_node_path, serialized_error)) + { + auto [exception, host] = parseErrorNode(serialized_error); + if (exception) + std::rethrow_exception(exception); + } + + if (zookeeper->exists(finish_node_path)) + return; + + bool start_node_exists = zookeeper->exists(start_node_path); + Coordination::Requests requests; requests.reserve(3); requests.emplace_back(zkutil::makeCreateRequest(finish_node_path, "", zkutil::CreateMode::Persistent)); - size_t num_hosts_node_path_pos = requests.size(); - requests.emplace_back(zkutil::makeSetRequest(num_hosts_node_path, toString(*num_hosts - 1), num_hosts_version)); - - size_t alive_node_path_pos = static_cast(-1); + size_t alive_node_pos = static_cast(-1); if (zookeeper->exists(alive_node_path)) { - alive_node_path_pos = requests.size(); + alive_node_pos = requests.size(); requests.emplace_back(zkutil::makeRemoveRequest(alive_node_path, -1)); } + size_t num_hosts_node_pos = static_cast(-1); + if (num_hosts) + { + num_hosts_node_pos = requests.size(); + requests.emplace_back(zkutil::makeSetRequest(num_hosts_node_path, toString(start_node_exists ? (*num_hosts - 1) : *num_hosts), num_hosts_version)); + } + Coordination::Responses responses; auto code = zookeeper->tryMulti(requests, responses); if (code == Coordination::Error::ZOK) { - --*num_hosts; - String hosts_left_desc = ((*num_hosts == 0) ? "no hosts left" : fmt::format("{} hosts left", *num_hosts)); - LOG_INFO(log, "Created the 'finish' node in ZooKeeper for {}, {}", current_host_desc, hosts_left_desc); + String hosts_left_desc; + if (num_hosts) + { + if (start_node_exists) + --*num_hosts; + hosts_left_desc = (*num_hosts == 0) ? ", no hosts left" : fmt::format(", {} hosts left", *num_hosts); + } + LOG_INFO(log, "Created the 'finish' node in ZooKeeper for {}{}", current_host_desc, hosts_left_desc); return; } @@ -999,18 +1048,18 @@ void BackupCoordinationStageSync::createFinishNodeAndRemoveAliveNode(Coordinatio LOG_TRACE(log, "{} (attempt #{}){}", message, attempt_no, will_try_again ? ", will try again" : ""); }; - if ((responses.size() > num_hosts_node_path_pos) && - (responses[num_hosts_node_path_pos]->error == Coordination::Error::ZBADVERSION)) + if ((alive_node_pos < responses.size()) && + (responses[alive_node_pos]->error == Coordination::Error::ZNONODE)) { - show_error_before_next_attempt("Other host changed the 'num_hosts' node in ZooKeeper"); - num_hosts.reset(); /// needs to reread 'num_hosts' again - } - else if ((responses.size() > alive_node_path_pos) && - (responses[alive_node_path_pos]->error == Coordination::Error::ZNONODE)) - { - show_error_before_next_attempt(fmt::format("Node {} in ZooKeeper doesn't exist", alive_node_path_pos)); + show_error_before_next_attempt(fmt::format("Node {} doesn't exist", alive_node_path)); /// needs another attempt } + else if ((num_hosts_node_pos < responses.size()) && + (responses[num_hosts_node_pos]->error == Coordination::Error::ZBADVERSION)) + { + show_error_before_next_attempt(fmt::format("The version of node {} changed", num_hosts_node_path)); + num_hosts.reset(); /// needs to reread 'num_hosts' again + } else { zkutil::KeeperMultiException::check(code, requests, responses); @@ -1026,60 +1075,73 @@ void BackupCoordinationStageSync::createFinishNodeAndRemoveAliveNode(Coordinatio int BackupCoordinationStageSync::getInitiatorVersion() const { std::lock_guard lock{mutex}; - auto it = state.hosts.find(String{kInitiator}); - if (it == state.hosts.end()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "There is no initiator of this {} query, it's a bug", operation_name); - const HostInfo & host_info = it->second; - return host_info.version; + return state.hosts.at(String{kInitiator}).version; } -void BackupCoordinationStageSync::waitForOtherHostsToFinish() const -{ - tryWaitForOtherHostsToFinishImpl(/* reason = */ "", /* throw_if_error = */ true, /* timeout = */ {}); -} - - -bool BackupCoordinationStageSync::tryWaitForOtherHostsToFinishAfterError() const noexcept +bool BackupCoordinationStageSync::waitOtherHostsFinish(bool throw_if_error) const { std::optional timeout; - if (finish_timeout_after_error.count() != 0) - timeout = finish_timeout_after_error; + String reason; - String reason = fmt::format("{} needs other hosts to finish before cleanup", current_host_desc); - return tryWaitForOtherHostsToFinishImpl(reason, /* throw_if_error = */ false, timeout); + if (!throw_if_error) + { + if (finish_timeout_after_error.count() != 0) + timeout = finish_timeout_after_error; + reason = "after error before cleanup"; + } + + return waitOtherHostsFinishImpl(reason, timeout, throw_if_error); } -bool BackupCoordinationStageSync::tryWaitForOtherHostsToFinishImpl(const String & reason, bool throw_if_error, std::optional timeout) const +bool BackupCoordinationStageSync::waitOtherHostsFinishImpl(const String & reason, std::optional timeout, bool throw_if_error) const { std::unique_lock lock{mutex}; /// TSA_NO_THREAD_SAFETY_ANALYSIS is here because Clang Thread Safety Analysis doesn't understand std::unique_lock. - auto check_if_other_hosts_finish = [&](bool time_is_out) TSA_NO_THREAD_SAFETY_ANALYSIS + auto other_hosts_finished = [&]() TSA_NO_THREAD_SAFETY_ANALYSIS { return otherHostsFinishedNoLock(); }; + + if (other_hosts_finished()) { - return checkIfOtherHostsFinish(reason, throw_if_error, time_is_out, timeout); + LOG_TRACE(log, "Other hosts have already finished"); + return true; + } + + bool failed_to_set_error = TSA_SUPPRESS_WARNING_FOR_READ(tried_to_set_error) && !TSA_SUPPRESS_WARNING_FOR_READ(state).host_with_error; + if (failed_to_set_error) + { + /// Tried to create the 'error' node, but failed. + /// Then it's better not to wait for other hosts to finish in this case because other hosts don't know they should finish. + LOG_INFO(log, "Skipping waiting for other hosts to finish because there was an error which we were unable to send to other hosts"); + return false; + } + + bool result = false; + + /// TSA_NO_THREAD_SAFETY_ANALYSIS is here because Clang Thread Safety Analysis doesn't understand std::unique_lock. + auto check_if_hosts_finish = [&](bool time_is_out) TSA_NO_THREAD_SAFETY_ANALYSIS + { + return checkIfOtherHostsFinish(reason, timeout, time_is_out, result, throw_if_error); }; if (timeout) { - if (state_changed.wait_for(lock, *timeout, [&] { return check_if_other_hosts_finish(/* time_is_out = */ false); })) - return true; - return check_if_other_hosts_finish(/* time_is_out = */ true); + if (!state_changed.wait_for(lock, *timeout, [&] { return check_if_hosts_finish(/* time_is_out = */ false); })) + check_if_hosts_finish(/* time_is_out = */ true); } else { - state_changed.wait(lock, [&] { return check_if_other_hosts_finish(/* time_is_out = */ false); }); - return true; + state_changed.wait(lock, [&] { return check_if_hosts_finish(/* time_is_out = */ false); }); } + + return result; } -bool BackupCoordinationStageSync::checkIfOtherHostsFinish(const String & reason, bool throw_if_error, bool time_is_out, std::optional timeout) const +bool BackupCoordinationStageSync::checkIfOtherHostsFinish( + const String & reason, std::optional timeout, bool time_is_out, bool & result, bool throw_if_error) const { - if (should_stop_watching_thread) - throw Exception(ErrorCodes::LOGICAL_ERROR, "finish() was called while waiting for other hosts to finish"); - if (throw_if_error) process_list_element->checkTimeLimit(); @@ -1088,38 +1150,261 @@ bool BackupCoordinationStageSync::checkIfOtherHostsFinish(const String & reason, if ((host == current_host) || host_info.finished) continue; + String reason_text = reason.empty() ? "" : (" " + reason); + String host_status; if (!host_info.started) host_status = fmt::format(": the host hasn't started working on this {} yet", operation_name); else if (!host_info.connected) host_status = fmt::format(": the host is currently disconnected, last connection was at {}", host_info.last_connection_time); - if (!time_is_out) + if (time_is_out) { - String reason_text = reason.empty() ? "" : (" because " + reason); - LOG_TRACE(log, "Waiting for {} to finish{}{}", getHostDesc(host), reason_text, host_status); - return false; - } - else - { - String reason_text = reason.empty() ? "" : fmt::format(" (reason of waiting: {})", reason); - if (!throw_if_error) - { - LOG_INFO(log, "Waited longer than timeout {} for {} to finish{}{}", - *timeout, getHostDesc(host), host_status, reason_text); - return false; - } - else + if (throw_if_error) { throw Exception(ErrorCodes::FAILED_TO_SYNC_BACKUP_OR_RESTORE, "Waited longer than timeout {} for {} to finish{}{}", - *timeout, getHostDesc(host), host_status, reason_text); + *timeout, getHostDesc(host), reason_text, host_status); } + LOG_INFO(log, "Waited longer than timeout {} for {} to finish{}{}", + *timeout, getHostDesc(host), reason_text, host_status); + result = false; + return true; /// stop waiting } + + if (should_stop_watching_thread) + { + LOG_ERROR(log, "waitOtherHostFinish({}) can't wait for other hosts to finish after the watching thread stopped", throw_if_error); + chassert(false, "waitOtherHostFinish() can't wait for other hosts to finish after the watching thread stopped"); + if (throw_if_error) + throw Exception(ErrorCodes::LOGICAL_ERROR, "waitOtherHostsFinish() can't wait for other hosts to finish after the watching thread stopped"); + result = false; + return true; /// stop waiting + } + + LOG_TRACE(log, "Waiting for {} to finish{}{}", getHostDesc(host), reason_text, host_status); + return false; /// wait for next change of `state_changed` } LOG_TRACE(log, "Other hosts finished working on this {}", operation_name); + result = true; + return true; /// stop waiting +} + + +bool BackupCoordinationStageSync::finished() const +{ + std::lock_guard lock{mutex}; + return finishedNoLock(); +} + + +bool BackupCoordinationStageSync::finishedNoLock() const +{ + return state.hosts.at(current_host).finished; +} + + +bool BackupCoordinationStageSync::otherHostsFinished() const +{ + std::lock_guard lock{mutex}; + return otherHostsFinishedNoLock(); +} + + +bool BackupCoordinationStageSync::otherHostsFinishedNoLock() const +{ + for (const auto & [host, host_info] : state.hosts) + { + if (!host_info.finished && (host != current_host)) + return false; + } return true; } + +bool BackupCoordinationStageSync::allHostsFinishedNoLock() const +{ + return finishedNoLock() && otherHostsFinishedNoLock(); +} + + +Strings BackupCoordinationStageSync::getUnfinishedHosts() const +{ + std::lock_guard lock{mutex}; + return getUnfinishedHostsNoLock(); +} + + +Strings BackupCoordinationStageSync::getUnfinishedHostsNoLock() const +{ + if (allHostsFinishedNoLock()) + return {}; + + Strings res; + res.reserve(all_hosts.size()); + for (const auto & [host, host_info] : state.hosts) + { + if (!host_info.finished) + res.emplace_back(host); + } + return res; +} + + +Strings BackupCoordinationStageSync::getUnfinishedOtherHosts() const +{ + std::lock_guard lock{mutex}; + return getUnfinishedOtherHostsNoLock(); +} + + +Strings BackupCoordinationStageSync::getUnfinishedOtherHostsNoLock() const +{ + if (otherHostsFinishedNoLock()) + return {}; + + Strings res; + res.reserve(all_hosts.size() - 1); + for (const auto & [host, host_info] : state.hosts) + { + if (!host_info.finished && (host != current_host)) + res.emplace_back(host); + } + return res; +} + + +bool BackupCoordinationStageSync::setError(std::exception_ptr exception, bool throw_if_error) +{ + try + { + std::rethrow_exception(exception); + } + catch (const Exception & e) + { + return setError(e, throw_if_error); + } + catch (...) + { + return setError(Exception{getCurrentExceptionMessageAndPattern(true, true), getCurrentExceptionCode()}, throw_if_error); + } +} + + +bool BackupCoordinationStageSync::setError(const Exception & exception, bool throw_if_error) +{ + try + { + /// Most likely this exception has been already logged so here we're logging it without stacktrace. + String exception_message = getExceptionMessage(exception, /* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true); + LOG_INFO(log, "Sending exception from {} to other hosts: {}", current_host_desc, exception_message); + + { + std::lock_guard lock{mutex}; + if (state.host_with_error) + { + LOG_INFO(log, "The error node already exists"); + return true; + } + + if (tried_to_set_error) + { + LOG_INFO(log, "Skipped creating the error node because earlier we failed to do that"); + return false; + } + } + + auto holder = with_retries.createRetriesControlHolder("BackupCoordinationStageSync::setError", WithRetries::kErrorHandling); + holder.retries_ctl.retryLoop([&, &zookeeper = holder.faulty_zookeeper]() + { + with_retries.renewZooKeeper(zookeeper); + createErrorNode(exception, zookeeper); + }); + + { + std::lock_guard lock{mutex}; + tried_to_set_error = true; + return true; + } + } + catch (...) + { + LOG_TRACE(log, "Caught exception while removing nodes from ZooKeeper for this {}: {}", + is_restore ? "restore" : "backup", + getCurrentExceptionMessage(/* with_stacktrace= */ false, /* check_embedded_stacktrace= */ true)); + + std::lock_guard lock{mutex}; + tried_to_set_error = true; + + if (throw_if_error) + throw; + return false; + } +} + + +void BackupCoordinationStageSync::createErrorNode(const Exception & exception, Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper) +{ + String serialized_error; + { + WriteBufferFromOwnString buf; + writeStringBinary(current_host, buf); + writeException(exception, buf, true); + serialized_error = buf.str(); + } + + auto code = zookeeper->tryCreate(error_node_path, serialized_error, zkutil::CreateMode::Persistent); + + if (code == Coordination::Error::ZOK) + { + std::lock_guard lock{mutex}; + if (!state.host_with_error) + { + state.host_with_error = current_host; + state.hosts.at(current_host).exception = parseErrorNode(serialized_error).first; + } + LOG_TRACE(log, "Sent exception from {} to other hosts", current_host_desc); + return; + } + + if (code == Coordination::Error::ZNODEEXISTS) + { + String another_error = zookeeper->get(error_node_path); + auto [another_exception, host] = parseErrorNode(another_error); + if (another_exception) + { + std::lock_guard lock{mutex}; + if (!state.host_with_error) + { + state.host_with_error = host; + state.hosts.at(host).exception = another_exception; + } + LOG_INFO(log, "Another error is already assigned for this {}", operation_name); + return; + } + } + + throw zkutil::KeeperException::fromPath(code, error_node_path); +} + + +std::pair BackupCoordinationStageSync::parseErrorNode(const String & error_node_contents) const +{ + ReadBufferFromOwnString buf{error_node_contents}; + String host; + readStringBinary(host, buf); + if (std::find(all_hosts.begin(), all_hosts.end(), host) == all_hosts.end()) + return {}; + auto exception = std::make_exception_ptr(readException(buf, fmt::format("Got error from {}", getHostDesc(host)))); + return {exception, host}; +} + + +bool BackupCoordinationStageSync::isErrorSet() const +{ + std::lock_guard lock{mutex}; + return state.host_with_error.has_value(); +} + } diff --git a/src/Backups/BackupCoordinationStageSync.h b/src/Backups/BackupCoordinationStageSync.h index dc0d3c3c83d..879b2422b84 100644 --- a/src/Backups/BackupCoordinationStageSync.h +++ b/src/Backups/BackupCoordinationStageSync.h @@ -1,7 +1,9 @@ #pragma once +#include #include + namespace DB { @@ -9,12 +11,16 @@ namespace DB class BackupCoordinationStageSync { 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( 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 & 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 bool allow_concurrency_, /// whether it's allowed to have concurrent backups or restores. + BackupConcurrencyCounters & concurrency_counters_, const WithRetries & with_retries_, ThreadPoolCallbackRunnerUnsafe schedule_, QueryStatusPtr process_list_element_, @@ -22,30 +28,37 @@ public: ~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. void setStage(const String & stage, const String & stage_result = {}); - /// Waits until all the specified hosts come to the specified stage. - /// The function returns the results which 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 waitForHostsToReachStage(const String & stage_to_wait, const Strings & hosts, std::optional 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); + /// Waits until specified hosts come to the specified stage. + /// The function returns the results which the specified hosts set when they came to the required stage. + Strings waitHostsReachStage(const Strings & hosts, const String & stage_to_wait) const; /// 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). - /// Doesn't stops waiting if some host encounters an error or gets cancelled. - bool tryWaitForOtherHostsToFinishAfterError() const noexcept; + /// Waits until the hosts other than the current host finish their work. Must be called before finish(). + /// Stops waiting and throws an exception if another host encounters an error or if some host gets cancelled. + 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). - bool tryFinishAfterError(bool & other_hosts_also_finished) noexcept; + /// Lets other hosts know that the current host has finished its work. + 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". static String getHostDesc(const String & host); @@ -59,8 +72,8 @@ private: 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. - void createStartAndAliveNodes(); - void createStartAndAliveNodes(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper); + void createStartAndAliveNodesAndCheckConcurrency(BackupConcurrencyCounters & concurrency_counters_); + void createStartAndAliveNodesAndCheckConcurrency(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper); /// Deserialize the version of a node stored in the 'start' node. 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. 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; /// Lets other hosts know that the current host has encountered an error. - bool trySetError(const Exception & exception); - void setError(const Exception & exception); + bool setError(const Exception & exception, bool throw_if_error); + void createErrorNode(const Exception & exception, Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper); /// Deserializes an error stored in the error node. - static std::pair parseErrorNode(const String & error_node_contents); + std::pair parseErrorNode(const String & error_node_contents) const; /// Reset the `connected` flag for each host. void resetConnectedFlag(); @@ -102,19 +118,27 @@ private: void cancelQueryIfDisconnectedTooLong(); /// 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 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. - bool tryFinishImpl(); - bool tryFinishImpl(bool & other_hosts_also_finished, bool throw_if_error, WithRetries::Kind retries_kind); - void createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper); + bool finishImpl(bool throw_if_error, WithRetries::Kind retries_kind); + void createFinishNodeAndRemoveAliveNode(Coordination::ZooKeeperWithFaultInjection::Ptr zookeeper, bool throw_if_error); /// Returns the version used by the initiator. int getInitiatorVersion() const; /// Waits until all the other hosts finish their work. - bool tryWaitForOtherHostsToFinishImpl(const String & reason, bool throw_if_error, std::optional timeout) const; - bool checkIfOtherHostsFinish(const String & reason, bool throw_if_error, bool time_is_out, std::optional timeout) const TSA_REQUIRES(mutex); + bool waitOtherHostsFinishImpl(const String & reason, std::optional timeout, bool throw_if_error) const; + bool checkIfOtherHostsFinish(const String & reason, std::optional 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 String operation_name; @@ -138,15 +162,16 @@ private: /// Paths in ZooKeeper. const std::filesystem::path zookeeper_path; const String root_zookeeper_path; - const String operation_node_path; + const String operation_zookeeper_path; const String operation_node_name; - const String stage_node_path; const String start_node_path; const String finish_node_path; const String num_hosts_node_path; + const String error_node_path; const String alive_node_path; const String alive_tracker_node_path; - const String error_node_path; + + std::optional local_concurrency_check; std::shared_ptr zk_nodes_changed; @@ -176,25 +201,21 @@ private: { std::map hosts; /// std::map because we need to compare states std::optional host_with_error; - bool cancelled = false; bool operator ==(const State & other) const; bool operator !=(const State & other) const; + void merge(const State & other); }; State state TSA_GUARDED_BY(mutex); mutable std::condition_variable state_changed; std::future watching_thread_future; - std::atomic should_stop_watching_thread = false; + bool should_stop_watching_thread TSA_GUARDED_BY(mutex) = false; - struct FinishResult - { - bool succeeded = false; - std::exception_ptr exception; - bool other_hosts_also_finished = false; - }; - FinishResult finish_result TSA_GUARDED_BY(mutex); + bool query_is_sent_to_other_hosts TSA_GUARDED_BY(mutex) = false; + bool tried_to_finish TSA_GUARDED_BY(mutex) = false; + bool tried_to_set_error TSA_GUARDED_BY(mutex) = false; mutable std::mutex mutex; }; diff --git a/src/Backups/BackupsWorker.cpp b/src/Backups/BackupsWorker.cpp index 8480dc5d64d..88ebf8eef32 100644 --- a/src/Backups/BackupsWorker.cpp +++ b/src/Backups/BackupsWorker.cpp @@ -329,6 +329,7 @@ std::pair BackupsWorker::start(const ASTPtr & backup_ struct BackupsWorker::BackupStarter { BackupsWorker & backups_worker; + LoggerPtr log; std::shared_ptr 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. ContextMutablePtr backup_context; @@ -345,6 +346,7 @@ struct BackupsWorker::BackupStarter BackupStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_) : backups_worker(backups_worker_) + , log(backups_worker.log) , backup_query(std::static_pointer_cast(query_->clone())) , query_context(context_) , backup_context(Context::createCopy(query_context)) @@ -399,9 +401,20 @@ struct BackupsWorker::BackupStarter chassert(!backup); backup = backups_worker.openBackupForWriting(backup_info, backup_settings, backup_coordination, backup_context); - backups_worker.doBackup( - backup, backup_query, backup_id, backup_name_for_logging, backup_settings, backup_coordination, backup_context, - on_cluster, cluster); + backups_worker.doBackup(backup, backup_query, backup_id, backup_settings, backup_coordination, backup_context, + 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() @@ -416,16 +429,29 @@ struct BackupsWorker::BackupStarter if (backup && !backup->setIsCorrupted()) 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) - backup->tryRemoveAllFiles(); - - backup_coordination->tryFinishAfterError(); + all_hosts_finished = backup_coordination->finish(/* throw_if_error = */ false) && other_hosts_finished; } + 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()); } }; @@ -497,7 +523,6 @@ void BackupsWorker::doBackup( BackupMutablePtr backup, const std::shared_ptr & backup_query, const OperationID & backup_id, - const String & backup_name_for_logging, const BackupSettings & backup_settings, std::shared_ptr backup_coordination, ContextMutablePtr context, @@ -521,10 +546,10 @@ void BackupsWorker::doBackup( backup_settings.copySettingsToQuery(*backup_query); sendQueryToOtherHosts(*backup_query, cluster, backup_settings.shard_num, backup_settings.replica_num, context, required_access, backup_coordination->getOnClusterInitializationKeeperRetriesInfo()); - backup_coordination->setBackupQueryWasSentToOtherHosts(); + backup_coordination->setBackupQueryIsSentToOtherHosts(); /// Wait until all the hosts have written their backup entries. - backup_coordination->waitForOtherHostsToFinish(); + backup_coordination->waitOtherHostsFinish(/* throw_if_error = */ true); } else { @@ -569,18 +594,8 @@ void BackupsWorker::doBackup( 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. 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 { BackupsWorker & backups_worker; + LoggerPtr log; std::shared_ptr 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. ContextMutablePtr restore_context; @@ -702,6 +718,7 @@ struct BackupsWorker::RestoreStarter RestoreStarter(BackupsWorker & backups_worker_, const ASTPtr & query_, const ContextPtr & context_) : backups_worker(backups_worker_) + , log(backups_worker.log) , restore_query(std::static_pointer_cast(query_->clone())) , query_context(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); - backups_worker.doRestore( - restore_query, - restore_id, - backup_name_for_logging, - backup_info, - restore_settings, - restore_coordination, - restore_context, - on_cluster, - cluster); + backups_worker.doRestore(restore_query, restore_id, backup_info, restore_settings, restore_coordination, restore_context, + on_cluster, cluster); + + /// The restore coordination is not needed anymore. + restore_coordination->finish(/* throw_if_error = */ true); + if (!is_internal_restore) + restore_coordination->cleanup(/* throw_if_error = */ true); + restore_coordination.reset(); + + 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() @@ -770,12 +788,16 @@ struct BackupsWorker::RestoreStarter /// 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)); - 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(); - restore_coordination->tryFinishAfterError(); + bool other_hosts_finished = !is_internal_restore + && (!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()); } }; @@ -838,7 +860,6 @@ BackupPtr BackupsWorker::openBackupForReading(const BackupInfo & backup_info, co void BackupsWorker::doRestore( const std::shared_ptr & restore_query, const OperationID & restore_id, - const String & backup_name_for_logging, const BackupInfo & backup_info, RestoreSettings restore_settings, std::shared_ptr restore_coordination, @@ -882,10 +903,10 @@ void BackupsWorker::doRestore( restore_settings.copySettingsToQuery(*restore_query); sendQueryToOtherHosts(*restore_query, cluster, restore_settings.shard_num, restore_settings.replica_num, context, {}, restore_coordination->getOnClusterInitializationKeeperRetriesInfo()); - restore_coordination->setRestoreQueryWasSentToOtherHosts(); + restore_coordination->setRestoreQueryIsSentToOtherHosts(); /// Wait until all the hosts have done with their restoring work. - restore_coordination->waitForOtherHostsToFinish(); + restore_coordination->waitOtherHostsFinish(/* throw_if_error = */ true); } else { @@ -905,12 +926,6 @@ void BackupsWorker::doRestore( backup, context, getThreadPool(ThreadPoolId::RESTORE), after_task_callback}; 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) { return std::make_shared( - *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; @@ -981,8 +996,7 @@ BackupsWorker::makeRestoreCoordination(bool on_cluster, const RestoreSettings & { if (!on_cluster) { - return std::make_shared( - *restore_settings.restore_uuid, allow_concurrent_restores, *concurrency_counters); + return std::make_shared(allow_concurrent_restores, *concurrency_counters); } bool is_internal_restore = restore_settings.internal; diff --git a/src/Backups/BackupsWorker.h b/src/Backups/BackupsWorker.h index 37f91e269a9..2e5ca84f3f6 100644 --- a/src/Backups/BackupsWorker.h +++ b/src/Backups/BackupsWorker.h @@ -81,7 +81,6 @@ private: BackupMutablePtr backup, const std::shared_ptr & backup_query, const BackupOperationID & backup_id, - const String & backup_name_for_logging, const BackupSettings & backup_settings, std::shared_ptr backup_coordination, ContextMutablePtr context, @@ -102,7 +101,6 @@ private: void doRestore( const std::shared_ptr & restore_query, const BackupOperationID & restore_id, - const String & backup_name_for_logging, const BackupInfo & backup_info, RestoreSettings restore_settings, std::shared_ptr restore_coordination, diff --git a/src/Backups/IBackupCoordination.h b/src/Backups/IBackupCoordination.h index c0eb90de89b..8bd874b9d0d 100644 --- a/src/Backups/IBackupCoordination.h +++ b/src/Backups/IBackupCoordination.h @@ -20,29 +20,27 @@ class IBackupCoordination public: 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. 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. - virtual bool trySetError(std::exception_ptr exception) = 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; + /// 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; /// 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. - 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). - /// Doesn't stops waiting if some host encounters an error or gets cancelled. - virtual bool tryWaitForOtherHostsToFinishAfterError() noexcept = 0; + /// Lets other hosts know that the current host has finished its work. + virtual bool finish(bool throw_if_error) = 0; + + /// Removes temporary nodes in ZooKeeper. + virtual bool cleanup(bool throw_if_error) = 0; struct PartNameAndChecksum { diff --git a/src/Backups/IRestoreCoordination.h b/src/Backups/IRestoreCoordination.h index daabf1745f3..cc7bfd24202 100644 --- a/src/Backups/IRestoreCoordination.h +++ b/src/Backups/IRestoreCoordination.h @@ -18,29 +18,27 @@ class IRestoreCoordination public: 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. 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. - virtual bool trySetError(std::exception_ptr exception) = 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; + /// 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; /// 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. - 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). - /// Doesn't stops waiting if some host encounters an error or gets cancelled. - virtual bool tryWaitForOtherHostsToFinishAfterError() noexcept = 0; + /// Lets other hosts know that the current host has finished its work. + virtual bool finish(bool throw_if_error) = 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. virtual bool acquireCreatingTableInReplicatedDatabase(const String & database_zk_path, const String & table_name) = 0; diff --git a/src/Backups/RestoreCoordinationLocal.cpp b/src/Backups/RestoreCoordinationLocal.cpp index 569f58f1909..a9eee1fb159 100644 --- a/src/Backups/RestoreCoordinationLocal.cpp +++ b/src/Backups/RestoreCoordinationLocal.cpp @@ -10,9 +10,9 @@ namespace DB { RestoreCoordinationLocal::RestoreCoordinationLocal( - const UUID & restore_uuid, bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_) + bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_) : 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_) { } diff --git a/src/Backups/RestoreCoordinationLocal.h b/src/Backups/RestoreCoordinationLocal.h index 6be357c4b7e..6e3262a8a2e 100644 --- a/src/Backups/RestoreCoordinationLocal.h +++ b/src/Backups/RestoreCoordinationLocal.h @@ -17,16 +17,16 @@ class ASTCreateQuery; class RestoreCoordinationLocal : public IRestoreCoordination { public: - RestoreCoordinationLocal(const UUID & restore_uuid_, bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_); + RestoreCoordinationLocal(bool allow_concurrent_restore_, BackupConcurrencyCounters & concurrency_counters_); ~RestoreCoordinationLocal() override; + void setRestoreQueryIsSentToOtherHosts() override {} + bool isRestoreQuerySentToOtherHosts() const override { return false; } Strings setStage(const String &, const String &, bool) override { return {}; } - void setRestoreQueryWasSentToOtherHosts() override {} - bool trySetError(std::exception_ptr) override { return true; } - void finish() override {} - bool tryFinishAfterError() noexcept override { return true; } - void waitForOtherHostsToFinish() override {} - bool tryWaitForOtherHostsToFinishAfterError() noexcept override { return true; } + bool setError(std::exception_ptr, bool) override { return true; } + bool waitOtherHostsFinish(bool) const override { return true; } + bool finish(bool) override { return true; } + bool cleanup(bool) override { return true; } /// 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; diff --git a/src/Backups/RestoreCoordinationOnCluster.cpp b/src/Backups/RestoreCoordinationOnCluster.cpp index 2029ad8b072..fad7341c044 100644 --- a/src/Backups/RestoreCoordinationOnCluster.cpp +++ b/src/Backups/RestoreCoordinationOnCluster.cpp @@ -35,17 +35,21 @@ RestoreCoordinationOnCluster::RestoreCoordinationOnCluster( , current_host_index(BackupCoordinationOnCluster::findCurrentHostIndex(current_host, all_hosts)) , 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_); }) - , concurrency_check(restore_uuid_, /* is_restore = */ true, /* on_cluster = */ true, allow_concurrent_restore_, concurrency_counters_) - , stage_sync(/* is_restore = */ true, fs::path{zookeeper_path} / "stage", current_host, all_hosts, allow_concurrent_restore_, with_retries, schedule_, process_list_element_, log) - , cleaner(zookeeper_path, with_retries, log) + , 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_, concurrency_counters_, with_retries, schedule_, process_list_element_, log) { - createRootNodes(); + try + { + createRootNodes(); + } + catch (...) + { + stage_sync.setError(std::current_exception(), /* throw_if_error = */ false); + throw; + } } -RestoreCoordinationOnCluster::~RestoreCoordinationOnCluster() -{ - tryFinishImpl(); -} +RestoreCoordinationOnCluster::~RestoreCoordinationOnCluster() = default; 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) { stage_sync.setStage(new_stage, message); - - if (!sync) - return {}; - - return stage_sync.waitForHostsToReachStage(new_stage, all_hosts_without_initiator); + if (sync) + return stage_sync.waitHostsReachStage(all_hosts_without_initiator, new_stage); + return {}; } -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; - stage_sync.finish(other_hosts_also_finished); - - if ((current_host == kInitiator) && (other_hosts_also_finished || !restore_query_was_sent_to_other_hosts)) - cleaner.cleanup(); + return stage_sync.finish(throw_if_error); } -bool RestoreCoordinationOnCluster::tryFinishAfterError() noexcept +bool RestoreCoordinationOnCluster::cleanup(bool throw_if_error) { - return tryFinishImpl(); -} - -bool RestoreCoordinationOnCluster::tryFinishImpl() noexcept -{ - 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)) + /// 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); + if (!all_hosts_finished) { - if (!cleaner.tryCleanupAfterError()) - return false; - } - - 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) + auto unfinished_hosts = expect_other_hosts_finished ? stage_sync.getUnfinishedHosts() : Strings{current_host}; + LOG_INFO(log, "Skipping removing nodes from ZooKeeper because hosts {} didn't finish", + BackupCoordinationStageSync::getHostsDesc(unfinished_hosts)); return false; - if (!restore_query_was_sent_to_other_hosts) - return true; - return stage_sync.tryWaitForOtherHostsToFinishAfterError(); + } + return cleaner.cleanup(throw_if_error); } ZooKeeperRetriesInfo RestoreCoordinationOnCluster::getOnClusterInitializationKeeperRetriesInfo() const diff --git a/src/Backups/RestoreCoordinationOnCluster.h b/src/Backups/RestoreCoordinationOnCluster.h index 87a8dd3ce83..99929cbdac3 100644 --- a/src/Backups/RestoreCoordinationOnCluster.h +++ b/src/Backups/RestoreCoordinationOnCluster.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -15,7 +14,7 @@ class RestoreCoordinationOnCluster : public IRestoreCoordination { public: /// 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( const UUID & restore_uuid_, @@ -31,13 +30,13 @@ public: ~RestoreCoordinationOnCluster() override; + void setRestoreQueryIsSentToOtherHosts() override; + bool isRestoreQuerySentToOtherHosts() const override; Strings setStage(const String & new_stage, const String & message, bool sync) override; - void setRestoreQueryWasSentToOtherHosts() override; - bool trySetError(std::exception_ptr exception) override; - void finish() override; - bool tryFinishAfterError() noexcept override; - void waitForOtherHostsToFinish() override; - bool tryWaitForOtherHostsToFinishAfterError() noexcept override; + bool setError(std::exception_ptr exception, bool throw_if_error) override; + bool waitOtherHostsFinish(bool throw_if_error) const override; + bool finish(bool throw_if_error) override; + bool cleanup(bool throw_if_error) override; /// 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; @@ -78,11 +77,10 @@ private: const size_t current_host_index; LoggerPtr const log; + /// The order is important: `stage_sync` must be initialized after `with_retries` and `cleaner`. const WithRetries with_retries; - BackupConcurrencyCheck concurrency_check; - BackupCoordinationStageSync stage_sync; BackupCoordinationCleaner cleaner; - std::atomic restore_query_was_sent_to_other_hosts = false; + BackupCoordinationStageSync stage_sync; }; } diff --git a/src/Client/ClientBase.cpp b/src/Client/ClientBase.cpp index ce47f503931..90120e009f0 100644 --- a/src/Client/ClientBase.cpp +++ b/src/Client/ClientBase.cpp @@ -68,15 +68,16 @@ #include #include -#include -#include -#include #include +#include #include #include #include +#include #include #include +#include +#include #include #include @@ -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 (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)) - progress_table.clearTableOutput(*tty_buf); + { + std::unique_lock lock(tty_mutex); + progress_table.clearTableOutput(*tty_buf, lock); + } try { @@ -464,13 +471,15 @@ void ClientBase::onData(Block & block, ASTPtr parsed_query) { if (select_into_file && !select_into_file_and_stdout) 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 && select_into_file && !select_into_file_and_stdout) 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(); 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) - 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->flush(); } @@ -1151,34 +1166,8 @@ void ClientBase::receiveResult(ASTPtr parsed_query, Int32 signals_before_stop, b std::exception_ptr local_format_error; - if (keystroke_interceptor) - { - 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(); - } - } - }); + startKeystrokeInterceptorIfExists(); + SCOPE_EXIT({ stopKeystrokeInterceptorIfExists(); }); while (true) { @@ -1318,7 +1307,10 @@ void ClientBase::onProgress(const Progress & value) output_format->onProgress(value); 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) @@ -1330,9 +1322,15 @@ void ClientBase::onTimezoneUpdate(const String & tz) void ClientBase::onEndOfStream() { 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) - progress_table.clearTableOutput(*tty_buf); + { + std::unique_lock lock(tty_mutex); + progress_table.clearTableOutput(*tty_buf, lock); + } if (output_format) { @@ -1414,11 +1412,15 @@ void ClientBase::onProfileEvents(Block & block) progress_table.updateTable(block); 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) { 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) @@ -1429,9 +1431,15 @@ void ClientBase::onProfileEvents(Block & block) profile_events.watch.restart(); initLogsOutputStream(); 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) - 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->flush(); @@ -1450,7 +1458,10 @@ void ClientBase::onProfileEvents(Block & block) void ClientBase::resetOutput() { 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 @@ -1619,6 +1630,9 @@ void ClientBase::processInsertQuery(const String & query_to_execute, ASTPtr pars if (send_external_tables) sendExternalTables(parsed_query); + startKeystrokeInterceptorIfExists(); + SCOPE_EXIT({ stopKeystrokeInterceptorIfExists(); }); + /// Receive description of table structure. Block sample; ColumnsDescription columns_description; @@ -1665,7 +1679,7 @@ void ClientBase::sendData(Block & sample, const ColumnsDescription & columns_des /// Set callback to be called on file progress. 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) @@ -1947,9 +1961,15 @@ void ClientBase::cancelQuery() } 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) - progress_table.clearTableOutput(*tty_buf); + { + std::unique_lock lock(tty_mutex); + progress_table.clearTableOutput(*tty_buf, lock); + } if (is_interactive) output_stream << "Cancelling query." << std::endl; @@ -2112,9 +2132,15 @@ void ClientBase::processParsedSingleQuery(const String & full_query, const Strin { initLogsOutputStream(); 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) - 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->flush(); @@ -2613,6 +2639,39 @@ bool ClientBase::addMergeTreeSettings(ASTCreateQuery & ast_create) 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() { if (getClientConfiguration().has("query_id")) diff --git a/src/Client/ClientBase.h b/src/Client/ClientBase.h index 6b261714ff6..7660efff582 100644 --- a/src/Client/ClientBase.h +++ b/src/Client/ClientBase.h @@ -208,6 +208,9 @@ private: void initQueryIdFormats(); bool addMergeTreeSettings(ASTCreateQuery & ast_create); + void startKeystrokeInterceptorIfExists(); + void stopKeystrokeInterceptorIfExists(); + protected: class QueryInterruptHandler : private boost::noncopyable @@ -325,6 +328,7 @@ protected: /// /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. std::unique_ptr tty_buf; + std::mutex tty_mutex; String home_path; String history_file; /// Path to a file containing command history. diff --git a/src/Client/ClientBaseHelpers.cpp b/src/Client/ClientBaseHelpers.cpp index e8e009ec306..7b4651a638f 100644 --- a/src/Client/ClientBaseHelpers.cpp +++ b/src/Client/ClientBaseHelpers.cpp @@ -140,8 +140,6 @@ void highlight(const String & query, std::vector & colors /// We don't do highlighting for foreign dialects, such as PRQL and Kusto. /// 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]); ASTPtr ast; bool parse_res = false; diff --git a/src/Client/ProgressTable.cpp b/src/Client/ProgressTable.cpp index f63935440e4..8a1e60b1b0c 100644 --- a/src/Client/ProgressTable.cpp +++ b/src/Client/ProgressTable.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -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 &, bool show_table, bool toggle_enabled) { std::lock_guard lock{mutex}; if (!show_table && toggle_enabled) @@ -360,7 +362,7 @@ void ProgressTable::updateTable(const Block & block) written_first_block = true; } -void ProgressTable::clearTableOutput(WriteBufferFromFileDescriptor & message) +void ProgressTable::clearTableOutput(WriteBufferFromFileDescriptor & message, std::unique_lock &) { message << "\r" << CLEAR_TO_END_OF_SCREEN << SHOW_CURSOR; message.next(); diff --git a/src/Client/ProgressTable.h b/src/Client/ProgressTable.h index f2563d91217..44f91c2e408 100644 --- a/src/Client/ProgressTable.h +++ b/src/Client/ProgressTable.h @@ -27,8 +27,9 @@ public: } /// Write progress table with metrics. - void writeTable(WriteBufferFromFileDescriptor & message, bool show_table, bool toggle_enabled); - void clearTableOutput(WriteBufferFromFileDescriptor & message); + void writeTable(WriteBufferFromFileDescriptor & message, std::unique_lock & message_lock, + bool show_table, bool toggle_enabled); + void clearTableOutput(WriteBufferFromFileDescriptor & message, std::unique_lock & message_lock); void writeFinalTable(); /// Update the metric values. They can be updated from: diff --git a/src/Columns/ColumnArray.cpp b/src/Columns/ColumnArray.cpp index 0c6d7c4e5c6..3f88ca93a97 100644 --- a/src/Columns/ColumnArray.cpp +++ b/src/Columns/ColumnArray.cpp @@ -662,6 +662,8 @@ ColumnPtr ColumnArray::filter(const Filter & filt, ssize_t result_size_hint) con return filterNumber(filt, result_size_hint); if (typeid_cast(data.get())) return filterNumber(filt, result_size_hint); + if (typeid_cast(data.get())) + return filterNumber(filt, result_size_hint); if (typeid_cast(data.get())) return filterNumber(filt, result_size_hint); if (typeid_cast(data.get())) @@ -1065,6 +1067,8 @@ ColumnPtr ColumnArray::replicate(const Offsets & replicate_offsets) const return replicateNumber(replicate_offsets); if (typeid_cast(data.get())) return replicateNumber(replicate_offsets); + if (typeid_cast(data.get())) + return replicateNumber(replicate_offsets); if (typeid_cast(data.get())) return replicateNumber(replicate_offsets); if (typeid_cast(data.get())) diff --git a/src/Columns/ColumnUnique.cpp b/src/Columns/ColumnUnique.cpp index 54f45204c00..773edbfd590 100644 --- a/src/Columns/ColumnUnique.cpp +++ b/src/Columns/ColumnUnique.cpp @@ -16,6 +16,7 @@ template class ColumnUnique; template class ColumnUnique; template class ColumnUnique; template class ColumnUnique; +template class ColumnUnique; template class ColumnUnique; template class ColumnUnique; template class ColumnUnique; diff --git a/src/Columns/ColumnUnique.h b/src/Columns/ColumnUnique.h index ffa7c311e9e..ce7bbf0766f 100644 --- a/src/Columns/ColumnUnique.h +++ b/src/Columns/ColumnUnique.h @@ -760,6 +760,7 @@ extern template class ColumnUnique; extern template class ColumnUnique; extern template class ColumnUnique; extern template class ColumnUnique; +extern template class ColumnUnique; extern template class ColumnUnique; extern template class ColumnUnique; extern template class ColumnUnique; diff --git a/src/Columns/ColumnVector.cpp b/src/Columns/ColumnVector.cpp index dc4941988e9..84fc6ebc61d 100644 --- a/src/Columns/ColumnVector.cpp +++ b/src/Columns/ColumnVector.cpp @@ -118,9 +118,9 @@ struct ColumnVector::less_stable if (unlikely(parent.data[lhs] == parent.data[rhs])) return lhs < rhs; - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { - 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; } @@ -150,9 +150,9 @@ struct ColumnVector::greater_stable if (unlikely(parent.data[lhs] == parent.data[rhs])) return lhs < rhs; - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { - 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; } @@ -224,9 +224,9 @@ void ColumnVector::getPermutation(IColumn::PermutationSortDirection direction iota(res.data(), data_size, IColumn::Permutation::value_type(0)); - if constexpr (has_find_extreme_implementation && !std::is_floating_point_v) + if constexpr (has_find_extreme_implementation && !is_floating_point) { - /// Disabled for:floating point + /// Disabled for floating point: /// * floating point: We don't deal with nan_direction_hint /// * stability::Stable: We might return any value, not the first if ((limit == 1) && (stability == IColumn::PermutationSortStability::Unstable)) @@ -256,7 +256,7 @@ void ColumnVector::getPermutation(IColumn::PermutationSortDirection direction bool sort_is_stable = stability == IColumn::PermutationSortStability::Stable; /// 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) || !sort_is_stable; + bool use_radix_sort = (sort_is_stable && ascending && !is_floating_point) || !sort_is_stable; /// 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::max() && use_radix_sort) @@ -283,7 +283,7 @@ void ColumnVector::getPermutation(IColumn::PermutationSortDirection direction /// Radix sort treats all NaNs to be greater than all numbers. /// If the user needs the opposite, we must move them accordingly. - if (std::is_floating_point_v && nan_direction_hint < 0) + if (is_floating_point && nan_direction_hint < 0) { size_t nans_to_move = 0; @@ -330,7 +330,7 @@ void ColumnVector::updatePermutation(IColumn::PermutationSortDirection direct if constexpr (is_arithmetic_v && !is_big_int_v) { /// 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) || !sort_is_stable; + bool use_radix_sort = (sort_is_stable && ascending && !is_floating_point) || !sort_is_stable; size_t size = end - begin; /// Thresholds on size. Lower threshold is arbitrary. Upper threshold is chosen by the type for histogram counters. @@ -353,7 +353,7 @@ void ColumnVector::updatePermutation(IColumn::PermutationSortDirection direct /// Radix sort treats all NaNs to be greater than all numbers. /// If the user needs the opposite, we must move them accordingly. - if (std::is_floating_point_v && nan_direction_hint < 0) + if (is_floating_point && nan_direction_hint < 0) { size_t nans_to_move = 0; @@ -1005,6 +1005,7 @@ template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; +template class ColumnVector; template class ColumnVector; template class ColumnVector; template class ColumnVector; diff --git a/src/Columns/ColumnVector.h b/src/Columns/ColumnVector.h index 8f81da86375..47840a90a0e 100644 --- a/src/Columns/ColumnVector.h +++ b/src/Columns/ColumnVector.h @@ -481,6 +481,7 @@ extern template class ColumnVector; extern template class ColumnVector; extern template class ColumnVector; extern template class ColumnVector; +extern template class ColumnVector; extern template class ColumnVector; extern template class ColumnVector; extern template class ColumnVector; diff --git a/src/Columns/ColumnsCommon.cpp b/src/Columns/ColumnsCommon.cpp index 591c56a00bd..3e0ead39486 100644 --- a/src/Columns/ColumnsCommon.cpp +++ b/src/Columns/ColumnsCommon.cpp @@ -328,6 +328,7 @@ INSTANTIATE(Int32) INSTANTIATE(Int64) INSTANTIATE(Int128) INSTANTIATE(Int256) +INSTANTIATE(BFloat16) INSTANTIATE(Float32) INSTANTIATE(Float64) INSTANTIATE(Decimal32) diff --git a/src/Columns/ColumnsNumber.h b/src/Columns/ColumnsNumber.h index ae7eddb0b22..2dce2269079 100644 --- a/src/Columns/ColumnsNumber.h +++ b/src/Columns/ColumnsNumber.h @@ -23,6 +23,7 @@ using ColumnInt64 = ColumnVector; using ColumnInt128 = ColumnVector; using ColumnInt256 = ColumnVector; +using ColumnBFloat16 = ColumnVector; using ColumnFloat32 = ColumnVector; using ColumnFloat64 = ColumnVector; diff --git a/src/Columns/IColumn.cpp b/src/Columns/IColumn.cpp index c9a0514af4e..4a3886dddb6 100644 --- a/src/Columns/IColumn.cpp +++ b/src/Columns/IColumn.cpp @@ -443,6 +443,7 @@ template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; +template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; template class IColumnHelper, ColumnFixedSizeHelper>; diff --git a/src/Columns/MaskOperations.cpp b/src/Columns/MaskOperations.cpp index 873a4060872..eac42400517 100644 --- a/src/Columns/MaskOperations.cpp +++ b/src/Columns/MaskOperations.cpp @@ -63,6 +63,7 @@ INSTANTIATE(Int32) INSTANTIATE(Int64) INSTANTIATE(Int128) INSTANTIATE(Int256) +INSTANTIATE(BFloat16) INSTANTIATE(Float32) INSTANTIATE(Float64) INSTANTIATE(Decimal32) @@ -200,6 +201,7 @@ static MaskInfo extractMaskImpl( || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info) || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info) || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info) + || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info) || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info) || extractMaskNumeric(mask, column, null_value, null_bytemap, nulls, mask_info))) throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Cannot convert column {} to mask.", column->getName()); diff --git a/src/Columns/tests/gtest_column_vector.cpp b/src/Columns/tests/gtest_column_vector.cpp index b71d4a095ab..3a084a89079 100644 --- a/src/Columns/tests/gtest_column_vector.cpp +++ b/src/Columns/tests/gtest_column_vector.cpp @@ -93,6 +93,7 @@ TEST(ColumnVector, Filter) testFilter(); testFilter(); testFilter(); + testFilter(); testFilter(); testFilter(); testFilter(); diff --git a/src/Columns/tests/gtest_low_cardinality.cpp b/src/Columns/tests/gtest_low_cardinality.cpp index ce16d2cadb1..301fa2a6090 100644 --- a/src/Columns/tests/gtest_low_cardinality.cpp +++ b/src/Columns/tests/gtest_low_cardinality.cpp @@ -45,6 +45,7 @@ TEST(ColumnLowCardinality, Insert) testLowCardinalityNumberInsert(std::make_shared()); testLowCardinalityNumberInsert(std::make_shared()); + testLowCardinalityNumberInsert(std::make_shared()); testLowCardinalityNumberInsert(std::make_shared()); testLowCardinalityNumberInsert(std::make_shared()); } diff --git a/src/Common/CPUID.h b/src/Common/CPUID.h index b49f7706904..b5c26e64d1e 100644 --- a/src/Common/CPUID.h +++ b/src/Common/CPUID.h @@ -266,6 +266,11 @@ inline bool haveAVX512VBMI2() noexcept 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 { return CPUInfo(0x0).registers.eax >= 0x7 && ((CPUInfo(0x1).registers.ecx >> 30) & 1u); @@ -326,6 +331,7 @@ inline bool haveAMXINT8() noexcept OP(AVX512VL) \ OP(AVX512VBMI) \ OP(AVX512VBMI2) \ + OP(AVX512BF16) \ OP(PREFETCHWT1) \ OP(SHA) \ OP(ADX) \ diff --git a/src/Common/CurrentMetrics.cpp b/src/Common/CurrentMetrics.cpp index 0526596509d..0a987cf36af 100644 --- a/src/Common/CurrentMetrics.cpp +++ b/src/Common/CurrentMetrics.cpp @@ -255,6 +255,7 @@ M(PartsActive, "Active data part, used by current and upcoming SELECTs.") \ M(AttachedDatabase, "Active databases.") \ M(AttachedTable, "Active tables.") \ + M(AttachedReplicatedTable, "Active replicated tables.") \ M(AttachedView, "Active views.") \ M(AttachedDictionary, "Active dictionaries.") \ M(PartsOutdated, "Not active data part, but could be used by only current SELECTs, could be deleted after SELECTs finishes.") \ diff --git a/src/Common/FailPoint.cpp b/src/Common/FailPoint.cpp index 0898bdded83..bc1b604d0e5 100644 --- a/src/Common/FailPoint.cpp +++ b/src/Common/FailPoint.cpp @@ -87,6 +87,7 @@ APPLY_FOR_FAILPOINTS(M, M, M, M) std::unordered_map> FailPointInjection::fail_point_wait_channels; std::mutex FailPointInjection::mu; + class FailPointChannel : private boost::noncopyable { public: diff --git a/src/Common/FailPoint.h b/src/Common/FailPoint.h index 1af13d08553..69aa8d75b5b 100644 --- a/src/Common/FailPoint.h +++ b/src/Common/FailPoint.h @@ -15,6 +15,7 @@ #include + namespace DB { @@ -27,6 +28,7 @@ namespace DB /// 3. in test file, we can use system failpoint enable/disable 'failpoint_name' class FailPointChannel; + class FailPointInjection { public: diff --git a/src/Common/FieldVisitorConvertToNumber.cpp b/src/Common/FieldVisitorConvertToNumber.cpp index 75b3fbfe02a..a5963e3d028 100644 --- a/src/Common/FieldVisitorConvertToNumber.cpp +++ b/src/Common/FieldVisitorConvertToNumber.cpp @@ -1,5 +1,4 @@ #include -#include "base/Decimal.h" namespace DB { @@ -17,6 +16,7 @@ template class FieldVisitorConvertToNumber; template class FieldVisitorConvertToNumber; template class FieldVisitorConvertToNumber; template class FieldVisitorConvertToNumber; +//template class FieldVisitorConvertToNumber; template class FieldVisitorConvertToNumber; template class FieldVisitorConvertToNumber; diff --git a/src/Common/FieldVisitorConvertToNumber.h b/src/Common/FieldVisitorConvertToNumber.h index 4c3424e0e18..38d5dc473c4 100644 --- a/src/Common/FieldVisitorConvertToNumber.h +++ b/src/Common/FieldVisitorConvertToNumber.h @@ -58,7 +58,7 @@ public: T operator() (const Float64 & x) const { - if constexpr (!std::is_floating_point_v) + if constexpr (!is_floating_point) { if (!isFinite(x)) { @@ -88,7 +88,7 @@ public: template T operator() (const DecimalField & x) const { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) return x.getValue().template convertTo() / x.getScaleMultiplier().template convertTo(); else return (x.getValue() / x.getScaleMultiplier()).template convertTo(); @@ -129,6 +129,7 @@ extern template class FieldVisitorConvertToNumber; extern template class FieldVisitorConvertToNumber; extern template class FieldVisitorConvertToNumber; extern template class FieldVisitorConvertToNumber; +//extern template class FieldVisitorConvertToNumber; extern template class FieldVisitorConvertToNumber; extern template class FieldVisitorConvertToNumber; diff --git a/src/Common/HashTable/Hash.h b/src/Common/HashTable/Hash.h index fb6afcde133..b4bc6af1cef 100644 --- a/src/Common/HashTable/Hash.h +++ b/src/Common/HashTable/Hash.h @@ -322,6 +322,7 @@ DEFINE_HASH(Int32) DEFINE_HASH(Int64) DEFINE_HASH(Int128) DEFINE_HASH(Int256) +DEFINE_HASH(BFloat16) DEFINE_HASH(Float32) DEFINE_HASH(Float64) DEFINE_HASH(DB::UUID) diff --git a/src/Common/HashTable/HashTable.h b/src/Common/HashTable/HashTable.h index d379c3f6a87..fb34ab7d4f9 100644 --- a/src/Common/HashTable/HashTable.h +++ b/src/Common/HashTable/HashTable.h @@ -76,7 +76,7 @@ struct HashTableNoState template inline bool bitEquals(T a, T b) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) /// Note that memcmp with constant size is a compiler builtin. return 0 == memcmp(&a, &b, sizeof(T)); /// NOLINT else diff --git a/src/Common/HostResolvePool.cpp b/src/Common/HostResolvePool.cpp index e8a05a269bc..2c5bf039fe5 100644 --- a/src/Common/HostResolvePool.cpp +++ b/src/Common/HostResolvePool.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace ProfileEvents @@ -49,16 +50,18 @@ HostResolver::WeakPtr HostResolver::getWeakFromThis() } HostResolver::HostResolver(String host_, Poco::Timespan history_) - : host(std::move(host_)) - , history(history_) - , resolve_function([](const String & host_to_resolve) { return DNSResolver::instance().resolveHostAllInOriginOrder(host_to_resolve); }) -{ - update(); -} + : HostResolver( + [](const String & host_to_resolve) { return DNSResolver::instance().resolveHostAllInOriginOrder(host_to_resolve); }, + host_, + history_) +{} HostResolver::HostResolver( 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(); } @@ -203,7 +206,7 @@ bool HostResolver::isUpdateNeeded() Poco::Timestamp now; 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 & next_gen) diff --git a/src/Common/HostResolvePool.h b/src/Common/HostResolvePool.h index d148e909ca9..b979da3d142 100644 --- a/src/Common/HostResolvePool.h +++ b/src/Common/HostResolvePool.h @@ -26,7 +26,7 @@ // a) it still occurs in resolve set after `history_` time or b) all other addresses are pessimized as well. // - resolve schedule // 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. namespace DB @@ -212,6 +212,7 @@ protected: const String host; const Poco::Timespan history; + const Poco::Timespan resolve_interval; const HostResolverMetrics metrics = getMetrics(); // for tests purpose @@ -245,4 +246,3 @@ private: }; } - diff --git a/src/Common/NaNUtils.h b/src/Common/NaNUtils.h index 2ff3e2f5661..3b99084549f 100644 --- a/src/Common/NaNUtils.h +++ b/src/Common/NaNUtils.h @@ -3,24 +3,24 @@ #include #include #include +#include template inline bool isNaN(T x) { /// To be sure, that this function is zero-cost for non-floating point types. - if constexpr (std::is_floating_point_v) - return std::isnan(x); + if constexpr (is_floating_point) + return DecomposedFloat(x).isNaN(); else return false; } - template inline bool isFinite(T x) { - if constexpr (std::is_floating_point_v) - return std::isfinite(x); + if constexpr (is_floating_point) + return DecomposedFloat(x).isFinite(); else return true; } @@ -28,7 +28,7 @@ inline bool isFinite(T x) template bool canConvertTo(Float64 x) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) return true; if (!isFinite(x)) return false; @@ -46,3 +46,12 @@ T NaNOrZero() else return {}; } + +template +bool signBit(T x) +{ + if constexpr (is_floating_point) + return DecomposedFloat(x).isNegative(); + else + return x < 0; +} diff --git a/src/Common/ProgressIndication.cpp b/src/Common/ProgressIndication.cpp index 79c694574b0..8702b0c9aea 100644 --- a/src/Common/ProgressIndication.cpp +++ b/src/Common/ProgressIndication.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -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) { 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) << "."; } -void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message) +void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message, std::unique_lock &) { std::lock_guard lock(progress_mutex); @@ -274,7 +276,7 @@ void ProgressIndication::writeProgress(WriteBufferFromFileDescriptor & message) message.next(); } -void ProgressIndication::clearProgressOutput(WriteBufferFromFileDescriptor & message) +void ProgressIndication::clearProgressOutput(WriteBufferFromFileDescriptor & message, std::unique_lock &) { std::lock_guard lock(progress_mutex); diff --git a/src/Common/ProgressIndication.h b/src/Common/ProgressIndication.h index 61b4ca1b305..6beadff1fc4 100644 --- a/src/Common/ProgressIndication.h +++ b/src/Common/ProgressIndication.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -47,8 +48,8 @@ public: } /// Write progress bar. - void writeProgress(WriteBufferFromFileDescriptor & message); - void clearProgressOutput(WriteBufferFromFileDescriptor & message); + void writeProgress(WriteBufferFromFileDescriptor & message, std::unique_lock & message_lock); + void clearProgressOutput(WriteBufferFromFileDescriptor & message, std::unique_lock & message_lock); /// Write summary. 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 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. - void setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message); + void setFileProgressCallback(ContextMutablePtr context, WriteBufferFromFileDescriptor & message, std::mutex & message_mutex); /// How much seconds passed since query execution start. double elapsedSeconds() const { return getElapsedNanoseconds() / 1e9; } diff --git a/src/Common/TargetSpecific.cpp b/src/Common/TargetSpecific.cpp index 8540c9a9986..4400d9a60b3 100644 --- a/src/Common/TargetSpecific.cpp +++ b/src/Common/TargetSpecific.cpp @@ -23,6 +23,8 @@ UInt32 getSupportedArchs() result |= static_cast(TargetArch::AVX512VBMI); if (CPU::CPUFlagsCache::have_AVX512VBMI2) result |= static_cast(TargetArch::AVX512VBMI2); + if (CPU::CPUFlagsCache::have_AVX512BF16) + result |= static_cast(TargetArch::AVX512BF16); if (CPU::CPUFlagsCache::have_AMXBF16) result |= static_cast(TargetArch::AMXBF16); if (CPU::CPUFlagsCache::have_AMXTILE) @@ -50,6 +52,7 @@ String toString(TargetArch arch) case TargetArch::AVX512BW: return "avx512bw"; case TargetArch::AVX512VBMI: return "avx512vbmi"; case TargetArch::AVX512VBMI2: return "avx512vbmi2"; + case TargetArch::AVX512BF16: return "avx512bf16"; case TargetArch::AMXBF16: return "amxbf16"; case TargetArch::AMXTILE: return "amxtile"; case TargetArch::AMXINT8: return "amxint8"; diff --git a/src/Common/TargetSpecific.h b/src/Common/TargetSpecific.h index f9523f667b2..5584bd1f63a 100644 --- a/src/Common/TargetSpecific.h +++ b/src/Common/TargetSpecific.h @@ -83,9 +83,10 @@ enum class TargetArch : UInt32 AVX512BW = (1 << 4), AVX512VBMI = (1 << 5), AVX512VBMI2 = (1 << 6), - AMXBF16 = (1 << 7), - AMXTILE = (1 << 8), - AMXINT8 = (1 << 9), + AVX512BF16 = (1 << 7), + AMXBF16 = (1 << 8), + AMXTILE = (1 << 9), + AMXINT8 = (1 << 10), }; /// Runtime detection. @@ -102,6 +103,7 @@ String toString(TargetArch arch); /// NOLINTNEXTLINE #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 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"))) @@ -111,6 +113,8 @@ String toString(TargetArch arch); #define SSE42_FUNCTION_SPECIFIC_ATTRIBUTE __attribute__((target("sse,sse2,sse3,ssse3,sse4,popcnt"))) #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 \ _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 \ @@ -197,6 +201,14 @@ namespace TargetSpecific::AVX512VBMI2 { \ } \ 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 @@ -211,6 +223,7 @@ END_TARGET_SPECIFIC_CODE #define DECLARE_AVX512BW_SPECIFIC_CODE(...) #define DECLARE_AVX512VBMI_SPECIFIC_CODE(...) #define DECLARE_AVX512VBMI2_SPECIFIC_CODE(...) +#define DECLARE_AVX512BF16_SPECIFIC_CODE(...) #endif @@ -229,7 +242,8 @@ DECLARE_AVX2_SPECIFIC_CODE (__VA_ARGS__) \ DECLARE_AVX512F_SPECIFIC_CODE(__VA_ARGS__) \ DECLARE_AVX512BW_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( constexpr auto BuildArch = TargetArch::Default; /// NOLINT @@ -263,6 +277,10 @@ DECLARE_AVX512VBMI2_SPECIFIC_CODE( constexpr auto BuildArch = TargetArch::AVX512VBMI2; /// NOLINT ) // DECLARE_AVX512VBMI2_SPECIFIC_CODE +DECLARE_AVX512BF16_SPECIFIC_CODE( + constexpr auto BuildArch = TargetArch::AVX512BF16; /// NOLINT +) // DECLARE_AVX512BF16_SPECIFIC_CODE + /** Runtime Dispatch helpers for class members. * * Example of usage: diff --git a/src/Common/findExtreme.cpp b/src/Common/findExtreme.cpp index ce3bbb86d7c..a29750b848a 100644 --- a/src/Common/findExtreme.cpp +++ b/src/Common/findExtreme.cpp @@ -47,7 +47,7 @@ MULTITARGET_FUNCTION_AVX2_SSE42( /// Unroll the loop manually for floating point, since the compiler doesn't do it without fastmath /// as it might change the return value - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { constexpr size_t unroll_block = 512 / sizeof(T); /// Chosen via benchmarks with AVX2 so YMMV size_t unrolled_end = i + (((count - i) / unroll_block) * unroll_block); diff --git a/src/Common/transformEndianness.h b/src/Common/transformEndianness.h index 1657305acda..e6e04ec75af 100644 --- a/src/Common/transformEndianness.h +++ b/src/Common/transformEndianness.h @@ -38,7 +38,7 @@ inline void transformEndianness(T & x) } template -requires std::is_floating_point_v +requires is_floating_point inline void transformEndianness(T & value) { if constexpr (ToEndian != FromEndian) diff --git a/src/Compression/CompressionCodecNone.h b/src/Compression/CompressionCodecNone.h index 5d6f135b351..0aaa973b55f 100644 --- a/src/Compression/CompressionCodecNone.h +++ b/src/Compression/CompressionCodecNone.h @@ -3,7 +3,7 @@ #include #include #include -#include + namespace DB { diff --git a/src/Compression/getCompressionCodecForFile.cpp b/src/Compression/getCompressionCodecForFile.cpp index 027ee0ac57a..b04e4b6371a 100644 --- a/src/Compression/getCompressionCodecForFile.cpp +++ b/src/Compression/getCompressionCodecForFile.cpp @@ -10,33 +10,50 @@ namespace DB { - using Checksum = CityHash_v1_0_2::uint128; -CompressionCodecPtr getCompressionCodecForFile(const IDataPartStorage & data_part_storage, const String & relative_path) +CompressionCodecPtr +getCompressionCodecForFile(ReadBuffer & read_buffer, UInt32 & size_compressed, UInt32 & size_decompressed, bool skip_to_next_block) { - auto read_buffer = data_part_storage.readFile(relative_path, {}, std::nullopt, std::nullopt); - read_buffer->ignore(sizeof(Checksum)); + read_buffer.ignore(sizeof(Checksum)); UInt8 header_size = ICompressionCodec::getHeaderSize(); + size_t starting_bytes = read_buffer.count(); PODArray compressed_buffer; compressed_buffer.resize(header_size); - read_buffer->readStrict(compressed_buffer.data(), header_size); + read_buffer.readStrict(compressed_buffer.data(), header_size); uint8_t method = ICompressionCodec::readMethod(compressed_buffer.data()); + size_compressed = unalignedLoad(&compressed_buffer[1]); + size_decompressed = unalignedLoad(&compressed_buffer[5]); if (method == static_cast(CompressionMethodByte::Multiple)) { compressed_buffer.resize(1); - read_buffer->readStrict(compressed_buffer.data(), 1); + read_buffer.readStrict(compressed_buffer.data(), 1); compressed_buffer.resize(1 + compressed_buffer[0]); - read_buffer->readStrict(compressed_buffer.data() + 1, compressed_buffer[0]); + read_buffer.readStrict(compressed_buffer.data() + 1, compressed_buffer[0]); auto codecs_bytes = CompressionCodecMultiple::getCodecsBytesFromData(compressed_buffer.data()); Codecs codecs; for (auto byte : codecs_bytes) codecs.push_back(CompressionCodecFactory::instance().get(byte)); + if (skip_to_next_block) + read_buffer.ignore(size_compressed - (read_buffer.count() - starting_bytes)); + return std::make_shared(codecs); } + + if (skip_to_next_block) + read_buffer.ignore(size_compressed - (read_buffer.count() - starting_bytes)); + return CompressionCodecFactory::instance().get(method); } +CompressionCodecPtr getCompressionCodecForFile(const IDataPartStorage & data_part_storage, const String & relative_path) +{ + auto read_buffer = data_part_storage.readFile(relative_path, {}, std::nullopt, std::nullopt); + UInt32 size_compressed; + UInt32 size_decompressed; + return getCompressionCodecForFile(*read_buffer, size_compressed, size_decompressed, false); +} + } diff --git a/src/Compression/getCompressionCodecForFile.h b/src/Compression/getCompressionCodecForFile.h index b6f22750e4d..535befa37e1 100644 --- a/src/Compression/getCompressionCodecForFile.h +++ b/src/Compression/getCompressionCodecForFile.h @@ -13,4 +13,8 @@ namespace DB /// from metadata. CompressionCodecPtr getCompressionCodecForFile(const IDataPartStorage & data_part_storage, const String & relative_path); +/// Same as above which is used by clickhouse-compressor to print compression statistics of each data block. +CompressionCodecPtr +getCompressionCodecForFile(ReadBuffer & read_buffer, UInt32 & size_compressed, UInt32 & size_decompressed, bool skip_to_next_block); + } diff --git a/src/Compression/tests/gtest_compressionCodec.cpp b/src/Compression/tests/gtest_compressionCodec.cpp index 283ccd95f14..8265ba63fc2 100644 --- a/src/Compression/tests/gtest_compressionCodec.cpp +++ b/src/Compression/tests/gtest_compressionCodec.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/src/Core/AccurateComparison.h b/src/Core/AccurateComparison.h index 139ee4d88dc..87ff14e40e7 100644 --- a/src/Core/AccurateComparison.h +++ b/src/Core/AccurateComparison.h @@ -25,7 +25,7 @@ bool lessOp(A a, B b) return a < b; /// float vs float - if constexpr (std::is_floating_point_v && std::is_floating_point_v) + if constexpr (is_floating_point && is_floating_point) return a < b; /// anything vs NaN @@ -49,7 +49,7 @@ bool lessOp(A a, B b) } /// int vs float - if constexpr (is_integer && std::is_floating_point_v) + if constexpr (is_integer && is_floating_point) { if constexpr (sizeof(A) <= 4) return static_cast(a) < static_cast(b); @@ -57,7 +57,7 @@ bool lessOp(A a, B b) return DecomposedFloat(b).greater(a); } - if constexpr (std::is_floating_point_v && is_integer) + if constexpr (is_floating_point && is_integer) { if constexpr (sizeof(B) <= 4) return static_cast(a) < static_cast(b); @@ -65,8 +65,8 @@ bool lessOp(A a, B b) return DecomposedFloat(a).less(b); } - static_assert(is_integer || std::is_floating_point_v); - static_assert(is_integer || std::is_floating_point_v); + static_assert(is_integer || is_floating_point); + static_assert(is_integer || is_floating_point); UNREACHABLE(); } @@ -101,7 +101,7 @@ bool equalsOp(A a, B b) return a == b; /// float vs float - if constexpr (std::is_floating_point_v && std::is_floating_point_v) + if constexpr (is_floating_point && is_floating_point) return a == b; /// anything vs NaN @@ -125,7 +125,7 @@ bool equalsOp(A a, B b) } /// int vs float - if constexpr (is_integer && std::is_floating_point_v) + if constexpr (is_integer && is_floating_point) { if constexpr (sizeof(A) <= 4) return static_cast(a) == static_cast(b); @@ -133,7 +133,7 @@ bool equalsOp(A a, B b) return DecomposedFloat(b).equals(a); } - if constexpr (std::is_floating_point_v && is_integer) + if constexpr (is_floating_point && is_integer) { if constexpr (sizeof(B) <= 4) return static_cast(a) == static_cast(b); @@ -163,7 +163,7 @@ inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result) return true; } - if constexpr (std::is_floating_point_v && std::is_floating_point_v) + if constexpr (is_floating_point && is_floating_point) { /// Note that NaNs doesn't compare equal to anything, but they are still in range of any Float type. if (isNaN(value)) diff --git a/src/Core/DecimalFunctions.h b/src/Core/DecimalFunctions.h index 8dad00c3a1e..abd660a8a7f 100644 --- a/src/Core/DecimalFunctions.h +++ b/src/Core/DecimalFunctions.h @@ -17,6 +17,7 @@ class DataTypeNumber; namespace ErrorCodes { + extern const int NOT_IMPLEMENTED; extern const int DECIMAL_OVERFLOW; extern const int ARGUMENT_OUT_OF_BOUND; } @@ -310,7 +311,14 @@ ReturnType convertToImpl(const DecimalType & decimal, UInt32 scale, To & result) using DecimalNativeType = typename DecimalType::NativeType; static constexpr bool throw_exception = std::is_void_v; - if constexpr (std::is_floating_point_v) + if constexpr (std::is_same_v) + { + if constexpr (throw_exception) + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Conversion from Decimal to BFloat16 is not implemented"); + else + return ReturnType(false); + } + else if constexpr (is_floating_point) { result = static_cast(decimal.value) / static_cast(scaleMultiplier(scale)); } diff --git a/src/Core/Field.h b/src/Core/Field.h index 7b916d30646..c08d5c9eb42 100644 --- a/src/Core/Field.h +++ b/src/Core/Field.h @@ -257,6 +257,7 @@ template <> struct NearestFieldTypeImpl> { using Type = template <> struct NearestFieldTypeImpl> { using Type = DecimalField; }; template <> struct NearestFieldTypeImpl> { using Type = DecimalField; }; template <> struct NearestFieldTypeImpl> { using Type = DecimalField; }; +template <> struct NearestFieldTypeImpl { using Type = Float64; }; template <> struct NearestFieldTypeImpl { using Type = Float64; }; template <> struct NearestFieldTypeImpl { using Type = Float64; }; template <> struct NearestFieldTypeImpl { using Type = String; }; diff --git a/src/Core/ServerSettings.cpp b/src/Core/ServerSettings.cpp index d573377fc8b..2f8e7b6843a 100644 --- a/src/Core/ServerSettings.cpp +++ b/src/Core/ServerSettings.cpp @@ -131,6 +131,9 @@ namespace DB DECLARE(UInt64, max_database_num_to_warn, 1000lu, "If the number of databases is greater than this value, the server will create a warning that will displayed to user.", 0) \ DECLARE(UInt64, max_part_num_to_warn, 100000lu, "If the number of parts is greater than this value, the server will create a warning that will displayed to user.", 0) \ DECLARE(UInt64, max_table_num_to_throw, 0lu, "If number of tables is greater than this value, server will throw an exception. 0 means no limitation. View, remote tables, dictionary, system tables are not counted. Only count table in Atomic/Ordinary/Replicated/Lazy database engine.", 0) \ + DECLARE(UInt64, max_replicated_table_num_to_throw, 0lu, "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.", 0) \ + DECLARE(UInt64, max_dictionary_num_to_throw, 0lu, "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.", 0) \ + DECLARE(UInt64, max_view_num_to_throw, 0lu, "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.", 0) \ DECLARE(UInt64, max_database_num_to_throw, 0lu, "If number of databases is greater than this value, server will throw an exception. 0 means no limitation.", 0) \ DECLARE(UInt64, max_authentication_methods_per_user, 100, "The maximum number of authentication methods a user can be created with or altered. Changing this setting does not affect existing users. Zero means unlimited", 0) \ DECLARE(UInt64, concurrent_threads_soft_limit_num, 0, "Sets how many concurrent thread can be allocated before applying CPU pressure. Zero means unlimited.", 0) \ diff --git a/src/Core/Settings.cpp b/src/Core/Settings.cpp index 0f7d3d1752c..b685e2fff8d 100644 --- a/src/Core/Settings.cpp +++ b/src/Core/Settings.cpp @@ -3676,6 +3676,11 @@ Given that, for example, dictionaries, can be out of sync across nodes, mutation ``` +)", 0) \ + DECLARE(Bool, validate_mutation_query, true, R"( +Validate mutation queries before accepting them. Mutations are executed in the background, and running an invalid query will cause mutations to get stuck, requiring manual intervention. + +Only change this setting if you encounter a backward-incompatible bug. )", 0) \ DECLARE(Seconds, lock_acquire_timeout, DBMS_DEFAULT_LOCK_ACQUIRE_TIMEOUT_SEC, R"( Defines how many seconds a locking request waits before failing. @@ -4567,7 +4572,7 @@ Possible values: - 0 - Disable - 1 - Enable )", 0) \ - DECLARE(Bool, query_plan_merge_filters, true, R"( + DECLARE(Bool, query_plan_merge_filters, false, R"( Allow to merge filters in the query plan )", 0) \ DECLARE(Bool, query_plan_filter_push_down, true, R"( @@ -4868,9 +4873,9 @@ Allows to record the filesystem caching log for each query DECLARE(Bool, read_from_filesystem_cache_if_exists_otherwise_bypass_cache, false, R"( Allow to use the filesystem cache in passive mode - benefit from the existing cache entries, but don't put more entries into the cache. If you set this setting for heavy ad-hoc queries and leave it disabled for short real-time queries, this will allows to avoid cache threshing by too heavy queries and to improve the overall system efficiency. )", 0) \ - DECLARE(Bool, skip_download_if_exceeds_query_cache, true, R"( + DECLARE(Bool, filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit, true, R"( Skip download from remote filesystem if exceeds query cache size -)", 0) \ +)", 0) ALIAS(skip_download_if_exceeds_query_cache) \ DECLARE(UInt64, filesystem_cache_max_download_size, (128UL * 1024 * 1024 * 1024), R"( Max remote filesystem cache size that can be downloaded by a single query )", 0) \ @@ -5744,7 +5749,10 @@ Enable experimental functions for natural language processing. Enable experimental hash functions )", EXPERIMENTAL) \ DECLARE(Bool, allow_experimental_object_type, false, R"( -Allow Object and JSON data types +Allow the obsolete Object data type +)", EXPERIMENTAL) \ + DECLARE(Bool, allow_experimental_bfloat16_type, false, R"( +Allow BFloat16 data type (under development). )", EXPERIMENTAL) \ DECLARE(Bool, allow_experimental_time_series_table, false, R"( Allows creation of tables with the [TimeSeries](../../engines/table-engines/integrations/time-series.md) table engine. diff --git a/src/Core/SettingsChangesHistory.cpp b/src/Core/SettingsChangesHistory.cpp index aa595b793a8..1d8fdf83909 100644 --- a/src/Core/SettingsChangesHistory.cpp +++ b/src/Core/SettingsChangesHistory.cpp @@ -64,6 +64,7 @@ static std::initializer_list>, strategy>, SortingQueueImpl>, strategy>, + SortingQueueImpl>, strategy>, SortingQueueImpl>, strategy>, SortingQueueImpl>, strategy>, diff --git a/src/Core/TypeId.h b/src/Core/TypeId.h index 1eba944e63e..f8991a08d3c 100644 --- a/src/Core/TypeId.h +++ b/src/Core/TypeId.h @@ -21,6 +21,7 @@ enum class TypeIndex : uint8_t Int64, Int128, Int256, + BFloat16, Float32, Float64, Date, @@ -94,6 +95,7 @@ TYPEID_MAP(Int32) TYPEID_MAP(Int64) TYPEID_MAP(Int128) TYPEID_MAP(Int256) +TYPEID_MAP(BFloat16) TYPEID_MAP(Float32) TYPEID_MAP(Float64) TYPEID_MAP(UUID) diff --git a/src/Core/Types_fwd.h b/src/Core/Types_fwd.h index d3b1d168edf..b94a29ce72c 100644 --- a/src/Core/Types_fwd.h +++ b/src/Core/Types_fwd.h @@ -21,6 +21,7 @@ using Int128 = wide::integer<128, signed>; using UInt128 = wide::integer<128, unsigned>; using Int256 = wide::integer<256, signed>; using UInt256 = wide::integer<256, unsigned>; +class BFloat16; namespace DB { diff --git a/src/Core/callOnTypeIndex.h b/src/Core/callOnTypeIndex.h index ae5afce36be..0c8f2201b0d 100644 --- a/src/Core/callOnTypeIndex.h +++ b/src/Core/callOnTypeIndex.h @@ -63,6 +63,7 @@ static bool callOnBasicType(TypeIndex number, F && f) { switch (number) { + case TypeIndex::BFloat16: return f(TypePair()); case TypeIndex::Float32: return f(TypePair()); case TypeIndex::Float64: return f(TypePair()); default: @@ -133,6 +134,7 @@ static inline bool callOnBasicTypes(TypeIndex type_num1, TypeIndex type_num2, F { switch (type_num1) { + case TypeIndex::BFloat16: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Float32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Float64: return callOnBasicType(type_num2, std::forward(f)); default: @@ -190,6 +192,7 @@ static bool callOnIndexAndDataType(TypeIndex number, F && f, ExtraArgs && ... ar case TypeIndex::Int128: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int256: return f(TypePair, T>(), std::forward(args)...); + case TypeIndex::BFloat16: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Float32: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Float64: return f(TypePair, T>(), std::forward(args)...); diff --git a/src/DataTypes/DataTypeNumberBase.cpp b/src/DataTypes/DataTypeNumberBase.cpp index be448fe1491..636d557f4d0 100644 --- a/src/DataTypes/DataTypeNumberBase.cpp +++ b/src/DataTypes/DataTypeNumberBase.cpp @@ -42,6 +42,7 @@ template class DataTypeNumberBase; template class DataTypeNumberBase; template class DataTypeNumberBase; template class DataTypeNumberBase; +template class DataTypeNumberBase; template class DataTypeNumberBase; template class DataTypeNumberBase; diff --git a/src/DataTypes/DataTypeNumberBase.h b/src/DataTypes/DataTypeNumberBase.h index 3a5b11c5124..11b9427a14d 100644 --- a/src/DataTypes/DataTypeNumberBase.h +++ b/src/DataTypes/DataTypeNumberBase.h @@ -68,6 +68,7 @@ extern template class DataTypeNumberBase; extern template class DataTypeNumberBase; extern template class DataTypeNumberBase; extern template class DataTypeNumberBase; +extern template class DataTypeNumberBase; extern template class DataTypeNumberBase; extern template class DataTypeNumberBase; diff --git a/src/DataTypes/DataTypesBinaryEncoding.cpp b/src/DataTypes/DataTypesBinaryEncoding.cpp index dc0f2f3f5aa..c3190b462c3 100644 --- a/src/DataTypes/DataTypesBinaryEncoding.cpp +++ b/src/DataTypes/DataTypesBinaryEncoding.cpp @@ -96,6 +96,7 @@ enum class BinaryTypeIndex : uint8_t SimpleAggregateFunction = 0x2E, Nested = 0x2F, JSON = 0x30, + BFloat16 = 0x31, }; /// In future we can introduce more arguments in the JSON data type definition. @@ -151,6 +152,8 @@ BinaryTypeIndex getBinaryTypeIndex(const DataTypePtr & type) return BinaryTypeIndex::Int128; case TypeIndex::Int256: return BinaryTypeIndex::Int256; + case TypeIndex::BFloat16: + return BinaryTypeIndex::BFloat16; case TypeIndex::Float32: return BinaryTypeIndex::Float32; case TypeIndex::Float64: @@ -565,6 +568,8 @@ DataTypePtr decodeDataType(ReadBuffer & buf) return std::make_shared(); case BinaryTypeIndex::Int256: return std::make_shared(); + case BinaryTypeIndex::BFloat16: + return std::make_shared(); case BinaryTypeIndex::Float32: return std::make_shared(); case BinaryTypeIndex::Float64: diff --git a/src/DataTypes/DataTypesDecimal.cpp b/src/DataTypes/DataTypesDecimal.cpp index 038a00932ee..63bd4bf2a59 100644 --- a/src/DataTypes/DataTypesDecimal.cpp +++ b/src/DataTypes/DataTypesDecimal.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,7 @@ namespace ErrorCodes extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int DECIMAL_OVERFLOW; + extern const int NOT_IMPLEMENTED; } @@ -268,9 +270,13 @@ ReturnType convertToDecimalImpl(const typename FromDataType::FieldType & value, static constexpr bool throw_exception = std::is_same_v; - if constexpr (std::is_floating_point_v) + if constexpr (std::is_same_v) { - if (!std::isfinite(value)) + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Conversion from BFloat16 to Decimal is not implemented"); + } + else if constexpr (is_floating_point) + { + if (!isFinite(value)) { if constexpr (throw_exception) throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "{} convert overflow. Cannot convert infinity or NaN to decimal", ToDataType::family_name); diff --git a/src/DataTypes/DataTypesDecimal.h b/src/DataTypes/DataTypesDecimal.h index badefc4c75a..09a25617506 100644 --- a/src/DataTypes/DataTypesDecimal.h +++ b/src/DataTypes/DataTypesDecimal.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -205,7 +204,6 @@ FOR_EACH_DECIMAL_TYPE(INVOKE); #undef INVOKE #undef DISPATCH - template requires (is_arithmetic_v && IsDataTypeDecimal) typename ToDataType::FieldType convertToDecimal(const typename FromDataType::FieldType & value, UInt32 scale); diff --git a/src/DataTypes/DataTypesNumber.cpp b/src/DataTypes/DataTypesNumber.cpp index 72020b0a5aa..4c8918521fe 100644 --- a/src/DataTypes/DataTypesNumber.cpp +++ b/src/DataTypes/DataTypesNumber.cpp @@ -54,6 +54,7 @@ void registerDataTypeNumbers(DataTypeFactory & factory) factory.registerDataType("Int32", createNumericDataType); factory.registerDataType("Int64", createNumericDataType); + factory.registerDataType("BFloat16", createNumericDataType); factory.registerDataType("Float32", createNumericDataType); factory.registerDataType("Float64", createNumericDataType); @@ -111,6 +112,7 @@ template class DataTypeNumber; template class DataTypeNumber; template class DataTypeNumber; template class DataTypeNumber; +template class DataTypeNumber; template class DataTypeNumber; template class DataTypeNumber; diff --git a/src/DataTypes/DataTypesNumber.h b/src/DataTypes/DataTypesNumber.h index d550ceababc..a9e77e01b13 100644 --- a/src/DataTypes/DataTypesNumber.h +++ b/src/DataTypes/DataTypesNumber.h @@ -63,6 +63,7 @@ extern template class DataTypeNumber; extern template class DataTypeNumber; extern template class DataTypeNumber; extern template class DataTypeNumber; +extern template class DataTypeNumber; extern template class DataTypeNumber; extern template class DataTypeNumber; @@ -79,6 +80,7 @@ using DataTypeInt8 = DataTypeNumber; using DataTypeInt16 = DataTypeNumber; using DataTypeInt32 = DataTypeNumber; using DataTypeInt64 = DataTypeNumber; +using DataTypeBFloat16 = DataTypeNumber; using DataTypeFloat32 = DataTypeNumber; using DataTypeFloat64 = DataTypeNumber; diff --git a/src/DataTypes/IDataType.h b/src/DataTypes/IDataType.h index 33eddf8e9b8..8f06526ddbb 100644 --- a/src/DataTypes/IDataType.h +++ b/src/DataTypes/IDataType.h @@ -408,9 +408,11 @@ struct WhichDataType constexpr bool isDecimal256() const { return idx == TypeIndex::Decimal256; } constexpr bool isDecimal() const { return isDecimal32() || isDecimal64() || isDecimal128() || isDecimal256(); } + constexpr bool isBFloat16() const { return idx == TypeIndex::BFloat16; } constexpr bool isFloat32() const { return idx == TypeIndex::Float32; } constexpr bool isFloat64() const { return idx == TypeIndex::Float64; } - constexpr bool isFloat() const { return isFloat32() || isFloat64(); } + constexpr bool isNativeFloat() const { return isFloat32() || isFloat64(); } + constexpr bool isFloat() const { return isNativeFloat() || isBFloat16(); } constexpr bool isNativeNumber() const { return isNativeInteger() || isFloat(); } constexpr bool isNumber() const { return isInteger() || isFloat() || isDecimal(); } @@ -621,6 +623,7 @@ template inline constexpr bool IsDataTypeEnum> = tr M(Int64) \ M(Int128) \ M(Int256) \ + M(BFloat16) \ M(Float32) \ M(Float64) } diff --git a/src/DataTypes/Native.cpp b/src/DataTypes/Native.cpp index 5dc490b0bd5..53354d7c6e0 100644 --- a/src/DataTypes/Native.cpp +++ b/src/DataTypes/Native.cpp @@ -37,7 +37,7 @@ bool canBeNativeType(const IDataType & type) return canBeNativeType(*data_type_nullable.getNestedType()); } - return data_type.isNativeInt() || data_type.isNativeUInt() || data_type.isFloat() || data_type.isDate() + return data_type.isNativeInt() || data_type.isNativeUInt() || data_type.isNativeFloat() || data_type.isDate() || data_type.isDate32() || data_type.isDateTime() || data_type.isEnum(); } diff --git a/src/DataTypes/NumberTraits.h b/src/DataTypes/NumberTraits.h index 59a64017af3..ee0d9812097 100644 --- a/src/DataTypes/NumberTraits.h +++ b/src/DataTypes/NumberTraits.h @@ -74,7 +74,7 @@ template struct ResultOfAdditionMultiplication { using Type = typename Construct< is_signed_v || is_signed_v, - std::is_floating_point_v || std::is_floating_point_v, + is_floating_point || is_floating_point, nextSize(max(sizeof(A), sizeof(B)))>::Type; }; @@ -82,7 +82,7 @@ template struct ResultOfSubtraction { using Type = typename Construct< true, - std::is_floating_point_v || std::is_floating_point_v, + is_floating_point || is_floating_point, nextSize(max(sizeof(A), sizeof(B)))>::Type; }; @@ -113,7 +113,7 @@ template struct ResultOfModulo /// Example: toInt32(-199) % toUInt8(200) will return -199 that does not fit in Int8, only in Int16. static constexpr size_t size_of_result = result_is_signed ? nextSize(sizeof(B)) : sizeof(B); using Type0 = typename Construct::Type; - using Type = std::conditional_t || std::is_floating_point_v, Float64, Type0>; + using Type = std::conditional_t || is_floating_point, Float64, Type0>; }; template struct ResultOfPositiveModulo @@ -121,21 +121,21 @@ template struct ResultOfPositiveModulo /// function positive_modulo always return non-negative number. static constexpr size_t size_of_result = sizeof(B); using Type0 = typename Construct::Type; - using Type = std::conditional_t || std::is_floating_point_v, Float64, Type0>; + using Type = std::conditional_t || is_floating_point, Float64, Type0>; }; template struct ResultOfModuloLegacy { using Type0 = typename Construct || is_signed_v, false, sizeof(B)>::Type; - using Type = std::conditional_t || std::is_floating_point_v, Float64, Type0>; + using Type = std::conditional_t || is_floating_point, Float64, Type0>; }; template struct ResultOfNegate { using Type = typename Construct< true, - std::is_floating_point_v, + is_floating_point, is_signed_v ? sizeof(A) : nextSize(sizeof(A))>::Type; }; @@ -143,7 +143,7 @@ template struct ResultOfAbs { using Type = typename Construct< false, - std::is_floating_point_v, + is_floating_point, sizeof(A)>::Type; }; @@ -154,7 +154,7 @@ template struct ResultOfBit using Type = typename Construct< is_signed_v || is_signed_v, false, - std::is_floating_point_v || std::is_floating_point_v ? 8 : max(sizeof(A), sizeof(B))>::Type; + is_floating_point || is_floating_point ? 8 : max(sizeof(A), sizeof(B))>::Type; }; template struct ResultOfBitNot @@ -180,7 +180,7 @@ template struct ResultOfBitNot template struct ResultOfIf { - static constexpr bool has_float = std::is_floating_point_v || std::is_floating_point_v; + static constexpr bool has_float = is_floating_point || is_floating_point; static constexpr bool has_integer = is_integer || is_integer; static constexpr bool has_signed = is_signed_v || is_signed_v; static constexpr bool has_unsigned = !is_signed_v || !is_signed_v; @@ -189,7 +189,7 @@ struct ResultOfIf static constexpr size_t max_size_of_unsigned_integer = max(is_signed_v ? 0 : sizeof(A), is_signed_v ? 0 : sizeof(B)); static constexpr size_t max_size_of_signed_integer = max(is_signed_v ? sizeof(A) : 0, is_signed_v ? sizeof(B) : 0); static constexpr size_t max_size_of_integer = max(is_integer ? sizeof(A) : 0, is_integer ? sizeof(B) : 0); - static constexpr size_t max_size_of_float = max(std::is_floating_point_v ? sizeof(A) : 0, std::is_floating_point_v ? sizeof(B) : 0); + static constexpr size_t max_size_of_float = max(is_floating_point ? sizeof(A) : 0, is_floating_point ? sizeof(B) : 0); using ConstructedType = typename Construct= max_size_of_float) @@ -211,7 +211,7 @@ template struct ToInteger using Type = typename Construct< is_signed_v, false, - std::is_floating_point_v ? 8 : sizeof(A)>::Type; + is_floating_point ? 8 : sizeof(A)>::Type; }; diff --git a/src/DataTypes/Serializations/SerializationNumber.cpp b/src/DataTypes/Serializations/SerializationNumber.cpp index bfc13af8ca3..a20b97daf07 100644 --- a/src/DataTypes/Serializations/SerializationNumber.cpp +++ b/src/DataTypes/Serializations/SerializationNumber.cpp @@ -238,6 +238,7 @@ template class SerializationNumber; template class SerializationNumber; template class SerializationNumber; template class SerializationNumber; +template class SerializationNumber; template class SerializationNumber; template class SerializationNumber; diff --git a/src/DataTypes/Utils.cpp b/src/DataTypes/Utils.cpp index a6e9452d7ef..3004322475c 100644 --- a/src/DataTypes/Utils.cpp +++ b/src/DataTypes/Utils.cpp @@ -54,6 +54,13 @@ bool canBeSafelyCasted(const DataTypePtr & from_type, const DataTypePtr & to_typ return false; } + case TypeIndex::BFloat16: + { + if (to_which_type.isFloat32() || to_which_type.isFloat64() || to_which_type.isString()) + return true; + + return false; + } case TypeIndex::Float32: { if (to_which_type.isFloat64() || to_which_type.isString()) diff --git a/src/DataTypes/getLeastSupertype.cpp b/src/DataTypes/getLeastSupertype.cpp index 9664e769611..1b258a8decc 100644 --- a/src/DataTypes/getLeastSupertype.cpp +++ b/src/DataTypes/getLeastSupertype.cpp @@ -109,6 +109,8 @@ DataTypePtr getNumericType(const TypeIndexSet & types) maximize(max_bits_of_signed_integer, 128); else if (type == TypeIndex::Int256) maximize(max_bits_of_signed_integer, 256); + else if (type == TypeIndex::BFloat16) + maximize(max_mantissa_bits_of_floating, 8); else if (type == TypeIndex::Float32) maximize(max_mantissa_bits_of_floating, 24); else if (type == TypeIndex::Float64) @@ -145,7 +147,9 @@ DataTypePtr getNumericType(const TypeIndexSet & types) if (max_mantissa_bits_of_floating) { size_t min_mantissa_bits = std::max(min_bit_width_of_integer, max_mantissa_bits_of_floating); - if (min_mantissa_bits <= 24) + if (min_mantissa_bits <= 8) + return std::make_shared(); + else if (min_mantissa_bits <= 24) return std::make_shared(); if (min_mantissa_bits <= 53) return std::make_shared(); diff --git a/src/DataTypes/getMostSubtype.cpp b/src/DataTypes/getMostSubtype.cpp index b3c76079646..8cb16c04079 100644 --- a/src/DataTypes/getMostSubtype.cpp +++ b/src/DataTypes/getMostSubtype.cpp @@ -297,6 +297,8 @@ DataTypePtr getMostSubtype(const DataTypes & types, bool throw_if_result_is_noth minimize(min_bits_of_signed_integer, 128); else if (typeid_cast(type.get())) minimize(min_bits_of_signed_integer, 256); + else if (typeid_cast(type.get())) + minimize(min_mantissa_bits_of_floating, 8); else if (typeid_cast(type.get())) minimize(min_mantissa_bits_of_floating, 24); else if (typeid_cast(type.get())) @@ -313,7 +315,9 @@ DataTypePtr getMostSubtype(const DataTypes & types, bool throw_if_result_is_noth /// If the result must be floating. if (!min_bits_of_signed_integer && !min_bits_of_unsigned_integer) { - if (min_mantissa_bits_of_floating <= 24) + if (min_mantissa_bits_of_floating <= 8) + return std::make_shared(); + else if (min_mantissa_bits_of_floating <= 24) return std::make_shared(); if (min_mantissa_bits_of_floating <= 53) return std::make_shared(); diff --git a/src/Databases/DatabasesCommon.cpp b/src/Databases/DatabasesCommon.cpp index d26ec9d6eec..23d199cd160 100644 --- a/src/Databases/DatabasesCommon.cpp +++ b/src/Databases/DatabasesCommon.cpp @@ -382,7 +382,8 @@ StoragePtr DatabaseWithOwnTablesBase::detachTableUnlocked(const String & table_n if (!table_storage->isSystemStorage() && !DatabaseCatalog::isPredefinedDatabase(database_name)) { LOG_TEST(log, "Counting detached table {} to database {}", table_name, database_name); - CurrentMetrics::sub(getAttachedCounterForStorage(table_storage)); + for (auto metric : getAttachedCountersForStorage(table_storage)) + CurrentMetrics::sub(metric); } auto table_id = table_storage->getStorageID(); @@ -430,7 +431,8 @@ void DatabaseWithOwnTablesBase::attachTableUnlocked(const String & table_name, c if (!table->isSystemStorage() && !DatabaseCatalog::isPredefinedDatabase(database_name)) { LOG_TEST(log, "Counting attached table {} to database {}", table_name, database_name); - CurrentMetrics::add(getAttachedCounterForStorage(table)); + for (auto metric : getAttachedCountersForStorage(table)) + CurrentMetrics::add(metric); } } diff --git a/src/Databases/enableAllExperimentalSettings.cpp b/src/Databases/enableAllExperimentalSettings.cpp index d51d2671992..1be54664bc9 100644 --- a/src/Databases/enableAllExperimentalSettings.cpp +++ b/src/Databases/enableAllExperimentalSettings.cpp @@ -24,10 +24,11 @@ void enableAllExperimentalSettings(ContextMutablePtr context) context->setSetting("allow_experimental_dynamic_type", 1); context->setSetting("allow_experimental_json_type", 1); context->setSetting("allow_experimental_vector_similarity_index", 1); - context->setSetting("allow_experimental_bigint_types", 1); context->setSetting("allow_experimental_window_functions", 1); context->setSetting("allow_experimental_geo_types", 1); context->setSetting("allow_experimental_map_type", 1); + context->setSetting("allow_experimental_bigint_types", 1); + context->setSetting("allow_experimental_bfloat16_type", 1); context->setSetting("allow_deprecated_error_prone_window_functions", 1); context->setSetting("allow_suspicious_low_cardinality_types", 1); diff --git a/src/Dictionaries/RangeHashedDictionary.h b/src/Dictionaries/RangeHashedDictionary.h index bc335b890fc..5e93391816f 100644 --- a/src/Dictionaries/RangeHashedDictionary.h +++ b/src/Dictionaries/RangeHashedDictionary.h @@ -298,7 +298,8 @@ namespace impl using Types = std::decay_t; using DataType = typename Types::LeftType; - if constexpr (IsDataTypeDecimalOrNumber || IsDataTypeDateOrDateTime || IsDataTypeEnum) + if constexpr ((IsDataTypeDecimalOrNumber || IsDataTypeDateOrDateTime || IsDataTypeEnum) + && !std::is_same_v) { using ColumnType = typename DataType::ColumnType; func(TypePair()); diff --git a/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.cpp b/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.cpp index 673c82806bd..b8386bcf967 100644 --- a/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.cpp +++ b/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.cpp @@ -277,19 +277,6 @@ void AzureObjectStorage::removeObjectImpl(const StoredObject & object, const Sha } } -/// Remove file. Throws exception if file doesn't exists or it's a directory. -void AzureObjectStorage::removeObject(const StoredObject & object) -{ - removeObjectImpl(object, client.get(), false); -} - -void AzureObjectStorage::removeObjects(const StoredObjects & objects) -{ - auto client_ptr = client.get(); - for (const auto & object : objects) - removeObjectImpl(object, client_ptr, false); -} - void AzureObjectStorage::removeObjectIfExists(const StoredObject & object) { removeObjectImpl(object, client.get(), true); diff --git a/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.h b/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.h index 58225eccd90..401493be367 100644 --- a/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.h +++ b/src/Disks/ObjectStorages/AzureBlobStorage/AzureObjectStorage.h @@ -59,11 +59,6 @@ public: size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE, const WriteSettings & write_settings = {}) override; - /// Remove file. Throws exception if file doesn't exists or it's a directory. - void removeObject(const StoredObject & object) override; - - void removeObjects(const StoredObjects & objects) override; - void removeObjectIfExists(const StoredObject & object) override; void removeObjectsIfExist(const StoredObjects & objects) override; diff --git a/src/Disks/ObjectStorages/Cached/CachedObjectStorage.cpp b/src/Disks/ObjectStorages/Cached/CachedObjectStorage.cpp index 163ff3a9c68..779b8830fab 100644 --- a/src/Disks/ObjectStorages/Cached/CachedObjectStorage.cpp +++ b/src/Disks/ObjectStorages/Cached/CachedObjectStorage.cpp @@ -148,20 +148,6 @@ void CachedObjectStorage::removeCacheIfExists(const std::string & path_key_for_c cache->removeKeyIfExists(getCacheKey(path_key_for_cache), FileCache::getCommonUser().user_id); } -void CachedObjectStorage::removeObject(const StoredObject & object) -{ - removeCacheIfExists(object.remote_path); - object_storage->removeObject(object); -} - -void CachedObjectStorage::removeObjects(const StoredObjects & objects) -{ - for (const auto & object : objects) - removeCacheIfExists(object.remote_path); - - object_storage->removeObjects(objects); -} - void CachedObjectStorage::removeObjectIfExists(const StoredObject & object) { removeCacheIfExists(object.remote_path); diff --git a/src/Disks/ObjectStorages/Cached/CachedObjectStorage.h b/src/Disks/ObjectStorages/Cached/CachedObjectStorage.h index b77baf21e40..77aa635b89b 100644 --- a/src/Disks/ObjectStorages/Cached/CachedObjectStorage.h +++ b/src/Disks/ObjectStorages/Cached/CachedObjectStorage.h @@ -45,10 +45,6 @@ public: size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE, const WriteSettings & write_settings = {}) override; - void removeObject(const StoredObject & object) override; - - void removeObjects(const StoredObjects & objects) override; - void removeObjectIfExists(const StoredObject & object) override; void removeObjectsIfExist(const StoredObjects & objects) override; diff --git a/src/Disks/ObjectStorages/DiskObjectStorageTransaction.cpp b/src/Disks/ObjectStorages/DiskObjectStorageTransaction.cpp index 64323fb6f3c..19de2bb78af 100644 --- a/src/Disks/ObjectStorages/DiskObjectStorageTransaction.cpp +++ b/src/Disks/ObjectStorages/DiskObjectStorageTransaction.cpp @@ -480,8 +480,7 @@ struct WriteFileObjectStorageOperation final : public IDiskObjectStorageOperatio void undo() override { - if (object_storage.exists(object)) - object_storage.removeObject(object); + object_storage.removeObjectIfExists(object); } void finalize() override @@ -543,8 +542,7 @@ struct CopyFileObjectStorageOperation final : public IDiskObjectStorageOperation void undo() override { - for (const auto & object : created_objects) - destination_object_storage.removeObject(object); + destination_object_storage.removeObjectsIfExist(created_objects); } void finalize() override diff --git a/src/Disks/ObjectStorages/HDFS/HDFSObjectStorage.h b/src/Disks/ObjectStorages/HDFS/HDFSObjectStorage.h index b53161beb76..7d6c914c398 100644 --- a/src/Disks/ObjectStorages/HDFS/HDFSObjectStorage.h +++ b/src/Disks/ObjectStorages/HDFS/HDFSObjectStorage.h @@ -77,11 +77,6 @@ public: size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE, const WriteSettings & write_settings = {}) override; - /// Remove file. Throws exception if file doesn't exists or it's a directory. - void removeObject(const StoredObject & object) override; - - void removeObjects(const StoredObjects & objects) override; - void removeObjectIfExists(const StoredObject & object) override; void removeObjectsIfExist(const StoredObjects & objects) override; @@ -117,6 +112,11 @@ private: void initializeHDFSFS() const; std::string extractObjectKeyFromURL(const StoredObject & object) const; + /// Remove file. Throws exception if file doesn't exists or it's a directory. + void removeObject(const StoredObject & object); + + void removeObjects(const StoredObjects & objects); + const Poco::Util::AbstractConfiguration & config; mutable HDFSBuilderWrapper hdfs_builder; diff --git a/src/Disks/ObjectStorages/IObjectStorage.h b/src/Disks/ObjectStorages/IObjectStorage.h index 8dde96b8b16..adb36762539 100644 --- a/src/Disks/ObjectStorages/IObjectStorage.h +++ b/src/Disks/ObjectStorages/IObjectStorage.h @@ -161,11 +161,11 @@ public: virtual bool isRemote() const = 0; /// Remove object. Throws exception if object doesn't exists. - virtual void removeObject(const StoredObject & object) = 0; + // virtual void removeObject(const StoredObject & object) = 0; /// Remove multiple objects. Some object storages can do batch remove in a more /// optimal way. - virtual void removeObjects(const StoredObjects & objects) = 0; + // virtual void removeObjects(const StoredObjects & objects) = 0; /// Remove object on path if exists virtual void removeObjectIfExists(const StoredObject & object) = 0; diff --git a/src/Disks/ObjectStorages/Local/LocalObjectStorage.cpp b/src/Disks/ObjectStorages/Local/LocalObjectStorage.cpp index 5f1b6aedc72..f24501dc60e 100644 --- a/src/Disks/ObjectStorages/Local/LocalObjectStorage.cpp +++ b/src/Disks/ObjectStorages/Local/LocalObjectStorage.cpp @@ -81,7 +81,7 @@ std::unique_ptr LocalObjectStorage::writeObject( /// NO return std::make_unique(object.remote_path, buf_size); } -void LocalObjectStorage::removeObject(const StoredObject & object) +void LocalObjectStorage::removeObject(const StoredObject & object) const { /// For local object storage files are actually removed when "metadata" is removed. if (!exists(object)) @@ -91,7 +91,7 @@ void LocalObjectStorage::removeObject(const StoredObject & object) ErrnoException::throwFromPath(ErrorCodes::CANNOT_UNLINK, object.remote_path, "Cannot unlink file {}", object.remote_path); } -void LocalObjectStorage::removeObjects(const StoredObjects & objects) +void LocalObjectStorage::removeObjects(const StoredObjects & objects) const { for (const auto & object : objects) removeObject(object); diff --git a/src/Disks/ObjectStorages/Local/LocalObjectStorage.h b/src/Disks/ObjectStorages/Local/LocalObjectStorage.h index f1a0391a984..5b3c3951364 100644 --- a/src/Disks/ObjectStorages/Local/LocalObjectStorage.h +++ b/src/Disks/ObjectStorages/Local/LocalObjectStorage.h @@ -42,10 +42,6 @@ public: size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE, const WriteSettings & write_settings = {}) override; - void removeObject(const StoredObject & object) override; - - void removeObjects(const StoredObjects & objects) override; - void removeObjectIfExists(const StoredObject & object) override; void removeObjectsIfExist(const StoredObjects & objects) override; @@ -82,6 +78,10 @@ public: ReadSettings patchSettings(const ReadSettings & read_settings) const override; private: + void removeObject(const StoredObject & object) const; + + void removeObjects(const StoredObjects & objects) const; + String key_prefix; LoggerPtr log; std::string description; diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorage.cpp b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorage.cpp index d56c5d9143c..27aa9304de7 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorage.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorage.cpp @@ -203,7 +203,7 @@ void MetadataStorageFromPlainObjectStorageTransaction::unlinkFile(const std::str { auto object_key = metadata_storage.object_storage->generateObjectKeyForPath(path, std::nullopt /* key_prefix */); auto object = StoredObject(object_key.serialize()); - metadata_storage.object_storage->removeObject(object); + metadata_storage.object_storage->removeObjectIfExists(object); } void MetadataStorageFromPlainObjectStorageTransaction::removeDirectory(const std::string & path) @@ -211,7 +211,7 @@ void MetadataStorageFromPlainObjectStorageTransaction::removeDirectory(const std if (metadata_storage.object_storage->isWriteOnce()) { for (auto it = metadata_storage.iterateDirectory(path); it->isValid(); it->next()) - metadata_storage.object_storage->removeObject(StoredObject(it->path())); + metadata_storage.object_storage->removeObjectIfExists(StoredObject(it->path())); } else { diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp index ea57d691908..62015631aa5 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp @@ -107,7 +107,7 @@ void MetadataStorageFromPlainObjectStorageCreateDirectoryOperation::undo(std::un auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; CurrentMetrics::sub(metric, 1); - object_storage->removeObject(StoredObject(metadata_object_key.serialize(), path / PREFIX_PATH_FILE_NAME)); + object_storage->removeObjectIfExists(StoredObject(metadata_object_key.serialize(), path / PREFIX_PATH_FILE_NAME)); } else if (write_created) object_storage->removeObjectIfExists(StoredObject(metadata_object_key.serialize(), path / PREFIX_PATH_FILE_NAME)); @@ -247,7 +247,7 @@ void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::execute(std: auto metadata_object_key = createMetadataObjectKey(key_prefix, metadata_key_prefix); auto metadata_object = StoredObject(/*remote_path*/ metadata_object_key.serialize(), /*local_path*/ path / PREFIX_PATH_FILE_NAME); - object_storage->removeObject(metadata_object); + object_storage->removeObjectIfExists(metadata_object); { std::lock_guard lock(path_map.mutex); diff --git a/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp b/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp index 47ef97401f2..9fca3cad688 100644 --- a/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp +++ b/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp @@ -326,21 +326,11 @@ void S3ObjectStorage::removeObjectsImpl(const StoredObjects & objects, bool if_e ProfileEvents::DiskS3DeleteObjects); } -void S3ObjectStorage::removeObject(const StoredObject & object) -{ - removeObjectImpl(object, false); -} - void S3ObjectStorage::removeObjectIfExists(const StoredObject & object) { removeObjectImpl(object, true); } -void S3ObjectStorage::removeObjects(const StoredObjects & objects) -{ - removeObjectsImpl(objects, false); -} - void S3ObjectStorage::removeObjectsIfExist(const StoredObjects & objects) { removeObjectsImpl(objects, true); diff --git a/src/Disks/ObjectStorages/S3/S3ObjectStorage.h b/src/Disks/ObjectStorages/S3/S3ObjectStorage.h index d6e84cf57ef..4b9c968ede9 100644 --- a/src/Disks/ObjectStorages/S3/S3ObjectStorage.h +++ b/src/Disks/ObjectStorages/S3/S3ObjectStorage.h @@ -101,13 +101,6 @@ public: ObjectStorageIteratorPtr iterate(const std::string & path_prefix, size_t max_keys) const override; - /// Uses `DeleteObjectRequest`. - void removeObject(const StoredObject & object) override; - - /// Uses `DeleteObjectsRequest` if it is allowed by `s3_capabilities`, otherwise `DeleteObjectRequest`. - /// `DeleteObjectsRequest` is not supported on GCS, see https://issuetracker.google.com/issues/162653700 . - void removeObjects(const StoredObjects & objects) override; - /// Uses `DeleteObjectRequest`. void removeObjectIfExists(const StoredObject & object) override; diff --git a/src/Disks/ObjectStorages/Web/WebObjectStorage.cpp b/src/Disks/ObjectStorages/Web/WebObjectStorage.cpp index 871d3b506f6..35abc0ed0df 100644 --- a/src/Disks/ObjectStorages/Web/WebObjectStorage.cpp +++ b/src/Disks/ObjectStorages/Web/WebObjectStorage.cpp @@ -254,16 +254,6 @@ std::unique_ptr WebObjectStorage::writeObject( /// NOLI throwNotAllowed(); } -void WebObjectStorage::removeObject(const StoredObject &) -{ - throwNotAllowed(); -} - -void WebObjectStorage::removeObjects(const StoredObjects &) -{ - throwNotAllowed(); -} - void WebObjectStorage::removeObjectIfExists(const StoredObject &) { throwNotAllowed(); diff --git a/src/Disks/ObjectStorages/Web/WebObjectStorage.h b/src/Disks/ObjectStorages/Web/WebObjectStorage.h index 573221b7e21..1e612bd359c 100644 --- a/src/Disks/ObjectStorages/Web/WebObjectStorage.h +++ b/src/Disks/ObjectStorages/Web/WebObjectStorage.h @@ -47,10 +47,6 @@ public: size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE, const WriteSettings & write_settings = {}) override; - void removeObject(const StoredObject & object) override; - - void removeObjects(const StoredObjects & objects) override; - void removeObjectIfExists(const StoredObject & object) override; void removeObjectsIfExist(const StoredObjects & objects) override; diff --git a/src/Formats/EscapingRuleUtils.cpp b/src/Formats/EscapingRuleUtils.cpp index 67371784712..687814baaa6 100644 --- a/src/Formats/EscapingRuleUtils.cpp +++ b/src/Formats/EscapingRuleUtils.cpp @@ -10,7 +10,6 @@ #include #include #include -#include namespace DB diff --git a/src/Formats/JSONExtractTree.cpp b/src/Formats/JSONExtractTree.cpp index ae6051823b7..62905a2e630 100644 --- a/src/Formats/JSONExtractTree.cpp +++ b/src/Formats/JSONExtractTree.cpp @@ -131,7 +131,7 @@ bool tryGetNumericValueFromJSONElement( switch (element.type()) { case ElementType::DOUBLE: - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { /// We permit inaccurate conversion of double to float. /// Example: double 0.1 from JSON is not representable in float. @@ -175,7 +175,7 @@ bool tryGetNumericValueFromJSONElement( return false; auto rb = ReadBufferFromMemory{element.getString()}; - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { if (!tryReadFloatText(value, rb) || !rb.eof()) { diff --git a/src/Formats/ProtobufSerializer.cpp b/src/Formats/ProtobufSerializer.cpp index 2224af6579f..bd8aeff5a5d 100644 --- a/src/Formats/ProtobufSerializer.cpp +++ b/src/Formats/ProtobufSerializer.cpp @@ -540,7 +540,7 @@ namespace case FieldTypeId::TYPE_ENUM: { - if (std::is_floating_point_v) + if (is_floating_point) incompatibleColumnType(TypeName); write_function = [this](NumberType value) diff --git a/src/Functions/DivisionUtils.h b/src/Functions/DivisionUtils.h index 7fd5b7476e1..e8f5da342f8 100644 --- a/src/Functions/DivisionUtils.h +++ b/src/Functions/DivisionUtils.h @@ -47,9 +47,9 @@ inline auto checkedDivision(A a, B b) { throwIfDivisionLeadsToFPE(a, b); - if constexpr (is_big_int_v && std::is_floating_point_v) + if constexpr (is_big_int_v && is_floating_point) return static_cast(a) / b; - else if constexpr (is_big_int_v && std::is_floating_point_v) + else if constexpr (is_big_int_v && is_floating_point) return a / static_cast(b); else if constexpr (is_big_int_v && is_big_int_v) return static_cast(a / b); @@ -86,17 +86,17 @@ struct DivideIntegralImpl { /// Comparisons are not strict to avoid rounding issues when operand is implicitly casted to float. - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) if (isNaN(a) || a >= std::numeric_limits::max() || a <= std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Cannot perform integer division on infinite or too large floating point numbers"); - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) if (isNaN(b) || b >= std::numeric_limits::max() || b <= std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Cannot perform integer division on infinite or too large floating point numbers"); auto res = checkedDivision(CastA(a), CastB(b)); - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) if (isNaN(res) || res >= static_cast(std::numeric_limits::max()) || res <= std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Cannot perform integer division, because it will produce infinite or too large number"); @@ -122,18 +122,18 @@ struct ModuloImpl template static Result apply(A a, B b) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { /// This computation is similar to `fmod` but the latter is not inlined and has 40 times worse performance. return static_cast(a) - trunc(static_cast(a) / static_cast(b)) * static_cast(b); } else { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) if (isNaN(a) || a > std::numeric_limits::max() || a < std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Cannot perform integer division on infinite or too large floating point numbers"); - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) if (isNaN(b) || b > std::numeric_limits::max() || b < std::numeric_limits::lowest()) throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Cannot perform integer division on infinite or too large floating point numbers"); diff --git a/src/Functions/FunctionBinaryArithmetic.h b/src/Functions/FunctionBinaryArithmetic.h index df239b820af..e7f0d8d43b0 100644 --- a/src/Functions/FunctionBinaryArithmetic.h +++ b/src/Functions/FunctionBinaryArithmetic.h @@ -110,6 +110,7 @@ template constexpr bool IsIntegralOrExtendedOrDecimal = IsDataTypeDecimal; template constexpr bool IsFloatingPoint = false; +template <> inline constexpr bool IsFloatingPoint = true; template <> inline constexpr bool IsFloatingPoint = true; template <> inline constexpr bool IsFloatingPoint = true; @@ -803,7 +804,7 @@ class FunctionBinaryArithmetic : public IFunction DataTypeFixedString, DataTypeString, DataTypeInterval>; - using Floats = TypeList; + using Floats = TypeList; using ValidTypes = std::conditional_t, @@ -1690,6 +1691,13 @@ public: } else { + if constexpr ((std::is_same_v || std::is_same_v) + && (sizeof(typename LeftDataType::FieldType) > 8 || sizeof(typename RightDataType::FieldType) > 8)) + { + /// Big integers and BFloat16 are not supported together. + return false; + } + using ResultDataType = typename BinaryOperationTraits::ResultDataType; if constexpr (!std::is_same_v) @@ -2042,7 +2050,15 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A using DecimalResultType = typename BinaryOperationTraits::DecimalResultDataType; if constexpr (std::is_same_v) + { return nullptr; + } + else if constexpr ((std::is_same_v || std::is_same_v) + && (sizeof(typename LeftDataType::FieldType) > 8 || sizeof(typename RightDataType::FieldType) > 8)) + { + /// Big integers and BFloat16 are not supported together. + return nullptr; + } else // we can't avoid the else because otherwise the compiler may assume the ResultDataType may be Invalid // and that would produce the compile error. { @@ -2059,7 +2075,7 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A ColumnPtr left_col = nullptr; ColumnPtr right_col = nullptr; - /// When Decimal op Float32/64, convert both of them into Float64 + /// When Decimal op Float32/64/16, convert both of them into Float64 if constexpr (decimal_with_float) { const auto converted_type = std::make_shared(); @@ -2094,7 +2110,6 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A /// Here we check if we have `intDiv` or `intDivOrZero` and at least one of the arguments is decimal, because in this case originally we had result as decimal, so we need to convert result into integer after calculations else if constexpr (!decimal_with_float && (is_int_div || is_int_div_or_zero) && (IsDataTypeDecimal || IsDataTypeDecimal)) { - if constexpr (!std::is_same_v) { DataTypePtr type_res; diff --git a/src/Functions/FunctionMathUnary.h b/src/Functions/FunctionMathUnary.h index 4df70f4782b..12a15a072b2 100644 --- a/src/Functions/FunctionMathUnary.h +++ b/src/Functions/FunctionMathUnary.h @@ -70,7 +70,7 @@ private: /// Process all data as a whole and use FastOps implementation /// If the argument is integer, convert to Float64 beforehand - if constexpr (!std::is_floating_point_v) + if constexpr (!is_floating_point) { PODArray tmp_vec(size); for (size_t i = 0; i < size; ++i) @@ -152,7 +152,7 @@ private: { using Types = std::decay_t; using Type = typename Types::RightType; - using ReturnType = std::conditional_t, Float64, Type>; + using ReturnType = std::conditional_t, Float64, Type>; using ColVecType = ColumnVectorOrDecimal; const auto col_vec = checkAndGetColumn(col.column.get()); diff --git a/src/Functions/FunctionsBinaryRepresentation.cpp b/src/Functions/FunctionsBinaryRepresentation.cpp index c8e8f167e4c..50a3c0862f4 100644 --- a/src/Functions/FunctionsBinaryRepresentation.cpp +++ b/src/Functions/FunctionsBinaryRepresentation.cpp @@ -296,6 +296,7 @@ public: tryExecuteUIntOrInt(column, res_column) || tryExecuteString(column, res_column) || tryExecuteFixedString(column, res_column) || + tryExecuteFloat(column, res_column) || tryExecuteFloat(column, res_column) || tryExecuteFloat(column, res_column) || tryExecuteDecimal(column, res_column) || diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index be0875581a5..c9d3ccb4445 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -721,6 +721,7 @@ private: || (res = executeNumRightType(col_left, col_right_untyped)) || (res = executeNumRightType(col_left, col_right_untyped)) || (res = executeNumRightType(col_left, col_right_untyped)) + || (res = executeNumRightType(col_left, col_right_untyped)) || (res = executeNumRightType(col_left, col_right_untyped)) || (res = executeNumRightType(col_left, col_right_untyped))) return res; @@ -741,6 +742,7 @@ private: || (res = executeNumConstRightType(col_left_const, col_right_untyped)) || (res = executeNumConstRightType(col_left_const, col_right_untyped)) || (res = executeNumConstRightType(col_left_const, col_right_untyped)) + || (res = executeNumConstRightType(col_left_const, col_right_untyped)) || (res = executeNumConstRightType(col_left_const, col_right_untyped)) || (res = executeNumConstRightType(col_left_const, col_right_untyped))) return res; @@ -1033,6 +1035,9 @@ private: size_t tuple_size, size_t input_rows_count) const { + if (0 == tuple_size) + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Comparison of zero-sized tuples is not implemented"); + ColumnsWithTypeAndName less_columns(tuple_size); ColumnsWithTypeAndName equal_columns(tuple_size - 1); ColumnsWithTypeAndName tmp_columns(2); @@ -1289,9 +1294,10 @@ public: || (res = executeNumLeftType(col_left_untyped, col_right_untyped)) || (res = executeNumLeftType(col_left_untyped, col_right_untyped)) || (res = executeNumLeftType(col_left_untyped, col_right_untyped)) + || (res = executeNumLeftType(col_left_untyped, col_right_untyped)) || (res = executeNumLeftType(col_left_untyped, col_right_untyped)) || (res = executeNumLeftType(col_left_untyped, col_right_untyped)))) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first argument of function {}", + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of the first argument of function {}", col_left_untyped->getName(), getName()); return res; @@ -1339,7 +1345,7 @@ public: getName(), left_type->getName(), right_type->getName()); - /// When Decimal comparing to Float32/64, we convert both of them into Float64. + /// When Decimal comparing to Float32/64/16, we convert both of them into Float64. /// Other systems like MySQL and Spark also do as this. if (left_is_float || right_is_float) { diff --git a/src/Functions/FunctionsConversion.cpp b/src/Functions/FunctionsConversion.cpp index 1e7cb8f1749..d581ae510e8 100644 --- a/src/Functions/FunctionsConversion.cpp +++ b/src/Functions/FunctionsConversion.cpp @@ -7,10 +7,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -73,8 +71,10 @@ #include #include + namespace DB { + namespace Setting { extern const SettingsBool cast_ipv4_ipv6_default_on_conversion_error; @@ -653,7 +653,7 @@ inline void convertFromTime(DataTypeDateTime::FieldType & x, t template void parseImpl(typename DataType::FieldType & x, ReadBuffer & rb, const DateLUTImpl *, bool precise_float_parsing) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { if (precise_float_parsing) readFloatTextPrecise(x, rb); @@ -717,7 +717,7 @@ inline void parseImpl(DataTypeIPv6::FieldType & x, ReadBuffer & rb template bool tryParseImpl(typename DataType::FieldType & x, ReadBuffer & rb, const DateLUTImpl *, bool precise_float_parsing) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { if (precise_float_parsing) return tryReadFloatTextPrecise(x, rb); @@ -1847,7 +1847,7 @@ struct ConvertImpl else { /// If From Data is Nan or Inf and we convert to integer type, throw exception - if constexpr (std::is_floating_point_v && !std::is_floating_point_v) + if constexpr (is_floating_point && !is_floating_point) { if (!isFinite(vec_from[i])) { @@ -2333,9 +2333,9 @@ private: using RightT = typename RightDataType::FieldType; static constexpr bool bad_left = - is_decimal || std::is_floating_point_v || is_big_int_v || is_signed_v; + is_decimal || is_floating_point || is_big_int_v || is_signed_v; static constexpr bool bad_right = - is_decimal || std::is_floating_point_v || is_big_int_v || is_signed_v; + is_decimal || is_floating_point || is_big_int_v || is_signed_v; /// Disallow int vs UUID conversion (but support int vs UInt128 conversion) if constexpr ((bad_left && std::is_same_v) || @@ -2662,7 +2662,7 @@ struct ToNumberMonotonicity /// Float cases. /// When converting to Float, the conversion is always monotonic. - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) return { .is_monotonic = true, .is_always_monotonic = true }; const auto * low_cardinality = typeid_cast(&type); @@ -2875,6 +2875,7 @@ struct NameToInt32 { static constexpr auto name = "toInt32"; }; struct NameToInt64 { static constexpr auto name = "toInt64"; }; struct NameToInt128 { static constexpr auto name = "toInt128"; }; struct NameToInt256 { static constexpr auto name = "toInt256"; }; +struct NameToBFloat16 { static constexpr auto name = "toBFloat16"; }; struct NameToFloat32 { static constexpr auto name = "toFloat32"; }; struct NameToFloat64 { static constexpr auto name = "toFloat64"; }; struct NameToUUID { static constexpr auto name = "toUUID"; }; @@ -2893,6 +2894,7 @@ using FunctionToInt32 = FunctionConvert>; using FunctionToInt128 = FunctionConvert>; using FunctionToInt256 = FunctionConvert>; +using FunctionToBFloat16 = FunctionConvert>; using FunctionToFloat32 = FunctionConvert>; using FunctionToFloat64 = FunctionConvert>; @@ -2930,6 +2932,7 @@ template <> struct FunctionTo { using Type = FunctionToInt32; }; template <> struct FunctionTo { using Type = FunctionToInt64; }; template <> struct FunctionTo { using Type = FunctionToInt128; }; template <> struct FunctionTo { using Type = FunctionToInt256; }; +template <> struct FunctionTo { using Type = FunctionToBFloat16; }; template <> struct FunctionTo { using Type = FunctionToFloat32; }; template <> struct FunctionTo { using Type = FunctionToFloat64; }; @@ -2972,6 +2975,7 @@ struct NameToInt32OrZero { static constexpr auto name = "toInt32OrZero"; }; struct NameToInt64OrZero { static constexpr auto name = "toInt64OrZero"; }; struct NameToInt128OrZero { static constexpr auto name = "toInt128OrZero"; }; struct NameToInt256OrZero { static constexpr auto name = "toInt256OrZero"; }; +struct NameToBFloat16OrZero { static constexpr auto name = "toBFloat16OrZero"; }; struct NameToFloat32OrZero { static constexpr auto name = "toFloat32OrZero"; }; struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; }; struct NameToDateOrZero { static constexpr auto name = "toDateOrZero"; }; @@ -2998,6 +3002,7 @@ using FunctionToInt32OrZero = FunctionConvertFromString; using FunctionToInt128OrZero = FunctionConvertFromString; using FunctionToInt256OrZero = FunctionConvertFromString; +using FunctionToBFloat16OrZero = FunctionConvertFromString; using FunctionToFloat32OrZero = FunctionConvertFromString; using FunctionToFloat64OrZero = FunctionConvertFromString; using FunctionToDateOrZero = FunctionConvertFromString; @@ -3024,6 +3029,7 @@ struct NameToInt32OrNull { static constexpr auto name = "toInt32OrNull"; }; struct NameToInt64OrNull { static constexpr auto name = "toInt64OrNull"; }; struct NameToInt128OrNull { static constexpr auto name = "toInt128OrNull"; }; struct NameToInt256OrNull { static constexpr auto name = "toInt256OrNull"; }; +struct NameToBFloat16OrNull { static constexpr auto name = "toBFloat16OrNull"; }; struct NameToFloat32OrNull { static constexpr auto name = "toFloat32OrNull"; }; struct NameToFloat64OrNull { static constexpr auto name = "toFloat64OrNull"; }; struct NameToDateOrNull { static constexpr auto name = "toDateOrNull"; }; @@ -3050,6 +3056,7 @@ using FunctionToInt32OrNull = FunctionConvertFromString; using FunctionToInt128OrNull = FunctionConvertFromString; using FunctionToInt256OrNull = FunctionConvertFromString; +using FunctionToBFloat16OrNull = FunctionConvertFromString; using FunctionToFloat32OrNull = FunctionConvertFromString; using FunctionToFloat64OrNull = FunctionConvertFromString; using FunctionToDateOrNull = FunctionConvertFromString; @@ -5193,7 +5200,7 @@ private: if constexpr (is_any_of) { @@ -5446,6 +5453,17 @@ REGISTER_FUNCTION(Conversion) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + + factory.registerFunction(FunctionDocumentation{.description=R"( +Converts Float32 to BFloat16 with losing the precision. + +Example: +[example:typical] +)", + .examples{ + {"typical", "SELECT toBFloat16(12.3::Float32);", "12.3125"}}, + .categories{"Conversion"}}); + factory.registerFunction(); factory.registerFunction(); @@ -5484,6 +5502,31 @@ REGISTER_FUNCTION(Conversion) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + + factory.registerFunction(FunctionDocumentation{.description=R"( +Converts String to BFloat16. + +If the string does not represent a floating point value, the function returns zero. + +The function allows a silent loss of precision while converting from the string representation. In that case, it will return the truncated result. + +Example of successful conversion: +[example:typical] + +Examples of not successful conversion: +[example:invalid1] +[example:invalid2] + +Example of a loss of precision: +[example:precision] +)", + .examples{ + {"typical", "SELECT toBFloat16OrZero('12.3');", "12.3125"}, + {"invalid1", "SELECT toBFloat16OrZero('abc');", "0"}, + {"invalid2", "SELECT toBFloat16OrZero(' 1');", "0"}, + {"precision", "SELECT toBFloat16OrZero('12.3456789');", "12.375"}}, + .categories{"Conversion"}}); + factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); @@ -5512,6 +5555,31 @@ REGISTER_FUNCTION(Conversion) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + + factory.registerFunction(FunctionDocumentation{.description=R"( +Converts String to Nullable(BFloat16). + +If the string does not represent a floating point value, the function returns NULL. + +The function allows a silent loss of precision while converting from the string representation. In that case, it will return the truncated result. + +Example of successful conversion: +[example:typical] + +Examples of not successful conversion: +[example:invalid1] +[example:invalid2] + +Example of a loss of precision: +[example:precision] +)", + .examples{ + {"typical", "SELECT toBFloat16OrNull('12.3');", "12.3125"}, + {"invalid1", "SELECT toBFloat16OrNull('abc');", "NULL"}, + {"invalid2", "SELECT toBFloat16OrNull(' 1');", "NULL"}, + {"precision", "SELECT toBFloat16OrNull('12.3456789');", "12.375"}}, + .categories{"Conversion"}}); + factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); diff --git a/src/Functions/FunctionsRound.h b/src/Functions/FunctionsRound.h index ed7fe1a5de1..6c9cc8a37b3 100644 --- a/src/Functions/FunctionsRound.h +++ b/src/Functions/FunctionsRound.h @@ -268,6 +268,19 @@ inline double roundWithMode(double x, RoundingMode mode) std::unreachable(); } +inline BFloat16 roundWithMode(BFloat16 x, RoundingMode mode) +{ + switch (mode) + { + case RoundingMode::Round: return BFloat16(nearbyintf(Float32(x))); + case RoundingMode::Floor: return BFloat16(floorf(Float32(x))); + case RoundingMode::Ceil: return BFloat16(ceilf(Float32(x))); + case RoundingMode::Trunc: return BFloat16(truncf(Float32(x))); + } + + std::unreachable(); +} + template class FloatRoundingComputationBase { @@ -285,10 +298,15 @@ public: static VectorType prepare(size_t scale) { - return load1(scale); + return load1(ScalarType(scale)); } }; +template <> +class FloatRoundingComputationBase : public FloatRoundingComputationBase +{ +}; + /** Implementation of low-level round-off functions for floating-point values. */ @@ -511,7 +529,7 @@ template - using FunctionRoundingImpl = std::conditional_t, + using FunctionRoundingImpl = std::conditional_t, FloatRoundingImpl, IntegerRoundingImpl>; diff --git a/src/Functions/FunctionsVisitParam.h b/src/Functions/FunctionsVisitParam.h index a77fa740f9c..76d4a13687c 100644 --- a/src/Functions/FunctionsVisitParam.h +++ b/src/Functions/FunctionsVisitParam.h @@ -57,7 +57,7 @@ struct ExtractNumericType ResultType x = 0; if (!in.eof()) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) tryReadFloatText(x, in); else tryReadIntText(x, in); diff --git a/src/Functions/PolygonUtils.h b/src/Functions/PolygonUtils.h index bf8241774a6..601ffcb00b4 100644 --- a/src/Functions/PolygonUtils.h +++ b/src/Functions/PolygonUtils.h @@ -583,7 +583,7 @@ struct CallPointInPolygon template static ColumnPtr call(const IColumn & x, const IColumn & y, PointInPolygonImpl && impl) { - using Impl = TypeListChangeRoot; + using Impl = TypeListChangeRoot; if (auto column = typeid_cast *>(&x)) return Impl::template call(*column, y, impl); return CallPointInPolygon::call(x, y, impl); @@ -609,7 +609,7 @@ struct CallPointInPolygon<> template NO_INLINE ColumnPtr pointInPolygon(const IColumn & x, const IColumn & y, PointInPolygonImpl && impl) { - using Impl = TypeListChangeRoot; + using Impl = TypeListChangeRoot; return Impl::call(x, y, impl); } diff --git a/src/Functions/abs.cpp b/src/Functions/abs.cpp index 742d3b85619..0b701bb7108 100644 --- a/src/Functions/abs.cpp +++ b/src/Functions/abs.cpp @@ -22,7 +22,7 @@ struct AbsImpl return a < 0 ? static_cast(~a) + 1 : static_cast(a); else if constexpr (is_integer && is_unsigned_v) return static_cast(a); - else if constexpr (std::is_floating_point_v) + else if constexpr (is_floating_point) return static_cast(std::abs(a)); } diff --git a/src/Functions/array/arrayAggregation.cpp b/src/Functions/array/arrayAggregation.cpp index bb2503886f1..d073c79b832 100644 --- a/src/Functions/array/arrayAggregation.cpp +++ b/src/Functions/array/arrayAggregation.cpp @@ -87,7 +87,7 @@ struct ArrayAggregateResultImpl std::conditional_t, Decimal128, std::conditional_t, Decimal256, std::conditional_t, Decimal128, - std::conditional_t, Float64, + std::conditional_t, Float64, std::conditional_t, Int64, UInt64>>>>>>>>>>>; }; diff --git a/src/Functions/array/arrayDistance.cpp b/src/Functions/array/arrayDistance.cpp index a1f48747eb6..8a6c2649898 100644 --- a/src/Functions/array/arrayDistance.cpp +++ b/src/Functions/array/arrayDistance.cpp @@ -14,6 +14,7 @@ #include #endif + namespace DB { namespace ErrorCodes @@ -34,7 +35,7 @@ struct L1Distance template struct State { - FloatType sum = 0; + FloatType sum{}; }; template @@ -65,7 +66,7 @@ struct L2Distance template struct State { - FloatType sum = 0; + FloatType sum{}; }; template @@ -90,19 +91,17 @@ struct L2Distance size_t & i_y, State & state) { - static constexpr bool is_float32 = std::is_same_v; - __m512 sums; - if constexpr (is_float32) + if constexpr (sizeof(ResultType) <= 4) sums = _mm512_setzero_ps(); else sums = _mm512_setzero_pd(); - constexpr size_t n = is_float32 ? 16 : 8; + constexpr size_t n = sizeof(__m512) / sizeof(ResultType); for (; i_x + n < i_max; i_x += n, i_y += n) { - if constexpr (is_float32) + if constexpr (sizeof(ResultType) == 4) { __m512 x = _mm512_loadu_ps(data_x + i_x); __m512 y = _mm512_loadu_ps(data_y + i_y); @@ -118,11 +117,38 @@ struct L2Distance } } - if constexpr (is_float32) + if constexpr (sizeof(ResultType) <= 4) state.sum = _mm512_reduce_add_ps(sums); else state.sum = _mm512_reduce_add_pd(sums); } + + AVX512BF16_FUNCTION_SPECIFIC_ATTRIBUTE static void accumulateCombineBF16( + const BFloat16 * __restrict data_x, + const BFloat16 * __restrict data_y, + size_t i_max, + size_t & i_x, + size_t & i_y, + State & state) + { + __m512 sums = _mm512_setzero_ps(); + constexpr size_t n = sizeof(__m512) / sizeof(BFloat16); + + for (; i_x + n < i_max; i_x += n, i_y += n) + { + __m512 x_1 = _mm512_cvtpbh_ps(_mm256_loadu_ps(reinterpret_cast(data_x + i_x))); + __m512 x_2 = _mm512_cvtpbh_ps(_mm256_loadu_ps(reinterpret_cast(data_x + i_x + n / 2))); + __m512 y_1 = _mm512_cvtpbh_ps(_mm256_loadu_ps(reinterpret_cast(data_y + i_y))); + __m512 y_2 = _mm512_cvtpbh_ps(_mm256_loadu_ps(reinterpret_cast(data_y + i_y + n / 2))); + + __m512 differences_1 = _mm512_sub_ps(x_1, y_1); + __m512 differences_2 = _mm512_sub_ps(x_2, y_2); + sums = _mm512_fmadd_ps(differences_1, differences_1, sums); + sums = _mm512_fmadd_ps(differences_2, differences_2, sums); + } + + state.sum = _mm512_reduce_add_ps(sums); + } #endif template @@ -156,13 +182,13 @@ struct LpDistance template struct State { - FloatType sum = 0; + FloatType sum{}; }; template static void accumulate(State & state, ResultType x, ResultType y, const ConstParams & params) { - state.sum += static_cast(std::pow(fabs(x - y), params.power)); + state.sum += static_cast(pow(fabs(x - y), params.power)); } template @@ -174,7 +200,7 @@ struct LpDistance template static ResultType finalize(const State & state, const ConstParams & params) { - return static_cast(std::pow(state.sum, params.inverted_power)); + return static_cast(pow(state.sum, params.inverted_power)); } }; @@ -187,7 +213,7 @@ struct LinfDistance template struct State { - FloatType dist = 0; + FloatType dist{}; }; template @@ -218,9 +244,9 @@ struct CosineDistance template struct State { - FloatType dot_prod = 0; - FloatType x_squared = 0; - FloatType y_squared = 0; + FloatType dot_prod{}; + FloatType x_squared{}; + FloatType y_squared{}; }; template @@ -249,13 +275,11 @@ struct CosineDistance size_t & i_y, State & state) { - static constexpr bool is_float32 = std::is_same_v; - __m512 dot_products; __m512 x_squareds; __m512 y_squareds; - if constexpr (is_float32) + if constexpr (sizeof(ResultType) <= 4) { dot_products = _mm512_setzero_ps(); x_squareds = _mm512_setzero_ps(); @@ -268,11 +292,11 @@ struct CosineDistance y_squareds = _mm512_setzero_pd(); } - constexpr size_t n = is_float32 ? 16 : 8; + constexpr size_t n = sizeof(__m512) / sizeof(ResultType); for (; i_x + n < i_max; i_x += n, i_y += n) { - if constexpr (is_float32) + if constexpr (sizeof(ResultType) == 4) { __m512 x = _mm512_loadu_ps(data_x + i_x); __m512 y = _mm512_loadu_ps(data_y + i_y); @@ -290,7 +314,7 @@ struct CosineDistance } } - if constexpr (is_float32) + if constexpr (sizeof(ResultType) == 4) { state.dot_prod = _mm512_reduce_add_ps(dot_products); state.x_squared = _mm512_reduce_add_ps(x_squareds); @@ -303,16 +327,48 @@ struct CosineDistance state.y_squared = _mm512_reduce_add_pd(y_squareds); } } + + AVX512BF16_FUNCTION_SPECIFIC_ATTRIBUTE static void accumulateCombineBF16( + const BFloat16 * __restrict data_x, + const BFloat16 * __restrict data_y, + size_t i_max, + size_t & i_x, + size_t & i_y, + State & state) + { + __m512 dot_products; + __m512 x_squareds; + __m512 y_squareds; + + dot_products = _mm512_setzero_ps(); + x_squareds = _mm512_setzero_ps(); + y_squareds = _mm512_setzero_ps(); + + constexpr size_t n = sizeof(__m512) / sizeof(BFloat16); + + for (; i_x + n < i_max; i_x += n, i_y += n) + { + __m512 x = _mm512_loadu_ps(data_x + i_x); + __m512 y = _mm512_loadu_ps(data_y + i_y); + dot_products = _mm512_dpbf16_ps(dot_products, x, y); + x_squareds = _mm512_dpbf16_ps(x_squareds, x, x); + y_squareds = _mm512_dpbf16_ps(y_squareds, y, y); + } + + state.dot_prod = _mm512_reduce_add_ps(dot_products); + state.x_squared = _mm512_reduce_add_ps(x_squareds); + state.y_squared = _mm512_reduce_add_ps(y_squareds); + } #endif template static ResultType finalize(const State & state, const ConstParams &) { - return 1 - state.dot_prod / sqrt(state.x_squared * state.y_squared); + return 1.0f - state.dot_prod / sqrt(state.x_squared * state.y_squared); } }; -template +template class FunctionArrayDistance : public IFunction { public: @@ -352,12 +408,13 @@ public: case TypeIndex::Float64: return std::make_shared(); case TypeIndex::Float32: + case TypeIndex::BFloat16: return std::make_shared(); default: throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Arguments of function {} has nested type {}. " - "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, Float32, Float64.", + "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, BFloat16, Float32, Float64.", getName(), common_type->getName()); } @@ -369,10 +426,8 @@ public: { case TypeIndex::Float32: return executeWithResultType(arguments, input_rows_count); - break; case TypeIndex::Float64: return executeWithResultType(arguments, input_rows_count); - break; default: throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected result type {}", result_type->getName()); } @@ -388,6 +443,7 @@ public: ACTION(Int16) \ ACTION(Int32) \ ACTION(Int64) \ + ACTION(BFloat16) \ ACTION(Float32) \ ACTION(Float64) @@ -412,7 +468,7 @@ private: throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Arguments of function {} has nested type {}. " - "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, Float32, Float64.", + "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, BFloat16, Float32, Float64.", getName(), type_x->getName()); } @@ -437,7 +493,7 @@ private: throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Arguments of function {} has nested type {}. " - "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, Float32, Float64.", + "Supported types: UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, BFloat16, Float32, Float64.", getName(), type_y->getName()); } @@ -446,14 +502,10 @@ private: template ColumnPtr executeWithResultTypeAndLeftTypeAndRightType(ColumnPtr col_x, ColumnPtr col_y, size_t input_rows_count, const ColumnsWithTypeAndName & arguments) const { - if (typeid_cast(col_x.get())) - { + if (col_x->isConst()) return executeWithLeftArgConst(col_x, col_y, input_rows_count, arguments); - } - if (typeid_cast(col_y.get())) - { + if (col_y->isConst()) return executeWithLeftArgConst(col_y, col_x, input_rows_count, arguments); - } const auto & array_x = *assert_cast(col_x.get()); const auto & array_y = *assert_cast(col_y.get()); @@ -497,7 +549,7 @@ private: state, static_cast(data_x[prev]), static_cast(data_y[prev]), kernel_params); } result_data[row] = Kernel::finalize(state, kernel_params); - row++; + ++row; } return col_res; } @@ -548,36 +600,52 @@ private: /// SIMD optimization: process multiple elements in both input arrays at once. /// To avoid combinatorial explosion of SIMD kernels, focus on - /// - the two most common input/output types (Float32 x Float32) --> Float32 and (Float64 x Float64) --> Float64 instead of 10 x - /// 10 input types x 2 output types, + /// - the three most common input/output types (BFloat16 x BFloat16) --> Float32, + /// (Float32 x Float32) --> Float32 and (Float64 x Float64) --> Float64 + /// instead of 10 x 10 input types x 2 output types, /// - const/non-const inputs instead of non-const/non-const inputs /// - the two most common metrics L2 and cosine distance, /// - the most powerful SIMD instruction set (AVX-512F). + bool processed = false; #if USE_MULTITARGET_CODE - if constexpr (std::is_same_v && std::is_same_v) /// ResultType is Float32 or Float64 + /// ResultType is Float32 or Float64 + if constexpr (std::is_same_v || std::is_same_v) { - if constexpr (std::is_same_v - || std::is_same_v) + if constexpr (std::is_same_v && std::is_same_v) { if (isArchSupported(TargetArch::AVX512F)) + { Kernel::template accumulateCombine(data_x.data(), data_y.data(), i + offsets_x[0], i, prev, state); + processed = true; + } + } + else if constexpr (std::is_same_v && std::is_same_v && std::is_same_v) + { + if (isArchSupported(TargetArch::AVX512BF16)) + { + Kernel::accumulateCombineBF16(data_x.data(), data_y.data(), i + offsets_x[0], i, prev, state); + processed = true; + } } } -#else - /// Process chunks in vectorized manner - static constexpr size_t VEC_SIZE = 4; - typename Kernel::template State states[VEC_SIZE]; - for (; prev + VEC_SIZE < off; i += VEC_SIZE, prev += VEC_SIZE) +#endif + if (!processed) { - for (size_t s = 0; s < VEC_SIZE; ++s) - Kernel::template accumulate( - states[s], static_cast(data_x[i + s]), static_cast(data_y[prev + s]), kernel_params); + /// Process chunks in a vectorized manner. + static constexpr size_t VEC_SIZE = 32; + typename Kernel::template State states[VEC_SIZE]; + for (; prev + VEC_SIZE < off; i += VEC_SIZE, prev += VEC_SIZE) + { + for (size_t s = 0; s < VEC_SIZE; ++s) + Kernel::template accumulate( + states[s], static_cast(data_x[i + s]), static_cast(data_y[prev + s]), kernel_params); + } + + for (const auto & other_state : states) + Kernel::template combine(state, other_state, kernel_params); } - for (const auto & other_state : states) - Kernel::template combine(state, other_state, kernel_params); -#endif - /// Process the tail + /// Process the tail. for (; prev < off; ++i, ++prev) { Kernel::template accumulate( @@ -638,4 +706,5 @@ FunctionPtr createFunctionArrayL2SquaredDistance(ContextPtr context_) { return F FunctionPtr createFunctionArrayLpDistance(ContextPtr context_) { return FunctionArrayDistance::create(context_); } FunctionPtr createFunctionArrayLinfDistance(ContextPtr context_) { return FunctionArrayDistance::create(context_); } FunctionPtr createFunctionArrayCosineDistance(ContextPtr context_) { return FunctionArrayDistance::create(context_); } + } diff --git a/src/Functions/array/mapPopulateSeries.cpp b/src/Functions/array/mapPopulateSeries.cpp index 4083678b209..d2ca48ff186 100644 --- a/src/Functions/array/mapPopulateSeries.cpp +++ b/src/Functions/array/mapPopulateSeries.cpp @@ -452,23 +452,29 @@ private: using ValueType = typename Types::RightType; static constexpr bool key_and_value_are_numbers = IsDataTypeNumber && IsDataTypeNumber; - static constexpr bool key_is_float = std::is_same_v || std::is_same_v; - if constexpr (key_and_value_are_numbers && !key_is_float) + if constexpr (key_and_value_are_numbers) { - using KeyFieldType = typename KeyType::FieldType; - using ValueFieldType = typename ValueType::FieldType; + if constexpr (is_floating_point) + { + return false; + } + else + { + using KeyFieldType = typename KeyType::FieldType; + using ValueFieldType = typename ValueType::FieldType; - executeImplTyped( - input.key_column, - input.value_column, - input.offsets_column, - input.max_key_column, - std::move(result_columns.result_key_column), - std::move(result_columns.result_value_column), - std::move(result_columns.result_offset_column)); + executeImplTyped( + input.key_column, + input.value_column, + input.offsets_column, + input.max_key_column, + std::move(result_columns.result_key_column), + std::move(result_columns.result_value_column), + std::move(result_columns.result_offset_column)); - return true; + return true; + } } return false; diff --git a/src/Functions/divide.cpp b/src/Functions/divide.cpp index 7c67245c382..3947ba2d142 100644 --- a/src/Functions/divide.cpp +++ b/src/Functions/divide.cpp @@ -18,7 +18,7 @@ struct DivideFloatingImpl template static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]]) { - return static_cast(a) / b; + return static_cast(a) / static_cast(b); } #if USE_EMBEDDED_COMPILER diff --git a/src/Functions/exp.cpp b/src/Functions/exp.cpp index e67cbd6d819..24f1d313831 100644 --- a/src/Functions/exp.cpp +++ b/src/Functions/exp.cpp @@ -3,6 +3,12 @@ namespace DB { + +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} + namespace { @@ -21,7 +27,14 @@ namespace template static void execute(const T * src, size_t size, T * dst) { - NFastOps::Exp(src, size, dst); + if constexpr (std::is_same_v) + { + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Function `{}` is not implemented for BFloat16", name); + } + else + { + NFastOps::Exp(src, size, dst); + } } }; } diff --git a/src/Functions/factorial.cpp b/src/Functions/factorial.cpp index 9b319caad63..83c184f50cc 100644 --- a/src/Functions/factorial.cpp +++ b/src/Functions/factorial.cpp @@ -21,7 +21,7 @@ struct FactorialImpl static NO_SANITIZE_UNDEFINED ResultType apply(A a) { - if constexpr (std::is_floating_point_v || is_over_big_int) + if constexpr (is_floating_point || is_over_big_int) throw Exception( ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type of argument of function factorial, should not be floating point or big int"); diff --git a/src/Functions/if.cpp b/src/Functions/if.cpp index e03b27b3c39..5e1e7067e86 100644 --- a/src/Functions/if.cpp +++ b/src/Functions/if.cpp @@ -668,6 +668,9 @@ private: temporary_columns[0] = arguments[0]; size_t tuple_size = type1.getElements().size(); + if (tuple_size == 0) + return ColumnTuple::create(input_rows_count); + Columns tuple_columns(tuple_size); for (size_t i = 0; i < tuple_size; ++i) diff --git a/src/Functions/log.cpp b/src/Functions/log.cpp index 8bebdb8d7bd..49fc509634b 100644 --- a/src/Functions/log.cpp +++ b/src/Functions/log.cpp @@ -4,6 +4,11 @@ namespace DB { +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} + namespace { @@ -20,7 +25,14 @@ struct LogName { static constexpr auto name = "log"; }; template static void execute(const T * src, size_t size, T * dst) { - NFastOps::Log(src, size, dst); + if constexpr (std::is_same_v) + { + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Function `{}` is not implemented for BFloat16", name); + } + else + { + NFastOps::Log(src, size, dst); + } } }; diff --git a/src/Functions/minus.cpp b/src/Functions/minus.cpp index f3b9b8a7bcb..a372e8d5d78 100644 --- a/src/Functions/minus.cpp +++ b/src/Functions/minus.cpp @@ -17,8 +17,8 @@ struct MinusImpl { if constexpr (is_big_int_v || is_big_int_v) { - using CastA = std::conditional_t, B, A>; - using CastB = std::conditional_t, A, B>; + using CastA = std::conditional_t, B, A>; + using CastB = std::conditional_t, A, B>; return static_cast(static_cast(a)) - static_cast(static_cast(b)); } diff --git a/src/Functions/moduloOrZero.cpp b/src/Functions/moduloOrZero.cpp index cd7873b3b9e..5a4d1539345 100644 --- a/src/Functions/moduloOrZero.cpp +++ b/src/Functions/moduloOrZero.cpp @@ -17,7 +17,7 @@ struct ModuloOrZeroImpl template static Result apply(A a, B b) { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { /// This computation is similar to `fmod` but the latter is not inlined and has 40 times worse performance. return ResultType(a) - trunc(ResultType(a) / ResultType(b)) * ResultType(b); diff --git a/src/Functions/multiply.cpp b/src/Functions/multiply.cpp index 67b6fff6b58..740ab81d0d9 100644 --- a/src/Functions/multiply.cpp +++ b/src/Functions/multiply.cpp @@ -18,8 +18,8 @@ struct MultiplyImpl { if constexpr (is_big_int_v || is_big_int_v) { - using CastA = std::conditional_t, B, A>; - using CastB = std::conditional_t, A, B>; + using CastA = std::conditional_t, B, A>; + using CastB = std::conditional_t, A, B>; return static_cast(static_cast(a)) * static_cast(static_cast(b)); } diff --git a/src/Functions/plus.cpp b/src/Functions/plus.cpp index ffb0fe2ade7..26921713f78 100644 --- a/src/Functions/plus.cpp +++ b/src/Functions/plus.cpp @@ -19,8 +19,8 @@ struct PlusImpl /// Next everywhere, static_cast - so that there is no wrong result in expressions of the form Int64 c = UInt32(a) * Int32(-1). if constexpr (is_big_int_v || is_big_int_v) { - using CastA = std::conditional_t, B, A>; - using CastB = std::conditional_t, A, B>; + using CastA = std::conditional_t, B, A>; + using CastB = std::conditional_t, A, B>; return static_cast(static_cast(a)) + static_cast(static_cast(b)); } diff --git a/src/Functions/sigmoid.cpp b/src/Functions/sigmoid.cpp index d121bdc7389..bb9710a15fe 100644 --- a/src/Functions/sigmoid.cpp +++ b/src/Functions/sigmoid.cpp @@ -3,6 +3,12 @@ namespace DB { + +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} + namespace { @@ -21,7 +27,14 @@ namespace template static void execute(const T * src, size_t size, T * dst) { - NFastOps::Sigmoid<>(src, size, dst); + if constexpr (std::is_same_v) + { + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Function `{}` is not implemented for BFloat16", name); + } + else + { + NFastOps::Sigmoid<>(src, size, dst); + } } }; } @@ -47,4 +60,3 @@ REGISTER_FUNCTION(Sigmoid) } } - diff --git a/src/Functions/sign.cpp b/src/Functions/sign.cpp index 914e1ad9e1f..63d59e3e9da 100644 --- a/src/Functions/sign.cpp +++ b/src/Functions/sign.cpp @@ -13,7 +13,7 @@ struct SignImpl static NO_SANITIZE_UNDEFINED ResultType apply(A a) { - if constexpr (is_decimal || std::is_floating_point_v) + if constexpr (is_decimal || is_floating_point) return a < A(0) ? -1 : a == A(0) ? 0 : 1; else if constexpr (is_signed_v) return a < 0 ? -1 : a == 0 ? 0 : 1; diff --git a/src/Functions/tanh.cpp b/src/Functions/tanh.cpp index 62755737f70..d0e1440485b 100644 --- a/src/Functions/tanh.cpp +++ b/src/Functions/tanh.cpp @@ -3,6 +3,12 @@ namespace DB { + +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} + namespace { @@ -19,7 +25,14 @@ struct TanhName { static constexpr auto name = "tanh"; }; template static void execute(const T * src, size_t size, T * dst) { - NFastOps::Tanh<>(src, size, dst); + if constexpr (std::is_same_v) + { + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Function `{}` is not implemented for BFloat16", name); + } + else + { + NFastOps::Tanh<>(src, size, dst); + } } }; diff --git a/src/IO/ReadHelpers.h b/src/IO/ReadHelpers.h index 50131781e77..65808f76751 100644 --- a/src/IO/ReadHelpers.h +++ b/src/IO/ReadHelpers.h @@ -1420,7 +1420,9 @@ inline bool tryReadText(UUID & x, ReadBuffer & buf) { return tryReadUUIDText(x, inline bool tryReadText(IPv4 & x, ReadBuffer & buf) { return tryReadIPv4Text(x, buf); } inline bool tryReadText(IPv6 & x, ReadBuffer & buf) { return tryReadIPv6Text(x, buf); } -inline void readText(is_floating_point auto & x, ReadBuffer & buf) { readFloatText(x, buf); } +template +requires is_floating_point +inline void readText(T & x, ReadBuffer & buf) { readFloatText(x, buf); } inline void readText(String & x, ReadBuffer & buf) { readEscapedString(x, buf); } diff --git a/src/IO/ReadSettings.h b/src/IO/ReadSettings.h index c1747314c76..b66b9867e39 100644 --- a/src/IO/ReadSettings.h +++ b/src/IO/ReadSettings.h @@ -69,7 +69,7 @@ struct ReadSettings std::shared_ptr page_cache; size_t filesystem_cache_max_download_size = (128UL * 1024 * 1024 * 1024); - bool skip_download_if_exceeds_query_cache = true; + bool filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit = true; size_t remote_read_min_bytes_for_seek = DBMS_DEFAULT_BUFFER_SIZE; diff --git a/src/IO/S3/URI.cpp b/src/IO/S3/URI.cpp index 7c6a21941eb..aefe3ff338c 100644 --- a/src/IO/S3/URI.cpp +++ b/src/IO/S3/URI.cpp @@ -37,7 +37,7 @@ URI::URI(const std::string & uri_, bool allow_archive_path_syntax) /// Case when bucket name represented in domain name of S3 URL. /// E.g. (https://bucket-name.s3.region.amazonaws.com/key) /// https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#virtual-hosted-style-access - static const RE2 virtual_hosted_style_pattern(R"((.+)\.(s3express[\-a-z0-9]+|s3|cos|obs|oss|eos)([.\-][a-z0-9\-.:]+))"); + static const RE2 virtual_hosted_style_pattern(R"((.+)\.(s3express[\-a-z0-9]+|s3|cos|obs|oss-data-acc|oss|eos)([.\-][a-z0-9\-.:]+))"); /// Case when AWS Private Link Interface is being used /// E.g. (bucket.vpce-07a1cd78f1bd55c5f-j3a3vg6w.s3.us-east-1.vpce.amazonaws.com/bucket-name/key) @@ -115,7 +115,15 @@ URI::URI(const std::string & uri_, bool allow_archive_path_syntax) && re2::RE2::FullMatch(uri.getAuthority(), virtual_hosted_style_pattern, &bucket, &name, &endpoint_authority_from_uri)) { is_virtual_hosted_style = true; - endpoint = uri.getScheme() + "://" + name + endpoint_authority_from_uri; + if (name == "oss-data-acc") + { + bucket = bucket.substr(0, bucket.find('.')); + endpoint = uri.getScheme() + "://" + uri.getHost().substr(bucket.length() + 1); + } + else + { + endpoint = uri.getScheme() + "://" + name + endpoint_authority_from_uri; + } validateBucket(bucket, uri); if (!uri.getPath().empty()) diff --git a/src/IO/WriteHelpers.h b/src/IO/WriteHelpers.h index 27363093549..f7b2504f664 100644 --- a/src/IO/WriteHelpers.h +++ b/src/IO/WriteHelpers.h @@ -150,11 +150,12 @@ inline void writeBoolText(bool x, WriteBuffer & buf) template +requires is_floating_point inline size_t writeFloatTextFastPath(T x, char * buffer) { Int64 result = 0; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { /// The library Ryu has low performance on integers. /// This workaround improves performance 6..10 times. @@ -164,13 +165,22 @@ inline size_t writeFloatTextFastPath(T x, char * buffer) else result = jkj::dragonbox::to_chars_n(x, buffer) - buffer; } - else + else if constexpr (std::is_same_v) { if (DecomposedFloat32(x).isIntegerInRepresentableRange()) result = itoa(Int32(x), buffer) - buffer; else result = jkj::dragonbox::to_chars_n(x, buffer) - buffer; } + else if constexpr (std::is_same_v) + { + Float32 f32 = Float32(x); + + if (DecomposedFloat32(f32).isIntegerInRepresentableRange()) + result = itoa(Int32(f32), buffer) - buffer; + else + result = jkj::dragonbox::to_chars_n(f32, buffer) - buffer; + } if (result <= 0) throw Exception(ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER, "Cannot print floating point number"); @@ -178,10 +188,9 @@ inline size_t writeFloatTextFastPath(T x, char * buffer) } template +requires is_floating_point inline void writeFloatText(T x, WriteBuffer & buf) { - static_assert(std::is_same_v || std::is_same_v, "Argument for writeFloatText must be float or double"); - using Converter = DoubleConverter; if (likely(buf.available() >= Converter::MAX_REPRESENTATION_LENGTH)) { @@ -540,9 +549,9 @@ void writeJSONNumber(T x, WriteBuffer & ostr, const FormatSettings & settings) writeCString("null", ostr); else { - if constexpr (std::is_floating_point_v) + if constexpr (is_floating_point) { - if (std::signbit(x)) + if (signBit(x)) { if (isNaN(x)) writeCString("-nan", ostr); @@ -798,7 +807,6 @@ inline void writeXMLStringForTextElement(std::string_view s, WriteBuffer & buf) } /// @brief Serialize `uuid` into an array of characters in big-endian byte order. -/// @param uuid UUID to serialize. /// @return Array of characters in big-endian byte order. std::array formatUUID(const UUID & uuid); @@ -1099,7 +1107,9 @@ inline void writeText(is_integer auto x, WriteBuffer & buf) writeIntText(x, buf); } -inline void writeText(is_floating_point auto x, WriteBuffer & buf) { writeFloatText(x, buf); } +template +requires is_floating_point +inline void writeText(T x, WriteBuffer & buf) { writeFloatText(x, buf); } inline void writeText(is_enum auto x, WriteBuffer & buf) { writeText(magic_enum::enum_name(x), buf); } diff --git a/src/IO/readFloatText.cpp b/src/IO/readFloatText.cpp index 17ccc1b25b7..fb3c86fd7b6 100644 --- a/src/IO/readFloatText.cpp +++ b/src/IO/readFloatText.cpp @@ -47,26 +47,35 @@ void assertNaN(ReadBuffer & buf) } +template void readFloatTextPrecise(BFloat16 &, ReadBuffer &); template void readFloatTextPrecise(Float32 &, ReadBuffer &); template void readFloatTextPrecise(Float64 &, ReadBuffer &); +template bool tryReadFloatTextPrecise(BFloat16 &, ReadBuffer &); template bool tryReadFloatTextPrecise(Float32 &, ReadBuffer &); template bool tryReadFloatTextPrecise(Float64 &, ReadBuffer &); +template void readFloatTextFast(BFloat16 &, ReadBuffer &); template void readFloatTextFast(Float32 &, ReadBuffer &); template void readFloatTextFast(Float64 &, ReadBuffer &); +template bool tryReadFloatTextFast(BFloat16 &, ReadBuffer &); template bool tryReadFloatTextFast(Float32 &, ReadBuffer &); template bool tryReadFloatTextFast(Float64 &, ReadBuffer &); +template void readFloatTextSimple(BFloat16 &, ReadBuffer &); template void readFloatTextSimple(Float32 &, ReadBuffer &); template void readFloatTextSimple(Float64 &, ReadBuffer &); +template bool tryReadFloatTextSimple(BFloat16 &, ReadBuffer &); template bool tryReadFloatTextSimple(Float32 &, ReadBuffer &); template bool tryReadFloatTextSimple(Float64 &, ReadBuffer &); +template void readFloatText(BFloat16 &, ReadBuffer &); template void readFloatText(Float32 &, ReadBuffer &); template void readFloatText(Float64 &, ReadBuffer &); +template bool tryReadFloatText(BFloat16 &, ReadBuffer &); template bool tryReadFloatText(Float32 &, ReadBuffer &); template bool tryReadFloatText(Float64 &, ReadBuffer &); +template bool tryReadFloatTextNoExponent(BFloat16 &, ReadBuffer &); template bool tryReadFloatTextNoExponent(Float32 &, ReadBuffer &); template bool tryReadFloatTextNoExponent(Float64 &, ReadBuffer &); diff --git a/src/IO/readFloatText.h b/src/IO/readFloatText.h index c2fec9d4b0b..a7fd6058dd9 100644 --- a/src/IO/readFloatText.h +++ b/src/IO/readFloatText.h @@ -222,7 +222,6 @@ ReturnType readFloatTextPreciseImpl(T & x, ReadBuffer & buf) break; } - char tmp_buf[MAX_LENGTH]; int num_copied_chars = 0; @@ -597,22 +596,85 @@ ReturnType readFloatTextSimpleImpl(T & x, ReadBuffer & buf) return ReturnType(true); } -template void readFloatTextPrecise(T & x, ReadBuffer & in) { readFloatTextPreciseImpl(x, in); } -template bool tryReadFloatTextPrecise(T & x, ReadBuffer & in) { return readFloatTextPreciseImpl(x, in); } +template void readFloatTextPrecise(T & x, ReadBuffer & in) +{ + if constexpr (std::is_same_v) + { + Float32 tmp; + readFloatTextPreciseImpl(tmp, in); + x = BFloat16(tmp); + } + else + readFloatTextPreciseImpl(x, in); +} + +template bool tryReadFloatTextPrecise(T & x, ReadBuffer & in) +{ + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextPreciseImpl(tmp, in); + if (res) + x = BFloat16(tmp); + return res; + } + else + return readFloatTextPreciseImpl(x, in); +} template void readFloatTextFast(T & x, ReadBuffer & in) { bool has_fractional; - readFloatTextFastImpl(x, in, has_fractional); + if constexpr (std::is_same_v) + { + Float32 tmp; + readFloatTextFastImpl(tmp, in, has_fractional); + x = BFloat16(tmp); + } + else + readFloatTextFastImpl(x, in, has_fractional); } + template bool tryReadFloatTextFast(T & x, ReadBuffer & in) { bool has_fractional; - return readFloatTextFastImpl(x, in, has_fractional); + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextFastImpl(tmp, in, has_fractional); + if (res) + x = BFloat16(tmp); + return res; + } + else + return readFloatTextFastImpl(x, in, has_fractional); } -template void readFloatTextSimple(T & x, ReadBuffer & in) { readFloatTextSimpleImpl(x, in); } -template bool tryReadFloatTextSimple(T & x, ReadBuffer & in) { return readFloatTextSimpleImpl(x, in); } +template void readFloatTextSimple(T & x, ReadBuffer & in) +{ + if constexpr (std::is_same_v) + { + Float32 tmp; + readFloatTextSimpleImpl(tmp, in); + x = BFloat16(tmp); + } + else + readFloatTextSimpleImpl(x, in); +} + +template bool tryReadFloatTextSimple(T & x, ReadBuffer & in) +{ + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextSimpleImpl(tmp, in); + if (res) + x = BFloat16(tmp); + return res; + } + else + return readFloatTextSimpleImpl(x, in); +} /// Implementation that is selected as default. @@ -624,18 +686,47 @@ template bool tryReadFloatText(T & x, ReadBuffer & in) { return try template bool tryReadFloatTextNoExponent(T & x, ReadBuffer & in) { bool has_fractional; - return readFloatTextFastImpl(x, in, has_fractional); + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextFastImpl(tmp, in, has_fractional); + if (res) + x = BFloat16(tmp); + return res; + + } + else + return readFloatTextFastImpl(x, in, has_fractional); } /// With a @has_fractional flag /// Used for input_format_try_infer_integers template bool tryReadFloatTextExt(T & x, ReadBuffer & in, bool & has_fractional) { - return readFloatTextFastImpl(x, in, has_fractional); + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextFastImpl(tmp, in, has_fractional); + if (res) + x = BFloat16(tmp); + return res; + } + else + return readFloatTextFastImpl(x, in, has_fractional); } + template bool tryReadFloatTextExtNoExponent(T & x, ReadBuffer & in, bool & has_fractional) { - return readFloatTextFastImpl(x, in, has_fractional); + if constexpr (std::is_same_v) + { + Float32 tmp; + bool res = readFloatTextFastImpl(tmp, in, has_fractional); + if (res) + x = BFloat16(tmp); + return res; + } + else + return readFloatTextFastImpl(x, in, has_fractional); } } diff --git a/src/IO/tests/gtest_s3_uri.cpp b/src/IO/tests/gtest_s3_uri.cpp index 8696fab0616..6167313b634 100644 --- a/src/IO/tests/gtest_s3_uri.cpp +++ b/src/IO/tests/gtest_s3_uri.cpp @@ -212,6 +212,22 @@ TEST(S3UriTest, validPatterns) ASSERT_EQ("", uri.version_id); ASSERT_EQ(true, uri.is_virtual_hosted_style); } + { + S3::URI uri("https://bucket-test1.oss-cn-beijing-internal.aliyuncs.com/ab-test"); + ASSERT_EQ("https://oss-cn-beijing-internal.aliyuncs.com", uri.endpoint); + ASSERT_EQ("bucket-test1", uri.bucket); + ASSERT_EQ("ab-test", uri.key); + ASSERT_EQ("", uri.version_id); + ASSERT_EQ(true, uri.is_virtual_hosted_style); + } + { + S3::URI uri("https://bucket-test.cn-beijing-internal.oss-data-acc.aliyuncs.com/ab-test"); + ASSERT_EQ("https://cn-beijing-internal.oss-data-acc.aliyuncs.com", uri.endpoint); + ASSERT_EQ("bucket-test", uri.bucket); + ASSERT_EQ("ab-test", uri.key); + ASSERT_EQ("", uri.version_id); + ASSERT_EQ(true, uri.is_virtual_hosted_style); + } } TEST(S3UriTest, versionIdChecks) diff --git a/src/Interpreters/AggregatedData.h b/src/Interpreters/AggregatedData.h index 4b581c682ca..1a804afd33e 100644 --- a/src/Interpreters/AggregatedData.h +++ b/src/Interpreters/AggregatedData.h @@ -1,12 +1,16 @@ #pragma once + #include #include #include #include #include + + namespace DB { + /** Different data structures that can be used for aggregation * For efficiency, the aggregation data itself is put into the pool. * Data and pool ownership (states of aggregate functions) diff --git a/src/Interpreters/Cache/FileCache.cpp b/src/Interpreters/Cache/FileCache.cpp index 7de3f7af78d..8887165a75d 100644 --- a/src/Interpreters/Cache/FileCache.cpp +++ b/src/Interpreters/Cache/FileCache.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -53,16 +54,6 @@ namespace ErrorCodes namespace { - size_t roundDownToMultiple(size_t num, size_t multiple) - { - return (num / multiple) * multiple; - } - - size_t roundUpToMultiple(size_t num, size_t multiple) - { - return roundDownToMultiple(num + multiple - 1, multiple); - } - std::string getCommonUserID() { auto user_from_context = DB::Context::getGlobalContextInstance()->getFilesystemCacheUser(); @@ -96,6 +87,7 @@ FileCache::FileCache(const std::string & cache_name, const FileCacheSettings & s : max_file_segment_size(settings.max_file_segment_size) , bypass_cache_threshold(settings.enable_bypass_cache_with_threshold ? settings.bypass_cache_threshold : 0) , boundary_alignment(settings.boundary_alignment) + , background_download_max_file_segment_size(settings.background_download_max_file_segment_size) , load_metadata_threads(settings.load_metadata_threads) , load_metadata_asynchronously(settings.load_metadata_asynchronously) , write_cache_per_user_directory(settings.write_cache_per_user_id_directory) @@ -103,7 +95,10 @@ FileCache::FileCache(const std::string & cache_name, const FileCacheSettings & s , keep_current_elements_to_max_ratio(1 - settings.keep_free_space_elements_ratio) , keep_up_free_space_remove_batch(settings.keep_free_space_remove_batch) , log(getLogger("FileCache(" + cache_name + ")")) - , metadata(settings.base_path, settings.background_download_queue_size_limit, settings.background_download_threads, write_cache_per_user_directory) + , metadata(settings.base_path, + settings.background_download_queue_size_limit, + settings.background_download_threads, + write_cache_per_user_directory) { if (settings.cache_policy == "LRU") { @@ -601,8 +596,8 @@ FileCache::getOrSet( /// 2. max_file_segments_limit FileSegment::Range result_range = initial_range; - const auto aligned_offset = roundDownToMultiple(initial_range.left, boundary_alignment); - auto aligned_end_offset = std::min(roundUpToMultiple(initial_range.right + 1, boundary_alignment), file_size) - 1; + const auto aligned_offset = FileCacheUtils::roundDownToMultiple(initial_range.left, boundary_alignment); + auto aligned_end_offset = std::min(FileCacheUtils::roundUpToMultiple(initial_range.right + 1, boundary_alignment), file_size) - 1; chassert(aligned_offset <= initial_range.left); chassert(aligned_end_offset >= initial_range.right); @@ -1600,6 +1595,17 @@ void FileCache::applySettingsIfPossible(const FileCacheSettings & new_settings, } } + if (new_settings.background_download_max_file_segment_size != actual_settings.background_download_max_file_segment_size) + { + background_download_max_file_segment_size = new_settings.background_download_max_file_segment_size; + + LOG_INFO(log, "Changed background_download_max_file_segment_size from {} to {}", + actual_settings.background_download_max_file_segment_size, + new_settings.background_download_max_file_segment_size); + + actual_settings.background_download_max_file_segment_size = new_settings.background_download_max_file_segment_size; + } + if (new_settings.max_size != actual_settings.max_size || new_settings.max_elements != actual_settings.max_elements) { diff --git a/src/Interpreters/Cache/FileCache.h b/src/Interpreters/Cache/FileCache.h index 810ed481300..bbe8502fec9 100644 --- a/src/Interpreters/Cache/FileCache.h +++ b/src/Interpreters/Cache/FileCache.h @@ -161,6 +161,10 @@ public: size_t getMaxFileSegmentSize() const { return max_file_segment_size; } + size_t getBackgroundDownloadMaxFileSegmentSize() const { return background_download_max_file_segment_size.load(); } + + size_t getBoundaryAlignment() const { return boundary_alignment; } + bool tryReserve( FileSegment & file_segment, size_t size, @@ -199,6 +203,7 @@ private: std::atomic max_file_segment_size; const size_t bypass_cache_threshold; const size_t boundary_alignment; + std::atomic background_download_max_file_segment_size; size_t load_metadata_threads; const bool load_metadata_asynchronously; std::atomic stop_loading_metadata = false; diff --git a/src/Interpreters/Cache/FileCacheSettings.cpp b/src/Interpreters/Cache/FileCacheSettings.cpp index e162d6b7551..8f0c5206211 100644 --- a/src/Interpreters/Cache/FileCacheSettings.cpp +++ b/src/Interpreters/Cache/FileCacheSettings.cpp @@ -62,6 +62,9 @@ void FileCacheSettings::loadImpl(FuncHas has, FuncGetUInt get_uint, FuncGetStrin if (has("background_download_queue_size_limit")) background_download_queue_size_limit = get_uint("background_download_queue_size_limit"); + if (has("background_download_max_file_segment_size")) + background_download_max_file_segment_size = get_uint("background_download_max_file_segment_size"); + if (has("load_metadata_threads")) load_metadata_threads = get_uint("load_metadata_threads"); diff --git a/src/Interpreters/Cache/FileCacheSettings.h b/src/Interpreters/Cache/FileCacheSettings.h index 72a2b6c3369..9cf72a2bdff 100644 --- a/src/Interpreters/Cache/FileCacheSettings.h +++ b/src/Interpreters/Cache/FileCacheSettings.h @@ -43,6 +43,8 @@ struct FileCacheSettings double keep_free_space_elements_ratio = FILECACHE_DEFAULT_FREE_SPACE_ELEMENTS_RATIO; size_t keep_free_space_remove_batch = FILECACHE_DEFAULT_FREE_SPACE_REMOVE_BATCH; + size_t background_download_max_file_segment_size = FILECACHE_DEFAULT_MAX_FILE_SEGMENT_SIZE_WITH_BACKGROUND_DOWLOAD; + void loadFromConfig(const Poco::Util::AbstractConfiguration & config, const std::string & config_prefix); void loadFromCollection(const NamedCollection & collection); diff --git a/src/Interpreters/Cache/FileCacheUtils.h b/src/Interpreters/Cache/FileCacheUtils.h new file mode 100644 index 00000000000..b35ce867a79 --- /dev/null +++ b/src/Interpreters/Cache/FileCacheUtils.h @@ -0,0 +1,17 @@ +#pragma once +#include + +namespace FileCacheUtils +{ + +static size_t roundDownToMultiple(size_t num, size_t multiple) +{ + return (num / multiple) * multiple; +} + +static size_t roundUpToMultiple(size_t num, size_t multiple) +{ + return roundDownToMultiple(num + multiple - 1, multiple); +} + +} diff --git a/src/Interpreters/Cache/FileCache_fwd.h b/src/Interpreters/Cache/FileCache_fwd.h index da75f30f0e8..3d461abd065 100644 --- a/src/Interpreters/Cache/FileCache_fwd.h +++ b/src/Interpreters/Cache/FileCache_fwd.h @@ -6,6 +6,7 @@ namespace DB static constexpr int FILECACHE_DEFAULT_MAX_FILE_SEGMENT_SIZE = 32 * 1024 * 1024; /// 32Mi static constexpr int FILECACHE_DEFAULT_FILE_SEGMENT_ALIGNMENT = 4 * 1024 * 1024; /// 4Mi +static constexpr int FILECACHE_DEFAULT_MAX_FILE_SEGMENT_SIZE_WITH_BACKGROUND_DOWLOAD = 4 * 1024 * 1024; /// 4Mi static constexpr int FILECACHE_DEFAULT_BACKGROUND_DOWNLOAD_THREADS = 5; static constexpr int FILECACHE_DEFAULT_BACKGROUND_DOWNLOAD_QUEUE_SIZE_LIMIT = 5000; static constexpr int FILECACHE_DEFAULT_LOAD_METADATA_THREADS = 16; diff --git a/src/Interpreters/Cache/FileSegment.cpp b/src/Interpreters/Cache/FileSegment.cpp index 541f0f5607a..74148aa5461 100644 --- a/src/Interpreters/Cache/FileSegment.cpp +++ b/src/Interpreters/Cache/FileSegment.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -360,11 +361,14 @@ void FileSegment::write(char * from, size_t size, size_t offset_in_file) "Expected DOWNLOADING state, got {}", stateToString(download_state)); const size_t first_non_downloaded_offset = getCurrentWriteOffset(); + if (offset_in_file != first_non_downloaded_offset) + { throw Exception( ErrorCodes::LOGICAL_ERROR, "Attempt to write {} bytes to offset: {}, but current write offset is {}", size, offset_in_file, first_non_downloaded_offset); + } const size_t current_downloaded_size = getDownloadedSize(); chassert(reserved_size >= current_downloaded_size); @@ -375,8 +379,19 @@ void FileSegment::write(char * from, size_t size, size_t offset_in_file) ErrorCodes::LOGICAL_ERROR, "Not enough space is reserved. Available: {}, expected: {}", free_reserved_size, size); - if (!is_unbound && current_downloaded_size == range().size()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "File segment is already fully downloaded"); + if (!is_unbound) + { + if (current_downloaded_size == range().size()) + throw Exception(ErrorCodes::LOGICAL_ERROR, "File segment is already fully downloaded"); + + if (current_downloaded_size + size > range().size()) + { + throw Exception( + ErrorCodes::LOGICAL_ERROR, + "Cannot download beyond file segment boundaries: {}. Write offset: {}, size: {}, downloaded size: {}", + range().size(), first_non_downloaded_offset, size, current_downloaded_size); + } + } if (!cache_writer && current_downloaded_size > 0) throw Exception( @@ -629,6 +644,36 @@ void FileSegment::completePartAndResetDownloader() LOG_TEST(log, "Complete batch. ({})", getInfoForLogUnlocked(lk)); } +size_t FileSegment::getSizeForBackgroundDownload() const +{ + auto lk = lock(); + return getSizeForBackgroundDownloadUnlocked(lk); +} + +size_t FileSegment::getSizeForBackgroundDownloadUnlocked(const FileSegmentGuard::Lock &) const +{ + if (!background_download_enabled + || !downloaded_size + || !remote_file_reader) + { + return 0; + } + + chassert(downloaded_size <= range().size()); + + const size_t background_download_max_file_segment_size = cache->getBackgroundDownloadMaxFileSegmentSize(); + size_t desired_size; + if (downloaded_size >= background_download_max_file_segment_size) + desired_size = FileCacheUtils::roundUpToMultiple(downloaded_size, cache->getBoundaryAlignment()); + else + desired_size = FileCacheUtils::roundUpToMultiple(background_download_max_file_segment_size, cache->getBoundaryAlignment()); + + desired_size = std::min(desired_size, range().size()); + chassert(desired_size >= downloaded_size); + + return desired_size - downloaded_size; +} + void FileSegment::complete(bool allow_background_download) { ProfileEventTimeIncrement watch(ProfileEvents::FileSegmentCompleteMicroseconds); @@ -708,7 +753,8 @@ void FileSegment::complete(bool allow_background_download) if (is_last_holder) { bool added_to_download_queue = false; - if (allow_background_download && background_download_enabled && remote_file_reader) + size_t background_download_size = allow_background_download ? getSizeForBackgroundDownloadUnlocked(segment_lock) : 0; + if (background_download_size) { ProfileEvents::increment(ProfileEvents::FilesystemCacheBackgroundDownloadQueuePush); added_to_download_queue = locked_key->addToDownloadQueue(offset(), segment_lock); /// Finish download in background. @@ -862,7 +908,12 @@ bool FileSegment::assertCorrectnessUnlocked(const FileSegmentGuard::Lock & lock) chassert(downloaded_size == reserved_size); chassert(downloaded_size == range().size()); chassert(downloaded_size > 0); - chassert(fs::file_size(getPath()) > 0); + + auto file_size = fs::file_size(getPath()); + UNUSED(file_size); + + chassert(file_size == range().size()); + chassert(downloaded_size == range().size()); chassert(queue_iterator || on_delayed_removal); check_iterator(queue_iterator); @@ -884,7 +935,13 @@ bool FileSegment::assertCorrectnessUnlocked(const FileSegmentGuard::Lock & lock) chassert(reserved_size >= downloaded_size); chassert(downloaded_size > 0); - chassert(fs::file_size(getPath()) > 0); + + auto file_size = fs::file_size(getPath()); + UNUSED(file_size); + + chassert(file_size > 0); + chassert(file_size <= range().size()); + chassert(downloaded_size <= range().size()); chassert(queue_iterator); check_iterator(queue_iterator); diff --git a/src/Interpreters/Cache/FileSegment.h b/src/Interpreters/Cache/FileSegment.h index 21d5f9dab5f..a6bfb203cec 100644 --- a/src/Interpreters/Cache/FileSegment.h +++ b/src/Interpreters/Cache/FileSegment.h @@ -185,6 +185,8 @@ public: bool assertCorrectness() const; + size_t getSizeForBackgroundDownload() const; + /** * ========== Methods that must do cv.notify() ================== */ @@ -230,6 +232,7 @@ private: String getDownloaderUnlocked(const FileSegmentGuard::Lock &) const; bool isDownloaderUnlocked(const FileSegmentGuard::Lock & segment_lock) const; void resetDownloaderUnlocked(const FileSegmentGuard::Lock &); + size_t getSizeForBackgroundDownloadUnlocked(const FileSegmentGuard::Lock &) const; void setDownloadState(State state, const FileSegmentGuard::Lock &); void resetDownloadingStateUnlocked(const FileSegmentGuard::Lock &); diff --git a/src/Interpreters/Cache/Metadata.cpp b/src/Interpreters/Cache/Metadata.cpp index 231545212cd..4d3033191dc 100644 --- a/src/Interpreters/Cache/Metadata.cpp +++ b/src/Interpreters/Cache/Metadata.cpp @@ -676,13 +676,17 @@ void CacheMetadata::downloadImpl(FileSegment & file_segment, std::optionalinternalBuffer().empty()) { if (!memory) - memory.emplace(DBMS_DEFAULT_BUFFER_SIZE); + memory.emplace(std::min(size_t(DBMS_DEFAULT_BUFFER_SIZE), size_to_download)); reader->set(memory->data(), memory->size()); } @@ -701,9 +705,13 @@ void CacheMetadata::downloadImpl(FileSegment & file_segment, std::optional(reader->getPosition())) reader->seek(offset, SEEK_SET); - while (!reader->eof()) + while (size_to_download && !reader->eof()) { - auto size = reader->available(); + const auto available = reader->available(); + chassert(available); + + const auto size = std::min(available, size_to_download); + size_to_download -= size; std::string failure_reason; if (!file_segment.reserve(size, reserve_space_lock_wait_timeout_milliseconds, failure_reason)) @@ -713,7 +721,7 @@ void CacheMetadata::downloadImpl(FileSegment & file_segment, std::optional LockedKey::sync() actual_size, expected_size, file_segment->getInfoForLog()); broken.push_back(FileSegment::getInfo(file_segment)); - it = removeFileSegment(file_segment->offset(), file_segment->lock(), /* can_be_broken */false); + it = removeFileSegment(file_segment->offset(), file_segment->lock(), /* can_be_broken */true); } return broken; } diff --git a/src/Interpreters/Cache/Metadata.h b/src/Interpreters/Cache/Metadata.h index 0e85ead3265..24683b2de71 100644 --- a/src/Interpreters/Cache/Metadata.h +++ b/src/Interpreters/Cache/Metadata.h @@ -210,6 +210,7 @@ public: bool setBackgroundDownloadThreads(size_t threads_num); size_t getBackgroundDownloadThreads() const { return download_threads.size(); } + bool setBackgroundDownloadQueueSizeLimit(size_t size); bool isBackgroundDownloadEnabled(); diff --git a/src/Interpreters/Cache/QueryLimit.cpp b/src/Interpreters/Cache/QueryLimit.cpp index b18d23a5b7f..a7c964022a5 100644 --- a/src/Interpreters/Cache/QueryLimit.cpp +++ b/src/Interpreters/Cache/QueryLimit.cpp @@ -53,7 +53,7 @@ FileCacheQueryLimit::QueryContextPtr FileCacheQueryLimit::getOrSetQueryContext( { it->second = std::make_shared( settings.filesystem_cache_max_download_size, - !settings.skip_download_if_exceeds_query_cache); + !settings.filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit); } return it->second; diff --git a/src/Interpreters/Context.cpp b/src/Interpreters/Context.cpp index d42002bf98d..d2aad0a52d8 100644 --- a/src/Interpreters/Context.cpp +++ b/src/Interpreters/Context.cpp @@ -237,7 +237,7 @@ namespace Setting extern const SettingsUInt64 remote_fs_read_backoff_max_tries; extern const SettingsUInt64 remote_read_min_bytes_for_seek; extern const SettingsBool throw_on_error_from_cache_on_write_operations; - extern const SettingsBool skip_download_if_exceeds_query_cache; + extern const SettingsBool filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit; extern const SettingsBool s3_allow_parallel_part_upload; extern const SettingsBool use_page_cache_for_disks_without_file_cache; extern const SettingsUInt64 use_structure_from_insertion_table_in_table_functions; @@ -5755,7 +5755,7 @@ ReadSettings Context::getReadSettings() const res.filesystem_cache_prefer_bigger_buffer_size = settings_ref[Setting::filesystem_cache_prefer_bigger_buffer_size]; res.filesystem_cache_max_download_size = settings_ref[Setting::filesystem_cache_max_download_size]; - res.skip_download_if_exceeds_query_cache = settings_ref[Setting::skip_download_if_exceeds_query_cache]; + res.filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit = settings_ref[Setting::filesystem_cache_skip_download_if_exceeds_per_query_cache_write_limit]; res.page_cache = getPageCache(); res.use_page_cache_for_disks_without_file_cache = settings_ref[Setting::use_page_cache_for_disks_without_file_cache]; diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index f6586f8bfc2..ff0e1d7f5a8 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -98,6 +98,9 @@ namespace CurrentMetrics { extern const Metric AttachedTable; + extern const Metric AttachedReplicatedTable; + extern const Metric AttachedDictionary; + extern const Metric AttachedView; } namespace DB @@ -145,7 +148,10 @@ namespace ServerSetting { extern const ServerSettingsBool ignore_empty_sql_security_in_create_view_query; extern const ServerSettingsUInt64 max_database_num_to_throw; + extern const ServerSettingsUInt64 max_dictionary_num_to_throw; extern const ServerSettingsUInt64 max_table_num_to_throw; + extern const ServerSettingsUInt64 max_replicated_table_num_to_throw; + extern const ServerSettingsUInt64 max_view_num_to_throw; } namespace ErrorCodes @@ -1912,16 +1918,8 @@ bool InterpreterCreateQuery::doCreateTable(ASTCreateQuery & create, } } - UInt64 table_num_limit = getContext()->getGlobalContext()->getServerSettings()[ServerSetting::max_table_num_to_throw]; - if (table_num_limit > 0 && !internal) - { - UInt64 table_count = CurrentMetrics::get(CurrentMetrics::AttachedTable); - if (table_count >= table_num_limit) - throw Exception(ErrorCodes::TOO_MANY_TABLES, - "Too many tables. " - "The limit (server configuration parameter `max_table_num_to_throw`) is set to {}, the current number of tables is {}", - table_num_limit, table_count); - } + if (!internal) + throwIfTooManyEntities(create, res); database->createTable(getContext(), create.getTable(), res, query_ptr); @@ -1948,6 +1946,30 @@ bool InterpreterCreateQuery::doCreateTable(ASTCreateQuery & create, } +void InterpreterCreateQuery::throwIfTooManyEntities(ASTCreateQuery & create, StoragePtr storage) const +{ + auto check_and_throw = [&](auto setting, CurrentMetrics::Metric metric, String setting_name, String entity_name) + { + UInt64 num_limit = getContext()->getGlobalContext()->getServerSettings()[setting]; + UInt64 attached_count = CurrentMetrics::get(metric); + if (num_limit > 0 && attached_count >= num_limit) + throw Exception(ErrorCodes::TOO_MANY_TABLES, + "Too many {}. " + "The limit (server configuration parameter `{}`) is set to {}, the current number is {}", + entity_name, setting_name, num_limit, attached_count); + }; + + if (typeid_cast(storage.get()) != nullptr) + check_and_throw(ServerSetting::max_replicated_table_num_to_throw, CurrentMetrics::AttachedReplicatedTable, "max_replicated_table_num_to_throw", "replicated tables"); + else if (create.is_dictionary) + check_and_throw(ServerSetting::max_dictionary_num_to_throw, CurrentMetrics::AttachedDictionary, "max_dictionary_num_to_throw", "dictionaries"); + else if (create.isView()) + check_and_throw(ServerSetting::max_view_num_to_throw, CurrentMetrics::AttachedView, "max_view_num_to_throw", "views"); + else + check_and_throw(ServerSetting::max_table_num_to_throw, CurrentMetrics::AttachedTable, "max_table_num_to_throw", "tables"); +} + + BlockIO InterpreterCreateQuery::doCreateOrReplaceTable(ASTCreateQuery & create, const InterpreterCreateQuery::TableProperties & properties, LoadingStrictnessLevel mode) { diff --git a/src/Interpreters/InterpreterCreateQuery.h b/src/Interpreters/InterpreterCreateQuery.h index cb7af25383e..24cf308951c 100644 --- a/src/Interpreters/InterpreterCreateQuery.h +++ b/src/Interpreters/InterpreterCreateQuery.h @@ -122,6 +122,8 @@ private: BlockIO executeQueryOnCluster(ASTCreateQuery & create); + void throwIfTooManyEntities(ASTCreateQuery & create, StoragePtr storage) const; + ASTPtr query_ptr; /// Skip safety threshold when loading tables. diff --git a/src/Interpreters/MutationsInterpreter.cpp b/src/Interpreters/MutationsInterpreter.cpp index 0f25d5ac21c..a35353a6b2a 100644 --- a/src/Interpreters/MutationsInterpreter.cpp +++ b/src/Interpreters/MutationsInterpreter.cpp @@ -53,6 +53,7 @@ namespace Setting extern const SettingsBool allow_nondeterministic_mutations; extern const SettingsUInt64 max_block_size; extern const SettingsBool use_concurrency_control; + extern const SettingsBool validate_mutation_query; } namespace MergeTreeSetting @@ -1386,6 +1387,18 @@ void MutationsInterpreter::validate() } } + // Make sure the mutation query is valid + if (context->getSettingsRef()[Setting::validate_mutation_query]) + { + if (context->getSettingsRef()[Setting::allow_experimental_analyzer]) + prepareQueryAffectedQueryTree(commands, source.getStorage(), context); + else + { + ASTPtr select_query = prepareQueryAffectedAST(commands, source.getStorage(), context); + InterpreterSelectQuery(select_query, context, source.getStorage(), metadata_snapshot); + } + } + QueryPlan plan; initQueryPlan(stages.front(), plan); diff --git a/src/Interpreters/RowRefs.cpp b/src/Interpreters/RowRefs.cpp index 1b397ab56ef..26524218b2b 100644 --- a/src/Interpreters/RowRefs.cpp +++ b/src/Interpreters/RowRefs.cpp @@ -183,7 +183,7 @@ private: if (sorted.load(std::memory_order_relaxed)) return; - if constexpr (std::is_arithmetic_v && !std::is_floating_point_v) + if constexpr (std::is_arithmetic_v && !is_floating_point) { if (likely(entries.size() > 256)) { diff --git a/src/Interpreters/parseColumnsListForTableFunction.cpp b/src/Interpreters/parseColumnsListForTableFunction.cpp index d8f526db592..d3bf6f860f3 100644 --- a/src/Interpreters/parseColumnsListForTableFunction.cpp +++ b/src/Interpreters/parseColumnsListForTableFunction.cpp @@ -20,6 +20,7 @@ namespace Setting extern const SettingsBool allow_experimental_json_type; extern const SettingsBool allow_experimental_object_type; extern const SettingsBool allow_experimental_variant_type; + extern const SettingsBool allow_experimental_bfloat16_type; extern const SettingsBool allow_suspicious_fixed_string_types; extern const SettingsBool allow_suspicious_low_cardinality_types; extern const SettingsBool allow_suspicious_variant_types; @@ -42,6 +43,7 @@ DataTypeValidationSettings::DataTypeValidationSettings(const DB::Settings & sett , allow_experimental_object_type(settings[Setting::allow_experimental_object_type]) , allow_suspicious_fixed_string_types(settings[Setting::allow_suspicious_fixed_string_types]) , allow_experimental_variant_type(settings[Setting::allow_experimental_variant_type]) + , allow_experimental_bfloat16_type(settings[Setting::allow_experimental_bfloat16_type]) , allow_suspicious_variant_types(settings[Setting::allow_suspicious_variant_types]) , validate_nested_types(settings[Setting::validate_experimental_and_suspicious_types_inside_nested_types]) , allow_experimental_dynamic_type(settings[Setting::allow_experimental_dynamic_type]) @@ -105,6 +107,18 @@ void validateDataType(const DataTypePtr & type_to_check, const DataTypeValidatio } } + if (!settings.allow_experimental_bfloat16_type) + { + if (WhichDataType(data_type).isBFloat16()) + { + throw Exception( + ErrorCodes::ILLEGAL_COLUMN, + "Cannot create column with type '{}' because experimental BFloat16 type is not allowed. " + "Set setting allow_experimental_bfloat16_type = 1 in order to allow it", + data_type.getName()); + } + } + if (!settings.allow_suspicious_variant_types) { if (const auto * variant_type = typeid_cast(&data_type)) diff --git a/src/Interpreters/parseColumnsListForTableFunction.h b/src/Interpreters/parseColumnsListForTableFunction.h index 6e00492c0ad..39b9f092d89 100644 --- a/src/Interpreters/parseColumnsListForTableFunction.h +++ b/src/Interpreters/parseColumnsListForTableFunction.h @@ -20,6 +20,7 @@ struct DataTypeValidationSettings bool allow_experimental_object_type = true; bool allow_suspicious_fixed_string_types = true; bool allow_experimental_variant_type = true; + bool allow_experimental_bfloat16_type = true; bool allow_suspicious_variant_types = true; bool validate_nested_types = true; bool allow_experimental_dynamic_type = true; diff --git a/src/Parsers/ParserPartition.cpp b/src/Parsers/ParserPartition.cpp index ab97b3d0e3b..55b0d5a3567 100644 --- a/src/Parsers/ParserPartition.cpp +++ b/src/Parsers/ParserPartition.cpp @@ -5,10 +5,10 @@ #include #include #include -#include #include #include + namespace DB { @@ -61,7 +61,7 @@ bool ParserPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) else fields_count = 0; } - else if (const auto* literal_ast = value->as(); literal_ast) + else if (const auto * literal_ast = value->as(); literal_ast) { if (literal_ast->value.getType() == Field::Types::Tuple) { diff --git a/src/Parsers/StringRange.h b/src/Parsers/StringRange.h deleted file mode 100644 index 3c5959fd0a3..00000000000 --- a/src/Parsers/StringRange.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - - -namespace DB -{ - -struct StringRange -{ - const char * first = nullptr; - const char * second = nullptr; - - StringRange() = default; - StringRange(const char * begin, const char * end) : first(begin), second(end) {} - explicit StringRange(TokenIterator token) : first(token->begin), second(token->end) {} - - StringRange(TokenIterator token_begin, TokenIterator token_end) - { - /// Empty range. - if (token_begin == token_end) - { - first = token_begin->begin; - second = token_begin->begin; - return; - } - - TokenIterator token_last = token_end; - --token_last; - - first = token_begin->begin; - second = token_last->end; - } -}; - -using StringPtr = std::shared_ptr; - - -inline String toString(const StringRange & range) -{ - return range.first ? String(range.first, range.second) : String(); -} - -/// Hashes only the values of pointers in StringRange. Is used with StringRangePointersEqualTo comparator. -struct StringRangePointersHash -{ - UInt64 operator()(const StringRange & range) const - { - SipHash hash; - hash.update(range.first); - hash.update(range.second); - return hash.get64(); - } -}; - -/// Ranges are equal only when they point to the same memory region. -/// It may be used when it's enough to compare substrings by their position in the same string. -struct StringRangePointersEqualTo -{ - constexpr bool operator()(const StringRange &lhs, const StringRange &rhs) const - { - return std::tie(lhs.first, lhs.second) == std::tie(rhs.first, rhs.second); - } -}; - -} - diff --git a/src/Processors/Formats/Impl/Parquet/ParquetDataValuesReader.cpp b/src/Processors/Formats/Impl/Parquet/ParquetDataValuesReader.cpp index b471989076b..4b79be98810 100644 --- a/src/Processors/Formats/Impl/Parquet/ParquetDataValuesReader.cpp +++ b/src/Processors/Formats/Impl/Parquet/ParquetDataValuesReader.cpp @@ -580,6 +580,7 @@ template class ParquetPlainValuesReader; template class ParquetPlainValuesReader; template class ParquetPlainValuesReader; template class ParquetPlainValuesReader; +template class ParquetPlainValuesReader; template class ParquetPlainValuesReader; template class ParquetPlainValuesReader; template class ParquetPlainValuesReader>; @@ -602,6 +603,7 @@ template class ParquetRleDictReader; template class ParquetRleDictReader; template class ParquetRleDictReader; template class ParquetRleDictReader; +template class ParquetRleDictReader; template class ParquetRleDictReader; template class ParquetRleDictReader; template class ParquetRleDictReader>; diff --git a/src/Processors/Formats/Impl/Parquet/ParquetLeafColReader.cpp b/src/Processors/Formats/Impl/Parquet/ParquetLeafColReader.cpp index c3c7db510ed..328dd37107e 100644 --- a/src/Processors/Formats/Impl/Parquet/ParquetLeafColReader.cpp +++ b/src/Processors/Formats/Impl/Parquet/ParquetLeafColReader.cpp @@ -644,6 +644,7 @@ template class ParquetLeafColReader; template class ParquetLeafColReader; template class ParquetLeafColReader; template class ParquetLeafColReader; +template class ParquetLeafColReader; template class ParquetLeafColReader; template class ParquetLeafColReader; template class ParquetLeafColReader; diff --git a/src/Processors/LimitTransform.cpp b/src/Processors/LimitTransform.cpp index 5e24062d67a..a531dd599b2 100644 --- a/src/Processors/LimitTransform.cpp +++ b/src/Processors/LimitTransform.cpp @@ -317,8 +317,9 @@ void LimitTransform::splitChunk(PortsData & data) length = offset + limit - (rows_read - num_rows) - start; } - /// check if other rows in current block equals to last one in limit - if (with_ties && length) + /// Check if other rows in current block equals to last one in limit + /// when rows read >= offset + limit. + if (with_ties && offset + limit <= rows_read && length) { UInt64 current_row_num = start + length; previous_row_chunk = makeChunkWithPreviousRow(data.current_chunk, current_row_num - 1); diff --git a/src/Processors/Transforms/AddingDefaultsTransform.cpp b/src/Processors/Transforms/AddingDefaultsTransform.cpp index a15ea9d67cb..122691e4ea8 100644 --- a/src/Processors/Transforms/AddingDefaultsTransform.cpp +++ b/src/Processors/Transforms/AddingDefaultsTransform.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -184,7 +185,7 @@ void AddingDefaultsTransform::transform(Chunk & chunk) std::unordered_map mixed_columns; - for (const ColumnWithTypeAndName & column_def : evaluate_block) + for (auto & column_def : evaluate_block) { const String & column_name = column_def.name; @@ -199,6 +200,9 @@ void AddingDefaultsTransform::transform(Chunk & chunk) if (!defaults_mask.empty()) { + column_read.column = recursiveRemoveSparse(column_read.column); + column_def.column = recursiveRemoveSparse(column_def.column); + /// TODO: FixedString if (isColumnedAsNumber(column_read.type) || isDecimal(column_read.type)) { diff --git a/src/Storages/MergeTree/IMergeTreeDataPart.cpp b/src/Storages/MergeTree/IMergeTreeDataPart.cpp index 51c445945e6..ea01a0ed0f9 100644 --- a/src/Storages/MergeTree/IMergeTreeDataPart.cpp +++ b/src/Storages/MergeTree/IMergeTreeDataPart.cpp @@ -2263,18 +2263,18 @@ void IMergeTreeDataPart::checkConsistencyWithProjections(bool require_part_metad proj_part->checkConsistency(require_part_metadata); } -void IMergeTreeDataPart::calculateColumnsAndSecondaryIndicesSizesOnDisk() +void IMergeTreeDataPart::calculateColumnsAndSecondaryIndicesSizesOnDisk(std::optional columns_sample) { - calculateColumnsSizesOnDisk(); + calculateColumnsSizesOnDisk(columns_sample); calculateSecondaryIndicesSizesOnDisk(); } -void IMergeTreeDataPart::calculateColumnsSizesOnDisk() +void IMergeTreeDataPart::calculateColumnsSizesOnDisk(std::optional columns_sample) { if (getColumns().empty() || checksums.empty()) throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot calculate columns sizes when columns or checksums are not initialized"); - calculateEachColumnSizes(columns_sizes, total_columns_size); + calculateEachColumnSizes(columns_sizes, total_columns_size, columns_sample); } void IMergeTreeDataPart::calculateSecondaryIndicesSizesOnDisk() @@ -2521,22 +2521,24 @@ ColumnPtr IMergeTreeDataPart::getColumnSample(const NameAndTypePair & column) co StorageMetadataPtr metadata_ptr = storage.getInMemoryMetadataPtr(); StorageSnapshotPtr storage_snapshot_ptr = std::make_shared(storage, metadata_ptr); + MergeTreeReaderSettings settings; + settings.can_read_part_without_marks = true; MergeTreeReaderPtr reader = getReader( cols, storage_snapshot_ptr, - MarkRanges{MarkRange(0, 1)}, + MarkRanges{MarkRange(0, total_mark)}, /*virtual_fields=*/ {}, /*uncompressed_cache=*/{}, storage.getContext()->getMarkCache().get(), std::make_shared(), - MergeTreeReaderSettings{}, + settings, ValueSizeMap{}, ReadBufferFromFileBase::ProfileCallback{}); Columns result; result.resize(1); - reader->readRows(0, 1, false, 0, result); + reader->readRows(0, total_mark, false, 0, result); return result[0]; } diff --git a/src/Storages/MergeTree/IMergeTreeDataPart.h b/src/Storages/MergeTree/IMergeTreeDataPart.h index 55f1265318c..24625edf154 100644 --- a/src/Storages/MergeTree/IMergeTreeDataPart.h +++ b/src/Storages/MergeTree/IMergeTreeDataPart.h @@ -428,7 +428,7 @@ public: bool shallParticipateInMerges(const StoragePolicyPtr & storage_policy) const; /// Calculate column and secondary indices sizes on disk. - void calculateColumnsAndSecondaryIndicesSizesOnDisk(); + void calculateColumnsAndSecondaryIndicesSizesOnDisk(std::optional columns_sample = std::nullopt); std::optional getRelativePathForPrefix(const String & prefix, bool detached = false, bool broken = false) const; @@ -633,7 +633,7 @@ protected: /// Fill each_columns_size and total_size with sizes from columns files on /// disk using columns and checksums. - virtual void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size) const = 0; + virtual void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size, std::optional columns_sample) const = 0; std::optional getRelativePathForDetachedPart(const String & prefix, bool broken) const; @@ -715,7 +715,7 @@ private: void loadPartitionAndMinMaxIndex(); - void calculateColumnsSizesOnDisk(); + void calculateColumnsSizesOnDisk(std::optional columns_sample = std::nullopt); void calculateSecondaryIndicesSizesOnDisk(); diff --git a/src/Storages/MergeTree/IMergeTreeDataPartWriter.h b/src/Storages/MergeTree/IMergeTreeDataPartWriter.h index d1c76505d7c..8923f6a59ca 100644 --- a/src/Storages/MergeTree/IMergeTreeDataPartWriter.h +++ b/src/Storages/MergeTree/IMergeTreeDataPartWriter.h @@ -54,6 +54,8 @@ public: const MergeTreeIndexGranularity & getIndexGranularity() const { return index_granularity; } + virtual Block getColumnsSample() const = 0; + protected: SerializationPtr getSerialization(const String & column_name) const; diff --git a/src/Storages/MergeTree/MergeTreeDataPartCompact.cpp b/src/Storages/MergeTree/MergeTreeDataPartCompact.cpp index 14c2da82de1..8856f467b90 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartCompact.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartCompact.cpp @@ -80,7 +80,7 @@ MergeTreeDataPartWriterPtr createMergeTreeDataPartCompactWriter( } -void MergeTreeDataPartCompact::calculateEachColumnSizes(ColumnSizeByName & /*each_columns_size*/, ColumnSize & total_size) const +void MergeTreeDataPartCompact::calculateEachColumnSizes(ColumnSizeByName & /*each_columns_size*/, ColumnSize & total_size, std::optional /*columns_sample*/) const { auto bin_checksum = checksums.files.find(DATA_FILE_NAME_WITH_EXTENSION); if (bin_checksum != checksums.files.end()) diff --git a/src/Storages/MergeTree/MergeTreeDataPartCompact.h b/src/Storages/MergeTree/MergeTreeDataPartCompact.h index 8e279571578..c394de0d7c1 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartCompact.h +++ b/src/Storages/MergeTree/MergeTreeDataPartCompact.h @@ -70,7 +70,7 @@ private: void loadIndexGranularity() override; /// Compact parts don't support per column size, only total size - void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size) const override; + void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size, std::optional columns_sample) const override; }; } diff --git a/src/Storages/MergeTree/MergeTreeDataPartWide.cpp b/src/Storages/MergeTree/MergeTreeDataPartWide.cpp index c515d645253..39f96ba06ad 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWide.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartWide.cpp @@ -82,7 +82,7 @@ MergeTreeDataPartWriterPtr createMergeTreeDataPartWideWriter( /// Takes into account the fact that several columns can e.g. share their .size substreams. /// When calculating totals these should be counted only once. ColumnSize MergeTreeDataPartWide::getColumnSizeImpl( - const NameAndTypePair & column, std::unordered_set * processed_substreams) const + const NameAndTypePair & column, std::unordered_set * processed_substreams, std::optional columns_sample) const { ColumnSize size; if (checksums.empty()) @@ -108,7 +108,7 @@ ColumnSize MergeTreeDataPartWide::getColumnSizeImpl( auto mrk_checksum = checksums.files.find(*stream_name + getMarksFileExtension()); if (mrk_checksum != checksums.files.end()) size.marks += mrk_checksum->second.file_size; - }); + }, column.type, columns_sample && columns_sample->has(column.name) ? columns_sample->getByName(column.name).column : getColumnSample(column)); return size; } @@ -374,12 +374,12 @@ std::optional MergeTreeDataPartWide::getFileNameForColumn(const NameAndT return filename; } -void MergeTreeDataPartWide::calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size) const +void MergeTreeDataPartWide::calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size, std::optional columns_sample) const { std::unordered_set processed_substreams; for (const auto & column : columns) { - ColumnSize size = getColumnSizeImpl(column, &processed_substreams); + ColumnSize size = getColumnSizeImpl(column, &processed_substreams, columns_sample); each_columns_size[column.name] = size; total_size.add(size); diff --git a/src/Storages/MergeTree/MergeTreeDataPartWide.h b/src/Storages/MergeTree/MergeTreeDataPartWide.h index 022a5fb746c..a6d4897ed87 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWide.h +++ b/src/Storages/MergeTree/MergeTreeDataPartWide.h @@ -64,9 +64,9 @@ private: /// Loads marks index granularity into memory void loadIndexGranularity() override; - ColumnSize getColumnSizeImpl(const NameAndTypePair & column, std::unordered_set * processed_substreams) const; + ColumnSize getColumnSizeImpl(const NameAndTypePair & column, std::unordered_set * processed_substreams, std::optional columns_sample) const; - void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size) const override; + void calculateEachColumnSizes(ColumnSizeByName & each_columns_size, ColumnSize & total_size, std::optional columns_sample) const override; }; diff --git a/src/Storages/MergeTree/MergeTreeDataPartWriterOnDisk.h b/src/Storages/MergeTree/MergeTreeDataPartWriterOnDisk.h index 49d654c15e1..b22d58ba51e 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartWriterOnDisk.h +++ b/src/Storages/MergeTree/MergeTreeDataPartWriterOnDisk.h @@ -123,6 +123,8 @@ public: written_offset_columns = written_offset_columns_; } + Block getColumnsSample() const override { return block_sample; } + protected: /// Count index_granularity for block and store in `index_granularity` size_t computeIndexGranularity(const Block & block) const; diff --git a/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp b/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp index 1b3c58000e7..c4ca545ca90 100644 --- a/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp +++ b/src/Storages/MergeTree/MergeTreeDataSelectExecutor.cpp @@ -1045,7 +1045,6 @@ MarkRanges MergeTreeDataSelectExecutor::markRangesFromPKRange( MarkRanges res; size_t marks_count = part->index_granularity.getMarksCount(); - const auto & index = part->getIndex(); if (marks_count == 0) return res; @@ -1073,14 +1072,19 @@ MarkRanges MergeTreeDataSelectExecutor::markRangesFromPKRange( auto index_columns = std::make_shared(); const auto & key_indices = key_condition.getKeyIndices(); DataTypes key_types; - for (size_t i : key_indices) + if (!key_indices.empty()) { - if (i < index->size()) - index_columns->emplace_back(index->at(i), primary_key.data_types[i], primary_key.column_names[i]); - else - index_columns->emplace_back(); /// The column of the primary key was not loaded in memory - we'll skip it. + const auto & index = part->getIndex(); - key_types.emplace_back(primary_key.data_types[i]); + for (size_t i : key_indices) + { + if (i < index->size()) + index_columns->emplace_back(index->at(i), primary_key.data_types[i], primary_key.column_names[i]); + else + index_columns->emplace_back(); /// The column of the primary key was not loaded in memory - we'll skip it. + + key_types.emplace_back(primary_key.data_types[i]); + } } /// If there are no monotonic functions, there is no need to save block reference. diff --git a/src/Storages/MergeTree/MergeTreeReaderWide.cpp b/src/Storages/MergeTree/MergeTreeReaderWide.cpp index 77231d8d392..885bd1ded8c 100644 --- a/src/Storages/MergeTree/MergeTreeReaderWide.cpp +++ b/src/Storages/MergeTree/MergeTreeReaderWide.cpp @@ -172,7 +172,7 @@ size_t MergeTreeReaderWide::readRows( throw; } - if (column->empty()) + if (column->empty() && max_rows_to_read > 0) res_columns[pos] = nullptr; } diff --git a/src/Storages/MergeTree/MergedBlockOutputStream.cpp b/src/Storages/MergeTree/MergedBlockOutputStream.cpp index 39096718b5c..14a521ce429 100644 --- a/src/Storages/MergeTree/MergedBlockOutputStream.cpp +++ b/src/Storages/MergeTree/MergedBlockOutputStream.cpp @@ -209,7 +209,7 @@ MergedBlockOutputStream::Finalizer MergedBlockOutputStream::finalizePartAsync( new_part->index_granularity = writer->getIndexGranularity(); /// Just in case new_part->index_granularity.shrinkToFitInMemory(); - new_part->calculateColumnsAndSecondaryIndicesSizesOnDisk(); + new_part->calculateColumnsAndSecondaryIndicesSizesOnDisk(writer->getColumnsSample()); /// In mutation, existing_rows_count is already calculated in PartMergerWriter /// In merge situation, lightweight deleted rows was physically deleted, existing_rows_count equals rows_count diff --git a/src/Storages/ObjectStorageQueue/ObjectStorageQueueSettings.cpp b/src/Storages/ObjectStorageQueue/ObjectStorageQueueSettings.cpp index 060f1cd2dd5..47eb57f918d 100644 --- a/src/Storages/ObjectStorageQueue/ObjectStorageQueueSettings.cpp +++ b/src/Storages/ObjectStorageQueue/ObjectStorageQueueSettings.cpp @@ -30,8 +30,8 @@ namespace ErrorCodes DECLARE(UInt64, tracked_files_limit, 1000, "For unordered mode. Max set size for tracking processed files in ZooKeeper", 0) \ DECLARE(UInt64, tracked_file_ttl_sec, 0, "Maximum number of seconds to store processed files in ZooKeeper node (store forever by default)", 0) \ DECLARE(UInt64, polling_min_timeout_ms, 1000, "Minimal timeout before next polling", 0) \ - DECLARE(UInt64, polling_max_timeout_ms, 10000, "Maximum timeout before next polling", 0) \ - DECLARE(UInt64, polling_backoff_ms, 1000, "Polling backoff", 0) \ + DECLARE(UInt64, polling_max_timeout_ms, 10 * 60 * 1000, "Maximum timeout before next polling", 0) \ + DECLARE(UInt64, polling_backoff_ms, 30 * 1000, "Polling backoff", 0) \ DECLARE(UInt32, cleanup_interval_min_ms, 60000, "For unordered mode. Polling backoff min for cleanup", 0) \ DECLARE(UInt32, cleanup_interval_max_ms, 60000, "For unordered mode. Polling backoff max for cleanup", 0) \ DECLARE(UInt32, buckets, 0, "Number of buckets for Ordered mode parallel processing", 0) \ diff --git a/src/Storages/ObjectStorageQueue/ObjectStorageQueueSource.cpp b/src/Storages/ObjectStorageQueue/ObjectStorageQueueSource.cpp index ba1a97bc2fb..e702f07208a 100644 --- a/src/Storages/ObjectStorageQueue/ObjectStorageQueueSource.cpp +++ b/src/Storages/ObjectStorageQueue/ObjectStorageQueueSource.cpp @@ -659,7 +659,7 @@ void ObjectStorageQueueSource::applyActionAfterProcessing(const String & path) { if (files_metadata->getTableMetadata().after_processing == ObjectStorageQueueAction::DELETE) { - object_storage->removeObject(StoredObject(path)); + object_storage->removeObjectIfExists(StoredObject(path)); } } diff --git a/src/Storages/Utils.cpp b/src/Storages/Utils.cpp index bd03a96c7cc..7143ca6cf76 100644 --- a/src/Storages/Utils.cpp +++ b/src/Storages/Utils.cpp @@ -1,10 +1,13 @@ +#include #include #include +#include namespace CurrentMetrics { extern const Metric AttachedTable; + extern const Metric AttachedReplicatedTable; extern const Metric AttachedView; extern const Metric AttachedDictionary; } @@ -12,17 +15,20 @@ namespace CurrentMetrics namespace DB { - CurrentMetrics::Metric getAttachedCounterForStorage(const StoragePtr & storage) + std::vector getAttachedCountersForStorage(const StoragePtr & storage) { if (storage->isView()) { - return CurrentMetrics::AttachedView; + return {CurrentMetrics::AttachedView}; } if (storage->isDictionary()) { - return CurrentMetrics::AttachedDictionary; + return {CurrentMetrics::AttachedDictionary}; } - - return CurrentMetrics::AttachedTable; + if (typeid_cast(storage.get()) != nullptr) + { + return {CurrentMetrics::AttachedTable, CurrentMetrics::AttachedReplicatedTable}; + } + return {CurrentMetrics::AttachedTable}; } } diff --git a/src/Storages/Utils.h b/src/Storages/Utils.h index c86c2a4c341..eb302178485 100644 --- a/src/Storages/Utils.h +++ b/src/Storages/Utils.h @@ -6,5 +6,5 @@ namespace DB { - CurrentMetrics::Metric getAttachedCounterForStorage(const StoragePtr & storage); + std::vector getAttachedCountersForStorage(const StoragePtr & storage); } diff --git a/tests/integration/compose/docker_compose_rabbitmq.yml b/tests/integration/compose/docker_compose_rabbitmq.yml index 0e5203b925f..7ab5e874110 100644 --- a/tests/integration/compose/docker_compose_rabbitmq.yml +++ b/tests/integration/compose/docker_compose_rabbitmq.yml @@ -16,4 +16,10 @@ services: - /misc/rabbitmq/ca-cert.pem:/etc/rabbitmq/ca-cert.pem - /misc/rabbitmq/server-cert.pem:/etc/rabbitmq/server-cert.pem - /misc/rabbitmq/server-key.pem:/etc/rabbitmq/server-key.pem - - /misc/rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins \ No newline at end of file + - /misc/rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins + # https://www.rabbitmq.com/docs/monitoring#health-checks + healthcheck: + test: rabbitmq-diagnostics -q ping + interval: 10s + retries: 10 + timeout: 2s diff --git a/tests/integration/test_backup_restore_on_cluster/test_cancel_backup.py b/tests/integration/test_backup_restore_on_cluster/test_cancel_backup.py index f63dc2aef3d..4ad53acc735 100644 --- a/tests/integration/test_backup_restore_on_cluster/test_cancel_backup.py +++ b/tests/integration/test_backup_restore_on_cluster/test_cancel_backup.py @@ -251,23 +251,16 @@ def kill_query( if is_initial_query is not None else "" ) + old_time = time.monotonic() node.query( f"KILL QUERY WHERE (query_kind='{query_kind}') AND (query LIKE '%{id}%'){filter_for_is_initial_query} SYNC" ) - node.query("SYSTEM FLUSH LOGS") - duration = ( - int( - node.query( - f"SELECT query_duration_ms FROM system.query_log WHERE query_kind='KillQuery' AND query LIKE '%{id}%' AND type='QueryFinish'" - ) - ) - / 1000 - ) + waited = time.monotonic() - old_time print( - f"{get_node_name(node)}: Cancelled {operation_name} {id} after {duration} seconds" + f"{get_node_name(node)}: Cancelled {operation_name} {id} after {waited} seconds" ) if timeout is not None: - assert duration < timeout + assert waited < timeout # Stops all ZooKeeper servers. @@ -305,7 +298,7 @@ def sleep(seconds): class NoTrashChecker: def __init__(self): self.expect_backups = [] - self.expect_unfinished_backups = [] + self.allow_unfinished_backups = [] self.expect_errors = [] self.allow_errors = [] self.check_zookeeper = True @@ -373,7 +366,7 @@ class NoTrashChecker: if unfinished_backups: print(f"Found unfinished backups: {unfinished_backups}") assert new_backups == set(self.expect_backups) - assert unfinished_backups == set(self.expect_unfinished_backups) + assert unfinished_backups.difference(self.allow_unfinished_backups) == set() all_errors = set() start_time = time.strftime( @@ -641,7 +634,7 @@ def test_long_disconnection_stops_backup(): assert get_status(initiator, backup_id=backup_id) == "CREATING_BACKUP" assert get_num_system_processes(initiator, backup_id=backup_id) >= 1 - no_trash_checker.expect_unfinished_backups = [backup_id] + no_trash_checker.allow_unfinished_backups = [backup_id] no_trash_checker.allow_errors = [ "FAILED_TO_SYNC_BACKUP_OR_RESTORE", "KEEPER_EXCEPTION", @@ -674,7 +667,7 @@ def test_long_disconnection_stops_backup(): # A backup is expected to fail, but it isn't expected to fail too soon. print(f"Backup failed after {time_to_fail} seconds disconnection") assert time_to_fail > 3 - assert time_to_fail < 30 + assert time_to_fail < 35 # A backup must NOT be stopped if Zookeeper is disconnected shorter than `failure_after_host_disconnected_for_seconds`. @@ -695,7 +688,7 @@ def test_short_disconnection_doesnt_stop_backup(): backup_id = random_id() initiator.query( f"BACKUP TABLE tbl ON CLUSTER 'cluster' TO {get_backup_name(backup_id)} SETTINGS id='{backup_id}' ASYNC", - settings={"backup_restore_failure_after_host_disconnected_for_seconds": 6}, + settings={"backup_restore_failure_after_host_disconnected_for_seconds": 10}, ) assert get_status(initiator, backup_id=backup_id) == "CREATING_BACKUP" @@ -703,13 +696,13 @@ def test_short_disconnection_doesnt_stop_backup(): # Dropping connection for less than `failure_after_host_disconnected_for_seconds` with PartitionManager() as pm: - random_sleep(3) + random_sleep(4) node_to_drop_zk_connection = random_node() print( f"Dropping connection between {get_node_name(node_to_drop_zk_connection)} and ZooKeeper" ) pm.drop_instance_zk_connections(node_to_drop_zk_connection) - random_sleep(3) + random_sleep(4) print( f"Restoring connection between {get_node_name(node_to_drop_zk_connection)} and ZooKeeper" ) diff --git a/tests/integration/test_failed_mutations/test.py b/tests/integration/test_failed_mutations/test.py index 5a2bf874da2..24b67ff86e5 100644 --- a/tests/integration/test_failed_mutations/test.py +++ b/tests/integration/test_failed_mutations/test.py @@ -27,6 +27,7 @@ REPLICATED_POSTPONE_MUTATION_LOG = ( POSTPONE_MUTATION_LOG = ( "According to exponential backoff policy, do not perform mutations for the part" ) +FAILING_MUTATION_QUERY = "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT throwIf(1)) SETTINGS allow_nondeterministic_mutations = 1" all_nodes = [node_with_backoff, node_no_backoff] @@ -83,17 +84,13 @@ def test_exponential_backoff_with_merge_tree(started_cluster, node, found_in_log assert not node.contains_in_log(POSTPONE_MUTATION_LOG) # Executing incorrect mutation. - node.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM notexist_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node.query(FAILING_MUTATION_QUERY) check_logs() node.query("KILL MUTATION WHERE table='test_mutations'") # Check that after kill new parts mutations are postponing. - node.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM notexist_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node.query(FAILING_MUTATION_QUERY) check_logs() @@ -101,9 +98,7 @@ def test_exponential_backoff_with_merge_tree(started_cluster, node, found_in_log def test_exponential_backoff_with_replicated_tree(started_cluster): prepare_cluster(True) - node_with_backoff.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM notexist_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node_with_backoff.query(FAILING_MUTATION_QUERY) assert node_with_backoff.wait_for_log_line(REPLICATED_POSTPONE_MUTATION_LOG) assert not node_no_backoff.contains_in_log(REPLICATED_POSTPONE_MUTATION_LOG) @@ -114,7 +109,7 @@ def test_exponential_backoff_create_dependent_table(started_cluster): # Executing incorrect mutation. node_with_backoff.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM dep_table) SETTINGS allow_nondeterministic_mutations=1" + "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM dep_table) SETTINGS allow_nondeterministic_mutations = 1, validate_mutation_query = 0" ) # Creating dependent table for mutation. @@ -148,9 +143,7 @@ def test_exponential_backoff_setting_override(started_cluster): node.query("INSERT INTO test_mutations SELECT * FROM system.numbers LIMIT 10") # Executing incorrect mutation. - node.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM dep_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node.query(FAILING_MUTATION_QUERY) assert not node.contains_in_log(POSTPONE_MUTATION_LOG) @@ -166,9 +159,7 @@ def test_backoff_clickhouse_restart(started_cluster, replicated_table): node = node_with_backoff # Executing incorrect mutation. - node.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM dep_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node.query(FAILING_MUTATION_QUERY) assert node.wait_for_log_line( REPLICATED_POSTPONE_MUTATION_LOG if replicated_table else POSTPONE_MUTATION_LOG ) @@ -193,11 +184,10 @@ def test_no_backoff_after_killing_mutation(started_cluster, replicated_table): node = node_with_backoff # Executing incorrect mutation. - node.query( - "ALTER TABLE test_mutations DELETE WHERE x IN (SELECT x FROM dep_table) SETTINGS allow_nondeterministic_mutations=1" - ) + node.query(FAILING_MUTATION_QUERY) + # Executing correct mutation. - node.query("ALTER TABLE test_mutations DELETE WHERE x=1") + node.query("ALTER TABLE test_mutations DELETE WHERE x=1") assert node.wait_for_log_line( REPLICATED_POSTPONE_MUTATION_LOG if replicated_table else POSTPONE_MUTATION_LOG ) diff --git a/tests/integration/test_storage_mongodb/test.py b/tests/integration/test_storage_mongodb/test.py index ec098d7ac54..e810b613290 100644 --- a/tests/integration/test_storage_mongodb/test.py +++ b/tests/integration/test_storage_mongodb/test.py @@ -395,7 +395,7 @@ def test_secure_connection_uri(started_cluster): simple_mongo_table.insert_many(data) node = started_cluster.instances["node"] node.query( - "CREATE OR REPLACE TABLE test_secure_connection_uri(key UInt64, data String) ENGINE = MongoDB('mongodb://root:clickhouse@mongo_secure:27017/test?tls=true&tlsAllowInvalidCertificates=true&tlsAllowInvalidHostnames=true', 'test_secure_connection_uri')" + "CREATE OR REPLACE TABLE test_secure_connection_uri(key UInt64, data String) ENGINE = MongoDB('mongodb://root:clickhouse@mongo_secure:27017/test?tls=true&tlsAllowInvalidCertificates=true&tlsAllowInvalidHostnames=true&authSource=admin', 'test_secure_connection_uri')" ) assert node.query("SELECT COUNT() FROM test_secure_connection_uri") == "100\n" diff --git a/tests/integration/test_storage_s3_queue/test.py b/tests/integration/test_storage_s3_queue/test.py index 62afc0b1c1d..aecc1df491b 100644 --- a/tests/integration/test_storage_s3_queue/test.py +++ b/tests/integration/test_storage_s3_queue/test.py @@ -407,6 +407,8 @@ def test_failed_retry(started_cluster, mode, engine_name): additional_settings={ "s3queue_loading_retries": retries_num, "keeper_path": keeper_path, + "polling_max_timeout_ms": 5000, + "polling_backoff_ms": 1000, }, engine_name=engine_name, ) @@ -852,6 +854,8 @@ def test_multiple_tables_streaming_sync_distributed(started_cluster, mode): additional_settings={ "keeper_path": keeper_path, "s3queue_buckets": 2, + "polling_max_timeout_ms": 2000, + "polling_backoff_ms": 1000, **({"s3queue_processing_threads_num": 1} if mode == "ordered" else {}), }, ) @@ -929,6 +933,8 @@ def test_max_set_age(started_cluster): "cleanup_interval_min_ms": max_age / 3, "cleanup_interval_max_ms": max_age / 3, "loading_retries": 0, + "polling_max_timeout_ms": 5000, + "polling_backoff_ms": 1000, "processing_threads_num": 1, "loading_retries": 0, }, @@ -1423,6 +1429,8 @@ def test_shards_distributed(started_cluster, mode, processing_threads): "keeper_path": keeper_path, "s3queue_processing_threads_num": processing_threads, "s3queue_buckets": shards_num, + "polling_max_timeout_ms": 1000, + "polling_backoff_ms": 0, }, ) i += 1 @@ -1673,6 +1681,8 @@ def test_processed_file_setting_distributed(started_cluster, processing_threads) "s3queue_processing_threads_num": processing_threads, "s3queue_last_processed_path": f"{files_path}/test_5.csv", "s3queue_buckets": 2, + "polling_max_timeout_ms": 2000, + "polling_backoff_ms": 1000, }, ) diff --git a/tests/integration/test_table_db_num_limit/config/config.xml b/tests/integration/test_table_db_num_limit/config/config.xml index 9a573b158fe..88438d51b94 100644 --- a/tests/integration/test_table_db_num_limit/config/config.xml +++ b/tests/integration/test_table_db_num_limit/config/config.xml @@ -1,4 +1,20 @@ + + + + + node1 + 9000 + + + node2 + 9000 + + + + + + 10 10 10 diff --git a/tests/integration/test_table_db_num_limit/config/config1.xml b/tests/integration/test_table_db_num_limit/config/config1.xml new file mode 100644 index 00000000000..73b695f3cd6 --- /dev/null +++ b/tests/integration/test_table_db_num_limit/config/config1.xml @@ -0,0 +1,4 @@ + + 5 + + diff --git a/tests/integration/test_table_db_num_limit/config/config2.xml b/tests/integration/test_table_db_num_limit/config/config2.xml new file mode 100644 index 00000000000..e46ca03d70f --- /dev/null +++ b/tests/integration/test_table_db_num_limit/config/config2.xml @@ -0,0 +1,4 @@ + + 3 + + diff --git a/tests/integration/test_table_db_num_limit/test.py b/tests/integration/test_table_db_num_limit/test.py index b3aff6ddca2..53a644a262c 100644 --- a/tests/integration/test_table_db_num_limit/test.py +++ b/tests/integration/test_table_db_num_limit/test.py @@ -1,11 +1,22 @@ import pytest -from helpers.client import QueryRuntimeException from helpers.cluster import ClickHouseCluster cluster = ClickHouseCluster(__file__) -node = cluster.add_instance("node", main_configs=["config/config.xml"]) +node = cluster.add_instance( + "node1", + with_zookeeper=True, + macros={"replica": "r1"}, + main_configs=["config/config.xml", "config/config1.xml"], +) + +node2 = cluster.add_instance( + "node2", + with_zookeeper=True, + macros={"replica": "r2"}, + main_configs=["config/config.xml", "config/config2.xml"], +) @pytest.fixture(scope="module") @@ -24,10 +35,9 @@ def test_table_db_limit(started_cluster): for i in range(9): node.query("create database db{}".format(i)) - with pytest.raises(QueryRuntimeException) as exp_info: - node.query("create database db_exp".format(i)) - - assert "TOO_MANY_DATABASES" in str(exp_info) + assert "TOO_MANY_DATABASES" in node.query_and_get_error( + "create database db_exp".format(i) + ) for i in range(10): node.query("create table t{} (a Int32) Engine = Log".format(i)) @@ -35,13 +45,72 @@ def test_table_db_limit(started_cluster): # This checks that system tables are not accounted in the number of tables. node.query("system flush logs") + # Regular tables for i in range(10): node.query("drop table t{}".format(i)) for i in range(10): node.query("create table t{} (a Int32) Engine = Log".format(i)) - with pytest.raises(QueryRuntimeException) as exp_info: - node.query("create table default.tx (a Int32) Engine = Log") + assert "TOO_MANY_TABLES" in node.query_and_get_error( + "create table default.tx (a Int32) Engine = Log" + ) - assert "TOO_MANY_TABLES" in str(exp_info) + # Dictionaries + for i in range(10): + node.query( + "create dictionary d{} (a Int32) primary key a source(null()) layout(flat()) lifetime(1000)".format( + i + ) + ) + + assert "TOO_MANY_TABLES" in node.query_and_get_error( + "create dictionary dx (a Int32) primary key a source(null()) layout(flat()) lifetime(1000)" + ) + + # Replicated tables + for i in range(10): + node.query("drop table t{}".format(i)) + + for i in range(3): + node.query( + "create table t{} on cluster 'cluster' (a Int32) Engine = ReplicatedMergeTree('/clickhouse/tables/t{}', '{{replica}}') order by a".format( + i, i + ) + ) + + # Test limit on other replica + assert "Too many replicated tables" in node2.query_and_get_error( + "create table tx (a Int32) Engine = ReplicatedMergeTree('/clickhouse/tables/tx', '{replica}') order by a" + ) + + for i in range(3, 5): + node.query( + "create table t{} (a Int32) Engine = ReplicatedMergeTree('/clickhouse/tables/t{}', '{{replica}}') order by a".format( + i, i + ) + ) + + assert "Too many replicated tables" in node.query_and_get_error( + "create table tx (a Int32) Engine = ReplicatedMergeTree('/clickhouse/tables/tx', '{replica}') order by a" + ) + + # Checks that replicated tables are also counted as regular tables + for i in range(5, 10): + node.query("create table t{} (a Int32) Engine = Log".format(i)) + + assert "TOO_MANY_TABLES" in node.query_and_get_error( + "create table tx (a Int32) Engine = Log" + ) + + # Cleanup + for i in range(10): + node.query("drop table t{} sync".format(i)) + for i in range(3): + node2.query("drop table t{} sync".format(i)) + node.query("system drop replica 'r1' from ZKPATH '/clickhouse/tables/tx'") + node.query("system drop replica 'r2' from ZKPATH '/clickhouse/tables/tx'") + for i in range(9): + node.query("drop database db{}".format(i)) + for i in range(10): + node.query("drop dictionary d{}".format(i)) diff --git a/tests/performance/avg_weighted.xml b/tests/performance/avg_weighted.xml index edf3c19fdfa..ec1b7aae5c2 100644 --- a/tests/performance/avg_weighted.xml +++ b/tests/performance/avg_weighted.xml @@ -1,6 +1,5 @@ - 1 1 8 diff --git a/tests/performance/reinterpret_as.xml b/tests/performance/reinterpret_as.xml index d05ef3bb038..2e0fa0571c3 100644 --- a/tests/performance/reinterpret_as.xml +++ b/tests/performance/reinterpret_as.xml @@ -1,6 +1,5 @@ - 1 15G diff --git a/tests/queries/0_stateless/00996_limit_with_ties.reference b/tests/queries/0_stateless/00996_limit_with_ties.reference index ecbbaa76f7a..43f3a21fcda 100644 --- a/tests/queries/0_stateless/00996_limit_with_ties.reference +++ b/tests/queries/0_stateless/00996_limit_with_ties.reference @@ -53,3 +53,5 @@ 100 100 100 +12 +12 diff --git a/tests/queries/0_stateless/00996_limit_with_ties.sql b/tests/queries/0_stateless/00996_limit_with_ties.sql index 8d7aedc2cb0..4ba2ccfc57d 100644 --- a/tests/queries/0_stateless/00996_limit_with_ties.sql +++ b/tests/queries/0_stateless/00996_limit_with_ties.sql @@ -35,4 +35,24 @@ select count() from (select number, number < 100 from numbers(2000) order by num SET max_block_size = 5; select count() from (select number < 100, number from numbers(2000) order by number < 100 desc limit 10 with ties); +SELECT count() FROM (WITH data AS ( + SELECT * FROM numbers(0, 10) + UNION ALL + SELECT * FROM numbers(10, 10) +) +SELECT number div 10 AS ten, number +FROM data +ORDER BY ten +LIMIT 8,6 WITH TIES); + +SELECT count() FROM (WITH data AS ( + SELECT * FROM numbers(0, 10) + UNION ALL + SELECT * FROM numbers(10, 10) +) +SELECT number div 11 AS eleven, number +FROM data +ORDER BY eleven +LIMIT 8,6 WITH TIES); + DROP TABLE ties; diff --git a/tests/queries/0_stateless/01035_avg.sql b/tests/queries/0_stateless/01035_avg.sql index a3cb35a80ec..0f7baddaec5 100644 --- a/tests/queries/0_stateless/01035_avg.sql +++ b/tests/queries/0_stateless/01035_avg.sql @@ -1,5 +1,3 @@ -SET allow_experimental_bigint_types=1; - CREATE TABLE IF NOT EXISTS test_01035_avg ( i8 Int8 DEFAULT i64, i16 Int16 DEFAULT i64, diff --git a/tests/queries/0_stateless/01182_materialized_view_different_structure.sql b/tests/queries/0_stateless/01182_materialized_view_different_structure.sql index 485f9985974..7e41172bd0c 100644 --- a/tests/queries/0_stateless/01182_materialized_view_different_structure.sql +++ b/tests/queries/0_stateless/01182_materialized_view_different_structure.sql @@ -20,7 +20,6 @@ SELECT sum(value) FROM (SELECT number, sum(number) AS value FROM (SELECT *, toDe CREATE TABLE src (n UInt64, s FixedString(16)) ENGINE=Memory; CREATE TABLE dst (n UInt8, s String) ENGINE = Memory; CREATE MATERIALIZED VIEW mv TO dst (n String) AS SELECT * FROM src; -SET allow_experimental_bigint_types=1; CREATE TABLE dist (n Int128) ENGINE=Distributed(test_cluster_two_shards, currentDatabase(), mv); INSERT INTO src SELECT number, toString(number) FROM numbers(1000); diff --git a/tests/queries/0_stateless/01440_big_int_exotic_casts.sql b/tests/queries/0_stateless/01440_big_int_exotic_casts.sql index 42fde9da01b..f411af897e8 100644 --- a/tests/queries/0_stateless/01440_big_int_exotic_casts.sql +++ b/tests/queries/0_stateless/01440_big_int_exotic_casts.sql @@ -32,8 +32,6 @@ SELECT number y, toInt128(number) - y, toInt256(number) - y, toUInt256(number) - SELECT -number y, toInt128(number) + y, toInt256(number) + y, toUInt256(number) + y FROM numbers_mt(10) ORDER BY number; -SET allow_experimental_bigint_types = 1; - DROP TABLE IF EXISTS t; CREATE TABLE t (x UInt64, i256 Int256, u256 UInt256, d256 Decimal256(2)) ENGINE = Memory; diff --git a/tests/queries/0_stateless/01554_bloom_filter_index_big_integer_uuid.sql b/tests/queries/0_stateless/01554_bloom_filter_index_big_integer_uuid.sql index 3472f41092d..f82fe39f439 100644 --- a/tests/queries/0_stateless/01554_bloom_filter_index_big_integer_uuid.sql +++ b/tests/queries/0_stateless/01554_bloom_filter_index_big_integer_uuid.sql @@ -1,5 +1,3 @@ -SET allow_experimental_bigint_types = 1; - CREATE TABLE 01154_test (x Int128, INDEX ix_x x TYPE bloom_filter(0.01) GRANULARITY 1) ENGINE = MergeTree() ORDER BY x SETTINGS index_granularity=8192; INSERT INTO 01154_test VALUES (1), (2), (3); SELECT x FROM 01154_test WHERE x = 1; diff --git a/tests/queries/0_stateless/01622_byte_size.sql b/tests/queries/0_stateless/01622_byte_size.sql index 9f9de4e58e9..f73011f4151 100644 --- a/tests/queries/0_stateless/01622_byte_size.sql +++ b/tests/queries/0_stateless/01622_byte_size.sql @@ -4,8 +4,6 @@ select ''; select '# byteSize'; -set allow_experimental_bigint_types = 1; - -- numbers #0 -- select ''; select 'byteSize for numbers #0'; diff --git a/tests/queries/0_stateless/01655_plan_optimizations.reference b/tests/queries/0_stateless/01655_plan_optimizations.reference index 7fc7556e85b..33c2593ccfc 100644 --- a/tests/queries/0_stateless/01655_plan_optimizations.reference +++ b/tests/queries/0_stateless/01655_plan_optimizations.reference @@ -163,6 +163,7 @@ Filter column: notEquals(__table1.y, 2_UInt8) > filter is pushed down before CreatingSets CreatingSets Filter +Filter 1 3 > one condition of filter is pushed down before LEFT JOIN diff --git a/tests/queries/0_stateless/01721_dictionary_decimal_p_s.sql b/tests/queries/0_stateless/01721_dictionary_decimal_p_s.sql index 272bd2d7104..57483430cc0 100644 --- a/tests/queries/0_stateless/01721_dictionary_decimal_p_s.sql +++ b/tests/queries/0_stateless/01721_dictionary_decimal_p_s.sql @@ -1,6 +1,5 @@ -- Tags: no-parallel -set allow_experimental_bigint_types=1; drop database if exists db_01721; drop table if exists db_01721.table_decimal_dict; drop dictionary if exists db_01721.decimal_dict; @@ -77,4 +76,3 @@ SELECT dictGet('db_01721.decimal_dict', 'Decimal32_', toUInt64(5000)), drop table if exists table_decimal_dict; drop dictionary if exists cache_dict; drop database if exists db_01721; - diff --git a/tests/queries/0_stateless/01804_dictionary_decimal256_type.sql b/tests/queries/0_stateless/01804_dictionary_decimal256_type.sql index 08a8d0feb27..32b029442b9 100644 --- a/tests/queries/0_stateless/01804_dictionary_decimal256_type.sql +++ b/tests/queries/0_stateless/01804_dictionary_decimal256_type.sql @@ -1,7 +1,5 @@ -- Tags: no-parallel -SET allow_experimental_bigint_types = 1; - DROP TABLE IF EXISTS dictionary_decimal_source_table; CREATE TABLE dictionary_decimal_source_table ( diff --git a/tests/queries/0_stateless/01875_ssd_cache_dictionary_decimal256_type.sh b/tests/queries/0_stateless/01875_ssd_cache_dictionary_decimal256_type.sh index 1294ba53e82..2a24a931696 100755 --- a/tests/queries/0_stateless/01875_ssd_cache_dictionary_decimal256_type.sh +++ b/tests/queries/0_stateless/01875_ssd_cache_dictionary_decimal256_type.sh @@ -6,8 +6,6 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) . "$CURDIR"/../shell_config.sh $CLICKHOUSE_CLIENT --query=" - SET allow_experimental_bigint_types = 1; - DROP TABLE IF EXISTS dictionary_decimal_source_table; CREATE TABLE dictionary_decimal_source_table ( diff --git a/tests/queries/0_stateless/02496_remove_redundant_sorting.reference b/tests/queries/0_stateless/02496_remove_redundant_sorting.reference index 00db41e8ac5..7824fd8cba9 100644 --- a/tests/queries/0_stateless/02496_remove_redundant_sorting.reference +++ b/tests/queries/0_stateless/02496_remove_redundant_sorting.reference @@ -332,12 +332,13 @@ SETTINGS optimize_aggregators_of_group_by_keys=0 -- avoid removing any() as it d Expression (Projection) Sorting (Sorting for ORDER BY) Expression (Before ORDER BY) - Filter (((WHERE + (Projection + Before ORDER BY)) + HAVING)) - Aggregating - Expression ((Before GROUP BY + Projection)) - Sorting (Sorting for ORDER BY) - Expression ((Before ORDER BY + (Projection + Before ORDER BY))) - ReadFromSystemNumbers + Filter ((WHERE + (Projection + Before ORDER BY))) + Filter (HAVING) + Aggregating + Expression ((Before GROUP BY + Projection)) + Sorting (Sorting for ORDER BY) + Expression ((Before ORDER BY + (Projection + Before ORDER BY))) + ReadFromSystemNumbers -- execute 1 2 diff --git a/tests/queries/0_stateless/02554_fix_grouping_sets_predicate_push_down.reference b/tests/queries/0_stateless/02554_fix_grouping_sets_predicate_push_down.reference index a382e14ce03..9bb0c022752 100644 --- a/tests/queries/0_stateless/02554_fix_grouping_sets_predicate_push_down.reference +++ b/tests/queries/0_stateless/02554_fix_grouping_sets_predicate_push_down.reference @@ -28,17 +28,21 @@ WHERE type_1 = \'all\' (Expression) ExpressionTransform × 2 (Filter) - FilterTransform × 6 - (Aggregating) - ExpressionTransform × 2 - AggregatingTransform × 2 - Copy 1 → 2 - (Expression) - ExpressionTransform - (Expression) - ExpressionTransform - (ReadFromMergeTree) - MergeTreeSelect(pool: ReadPoolInOrder, algorithm: InOrder) 0 → 1 + FilterTransform × 2 + (Filter) + FilterTransform × 2 + (Filter) + FilterTransform × 2 + (Aggregating) + ExpressionTransform × 2 + AggregatingTransform × 2 + Copy 1 → 2 + (Expression) + ExpressionTransform + (Expression) + ExpressionTransform + (ReadFromMergeTree) + MergeTreeSelect(pool: ReadPoolInOrder, algorithm: InOrder) 0 → 1 (Expression) ExpressionTransform × 2 (Filter) @@ -64,10 +68,14 @@ ExpressionTransform × 2 ExpressionTransform × 2 AggregatingTransform × 2 Copy 1 → 2 - (Expression) - ExpressionTransform - (ReadFromMergeTree) - MergeTreeSelect(pool: ReadPoolInOrder, algorithm: InOrder) 0 → 1 + (Filter) + FilterTransform + (Filter) + FilterTransform + (Expression) + ExpressionTransform + (ReadFromMergeTree) + MergeTreeSelect(pool: ReadPoolInOrder, algorithm: InOrder) 0 → 1 (Expression) ExpressionTransform × 2 (Aggregating) diff --git a/tests/queries/0_stateless/02993_lazy_index_loading.reference b/tests/queries/0_stateless/02993_lazy_index_loading.reference index 08f07a92815..445cb22b3ef 100644 --- a/tests/queries/0_stateless/02993_lazy_index_loading.reference +++ b/tests/queries/0_stateless/02993_lazy_index_loading.reference @@ -1,4 +1,18 @@ -100000000 100000000 -0 0 +Row 1: +────── +round(primary_key_bytes_in_memory, -7): 100000000 -- 100.00 million +round(primary_key_bytes_in_memory_allocated, -7): 100000000 -- 100.00 million +Row 1: +────── +primary_key_bytes_in_memory: 0 +primary_key_bytes_in_memory_allocated: 0 1 -100000000 100000000 +Row 1: +────── +primary_key_bytes_in_memory: 0 +primary_key_bytes_in_memory_allocated: 0 +1 +Row 1: +────── +round(primary_key_bytes_in_memory, -7): 100000000 -- 100.00 million +round(primary_key_bytes_in_memory_allocated, -7): 100000000 -- 100.00 million diff --git a/tests/queries/0_stateless/02993_lazy_index_loading.sql b/tests/queries/0_stateless/02993_lazy_index_loading.sql index ffb4b7547bf..5d4233e7d5e 100644 --- a/tests/queries/0_stateless/02993_lazy_index_loading.sql +++ b/tests/queries/0_stateless/02993_lazy_index_loading.sql @@ -3,17 +3,26 @@ CREATE TABLE test (s String) ENGINE = MergeTree ORDER BY s SETTINGS index_granul SET optimize_trivial_insert_select = 1; INSERT INTO test SELECT randomString(1000) FROM numbers(100000); -SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table = 'test'; +SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table = 'test' FORMAT Vertical; DETACH TABLE test; SET max_memory_usage = '50M'; ATTACH TABLE test; -SELECT primary_key_bytes_in_memory, primary_key_bytes_in_memory_allocated FROM system.parts WHERE database = currentDatabase() AND table = 'test'; +SELECT primary_key_bytes_in_memory, primary_key_bytes_in_memory_allocated FROM system.parts WHERE database = currentDatabase() AND table = 'test' FORMAT Vertical; SET max_memory_usage = '200M'; + +-- Run a query that doesn use indexes SELECT s != '' FROM test LIMIT 1; -SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table = 'test'; +-- Check that index was not loaded +SELECT primary_key_bytes_in_memory, primary_key_bytes_in_memory_allocated FROM system.parts WHERE database = currentDatabase() AND table = 'test' FORMAT Vertical; + +-- Run a query that uses PK index +SELECT s != '' FROM test WHERE s < '9999999999' LIMIT 1; + +-- Check that index was loaded +SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table = 'test' FORMAT Vertical; DROP TABLE test; diff --git a/tests/queries/0_stateless/03127_system_unload_primary_key_table.reference b/tests/queries/0_stateless/03127_system_unload_primary_key_table.reference index 2d33f7f6683..194d3d099b3 100644 --- a/tests/queries/0_stateless/03127_system_unload_primary_key_table.reference +++ b/tests/queries/0_stateless/03127_system_unload_primary_key_table.reference @@ -5,9 +5,19 @@ 100000000 100000000 0 0 0 0 +Query that does not use index for table `test` +1 +0 0 +0 0 +Query that uses index in for table `test` 1 100000000 100000000 0 0 +Query that does not use index for table `test2` +1 +100000000 100000000 +0 0 +Query that uses index for table `test2` 1 100000000 100000000 100000000 100000000 diff --git a/tests/queries/0_stateless/03127_system_unload_primary_key_table.sql b/tests/queries/0_stateless/03127_system_unload_primary_key_table.sql index de99464a9e6..414e661c5ba 100644 --- a/tests/queries/0_stateless/03127_system_unload_primary_key_table.sql +++ b/tests/queries/0_stateless/03127_system_unload_primary_key_table.sql @@ -16,8 +16,18 @@ SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory SYSTEM UNLOAD PRIMARY KEY {CLICKHOUSE_DATABASE:Identifier}.test2; SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table IN ('test', 'test2'); +SELECT 'Query that does not use index for table `test`'; SELECT s != '' FROM test LIMIT 1; SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table IN ('test', 'test2'); +SELECT 'Query that uses index in for table `test`'; +SELECT s != '' FROM test WHERE s < '99999999' LIMIT 1; +SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table IN ('test', 'test2'); + +SELECT 'Query that does not use index for table `test2`'; SELECT s != '' FROM test2 LIMIT 1; SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table IN ('test', 'test2'); + +SELECT 'Query that uses index for table `test2`'; +SELECT s != '' FROM test2 WHERE s < '99999999' LIMIT 1; +SELECT round(primary_key_bytes_in_memory, -7), round(primary_key_bytes_in_memory_allocated, -7) FROM system.parts WHERE database = currentDatabase() AND table IN ('test', 'test2'); diff --git a/tests/queries/0_stateless/03173_forbid_qualify.sql b/tests/queries/0_stateless/03173_forbid_qualify.sql index 0a41385c52f..f7b05a1eb7e 100644 --- a/tests/queries/0_stateless/03173_forbid_qualify.sql +++ b/tests/queries/0_stateless/03173_forbid_qualify.sql @@ -7,5 +7,5 @@ select count() from test_qualify; -- 100 select * from test_qualify qualify row_number() over (order by number) = 50 SETTINGS enable_analyzer = 1; -- 49 select * from test_qualify qualify row_number() over (order by number) = 50 SETTINGS enable_analyzer = 0; -- { serverError NOT_IMPLEMENTED } -delete from test_qualify where number in (select number from test_qualify qualify row_number() over (order by number) = 50); -- { serverError UNFINISHED } +delete from test_qualify where number in (select number from test_qualify qualify row_number() over (order by number) = 50) SETTINGS validate_mutation_query = 0; -- { serverError UNFINISHED } select count() from test_qualify; -- 100 diff --git a/tests/queries/0_stateless/03248_max_parts_to_move.reference b/tests/queries/0_stateless/03248_max_parts_to_move.reference new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/queries/0_stateless/03248_max_parts_to_move.sql b/tests/queries/0_stateless/03248_max_parts_to_move.sql new file mode 100644 index 00000000000..aed41021e94 --- /dev/null +++ b/tests/queries/0_stateless/03248_max_parts_to_move.sql @@ -0,0 +1,23 @@ +DROP TABLE IF EXISTS t; +DROP TABLE IF EXISTS t2; + +CREATE TABLE t (x Int32) ENGINE = MergeTree ORDER BY x; +CREATE TABLE t2 (x Int32) ENGINE = MergeTree ORDER BY x; + +SYSTEM STOP MERGES t; + +SET max_insert_block_size = 1; +SET min_insert_block_size_rows = 1; +SET max_block_size = 1; + +SET max_parts_to_move = 5; +INSERT INTO t SELECT number from numbers(10); + +ALTER TABLE t MOVE PARTITION tuple() TO TABLE t2; -- { serverError TOO_MANY_PARTS } + +SET max_parts_to_move = 15; + +ALTER TABLE t MOVE PARTITION tuple() TO TABLE t2; + +DROP TABLE IF EXISTS t; +DROP TABLE IF EXISTS t2; diff --git a/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.reference b/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.reference index 063b76b152c..e4be64155d1 100644 --- a/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.reference +++ b/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.reference @@ -1,14 +1,44 @@ +parseDateTime64InJodaSyntax +2077-10-09 10:30:10.123 +1970-01-01 08:00:00 +1970-01-01 08:00:01 +2024-01-02 00:00:00 +1970-01-01 10:30:50 +2025-01-01 15:30:10.123456 +2024-01-01 00:00:01.123456 2024-10-09 10:30:10.123 2024-10-09 10:30:10.123456 2024-10-10 02:30:10.123456 +2024-11-05 17:02:03.123456 2024-10-10 01:30:10.123456 +2024-10-09 08:00:10.123456 +2024-09-10 10:30:10.123 +2024-09-10 10:30:10.000999999 +2024-10-10 03:15:10.123456 +2024-03-01 03:23:34 +2024-02-29 15:22:33 +2023-03-01 15:22:33 +2024-03-04 16:22:33 +2023-03-04 16:22:33 +parseDateTime64InJodaSyntaxOrZero 2024-10-09 10:30:10.123 2024-10-09 10:30:10.123456 1970-01-01 08:00:00.000000000 2024-10-10 02:30:10.123456 2024-10-10 01:30:10.123456 +2024-09-10 10:30:10.123 +1970-01-01 08:00:00.000 +1970-01-01 08:00:00 +1970-01-01 08:00:00 +1970-01-01 08:00:00.000 +parseDateTime64InJodaSyntaxOrNull 2024-10-09 10:30:10.123 2024-10-09 10:30:10.123456 \N 2024-10-10 02:30:10.123456 2024-10-10 01:30:10.123456 +2024-09-10 10:30:10.123 +\N +\N +\N +1970-01-01 00:00:00 diff --git a/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.sql b/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.sql index 9ea854bc324..7e024288f1c 100644 --- a/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.sql +++ b/tests/queries/0_stateless/03252_parse_datetime64_in_joda_syntax.sql @@ -1,19 +1,54 @@ set session_timezone = 'Asia/Shanghai'; +select 'parseDateTime64InJodaSyntax'; +select parseDateTime64InJodaSyntax('', ''); -- { serverError VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE } +select parseDateTime64InJodaSyntax('2077-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); +select parseDateTime64InJodaSyntax('2177-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); -- { serverError CANNOT_PARSE_DATETIME } +select parseDateTime64InJodaSyntax('+0000', 'Z'); +select parseDateTime64InJodaSyntax('08:01', 'HH:ss'); +select parseDateTime64InJodaSyntax('2024-01-02', 'yyyy-MM-dd'); +select parseDateTime64InJodaSyntax('10:30:50', 'HH:mm:ss'); +select parseDateTime64InJodaSyntax('2024-12-31 23:30:10.123456-0800', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); +select parseDateTime64InJodaSyntax('2024-01-01 00:00:01.123456+0800', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456789', 'yyyy-MM-dd HH:mm:ss.SSSSSSSSS'); -- { serverError CANNOT_PARSE_DATETIME } select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456-0800', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); +select parseDateTime64InJodaSyntax('2024-11-05-0800 01:02:03.123456', 'yyyy-MM-ddZ HH:mm:ss.SSSSSS'); select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456America/Los_Angeles', 'yyyy-MM-dd HH:mm:ss.SSSSSSz'); - +select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456Australia/Adelaide', 'yyyy-MM-dd HH:mm:ss.SSSSSSz'); +select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123', 'yyyy-dd-MM HH:mm:ss.SSS'); +select parseDateTime64InJodaSyntax('999999 10-09-202410:30:10', 'SSSSSSSSS dd-MM-yyyyHH:mm:ss'); +select parseDateTime64InJodaSyntax('2024-10-09 10:30:10.123456-0845', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); +select parseDateTime64InJodaSyntax('2023-02-29 11:22:33Not/Timezone', 'yyyy-MM-dd HH:mm:ssz'); -- { serverError BAD_ARGUMENTS } +--leap years and non-leap years +select parseDateTime64InJodaSyntax('2024-02-29 11:23:34America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); +select parseDateTime64InJodaSyntax('2023-02-29 11:22:33America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); -- { serverError CANNOT_PARSE_DATETIME } +select parseDateTime64InJodaSyntax('2024-02-28 23:22:33America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); +select parseDateTime64InJodaSyntax('2023-02-28 23:22:33America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); +select parseDateTime64InJodaSyntax('2024-03-01 00:22:33-8000', 'yyyy-MM-dd HH:mm:ssZ'); +select parseDateTime64InJodaSyntax('2023-03-01 00:22:33-8000', 'yyyy-MM-dd HH:mm:ssZ'); +select 'parseDateTime64InJodaSyntaxOrZero'; select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123456', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123456789', 'yyyy-MM-dd HH:mm:ss.SSSSSSSSS'); select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123456-0800', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123456America/Los_Angeles', 'yyyy-MM-dd HH:mm:ss.SSSSSSz'); - +select parseDateTime64InJodaSyntaxOrZero('2024-10-09 10:30:10.123', 'yyyy-dd-MM HH:mm:ss.SSS'); +select parseDateTime64InJodaSyntaxOrZero('wrong value', 'yyyy-dd-MM HH:mm:ss.SSS'); +select parseDateTime64InJodaSyntaxOrZero('2023-02-29 11:22:33America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); +select parseDateTime64InJodaSyntaxOrZero('', ''); +select parseDateTime64InJodaSyntaxOrZero('2177-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); +select 'parseDateTime64InJodaSyntaxOrNull'; select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123456', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123456789', 'yyyy-MM-dd HH:mm:ss.SSSSSSSSS'); select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123456-0800', 'yyyy-MM-dd HH:mm:ss.SSSSSSZ'); select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123456America/Los_Angeles', 'yyyy-MM-dd HH:mm:ss.SSSSSSz'); +select parseDateTime64InJodaSyntaxOrNull('2024-10-09 10:30:10.123', 'yyyy-dd-MM HH:mm:ss.SSS'); +select parseDateTime64InJodaSyntaxOrNull('2023-02-29 11:22:33America/Los_Angeles', 'yyyy-MM-dd HH:mm:ssz'); +select parseDateTime64InJodaSyntaxOrNull('', ''); +select parseDateTime64InJodaSyntaxOrNull('2177-10-09 10:30:10.123', 'yyyy-MM-dd HH:mm:ss.SSS'); + +set session_timezone = 'UTC'; +select parseDateTime64InJodaSyntax('', ''); diff --git a/tests/queries/0_stateless/03256_invalid_mutation_query.reference b/tests/queries/0_stateless/03256_invalid_mutation_query.reference new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/queries/0_stateless/03256_invalid_mutation_query.sql b/tests/queries/0_stateless/03256_invalid_mutation_query.sql new file mode 100644 index 00000000000..9b4e8f9a7ea --- /dev/null +++ b/tests/queries/0_stateless/03256_invalid_mutation_query.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS t; +DROP TABLE IF EXISTS t2; + +CREATE TABLE t (x int) ENGINE = MergeTree() ORDER BY (); + +DELETE FROM t WHERE y in (SELECT x FROM t); -- { serverError UNKNOWN_IDENTIFIER } +DELETE FROM t WHERE x in (SELECT y FROM t); -- { serverError UNKNOWN_IDENTIFIER } +DELETE FROM t WHERE x IN (SELECT * FROM t2); -- { serverError UNKNOWN_TABLE } +ALTER TABLE t DELETE WHERE x in (SELECT y FROM t); -- { serverError UNKNOWN_IDENTIFIER } +ALTER TABLE t UPDATE x = 1 WHERE x IN (SELECT y FROM t); -- { serverError UNKNOWN_IDENTIFIER } + +DELETE FROM t WHERE x IN (SELECT foo FROM bar) SETTINGS validate_mutation_query = 0; + +ALTER TABLE t ADD COLUMN y int; +DELETE FROM t WHERE y in (SELECT y FROM t); + +CREATE TABLE t2 (x int) ENGINE = MergeTree() ORDER BY (); +DELETE FROM t WHERE x IN (SELECT * FROM t2); + +DROP TABLE t; +DROP TABLE t2; diff --git a/tests/queries/0_stateless/03260_compressor_stat.reference b/tests/queries/0_stateless/03260_compressor_stat.reference new file mode 100644 index 00000000000..ba84b26cc48 --- /dev/null +++ b/tests/queries/0_stateless/03260_compressor_stat.reference @@ -0,0 +1 @@ +CODEC(Delta(1), LZ4) 14 48 diff --git a/tests/queries/0_stateless/03260_compressor_stat.sh b/tests/queries/0_stateless/03260_compressor_stat.sh new file mode 100755 index 00000000000..8a03541763c --- /dev/null +++ b/tests/queries/0_stateless/03260_compressor_stat.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CURDIR"/../shell_config.sh + +echo "Hello, World!" | $CLICKHOUSE_COMPRESSOR --codec 'Delta' --codec 'LZ4' | $CLICKHOUSE_COMPRESSOR --stat diff --git a/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.reference b/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.reference new file mode 100644 index 00000000000..5e30d36d620 --- /dev/null +++ b/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.reference @@ -0,0 +1 @@ +test 10000000 352 39 39 diff --git a/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.sql b/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.sql new file mode 100644 index 00000000000..931990d582f --- /dev/null +++ b/tests/queries/0_stateless/03262_column_sizes_with_dynamic_structure.sql @@ -0,0 +1,23 @@ +-- Tags: no-random-settings, no-fasttest + +set allow_experimental_dynamic_type = 1; +set allow_experimental_json_type = 1; + + +drop table if exists test; +create table test (d Dynamic, json JSON) engine=MergeTree order by tuple() settings min_rows_for_wide_part=0, min_bytes_for_wide_part=1; +insert into test select number, '{"a" : 42, "b" : "Hello, World"}' from numbers(10000000); + +SELECT + `table`, + sum(rows) AS rows, + floor(sum(data_uncompressed_bytes) / (1024 * 1024)) AS data_size_uncompressed, + floor(sum(data_compressed_bytes) / (1024 * 1024)) AS data_size_compressed, + floor(sum(bytes_on_disk) / (1024 * 1024)) AS total_size_on_disk +FROM system.parts +WHERE active AND (database = currentDatabase()) AND (`table` = 'test') +GROUP BY `table` +ORDER BY `table` ASC; + +drop table test; + diff --git a/tests/queries/0_stateless/03262_filter_push_down_view.reference b/tests/queries/0_stateless/03262_filter_push_down_view.reference index 275ff18f73b..5c78173bb5a 100644 --- a/tests/queries/0_stateless/03262_filter_push_down_view.reference +++ b/tests/queries/0_stateless/03262_filter_push_down_view.reference @@ -1,2 +1,2 @@ -Condition: and((materialize(auid) in [1, 1]), (_CAST(toDate(ts)) in (-Inf, 1703980800])) -Granules: 1/3 +Condition: (_CAST(toDate(ts)) in (-Inf, 1703980800]) +Granules: 3/3 diff --git a/tests/queries/0_stateless/03268_empty_tuple_update.reference b/tests/queries/0_stateless/03268_empty_tuple_update.reference new file mode 100644 index 00000000000..30bc45d7a18 --- /dev/null +++ b/tests/queries/0_stateless/03268_empty_tuple_update.reference @@ -0,0 +1 @@ +() 2 diff --git a/tests/queries/0_stateless/03268_empty_tuple_update.sql b/tests/queries/0_stateless/03268_empty_tuple_update.sql new file mode 100644 index 00000000000..343117719fc --- /dev/null +++ b/tests/queries/0_stateless/03268_empty_tuple_update.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS t0; + +CREATE TABLE t0 (c0 Tuple(), c1 int) ENGINE = Memory(); + +INSERT INTO t0 VALUES ((), 1); + +ALTER TABLE t0 UPDATE c0 = (), c1 = 2 WHERE EXISTS (SELECT 1); + +SELECT * FROM t0; + +DROP TABLE t0; diff --git a/tests/queries/0_stateless/03269_bf16.reference b/tests/queries/0_stateless/03269_bf16.reference new file mode 100644 index 00000000000..896cc307623 --- /dev/null +++ b/tests/queries/0_stateless/03269_bf16.reference @@ -0,0 +1,47 @@ +1 -1 1.09375 -1.09375 1 -1 1.09375 -1.09375 18446744000000000000 -0 inf -inf nan +1.09375 1.09375 1.09375 1 +1 1 0 1 1 +0 2.1875 1.1962891 1 Float32 Float32 Float32 Float64 +-0.006250000000000089 2.19375 1.203125 1.0057142857142858 Float64 Float64 Float64 Float64 +0 0 1 0 +1000 1000 1 0 +2000 2000 1 0 +3000 2992 0 8 +4000 4000 1 0 +5000 4992 0 8 +6000 5984 0 16 +7000 6976 0 24 +8000 8000 1 0 +9000 8960 0 40 +49995000 49855104 4999.5 4985.5104 0 0 9999 9984 10000 925 10000 925 +0 0 1 0 +1000 1000 1 0 +2000 2000 1 0 +3000 2992 0 8 +4000 4000 1 0 +5000 4992 0 8 +6000 5984 0 16 +7000 6976 0 24 +8000 8000 1 0 +9000 8960 0 40 +49995000 49855104 4999.5 4985.5104 0 0 9999 9984 10000 925 10000 925 +Row 1: +────── +a32: [0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26,26.5,27,27.5,28,28.5,29,29.5,30,30.5,31,31.5,32,32.5,33,33.5,34,34.5,35,35.5,36,36.5,37,37.5,38,38.5,39,39.5,40,40.5,41,41.5,42,42.5,43,43.5,44,44.5,45,45.5,46,46.5,47,47.5,48,48.5,49,49.5,50,50.5,51,51.5,52,52.5,53,53.5,54,54.5,55,55.5,56,56.5,57,57.5,58,58.5,59,59.5,60,60.5,61,61.5,62,62.5,63,63.5,64,64.5,65,65.5,66,66.5,67,67.5,68,68.5,69,69.5,70,70.5,71,71.5,72,72.5,73,73.5,74,74.5,75,75.5,76,76.5,77,77.5,78,78.5,79,79.5,80,80.5,81,81.5,82,82.5,83,83.5,84,84.5,85,85.5,86,86.5,87,87.5,88,88.5,89,89.5,90,90.5,91,91.5,92,92.5,93,93.5,94,94.5,95,95.5,96,96.5,97,97.5,98,98.5,99,99.5,100,100.5,101,101.5,102,102.5,103,103.5,104,104.5,105,105.5,106,106.5,107,107.5,108,108.5,109,109.5,110,110.5,111,111.5,112,112.5,113,113.5,114,114.5,115,115.5,116,116.5,117,117.5,118,118.5,119,119.5,120,120.5,121,121.5,122,122.5,123,123.5,124,124.5,125,125.5,126,126.5,127,127.5,128,128.5,129,129.5,130,130.5,131,131.5,132,132.5,133,133.5,134,134.5,135,135.5,136,136.5,137,137.5,138,138.5,139,139.5,140,140.5,141,141.5,142,142.5,143,143.5,144,144.5,145,145.5,146,146.5,147,147.5,148,148.5,149,149.5,150,150.5,151,151.5,152,152.5,153,153.5,154,154.5,155,155.5,156,156.5,157,157.5,158,158.5,159,159.5,160,160.5,161,161.5,162,162.5,163,163.5,164,164.5,165,165.5,166,166.5,167,167.5,168,168.5,169,169.5,170,170.5,171,171.5,172,172.5,173,173.5,174,174.5,175,175.5,176,176.5,177,177.5,178,178.5,179,179.5,180,180.5,181,181.5,182,182.5,183,183.5,184,184.5,185,185.5,186,186.5,187,187.5,188,188.5,189,189.5,190,190.5,191,191.5] +a16: [0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26,26.5,27,27.5,28,28.5,29,29.5,30,30.5,31,31.5,32,32.5,33,33.5,34,34.5,35,35.5,36,36.5,37,37.5,38,38.5,39,39.5,40,40.5,41,41.5,42,42.5,43,43.5,44,44.5,45,45.5,46,46.5,47,47.5,48,48.5,49,49.5,50,50.5,51,51.5,52,52.5,53,53.5,54,54.5,55,55.5,56,56.5,57,57.5,58,58.5,59,59.5,60,60.5,61,61.5,62,62.5,63,63.5,64,64.5,65,65.5,66,66.5,67,67.5,68,68.5,69,69.5,70,70.5,71,71.5,72,72.5,73,73.5,74,74.5,75,75.5,76,76.5,77,77.5,78,78.5,79,79.5,80,80.5,81,81.5,82,82.5,83,83.5,84,84.5,85,85.5,86,86.5,87,87.5,88,88.5,89,89.5,90,90.5,91,91.5,92,92.5,93,93.5,94,94.5,95,95.5,96,96.5,97,97.5,98,98.5,99,99.5,100,100.5,101,101.5,102,102.5,103,103.5,104,104.5,105,105.5,106,106.5,107,107.5,108,108.5,109,109.5,110,110.5,111,111.5,112,112.5,113,113.5,114,114.5,115,115.5,116,116.5,117,117.5,118,118.5,119,119.5,120,120.5,121,121.5,122,122.5,123,123.5,124,124.5,125,125.5,126,126.5,127,127.5,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153,154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180,181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189,190,190,191,191] +a32_1: [1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26,26.5,27,27.5,28,28.5,29,29.5,30,30.5,31,31.5,32,32.5,33,33.5,34,34.5,35,35.5,36,36.5,37,37.5,38,38.5,39,39.5,40,40.5,41,41.5,42,42.5,43,43.5,44,44.5,45,45.5,46,46.5,47,47.5,48,48.5,49,49.5,50,50.5,51,51.5,52,52.5,53,53.5,54,54.5,55,55.5,56,56.5,57,57.5,58,58.5,59,59.5,60,60.5,61,61.5,62,62.5,63,63.5,64,64.5,65,65.5,66,66.5,67,67.5,68,68.5,69,69.5,70,70.5,71,71.5,72,72.5,73,73.5,74,74.5,75,75.5,76,76.5,77,77.5,78,78.5,79,79.5,80,80.5,81,81.5,82,82.5,83,83.5,84,84.5,85,85.5,86,86.5,87,87.5,88,88.5,89,89.5,90,90.5,91,91.5,92,92.5,93,93.5,94,94.5,95,95.5,96,96.5,97,97.5,98,98.5,99,99.5,100,100.5,101,101.5,102,102.5,103,103.5,104,104.5,105,105.5,106,106.5,107,107.5,108,108.5,109,109.5,110,110.5,111,111.5,112,112.5,113,113.5,114,114.5,115,115.5,116,116.5,117,117.5,118,118.5,119,119.5,120,120.5,121,121.5,122,122.5,123,123.5,124,124.5,125,125.5,126,126.5,127,127.5,128,128.5,129,129.5,130,130.5,131,131.5,132,132.5,133,133.5,134,134.5,135,135.5,136,136.5,137,137.5,138,138.5,139,139.5,140,140.5,141,141.5,142,142.5,143,143.5,144,144.5,145,145.5,146,146.5,147,147.5,148,148.5,149,149.5,150,150.5,151,151.5,152,152.5,153,153.5,154,154.5,155,155.5,156,156.5,157,157.5,158,158.5,159,159.5,160,160.5,161,161.5,162,162.5,163,163.5,164,164.5,165,165.5,166,166.5,167,167.5,168,168.5,169,169.5,170,170.5,171,171.5,172,172.5,173,173.5,174,174.5,175,175.5,176,176.5,177,177.5,178,178.5,179,179.5,180,180.5,181,181.5,182,182.5,183,183.5,184,184.5,185,185.5,186,186.5,187,187.5,188,188.5,189,189.5,190,190.5,191,191.5,192,192.5] +a16_1: [1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,25,25.5,26,26.5,27,27.5,28,28.5,29,29.5,30,30.5,31,31.5,32,32.5,33,33.5,34,34.5,35,35.5,36,36.5,37,37.5,38,38.5,39,39.5,40,40.5,41,41.5,42,42.5,43,43.5,44,44.5,45,45.5,46,46.5,47,47.5,48,48.5,49,49.5,50,50.5,51,51.5,52,52.5,53,53.5,54,54.5,55,55.5,56,56.5,57,57.5,58,58.5,59,59.5,60,60.5,61,61.5,62,62.5,63,63.5,64,64.5,65,65.5,66,66.5,67,67.5,68,68.5,69,69.5,70,70.5,71,71.5,72,72.5,73,73.5,74,74.5,75,75.5,76,76.5,77,77.5,78,78.5,79,79.5,80,80.5,81,81.5,82,82.5,83,83.5,84,84.5,85,85.5,86,86.5,87,87.5,88,88.5,89,89.5,90,90.5,91,91.5,92,92.5,93,93.5,94,94.5,95,95.5,96,96.5,97,97.5,98,98.5,99,99.5,100,100.5,101,101.5,102,102.5,103,103.5,104,104.5,105,105.5,106,106.5,107,107.5,108,108.5,109,109.5,110,110.5,111,111.5,112,112.5,113,113.5,114,114.5,115,115.5,116,116.5,117,117.5,118,118.5,119,119.5,120,120.5,121,121.5,122,122.5,123,123.5,124,124.5,125,125.5,126,126.5,127,127.5,128,128.5,129,129,130,130,131,131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153,154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180,181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189,190,190,191,191,192,192] +dotProduct(a32, a32_1): 4736944 -- 4.74 million +dotProduct(a16, a16_1): 4726688 -- 4.73 million +cosineDistance(a32, a32_1): 0.000010093636084174129 +cosineDistance(a16, a16_1): 0.00001010226319664298 +L2Distance(a32, a32_1): 19.595917942265423 +L2Distance(a16, a16_1): 19.595917942265423 +L1Distance(a32, a32_1): 384 +L1Distance(a16, a16_1): 384 +LinfDistance(a32, a32_1): 1 +LinfDistance(a16, a16_1): 1 +LpDistance(a32, a32_1, 5): 3.2875036590344515 +LpDistance(a16, a16_1, 5): 3.2875036590344515 +1.09375 8C3F 1000110000111111 2 16268 8C3F +1.09375 1 1.09375 1.0859375 0 diff --git a/tests/queries/0_stateless/03269_bf16.sql b/tests/queries/0_stateless/03269_bf16.sql new file mode 100644 index 00000000000..b332a6e3119 --- /dev/null +++ b/tests/queries/0_stateless/03269_bf16.sql @@ -0,0 +1,100 @@ +SET allow_experimental_bfloat16_type = 1; + +-- This is a smoke test, non exhaustive. + +-- Conversions + +SELECT + 1::BFloat16, + -1::BFloat16, + 1.1::BFloat16, + -1.1::BFloat16, + CAST(1 AS BFloat16), + CAST(-1 AS BFloat16), + CAST(1.1 AS BFloat16), + CAST(-1.1 AS BFloat16), + CAST(0xFFFFFFFFFFFFFFFF AS BFloat16), + CAST(-0.0 AS BFloat16), + CAST(inf AS BFloat16), + CAST(-inf AS BFloat16), + CAST(nan AS BFloat16); + +-- Conversions back + +SELECT + CAST(1.1::BFloat16 AS BFloat16), + CAST(1.1::BFloat16 AS Float32), + CAST(1.1::BFloat16 AS Float64), + CAST(1.1::BFloat16 AS Int8); + +-- Comparisons + +SELECT + 1.1::BFloat16 = 1.1::BFloat16, + 1.1::BFloat16 < 1.1, + 1.1::BFloat16 > 1.1, + 1.1::BFloat16 > 1, + 1.1::BFloat16 = 1.09375; + +-- Arithmetic + +SELECT + 1.1::BFloat16 - 1.1::BFloat16 AS a, + 1.1::BFloat16 + 1.1::BFloat16 AS b, + 1.1::BFloat16 * 1.1::BFloat16 AS c, + 1.1::BFloat16 / 1.1::BFloat16 AS d, + toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d); + +SELECT + 1.1::BFloat16 - 1.1 AS a, + 1.1 + 1.1::BFloat16 AS b, + 1.1::BFloat16 * 1.1 AS c, + 1.1 / 1.1::BFloat16 AS d, + toTypeName(a), toTypeName(b), toTypeName(c), toTypeName(d); + +-- Tables + +DROP TABLE IF EXISTS t; +CREATE TEMPORARY TABLE t (n UInt64, x BFloat16); +INSERT INTO t SELECT number, number FROM numbers(10000); +SELECT *, n = x, n - x FROM t WHERE n % 1000 = 0 ORDER BY n; + +-- Aggregate functions + +SELECT sum(n), sum(x), avg(n), avg(x), min(n), min(x), max(n), max(x), uniq(n), uniq(x), uniqExact(n), uniqExact(x) FROM t; + +-- MergeTree + +DROP TABLE t; +CREATE TABLE t (n UInt64, x BFloat16) ENGINE = MergeTree ORDER BY n; +INSERT INTO t SELECT number, number FROM numbers(10000); +SELECT *, n = x, n - x FROM t WHERE n % 1000 = 0 ORDER BY n; +SELECT sum(n), sum(x), avg(n), avg(x), min(n), min(x), max(n), max(x), uniq(n), uniq(x), uniqExact(n), uniqExact(x) FROM t; + +-- Distances + +WITH + arrayMap(x -> toFloat32(x) / 2, range(384)) AS a32, + arrayMap(x -> toBFloat16(x) / 2, range(384)) AS a16, + arrayMap(x -> x + 1, a32) AS a32_1, + arrayMap(x -> x + 1, a16) AS a16_1 +SELECT a32, a16, a32_1, a16_1, + dotProduct(a32, a32_1), dotProduct(a16, a16_1), + cosineDistance(a32, a32_1), cosineDistance(a16, a16_1), + L2Distance(a32, a32_1), L2Distance(a16, a16_1), + L1Distance(a32, a32_1), L1Distance(a16, a16_1), + LinfDistance(a32, a32_1), LinfDistance(a16, a16_1), + LpDistance(a32, a32_1, 5), LpDistance(a16, a16_1, 5) +FORMAT Vertical; + +-- Introspection + +SELECT 1.1::BFloat16 AS x, + hex(x), bin(x), + byteSize(x), + reinterpretAsUInt16(x), hex(reinterpretAsString(x)); + +-- Rounding (this could be not towards the nearest) + +SELECT 1.1::BFloat16 AS x, + round(x), round(x, 1), round(x, 2), round(x, -1); diff --git a/tests/queries/0_stateless/03271_benchmark_metrics.reference b/tests/queries/0_stateless/03271_benchmark_metrics.reference new file mode 100644 index 00000000000..573541ac970 --- /dev/null +++ b/tests/queries/0_stateless/03271_benchmark_metrics.reference @@ -0,0 +1 @@ +0 diff --git a/tests/queries/0_stateless/03271_benchmark_metrics.sh b/tests/queries/0_stateless/03271_benchmark_metrics.sh new file mode 100755 index 00000000000..23bd39fa987 --- /dev/null +++ b/tests/queries/0_stateless/03271_benchmark_metrics.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e + +CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CUR_DIR"/../shell_config.sh + +# A query with two seconds sleep cannot be processed with QPS > 0.5 +$CLICKHOUSE_BENCHMARK --query "SELECT sleep(2)" 2>&1 | grep -m1 -o -P 'QPS: \d+\.\d+' | $CLICKHOUSE_LOCAL --query "SELECT throwIf(extract(line, 'QPS: (.+)')::Float64 > 0.75) FROM table" --input-format LineAsString diff --git a/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.reference b/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.reference new file mode 100644 index 00000000000..c76adef1c23 --- /dev/null +++ b/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.reference @@ -0,0 +1,4 @@ +1 false +2 false +all_1_1_0 Sparse +all_2_2_0 Sparse diff --git a/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.sh b/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.sh new file mode 100755 index 00000000000..aa80de03754 --- /dev/null +++ b/tests/queries/0_stateless/03271_parse_sparse_columns_defaults.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CURDIR"/../shell_config.sh + +$CLICKHOUSE_CLIENT --query " + DROP TABLE IF EXISTS test_default_bool; + + CREATE TABLE test_default_bool (id Int8, b Bool DEFAULT false) + ENGINE = MergeTree ORDER BY id + SETTINGS ratio_of_defaults_for_sparse_serialization = 0.9; +" + +echo 'INSERT INTO test_default_bool FORMAT CSV 1,\N' | $CLICKHOUSE_CURL -sS "$CLICKHOUSE_URL" --data-binary @- +echo 'INSERT INTO test_default_bool FORMAT CSV 2,\N' | $CLICKHOUSE_CURL -sS "$CLICKHOUSE_URL" --data-binary @- + +$CLICKHOUSE_CLIENT --query " + SELECT * FROM test_default_bool ORDER BY id; + SELECT name, serialization_kind FROM system.parts_columns WHERE database = currentDatabase() AND table = 'test_default_bool' AND column = 'b' AND active; + DROP TABLE test_default_bool; +" diff --git a/tests/queries/0_stateless/03271_sqllancer_having_issue.reference b/tests/queries/0_stateless/03271_sqllancer_having_issue.reference new file mode 100644 index 00000000000..2ab0d6f120f --- /dev/null +++ b/tests/queries/0_stateless/03271_sqllancer_having_issue.reference @@ -0,0 +1,2 @@ +-0.07947094746692918 -1017248723 0 +-0.07947094746692918 -1017248723 0 diff --git a/tests/queries/0_stateless/03271_sqllancer_having_issue.sql b/tests/queries/0_stateless/03271_sqllancer_having_issue.sql new file mode 100644 index 00000000000..aa9659693f0 --- /dev/null +++ b/tests/queries/0_stateless/03271_sqllancer_having_issue.sql @@ -0,0 +1,10 @@ +-- https://s3.amazonaws.com/clickhouse-test-reports/0/a02b20a9813c6ba0880c67f079363ef1c5440109/sqlancer__debug_.html +-- Caused by enablement of query_plan_merge_filters. Will fail if the next line is uncommented +-- set query_plan_merge_filters=1; + +CREATE TABLE IF NOT EXISTS t3 (c0 Int32) ENGINE = Memory() ; +INSERT INTO t3(c0) VALUES (1110866669); + +-- These 2 queries are expected to return the same +SELECT (tan (t3.c0)), SUM(-1017248723), ((t3.c0)%(t3.c0)) FROM t3 GROUP BY t3.c0 SETTINGS aggregate_functions_null_for_empty=1, enable_optimize_predicate_expression=0; +SELECT (tan (t3.c0)), SUM(-1017248723), ((t3.c0)%(t3.c0)) FROM t3 GROUP BY t3.c0 HAVING ((tan ((- (SUM(-1017248723)))))) and ((sqrt (SUM(-1017248723)))) UNION ALL SELECT (tan (t3.c0)), SUM(-1017248723), ((t3.c0)%(t3.c0)) FROM t3 GROUP BY t3.c0 HAVING (NOT (((tan ((- (SUM(-1017248723)))))) and ((sqrt (SUM(-1017248723)))))) UNION ALL SELECT (tan (t3.c0)), SUM(-1017248723), ((t3.c0)%(t3.c0)) FROM t3 GROUP BY t3.c0 HAVING ((((tan ((- (SUM(-1017248723)))))) and ((sqrt (SUM(-1017248723))))) IS NULL) SETTINGS aggregate_functions_null_for_empty=1, enable_optimize_predicate_expression=0; diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index a0d4d1d349e..fa581c705f2 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -3156,3 +3156,4 @@ znode znodes zookeeperSessionUptime zstd +BFloat