From 1c74a7851ba95ab1ad788c07f09da18e9cd021e7 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 3 May 2017 18:21:16 +0300 Subject: [PATCH 01/76] Debian: disable verbose cmake output --- debian/rules | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 0679aa3f968..064919cd19c 100755 --- a/debian/rules +++ b/debian/rules @@ -2,7 +2,7 @@ # -*- makefile -*- # Uncomment this to turn on verbose mode. -export DH_VERBOSE=1 +#export DH_VERBOSE=1 # -pie only for static mode export DEB_BUILD_MAINT_OPTIONS=hardening=+all,-pie @@ -33,6 +33,9 @@ CXX := $(DEB_HOST_GNU_TYPE)-$(DEB_CXX) endif CMAKE_FLAGS ?= -DCMAKE_CXX_COMPILER=`which $(CXX)` -DCMAKE_C_COMPILER=`which $(CC)` -DENABLE_TESTS=0 $(CMAKE_FLAGS_ADD) +ifndef DH_VERBOSE + CMAKE_FLAGS += -DCMAKE_VERBOSE_MAKEFILE=0 +endif %: dh $@ --parallel --buildsystem=cmake --builddirectory=$(BUILDDIR) From 713168c98fe97d979a27e99d5057f7f549f0f9c5 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Wed, 3 May 2017 22:47:57 +0300 Subject: [PATCH 02/76] Auto version update to [54233] --- dbms/cmake/version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 411b98d0cc3..ba006fdf6c7 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ #This strings autochanged from release_lib.sh : -set(VERSION_DESCRIBE v1.1.54232-testing) -set(VERSION_REVISION 54232) +set(VERSION_DESCRIBE v1.1.54233-testing) +set(VERSION_REVISION 54233) #===end of autochange set (VERSION_MAJOR 1) From 6d93d9cefb120d5b9e8c1234797d02a73decd0ce Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 3 May 2017 22:46:41 +0300 Subject: [PATCH 03/76] Combinator -MergeState now returns AggregateFunction(nested_func). [#CLICKHOUSE-2891] --- .../AggregateFunctionMerge.h | 5 ++++ .../AggregateFunctionState.cpp | 26 +++++++++++++++++++ .../AggregateFunctionState.h | 6 ++--- ...e_function_scalars_and_constants.reference | 3 +++ ...gregate_function_scalars_and_constants.sql | 17 ++++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionMerge.h b/dbms/src/AggregateFunctions/AggregateFunctionMerge.h index bf4ad82c98d..435d5c4c638 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionMerge.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionMerge.h @@ -34,6 +34,11 @@ public: return nested_func->getReturnType(); } + AggregateFunctionPtr getNestedFunction() const + { + return nested_func_owner; + } + void setArguments(const DataTypes & arguments) override { if (arguments.size() != 1) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionState.cpp b/dbms/src/AggregateFunctions/AggregateFunctionState.cpp index f9d60a2f885..0bb1345cf00 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionState.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionState.cpp @@ -1,8 +1,34 @@ #include +#include namespace DB { +namespace ErrorCodes +{ + extern const int BAD_ARGUMENTS; +} + +DataTypePtr AggregateFunctionState::getReturnType() const +{ + auto ptr = std::make_shared(nested_func_owner, arguments, params); + + /// Special case: it is -MergeState combinator + if (typeid_cast(ptr->getFunction().get())) + { + if (arguments.size() != 1) + throw Exception("Combinator -MergeState expects only one argument", ErrorCodes::BAD_ARGUMENTS); + + if (!typeid_cast(arguments[0].get())) + throw Exception("Combinator -MergeState expects argument with AggregateFunction type", ErrorCodes::BAD_ARGUMENTS); + + return arguments[0]; + } + + return ptr; +} + + AggregateFunctionPtr createAggregateFunctionState(AggregateFunctionPtr & nested) { return std::make_shared(nested); diff --git a/dbms/src/AggregateFunctions/AggregateFunctionState.h b/dbms/src/AggregateFunctions/AggregateFunctionState.h index 59e5f984399..86511be93d0 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionState.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionState.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -30,10 +31,7 @@ public: return nested_func->getName() + "State"; } - DataTypePtr getReturnType() const override - { - return std::make_shared(nested_func_owner, arguments, params); - } + DataTypePtr getReturnType() const override; void setArguments(const DataTypes & arguments_) override { diff --git a/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.reference b/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.reference index 2b71732c082..6087cae7ec5 100644 --- a/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.reference +++ b/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.reference @@ -27,3 +27,6 @@ 1 0 + +1 +2 diff --git a/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.sql b/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.sql index 8235c6af5e9..e8d9704c3a9 100644 --- a/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.sql +++ b/dbms/tests/queries/0_stateless/00432_aggregate_function_scalars_and_constants.sql @@ -38,3 +38,20 @@ SELECT arrayReduce('groupUniqArrayMergeIf', SELECT ''; SELECT arrayReduce('avgState', [0]) IN (arrayReduce('avgState', [0, 1]), arrayReduce('avgState', [0])); SELECT arrayReduce('avgState', [0]) IN (arrayReduce('avgState', [0, 1]), arrayReduce('avgState', [1])); + +SELECT ''; +SELECT arrayReduce('uniqExactMerge', + [arrayReduce('uniqExactMergeState', + [ + arrayReduce('uniqExactState', [12345678901]), + arrayReduce('uniqExactState', [12345678901]) + ]) + ]); + +SELECT arrayReduce('uniqExactMerge', + [arrayReduce('uniqExactMergeState', + [ + arrayReduce('uniqExactState', [12345678901]), + arrayReduce('uniqExactState', [12345678902]) + ]) + ]); From f02a605900733c79c0e33aaae0eb246f96917acf Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 3 May 2017 22:06:47 +0300 Subject: [PATCH 04/76] Better "Protocol not supported" message --- dbms/src/Server/Server.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 93e1fdfdd29..b1c70b61797 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -553,7 +553,11 @@ int Server::main(const std::vector & args) catch (const Poco::Net::NetException & e) { if (try_listen && e.code() == POCO_EPROTONOSUPPORT) - LOG_ERROR(log, "Listen [" << listen_host << "]: " << e.what() << ": " << e.message()); + LOG_ERROR(log, "Listen [" << listen_host << "]: " << e.what() << ": " << e.message() + << " If it is an IPv6 or IPv4 address and your host has disabled IPv6 or IPv4, then consider to " + << "specify not disabled IPv4 or IPv6 address to listen in element of configuration " + << "file. Example for disabled IPv6: 0.0.0.0 ." + << " Example for disabled IPv4: ::"); else throw; } From 90bbdaffda117cbe1cb3d5efd5a21e3587a22dc1 Mon Sep 17 00:00:00 2001 From: proller Date: Wed, 3 May 2017 22:08:01 +0300 Subject: [PATCH 05/76] Remove old comment --- dbms/src/Server/Server.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index b1c70b61797..2907cb4eb19 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -459,7 +459,6 @@ int Server::main(const std::vector & args) } catch (const Poco::Net::DNSException & e) { - /// Better message when IPv6 is disabled on host. if (e.code() == EAI_FAMILY #if defined(EAI_ADDRFAMILY) || e.code() == EAI_ADDRFAMILY From 85e59ae3ffd02341b72b878a6f211ac47e1d23a8 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 3 May 2017 21:01:19 -0700 Subject: [PATCH 06/76] Update Server.cpp --- dbms/src/Server/Server.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 2907cb4eb19..18986cb57e1 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -467,9 +467,9 @@ int Server::main(const std::vector & args) { LOG_ERROR(log, "Cannot resolve listen_host (" << host << "), error: " << e.message() << ". " - << "If it is an IPv6 address and your host has disabled IPv6, then consider to " - << "specify IPv4 address to listen in element of configuration " - << "file. Example: 0.0.0.0"); + "If it is an IPv6 address and your host has disabled IPv6, then consider to " + "specify IPv4 address to listen in element of configuration " + "file. Example: 0.0.0.0"); } throw; From 99c360b6c79bb091f34b6cb1238361784954a2a0 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Wed, 3 May 2017 21:02:28 -0700 Subject: [PATCH 07/76] Update Server.cpp --- dbms/src/Server/Server.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 18986cb57e1..01f7a0ea7b6 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -553,10 +553,10 @@ int Server::main(const std::vector & args) { if (try_listen && e.code() == POCO_EPROTONOSUPPORT) LOG_ERROR(log, "Listen [" << listen_host << "]: " << e.what() << ": " << e.message() - << " If it is an IPv6 or IPv4 address and your host has disabled IPv6 or IPv4, then consider to " - << "specify not disabled IPv4 or IPv6 address to listen in element of configuration " - << "file. Example for disabled IPv6: 0.0.0.0 ." - << " Example for disabled IPv4: ::"); + << " If it is an IPv6 or IPv4 address and your host has disabled IPv6 or IPv4, then consider to " + "specify not disabled IPv4 or IPv6 address to listen in element of configuration " + "file. Example for disabled IPv6: 0.0.0.0 ." + " Example for disabled IPv4: ::"); else throw; } From d504c5454aa3acd5adffde828cd52dc40165daa7 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Wed, 3 May 2017 21:18:14 +0300 Subject: [PATCH 08/76] Resolves #750. Allow to load more than 16 external dictionaries. [#CLICKHOUSE-3] --- .../src/Dictionaries/ODBCDictionarySource.cpp | 22 ++++++++++++++++--- dbms/src/Dictionaries/ODBCDictionarySource.h | 8 ++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/dbms/src/Dictionaries/ODBCDictionarySource.cpp b/dbms/src/Dictionaries/ODBCDictionarySource.cpp index d5002bc94af..c2bad4eacca 100644 --- a/dbms/src/Dictionaries/ODBCDictionarySource.cpp +++ b/dbms/src/Dictionaries/ODBCDictionarySource.cpp @@ -21,12 +21,13 @@ ODBCDictionarySource::ODBCDictionarySource(const DictionaryStructure & dict_stru table{config.getString(config_prefix + ".table")}, where{config.getString(config_prefix + ".where", "")}, sample_block{sample_block}, - pool{std::make_shared( - config.getString(config_prefix + ".connector", "ODBC"), - config.getString(config_prefix + ".connection_string"))}, query_builder{dict_struct, db, table, where, ExternalQueryBuilder::None}, /// NOTE Better to obtain quoting style via ODBC interface. load_all_query{query_builder.composeLoadAllQuery()} { + pool = createAndCheckResizePocoSessionPool([&] () { return std::make_shared( + config.getString(config_prefix + ".connector", "ODBC"), + config.getString(config_prefix + ".connection_string")); + }); } /// copy-constructor is provided in order to support cloneability @@ -43,6 +44,21 @@ ODBCDictionarySource::ODBCDictionarySource(const ODBCDictionarySource & other) { } +std::shared_ptr ODBCDictionarySource::createAndCheckResizePocoSessionPool(PocoSessionPoolConstructor pool_constr) +{ + static std::mutex mutex; + + Poco::ThreadPool & pool = Poco::ThreadPool::defaultPool(); + + /// NOTE: The lock don't guarantee that external users of the pool don't change its capacity + std::unique_lock lock(mutex); + + if (pool.available() == 0) + pool.addCapacity(2 * std::max(pool.capacity(), 1)); + + return pool_constr(); +} + BlockInputStreamPtr ODBCDictionarySource::loadAll() { LOG_TRACE(log, load_all_query); diff --git a/dbms/src/Dictionaries/ODBCDictionarySource.h b/dbms/src/Dictionaries/ODBCDictionarySource.h index 7dbf95e720f..8e1ea57cc87 100644 --- a/dbms/src/Dictionaries/ODBCDictionarySource.h +++ b/dbms/src/Dictionaries/ODBCDictionarySource.h @@ -59,9 +59,15 @@ private: const std::string table; const std::string where; Block sample_block; - std::shared_ptr pool; + std::shared_ptr pool = nullptr; ExternalQueryBuilder query_builder; const std::string load_all_query; + + using PocoSessionPoolConstructor = std::function()>; + + /// Is used to adjust max size of default Poco thread pool. See issue #750 + /// Acquire the lock, resize pool and construct new Session + static std::shared_ptr createAndCheckResizePocoSessionPool(PocoSessionPoolConstructor pool_constr); }; From bb257eec01c1d4e9f80bf99acc838fcc5b7b6b35 Mon Sep 17 00:00:00 2001 From: Igor Hatarist Date: Wed, 3 May 2017 12:16:12 +0300 Subject: [PATCH 09/76] Add input_format_allow_errors options to the reference --- website/reference_en.html | 6 ++++++ website/reference_ru.html | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/website/reference_en.html b/website/reference_en.html index eef67e1e548..63fd353ca6b 100644 --- a/website/reference_en.html +++ b/website/reference_en.html @@ -6922,6 +6922,12 @@ If the parameter is true (default value), UInt64 and Int64 numbers are printed a Such behavior is compatible with most JavaScript interpreters that stores all numbers as double-precision floating point numbers. Otherwise, they are printed as regular numbers. +==input_format_allow_errors_num== +==input_format_allow_errors_ratio== + +Maximum amount of errors while reading text formats (like CSV, TSV). +In case of error, if both values are non-zero, and at least absolute or relative amount of errors is lower than corresponding value, will skip until next line and continue. + ==Restrictions on query complexity== Restrictions on query complexity are part of the settings. diff --git a/website/reference_ru.html b/website/reference_ru.html index 90de231cb80..c6d0b76800a 100644 --- a/website/reference_ru.html +++ b/website/reference_ru.html @@ -7174,6 +7174,12 @@ dictGetT('dict_name', 'attr_name', id, date) Если значение истинно, то при использовании JSON* форматов UInt64 и Int64 числа выводятся в кавычках (из соображений совместимости с большинством реализаций JavaScript), иначе - без кавычек. +==input_format_allow_errors_num== +==input_format_allow_errors_ratio== + +Максимальное количество ошибок при чтении из текстовых форматов (таких как CSV или TSV). +В случае ошибки, если оба параметра не равны нулю и количество ошибок меньше соответствующего значения, ошибочная строка игнорируется и чтение продолжается со следующей строки. + ==Ограничения на сложность запроса== From 0787bd66ff2b20624fa71edb57ba294acc148f82 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 4 May 2017 07:08:59 +0300 Subject: [PATCH 10/76] Merge: fail if cant convert columns (#753) * Merge: fail if cant convert columns * Merge: convert all different types, more tests * clean * clean * clean --- .../DataStreams/CastTypeBlockInputStream.cpp | 11 +-- dbms/src/Storages/StorageMerge.cpp | 6 ++ .../00458_merge_type_cast.reference | 18 ++++ .../0_stateless/00458_merge_type_cast.sql | 83 +++++++++++++++++++ 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/dbms/src/DataStreams/CastTypeBlockInputStream.cpp b/dbms/src/DataStreams/CastTypeBlockInputStream.cpp index 5c6d42b2001..a72f759492d 100644 --- a/dbms/src/DataStreams/CastTypeBlockInputStream.cpp +++ b/dbms/src/DataStreams/CastTypeBlockInputStream.cpp @@ -9,6 +9,7 @@ namespace DB { + CastTypeBlockInputStream::CastTypeBlockInputStream( const Context & context_, BlockInputStreamPtr input_, @@ -109,14 +110,8 @@ void CastTypeBlockInputStream::collectDifferent(const Block & in_sample, const B const auto & in_elem = in_sample.getByPosition(i); const auto & out_elem = out_sample.getByPosition(i); - /// Force conversion if source type is not Enum. - if (dynamic_cast(out_elem.type.get()) - && !dynamic_cast(in_elem.type.get())) - { - cast_types[i] = NameAndTypePair(out_elem.name, out_elem.type); - } - /// Force conversion if both types is numeric but not equal. - else if (in_elem.type->behavesAsNumber() && out_elem.type->behavesAsNumber() && !out_elem.type->equals(*in_elem.type)) + /// Force conversion if source and destination types is different. + if (!out_elem.type->equals(*in_elem.type)) { cast_types[i] = NameAndTypePair(out_elem.name, out_elem.type); } diff --git a/dbms/src/Storages/StorageMerge.cpp b/dbms/src/Storages/StorageMerge.cpp index e55c777d027..b1a6e1a1298 100644 --- a/dbms/src/Storages/StorageMerge.cpp +++ b/dbms/src/Storages/StorageMerge.cpp @@ -181,7 +181,10 @@ BlockInputStreams StorageMerge::read( /// Subordinary tables could have different but convertible types, like numeric types of different width. /// We must return streams with structure equals to structure of Merge table. for (auto & stream : source_streams) + { + /// will throw if some columns not convertible stream = std::make_shared(context, stream, table->getSampleBlock(), getSampleBlock()); + } } else { @@ -207,7 +210,10 @@ BlockInputStreams StorageMerge::read( auto stream = streams.empty() ? std::make_shared() : streams.front(); if (!streams.empty()) + { + /// will throw if some columns not convertible stream = std::make_shared(context, stream, table->getSampleBlock(), getSampleBlock()); + } return stream; })); } diff --git a/dbms/tests/queries/0_stateless/00458_merge_type_cast.reference b/dbms/tests/queries/0_stateless/00458_merge_type_cast.reference index 576cb06cab1..196ab90f4a9 100644 --- a/dbms/tests/queries/0_stateless/00458_merge_type_cast.reference +++ b/dbms/tests/queries/0_stateless/00458_merge_type_cast.reference @@ -1,3 +1,4 @@ + UInt32 | UInt64 = 1: 1 1 @@ -9,7 +10,24 @@ 4294967290 4294967299: 4294967299 + Int64 | UInt64 1: 1 1 -1: + Int32 | UInt64 +1 +1 +2147483650 + String | FixedString(16) +1 +1 + DateTime | UInt64 +1 +1 + Array(UInt32) | Array(UInt64) +[1] +[1] +[4294967290] +[4294967290] +[4294967299] diff --git a/dbms/tests/queries/0_stateless/00458_merge_type_cast.sql b/dbms/tests/queries/0_stateless/00458_merge_type_cast.sql index 032f00cbd61..6c4a7bd7661 100644 --- a/dbms/tests/queries/0_stateless/00458_merge_type_cast.sql +++ b/dbms/tests/queries/0_stateless/00458_merge_type_cast.sql @@ -1,3 +1,6 @@ + +SELECT ' UInt32 | UInt64 '; + DROP TABLE IF EXISTS test.u32; DROP TABLE IF EXISTS test.u64; DROP TABLE IF EXISTS test.merge_32_64; @@ -31,6 +34,7 @@ DROP TABLE test.u64; DROP TABLE test.merge_32_64; +SELECT ' Int64 | UInt64 '; DROP TABLE IF EXISTS test.s64; DROP TABLE IF EXISTS test.u64; @@ -52,3 +56,82 @@ SELECT x FROM test.merge_s64_u64 WHERE x IN (-1); DROP TABLE test.s64; DROP TABLE test.u64; DROP TABLE test.merge_s64_u64; + + +SELECT ' Int32 | UInt64 '; + +DROP TABLE IF EXISTS test.one; +DROP TABLE IF EXISTS test.two; +DROP TABLE IF EXISTS test.merge_one_two; + +CREATE TABLE test.one (x Int32) ENGINE = Memory; +CREATE TABLE test.two (x UInt64) ENGINE = Memory; +CREATE TABLE test.merge_one_two (x UInt64) ENGINE = Merge(test, 'one|two'); + +INSERT INTO test.one VALUES (1); +INSERT INTO test.two VALUES (1); + +INSERT INTO test.one VALUES (2147483650); +INSERT INTO test.two VALUES (2147483650); + +SELECT * FROM test.merge_one_two WHERE x IN (1); +SELECT x FROM test.merge_one_two WHERE x IN (2147483650); +SELECT x FROM test.merge_one_two WHERE x IN (-1); + + +SELECT ' String | FixedString(16) '; + +DROP TABLE IF EXISTS test.one; +DROP TABLE IF EXISTS test.two; +DROP TABLE IF EXISTS test.merge_one_two; + +CREATE TABLE test.one (x String) ENGINE = Memory; +CREATE TABLE test.two (x FixedString(16)) ENGINE = Memory; +CREATE TABLE test.merge_one_two (x String) ENGINE = Merge(test, 'one|two'); + +INSERT INTO test.one VALUES ('1'); +INSERT INTO test.two VALUES ('1'); + +SELECT * FROM test.merge_one_two WHERE x IN ('1'); + + +SELECT ' DateTime | UInt64 '; + +DROP TABLE IF EXISTS test.one; +DROP TABLE IF EXISTS test.two; +DROP TABLE IF EXISTS test.merge_one_two; + +CREATE TABLE test.one (x DateTime) ENGINE = Memory; +CREATE TABLE test.two (x UInt64) ENGINE = Memory; +CREATE TABLE test.merge_one_two (x UInt64) ENGINE = Merge(test, 'one|two'); + +INSERT INTO test.one VALUES (1); +INSERT INTO test.two VALUES (1); + +SELECT * FROM test.merge_one_two WHERE x IN (1); + + +SELECT ' Array(UInt32) | Array(UInt64) '; + +DROP TABLE IF EXISTS test.one; +DROP TABLE IF EXISTS test.two; +DROP TABLE IF EXISTS test.merge_one_two; + +CREATE TABLE test.one (x Array(UInt32)) ENGINE = Memory; +CREATE TABLE test.two (x Array(UInt64)) ENGINE = Memory; +CREATE TABLE test.merge_one_two (x Array(UInt64)) ENGINE = Merge(test, 'one|two'); + +INSERT INTO test.one VALUES ([1]); +INSERT INTO test.two VALUES ([1]); +INSERT INTO test.one VALUES ([4294967290]); +INSERT INTO test.two VALUES ([4294967290]); +INSERT INTO test.one VALUES ([4294967299]); +INSERT INTO test.two VALUES ([4294967299]); + +SELECT x FROM test.merge_one_two WHERE x IN (1); +SELECT x FROM test.merge_one_two WHERE x IN (4294967290); +SELECT x FROM test.merge_one_two WHERE x IN (4294967299); + +DROP TABLE IF EXISTS test.one; +DROP TABLE IF EXISTS test.two; +DROP TABLE IF EXISTS test.merge_one_two; From cb890e26b9988718396080f0364a0936224b19e4 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 4 May 2017 07:09:33 +0300 Subject: [PATCH 11/76] Add small .sh for easier report while investigating problem (#741) * Add small .sh for easier report while investigating problem * renamed: clickhouse_report.sh -> report/clickhouse_report.sh * fix new path --- utils/report/clickhouse_report.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 utils/report/clickhouse_report.sh diff --git a/utils/report/clickhouse_report.sh b/utils/report/clickhouse_report.sh new file mode 100755 index 00000000000..369529b50e0 --- /dev/null +++ b/utils/report/clickhouse_report.sh @@ -0,0 +1,20 @@ +#!/bin/sh -x +# Usages: +# ./clickhouse_report.sh > ch.`hostname`.`date '+%Y%M%''d%H%M%''S'`.dmp 2>&1 +# curl https://raw.githubusercontent.com/yandex/ClickHouse/master/utils/report/clickhouse_report.sh | sh > ch.`hostname`.`date '+%Y%M%''d%H%M%''S'`.dmp 2>&1 + +clickhouse --client -q 'SELECT * FROM system.events FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.metrics FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.asynchronous_metrics FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.build_options FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.processes FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.merges FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.parts FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.replication_queue FORMAT Pretty' +clickhouse --client -q 'SELECT * FROM system.dictionaries FORMAT Pretty' +ps auxw +df -h +top -bn1 +tail -n200 /var/log/clickhouse-server/clickhouse-server.err.log +tail -n200 /var/log/clickhouse-server/clickhouse-server.log +tail -n100 /var/log/clickhouse-server/stderr From d2d7aaac692d30ef8422774f1a8d0bd327546061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Mon, 1 May 2017 10:24:08 -0700 Subject: [PATCH 12/76] contrib/libpoco: update Crypto to last stable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the last stable version 1.7.8 fixes build with newer OpenSSL that’s in most of the distribution --- .../Crypto/include/Poco/Crypto/Cipher.h | 2 +- .../Crypto/include/Poco/Crypto/Crypto.h | 2 - .../Crypto/include/Poco/Crypto/DigestEngine.h | 2 +- .../include/Poco/Crypto/X509Certificate.h | 8 ++ contrib/libpoco/Crypto/src/CipherImpl.cpp | 74 ++++++++++++++----- contrib/libpoco/Crypto/src/CipherKeyImpl.cpp | 16 ++-- contrib/libpoco/Crypto/src/CryptoStream.cpp | 10 +-- contrib/libpoco/Crypto/src/DigestEngine.cpp | 27 ++++--- contrib/libpoco/Crypto/src/RSACipherImpl.cpp | 22 +++--- contrib/libpoco/Crypto/src/RSAKeyImpl.cpp | 24 ++++++ .../libpoco/Crypto/src/X509Certificate.cpp | 24 ++++-- .../Crypto/testsuite/src/CryptoTest.cpp | 5 ++ 12 files changed, 153 insertions(+), 63 deletions(-) diff --git a/contrib/libpoco/Crypto/include/Poco/Crypto/Cipher.h b/contrib/libpoco/Crypto/include/Poco/Crypto/Cipher.h index 30d17f3cd0d..92ba5da9f4e 100644 --- a/contrib/libpoco/Crypto/include/Poco/Crypto/Cipher.h +++ b/contrib/libpoco/Crypto/include/Poco/Crypto/Cipher.h @@ -96,7 +96,7 @@ public: ENC_BASE64 = 0x01, /// Base64-encoded output ENC_BINHEX = 0x02, /// BinHex-encoded output ENC_BASE64_NO_LF = 0x81, /// Base64-encoded output, no linefeeds - ENC_BINHEX_NO_LF = 0x82, /// BinHex-encoded output, no linefeeds + ENC_BINHEX_NO_LF = 0x82 /// BinHex-encoded output, no linefeeds }; diff --git a/contrib/libpoco/Crypto/include/Poco/Crypto/Crypto.h b/contrib/libpoco/Crypto/include/Poco/Crypto/Crypto.h index 1ed50941da1..fcfb20ec26f 100644 --- a/contrib/libpoco/Crypto/include/Poco/Crypto/Crypto.h +++ b/contrib/libpoco/Crypto/include/Poco/Crypto/Crypto.h @@ -22,7 +22,6 @@ #define Crypto_Crypto_INCLUDED -#pragma GCC diagnostic push #if defined(__APPLE__) // OS X 10.7 deprecates some OpenSSL functions #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -116,6 +115,5 @@ void Crypto_API uninitializeCrypto(); } } // namespace Poco::Crypto -#pragma GCC diagnostic pop #endif // Crypto_Crypto_INCLUDED diff --git a/contrib/libpoco/Crypto/include/Poco/Crypto/DigestEngine.h b/contrib/libpoco/Crypto/include/Poco/Crypto/DigestEngine.h index 5de75392a83..e2121c414df 100644 --- a/contrib/libpoco/Crypto/include/Poco/Crypto/DigestEngine.h +++ b/contrib/libpoco/Crypto/include/Poco/Crypto/DigestEngine.h @@ -61,7 +61,7 @@ protected: private: std::string _name; - EVP_MD_CTX* _ctx; + EVP_MD_CTX* _pContext; Poco::DigestEngine::Digest _digest; OpenSSLInitializer _openSSLInitializer; }; diff --git a/contrib/libpoco/Crypto/include/Poco/Crypto/X509Certificate.h b/contrib/libpoco/Crypto/include/Poco/Crypto/X509Certificate.h index 472c537637e..a6d86901248 100644 --- a/contrib/libpoco/Crypto/include/Poco/Crypto/X509Certificate.h +++ b/contrib/libpoco/Crypto/include/Poco/Crypto/X509Certificate.h @@ -130,6 +130,14 @@ public: /// Returns true if verification against the issuer certificate /// was successfull, false otherwise. + bool equals(const X509Certificate& otherCertificate) const; + /// Checks whether the certificate is equal to + /// the other certificate, by comparing the hashes + /// of both certificates. + /// + /// Returns true if both certificates are identical, + /// otherwise false. + const X509* certificate() const; /// Returns the underlying OpenSSL certificate. diff --git a/contrib/libpoco/Crypto/src/CipherImpl.cpp b/contrib/libpoco/Crypto/src/CipherImpl.cpp index c953aae52e2..b8708a78c81 100644 --- a/contrib/libpoco/Crypto/src/CipherImpl.cpp +++ b/contrib/libpoco/Crypto/src/CipherImpl.cpp @@ -30,7 +30,7 @@ namespace { unsigned long err; std::string msg; - + while ((err = ERR_get_error())) { if (!msg.empty()) @@ -60,24 +60,28 @@ namespace Direction dir); ~CryptoTransformImpl(); - + std::size_t blockSize() const; - int setPadding(int padding); + int setPadding(int padding); std::streamsize transform( const unsigned char* input, std::streamsize inputLength, unsigned char* output, std::streamsize outputLength); - + std::streamsize finalize( unsigned char* output, std::streamsize length); private: const EVP_CIPHER* _pCipher; - EVP_CIPHER_CTX _ctx; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_CIPHER_CTX* _pContext; +#else + EVP_CIPHER_CTX _context; +#endif ByteVec _key; ByteVec _iv; }; @@ -92,32 +96,54 @@ namespace _key(key), _iv(iv) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + _pContext = EVP_CIPHER_CTX_new(); EVP_CipherInit( - &_ctx, + _pContext, _pCipher, &_key[0], _iv.empty() ? 0 : &_iv[0], (dir == DIR_ENCRYPT) ? 1 : 0); +#else + EVP_CipherInit( + &_context, + _pCipher, + &_key[0], + _iv.empty() ? 0 : &_iv[0], + (dir == DIR_ENCRYPT) ? 1 : 0); +#endif } CryptoTransformImpl::~CryptoTransformImpl() { - EVP_CIPHER_CTX_cleanup(&_ctx); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_CIPHER_CTX_cleanup(_pContext); +#else + EVP_CIPHER_CTX_cleanup(&_context); +#endif } std::size_t CryptoTransformImpl::blockSize() const { - return EVP_CIPHER_CTX_block_size(&_ctx); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + return EVP_CIPHER_CTX_block_size(_pContext); +#else + return EVP_CIPHER_CTX_block_size(&_context); +#endif } - + int CryptoTransformImpl::setPadding(int padding) { - return EVP_CIPHER_CTX_set_padding(&_ctx, padding); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + return EVP_CIPHER_CTX_block_size(_pContext); +#else + return EVP_CIPHER_CTX_set_padding(&_context, padding); +#endif } - + std::streamsize CryptoTransformImpl::transform( const unsigned char* input, @@ -125,16 +151,24 @@ namespace unsigned char* output, std::streamsize outputLength) { - poco_assert (outputLength >= std::streamsize(inputLength + blockSize() - 1)); + poco_assert (outputLength >= (inputLength + blockSize() - 1)); int outLen = static_cast(outputLength); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L int rc = EVP_CipherUpdate( - &_ctx, + _pContext, output, &outLen, input, static_cast(inputLength)); - +#else + int rc = EVP_CipherUpdate( + &_context, + output, + &outLen, + input, + static_cast(inputLength)); +#endif if (rc == 0) throwError(); @@ -146,18 +180,22 @@ namespace unsigned char* output, std::streamsize length) { - poco_assert (length >= (std::streamsize)blockSize()); - + poco_assert (length >= blockSize()); + int len = static_cast(length); // Use the '_ex' version that does not perform implicit cleanup since we // will call EVP_CIPHER_CTX_cleanup() from the dtor as there is no // guarantee that finalize() will be called if an error occurred. - int rc = EVP_CipherFinal_ex(&_ctx, output, &len); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + int rc = EVP_CipherFinal_ex(_pContext, output, &len); +#else + int rc = EVP_CipherFinal_ex(&_context, output, &len); +#endif if (rc == 0) throwError(); - + return static_cast(len); } } diff --git a/contrib/libpoco/Crypto/src/CipherKeyImpl.cpp b/contrib/libpoco/Crypto/src/CipherKeyImpl.cpp index 58b51c9424d..bcd7452c696 100644 --- a/contrib/libpoco/Crypto/src/CipherKeyImpl.cpp +++ b/contrib/libpoco/Crypto/src/CipherKeyImpl.cpp @@ -27,8 +27,8 @@ namespace Poco { namespace Crypto { -CipherKeyImpl::CipherKeyImpl(const std::string& name, - const std::string& passphrase, +CipherKeyImpl::CipherKeyImpl(const std::string& name, + const std::string& passphrase, const std::string& salt, int iterationCount): _pCipher(0), @@ -48,8 +48,8 @@ CipherKeyImpl::CipherKeyImpl(const std::string& name, } -CipherKeyImpl::CipherKeyImpl(const std::string& name, - const ByteVec& key, +CipherKeyImpl::CipherKeyImpl(const std::string& name, + const ByteVec& key, const ByteVec& iv): _pCipher(0), _name(name), @@ -64,7 +64,7 @@ CipherKeyImpl::CipherKeyImpl(const std::string& name, throw Poco::NotFoundException("Cipher " + name + " was not found"); } - + CipherKeyImpl::CipherKeyImpl(const std::string& name): _pCipher(0), _name(name), @@ -117,7 +117,7 @@ void CipherKeyImpl::generateKey() getRandomBytes(vec, keySize()); setKey(vec); - + getRandomBytes(vec, ivSize()); setIV(vec); } @@ -126,11 +126,11 @@ void CipherKeyImpl::generateKey() void CipherKeyImpl::getRandomBytes(ByteVec& vec, std::size_t count) { Poco::RandomInputStream random; - + vec.clear(); vec.reserve(count); - for (std::size_t i = 0; i < count; ++i) + for (int i = 0; i < count; ++i) vec.push_back(static_cast(random.get())); } diff --git a/contrib/libpoco/Crypto/src/CryptoStream.cpp b/contrib/libpoco/Crypto/src/CryptoStream.cpp index 34ce13b4c39..97e73ce810f 100644 --- a/contrib/libpoco/Crypto/src/CryptoStream.cpp +++ b/contrib/libpoco/Crypto/src/CryptoStream.cpp @@ -43,7 +43,7 @@ CryptoStreamBuf::CryptoStreamBuf(std::istream& istr, CryptoTransform* pTransform _buffer(static_cast(bufferSize)) { poco_check_ptr (pTransform); - poco_assert ((size_t)bufferSize > 2 * pTransform->blockSize()); + poco_assert (bufferSize > 2 * pTransform->blockSize()); } @@ -56,7 +56,7 @@ CryptoStreamBuf::CryptoStreamBuf(std::ostream& ostr, CryptoTransform* pTransform _buffer(static_cast(bufferSize)) { poco_check_ptr (pTransform); - poco_assert ((size_t)bufferSize > 2 * pTransform->blockSize()); + poco_assert (bufferSize > 2 * pTransform->blockSize()); } @@ -88,10 +88,10 @@ void CryptoStreamBuf::close() // thrown. std::ostream* pOstr = _pOstr; _pOstr = 0; - + // Finalize transformation. std::streamsize n = _pTransform->finalize(_buffer.begin(), static_cast(_buffer.size())); - + if (n > 0) { pOstr->write(reinterpret_cast(_buffer.begin()), n); @@ -159,7 +159,7 @@ int CryptoStreamBuf::writeToDevice(const char* buffer, std::streamsize length) std::size_t maxChunkSize = _buffer.size()/2; std::size_t count = 0; - while (count < (size_t)length) + while (count < length) { // Truncate chunk size so that the maximum output fits into _buffer. std::size_t n = static_cast(length) - count; diff --git a/contrib/libpoco/Crypto/src/DigestEngine.cpp b/contrib/libpoco/Crypto/src/DigestEngine.cpp index 6e574ab42e1..64042589f17 100644 --- a/contrib/libpoco/Crypto/src/DigestEngine.cpp +++ b/contrib/libpoco/Crypto/src/DigestEngine.cpp @@ -23,46 +23,51 @@ namespace Crypto { DigestEngine::DigestEngine(const std::string& name): - _name(name) + _name(name), + _pContext(EVP_MD_CTX_create()) { const EVP_MD* md = EVP_get_digestbyname(_name.c_str()); if (!md) throw Poco::NotFoundException(_name); - _ctx = EVP_MD_CTX_create(); - EVP_DigestInit_ex(_ctx, md, NULL); + EVP_DigestInit_ex(_pContext, md, NULL); } DigestEngine::~DigestEngine() { - EVP_MD_CTX_destroy(_ctx); + EVP_MD_CTX_destroy(_pContext); } int DigestEngine::nid() const { - return EVP_MD_nid(_ctx->digest); + return EVP_MD_nid(EVP_MD_CTX_md(_pContext)); } std::size_t DigestEngine::digestLength() const { - return EVP_MD_CTX_size(_ctx); + return EVP_MD_CTX_size(_pContext); } void DigestEngine::reset() { - EVP_MD_CTX_cleanup(_ctx); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX_free(_pContext); + _pContext = EVP_MD_CTX_create(); +#else + EVP_MD_CTX_cleanup(_pContext); +#endif const EVP_MD* md = EVP_get_digestbyname(_name.c_str()); if (!md) throw Poco::NotFoundException(_name); - EVP_DigestInit_ex(_ctx, md, NULL); + EVP_DigestInit_ex(_pContext, md, NULL); } const Poco::DigestEngine::Digest& DigestEngine::digest() { _digest.clear(); - unsigned len = EVP_MD_CTX_size(_ctx); + unsigned len = EVP_MD_CTX_size(_pContext); _digest.resize(len); - EVP_DigestFinal_ex(_ctx, &_digest[0], &len); + EVP_DigestFinal_ex(_pContext, &_digest[0], &len); reset(); return _digest; } @@ -70,7 +75,7 @@ const Poco::DigestEngine::Digest& DigestEngine::digest() void DigestEngine::updateImpl(const void* data, std::size_t length) { - EVP_DigestUpdate(_ctx, data, length); + EVP_DigestUpdate(_pContext, data, length); } diff --git a/contrib/libpoco/Crypto/src/RSACipherImpl.cpp b/contrib/libpoco/Crypto/src/RSACipherImpl.cpp index 01b23851282..91c5b815d61 100644 --- a/contrib/libpoco/Crypto/src/RSACipherImpl.cpp +++ b/contrib/libpoco/Crypto/src/RSACipherImpl.cpp @@ -32,7 +32,7 @@ namespace { unsigned long err; std::string msg; - + while ((err = ERR_get_error())) { if (!msg.empty()) @@ -68,7 +68,7 @@ namespace public: RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode); ~RSAEncryptImpl(); - + std::size_t blockSize() const; std::size_t maxDataSize() const; @@ -77,7 +77,7 @@ namespace std::streamsize inputLength, unsigned char* output, std::streamsize outputLength); - + std::streamsize finalize(unsigned char* output, std::streamsize length); private: @@ -156,7 +156,7 @@ namespace output += n; outputLength -= n; _pos = 0; - + } else { @@ -175,8 +175,8 @@ namespace std::streamsize RSAEncryptImpl::finalize(unsigned char* output, std::streamsize length) { - poco_assert ((size_t)length >= blockSize()); - poco_assert ((size_t)_pos <= maxDataSize()); + poco_assert (length >= blockSize()); + poco_assert (_pos <= maxDataSize()); int rc = 0; if (_pos > 0) { @@ -192,7 +192,7 @@ namespace public: RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode); ~RSADecryptImpl(); - + std::size_t blockSize() const; std::streamsize transform( @@ -200,7 +200,7 @@ namespace std::streamsize inputLength, unsigned char* output, std::streamsize outputLength); - + std::streamsize finalize( unsigned char* output, std::streamsize length); @@ -241,7 +241,7 @@ namespace unsigned char* output, std::streamsize outputLength) { - + // always fill up the buffer before decrypting! std::streamsize rsaSize = static_cast(blockSize()); poco_assert_dbg(_pos <= rsaSize); @@ -261,7 +261,7 @@ namespace output += tmp; outputLength -= tmp; _pos = 0; - + } else { @@ -280,7 +280,7 @@ namespace std::streamsize RSADecryptImpl::finalize(unsigned char* output, std::streamsize length) { - poco_assert ((size_t)length >= blockSize()); + poco_assert (length >= blockSize()); int rc = 0; if (_pos > 0) { diff --git a/contrib/libpoco/Crypto/src/RSAKeyImpl.cpp b/contrib/libpoco/Crypto/src/RSAKeyImpl.cpp index 8333453cee0..3a1580f6912 100644 --- a/contrib/libpoco/Crypto/src/RSAKeyImpl.cpp +++ b/contrib/libpoco/Crypto/src/RSAKeyImpl.cpp @@ -207,19 +207,43 @@ int RSAKeyImpl::size() const RSAKeyImpl::ByteVec RSAKeyImpl::modulus() const { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + const BIGNUM* n = 0; + const BIGNUM* e = 0; + const BIGNUM* d = 0; + RSA_get0_key(_pRSA, &n, &e, &d); + return convertToByteVec(n); +#else return convertToByteVec(_pRSA->n); +#endif } RSAKeyImpl::ByteVec RSAKeyImpl::encryptionExponent() const { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + const BIGNUM* n = 0; + const BIGNUM* e = 0; + const BIGNUM* d = 0; + RSA_get0_key(_pRSA, &n, &e, &d); + return convertToByteVec(e); +#else return convertToByteVec(_pRSA->e); +#endif } RSAKeyImpl::ByteVec RSAKeyImpl::decryptionExponent() const { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + const BIGNUM* n = 0; + const BIGNUM* e = 0; + const BIGNUM* d = 0; + RSA_get0_key(_pRSA, &n, &e, &d); + return convertToByteVec(d); +#else return convertToByteVec(_pRSA->d); +#endif } diff --git a/contrib/libpoco/Crypto/src/X509Certificate.cpp b/contrib/libpoco/Crypto/src/X509Certificate.cpp index dd9ebd2cab3..f7f37965ed8 100644 --- a/contrib/libpoco/Crypto/src/X509Certificate.cpp +++ b/contrib/libpoco/Crypto/src/X509Certificate.cpp @@ -59,7 +59,11 @@ X509Certificate::X509Certificate(X509* pCert, bool shared): if (shared) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + X509_up_ref(_pCert); +#else _pCert->references++; +#endif } init(); @@ -205,10 +209,10 @@ std::string X509Certificate::issuerName(NID nid) const if (X509_NAME* issuer = X509_get_issuer_name(_pCert)) { char buffer[NAME_BUFFER_SIZE]; - X509_NAME_get_text_by_NID(issuer, nid, buffer, sizeof(buffer)); - return std::string(buffer); + if (X509_NAME_get_text_by_NID(issuer, nid, buffer, sizeof(buffer)) >= 0) + return std::string(buffer); } - else return std::string(); + return std::string(); } @@ -217,10 +221,10 @@ std::string X509Certificate::subjectName(NID nid) const if (X509_NAME* subj = X509_get_subject_name(_pCert)) { char buffer[NAME_BUFFER_SIZE]; - X509_NAME_get_text_by_NID(subj, nid, buffer, sizeof(buffer)); - return std::string(buffer); + if (X509_NAME_get_text_by_NID(subj, nid, buffer, sizeof(buffer)) >= 0) + return std::string(buffer); } - else return std::string(); + return std::string(); } @@ -280,4 +284,12 @@ bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const } +bool X509Certificate::equals(const X509Certificate& otherCertificate) const +{ + X509* pCert = const_cast(_pCert); + X509* pOtherCert = const_cast(otherCertificate.certificate()); + return X509_cmp(pCert, pOtherCert) == 0; +} + + } } // namespace Poco::Crypto diff --git a/contrib/libpoco/Crypto/testsuite/src/CryptoTest.cpp b/contrib/libpoco/Crypto/testsuite/src/CryptoTest.cpp index 8c403470950..53764df137c 100644 --- a/contrib/libpoco/Crypto/testsuite/src/CryptoTest.cpp +++ b/contrib/libpoco/Crypto/testsuite/src/CryptoTest.cpp @@ -246,6 +246,11 @@ void CryptoTest::testCertificate() // fails with recent OpenSSL versions: // assert (cert.issuedBy(cert)); + + std::istringstream otherCertStream(APPINF_PEM); + X509Certificate otherCert(otherCertStream); + + assert (cert.equals(otherCert)); } From 5f1e65b2523d7fee66404fc764a4c5d281c989fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Tue, 2 May 2017 14:08:37 -0700 Subject: [PATCH 13/76] AggregateFunctions: implemented topK(n) This implements a new function for approximate computation of the most frequent entries using Filtered Space Saving with a merge step adapted from Parallel Space Saving paper. It works better for cases where GROUP BY x is impractical due to high cardinality of x, such as top IP addresses or top search queries. --- .../AggregateFunctionFactory.cpp | 2 + .../AggregateFunctionTopK.cpp | 70 +++++ .../AggregateFunctionTopK.h | 264 ++++++++++++++++++ dbms/src/Common/SpaceSaving.h | 254 +++++++++++++++++ dbms/src/Common/tests/CMakeLists.txt | 3 + dbms/src/Common/tests/space_saving.cpp | 105 +++++++ dbms/src/IO/WriteHelpers.h | 1 + .../queries/0_stateless/00453_top_k.reference | 1 + .../tests/queries/0_stateless/00453_top_k.sql | 1 + website/reference_en.html | 11 + website/reference_ru.html | 11 + 11 files changed, 723 insertions(+) create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionTopK.cpp create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionTopK.h create mode 100644 dbms/src/Common/SpaceSaving.h create mode 100644 dbms/src/Common/tests/space_saving.cpp create mode 100644 dbms/tests/queries/0_stateless/00453_top_k.reference create mode 100644 dbms/tests/queries/0_stateless/00453_top_k.sql diff --git a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp index 6a1e922a8a4..a4325c45e7e 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp @@ -46,6 +46,7 @@ void registerAggregateFunctionsStatistics(AggregateFunctionFactory & factory); void registerAggregateFunctionSum(AggregateFunctionFactory & factory); void registerAggregateFunctionsUniq(AggregateFunctionFactory & factory); void registerAggregateFunctionUniqUpTo(AggregateFunctionFactory & factory); +void registerAggregateFunctionTopK(AggregateFunctionFactory & factory); void registerAggregateFunctionDebug(AggregateFunctionFactory & factory); AggregateFunctionPtr createAggregateFunctionArray(AggregateFunctionPtr & nested); @@ -76,6 +77,7 @@ AggregateFunctionFactory::AggregateFunctionFactory() registerAggregateFunctionSum(*this); registerAggregateFunctionsUniq(*this); registerAggregateFunctionUniqUpTo(*this); + registerAggregateFunctionTopK(*this); registerAggregateFunctionDebug(*this); } diff --git a/dbms/src/AggregateFunctions/AggregateFunctionTopK.cpp b/dbms/src/AggregateFunctions/AggregateFunctionTopK.cpp new file mode 100644 index 00000000000..3310691a8ab --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionTopK.cpp @@ -0,0 +1,70 @@ +#include +#include +#include + +namespace DB +{ + +namespace +{ + +/// Substitute return type for Date and DateTime +class AggregateFunctionTopKDate : public AggregateFunctionTopK +{ + DataTypePtr getReturnType() const override { return std::make_shared(std::make_shared()); } +}; + +class AggregateFunctionTopKDateTime : public AggregateFunctionTopK +{ + DataTypePtr getReturnType() const override { return std::make_shared(std::make_shared()); } +}; + + +static IAggregateFunction * createWithExtraTypes(const IDataType & argument_type) +{ + if (typeid_cast(&argument_type)) return new AggregateFunctionTopKDate; + else if (typeid_cast(&argument_type)) return new AggregateFunctionTopKDateTime; + else + { + /// Check that we can use plain version of AggregateFunctionTopKGeneric + if (typeid_cast(&argument_type) || typeid_cast(&argument_type)) + return new AggregateFunctionTopKGeneric; + + auto * array_type = typeid_cast(&argument_type); + if (array_type) + { + auto nested_type = array_type->getNestedType(); + if (nested_type->isNumeric() || typeid_cast(nested_type.get())) + return new AggregateFunctionTopKGeneric; + } + + return new AggregateFunctionTopKGeneric; + } +} + +AggregateFunctionPtr createAggregateFunctionTopK(const std::string & name, const DataTypes & argument_types) +{ + if (argument_types.size() != 1) + throw Exception("Incorrect number of arguments for aggregate function " + name, + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + AggregateFunctionPtr res(createWithNumericType(*argument_types[0])); + + if (!res) + res = AggregateFunctionPtr(createWithExtraTypes(*argument_types[0])); + + if (!res) + throw Exception("Illegal type " + argument_types[0]->getName() + + " of argument for aggregate function " + name, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return res; +} + +} + +void registerAggregateFunctionTopK(AggregateFunctionFactory & factory) +{ + factory.registerFunction("topK", createAggregateFunctionTopK); +} + +} diff --git a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h new file mode 100644 index 00000000000..b93780d127e --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h @@ -0,0 +1,264 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + + +namespace DB +{ + + +// Allow NxK more space before calculating top K to increase accuracy +#define TOP_K_LOAD_FACTOR 3 +#define TOP_K_MAX_SIZE 0xFFFFFF + + +template +struct AggregateFunctionTopKData +{ + using Set = SpaceSaving>; + Set value; +}; + + +template +class AggregateFunctionTopK + : public IUnaryAggregateFunction, AggregateFunctionTopK> +{ +private: + using State = AggregateFunctionTopKData; + size_t threshold = 10; // Default value if the parameter is not specified. + size_t reserved = TOP_K_LOAD_FACTOR * threshold; + +public: + String getName() const override { return "topK"; } + + DataTypePtr getReturnType() const override + { + return std::make_shared(std::make_shared>()); + } + + void setArgument(const DataTypePtr & argument) + { + } + + void setParameters(const Array & params) override + { + if (params.size() != 1) + throw Exception("Aggregate function " + getName() + " requires exactly one parameter.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + std::size_t k = applyVisitor(FieldVisitorConvertToNumber(), params[0]); + + if (k > TOP_K_MAX_SIZE) + throw Exception("Too large parameter for aggregate function " + getName() + ". Maximum: " + toString(TOP_K_MAX_SIZE), + ErrorCodes::ARGUMENT_OUT_OF_BOUND); + + threshold = k; + reserved = TOP_K_LOAD_FACTOR * k; + } + + void addImpl(AggregateDataPtr place, const IColumn & column, size_t row_num, Arena *) const + { + auto & set = this->data(place).value; + if (set.capacity() != reserved) { + set.resize(reserved); + } + set.insert(static_cast &>(column).getData()[row_num]); + } + + void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override + { + this->data(place).value.merge(this->data(rhs).value); + } + + void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override + { + this->data(place).value.write(buf); + } + + void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override + { + auto & set = this->data(place).value; + set.resize(reserved); + set.read(buf); + } + + void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override + { + ColumnArray & arr_to = static_cast(to); + ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets(); + + const typename State::Set & set = this->data(place).value; + auto resultVec = set.topK(threshold); + size_t size = resultVec.size(); + + offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size); + + typename ColumnVector::Container_t & data_to = static_cast &>(arr_to.getData()).getData(); + size_t old_size = data_to.size(); + data_to.resize(old_size + size); + + size_t i = 0; + for (auto it = resultVec.begin(); it != resultVec.end(); ++it, ++i) + data_to[old_size + i] = it->key; + } +}; + + +/// Generic implementation, it uses serialized representation as object descriptor. +struct AggregateFunctionTopKGenericData +{ + using Set = SpaceSaving; + + Set value; +}; + +/** Template parameter with true value should be used for columns that store their elements in memory continuously. + * For such columns topK() can be implemented more efficently (especially for small numeric arrays). + */ +template +class AggregateFunctionTopKGeneric : public IUnaryAggregateFunction> +{ +private: + using State = AggregateFunctionTopKGenericData; + DataTypePtr input_data_type; + size_t threshold = 10; // Default value if the parameter is not specified. + size_t reserved = TOP_K_LOAD_FACTOR * threshold; + + static StringRef getSerialization(const IColumn & column, size_t row_num, Arena & arena); + static void deserializeAndInsert(StringRef str, IColumn & data_to); + +public: + String getName() const override { return "topK"; } + + void setArgument(const DataTypePtr & argument) + { + input_data_type = argument; + } + + void setParameters(const Array & params) override + { + if (params.size() != 1) + throw Exception("Aggregate function " + getName() + " requires exactly one parameter.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + size_t k = applyVisitor(FieldVisitorConvertToNumber(), params[0]); + + if (k > TOP_K_MAX_SIZE) + throw Exception("Too large parameter for aggregate function " + getName() + ". Maximum: " + toString(TOP_K_MAX_SIZE), + ErrorCodes::ARGUMENT_OUT_OF_BOUND); + + threshold = k; + reserved = TOP_K_LOAD_FACTOR * k; + } + + DataTypePtr getReturnType() const override + { + return std::make_shared(input_data_type->clone()); + } + + bool allocatesMemoryInArena() const override + { + return true; + } + + void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override + { + this->data(place).value.write(buf); + } + + void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena * arena) const override + { + auto & set = this->data(place).value; + set.resize(reserved); + + size_t count = 0; + readVarUInt(count, buf); + for (size_t i = 0; i < count; ++i) { + auto key = readStringBinaryInto(*arena, buf); + UInt64 count, error; + readVarUInt(count, buf); + readVarUInt(error, buf); + set.insert(key, count, error); + } + } + + void addImpl(AggregateDataPtr place, const IColumn & column, size_t row_num, Arena * arena) const + { + auto & set = this->data(place).value; + if (set.capacity() != reserved) { + set.resize(reserved); + } + + StringRef str_serialized = getSerialization(column, row_num, *arena); + if (is_plain_column) { + auto ptr = arena->insert(str_serialized.data, str_serialized.size); + str_serialized = StringRef(ptr, str_serialized.size); + } + + set.insert(str_serialized); + } + + void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override + { + this->data(place).value.merge(this->data(rhs).value); + } + + void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override + { + ColumnArray & arr_to = static_cast(to); + ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets(); + IColumn & data_to = arr_to.getData(); + + auto resultVec = this->data(place).value.topK(threshold); + offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + resultVec.size()); + + for (auto & elem : resultVec) + { + deserializeAndInsert(elem.key, data_to); + } + } +}; + + +template <> +inline StringRef AggregateFunctionTopKGeneric::getSerialization(const IColumn & column, size_t row_num, Arena & arena) +{ + const char * begin = nullptr; + return column.serializeValueIntoArena(row_num, arena, begin); +} + +template <> +inline StringRef AggregateFunctionTopKGeneric::getSerialization(const IColumn & column, size_t row_num, Arena &) +{ + return column.getDataAt(row_num); +} + +template <> +inline void AggregateFunctionTopKGeneric::deserializeAndInsert(StringRef str, IColumn & data_to) +{ + data_to.deserializeAndInsertFromArena(str.data); +} + +template <> +inline void AggregateFunctionTopKGeneric::deserializeAndInsert(StringRef str, IColumn & data_to) +{ + data_to.insertData(str.data, str.size); +} + + +#undef TOP_K_MAX_SIZE +#undef TOP_K_LOAD_FACTOR + +} diff --git a/dbms/src/Common/SpaceSaving.h b/dbms/src/Common/SpaceSaving.h new file mode 100644 index 00000000000..4f11ebc3bbe --- /dev/null +++ b/dbms/src/Common/SpaceSaving.h @@ -0,0 +1,254 @@ +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Implementation of the Filtered Space-Saving for TopK streaming analysis. + * http://www.l2f.inesc-id.pt/~fmmb/wiki/uploads/Work/misnis.ref0a.pdf + * It implements suggested reduce-and-combine algorithm from Parallel Space Saving: + * https://arxiv.org/pdf/1401.0702.pdf + */ + +namespace DB +{ + +template > +class SpaceSaving +{ +public: + struct Counter { + Counter() {} + + Counter(const TKey & k, UInt64 c = 0, UInt64 e = 0) + : key(k), slot(0), count(c), error(e) {} + + void write(DB::WriteBuffer & wb) const + { + DB::writeBinary(key, wb); + DB::writeVarUInt(count, wb); + DB::writeVarUInt(error, wb); + } + + void read(DB::ReadBuffer & rb) + { + DB::readBinary(key, rb); + DB::readVarUInt(count, rb); + DB::readVarUInt(error, rb); + } + + // greater() taking slot error into account + bool operator >(const Counter &b) const + { + return (count > b.count) || (count == b.count && error < b.error); + } + + TKey key; + size_t slot; + UInt64 count, error; + }; + + // Suggested constants in the paper "Finding top-k elements in data streams", chap 6. equation (24) + SpaceSaving(size_t c = 10) : counterMap(), counterList(), alphaMap(6 * c), cap(c) {} + ~SpaceSaving() { destroyElements(); } + + inline size_t size() const + { + return counterList.size(); + } + + inline size_t capacity() const + { + return cap; + } + + void resize(size_t c) + { + counterList.reserve(c); + alphaMap.resize(c * 6); + cap = c; + } + + Counter * insert(const TKey & key, UInt64 increment = 1, UInt64 error = 0) + { + // Increase weight of a key that already exists + // It uses hashtable for both value mapping as a presence test (c_i != 0) + auto hash = counterMap.hash(key); + auto it = counterMap.find(key, hash); + if (it != counterMap.end()) { + auto c = it->second; + c->count += increment; + c->error += error; + percolate(c); + return c; + } + + // Key doesn't exist, but can fit in the top K + if (size() < capacity()) { + auto c = new Counter(key, increment, error); + push(c); + return c; + } + + auto min = counterList.back(); + auto & alpha = alphaMap[hash % alphaMap.size()]; + if (alpha + increment < min->count) { + alpha += increment; + return nullptr; + } + + // Erase the current minimum element + auto minHash = counterMap.hash(min->key); + it = counterMap.find(min->key, minHash); + if (it != counterMap.end()) { + auto cell = it.getPtr(); + cell->setZero(); + } + + // Replace minimum with newly inserted element + bool inserted = false; + counterMap.emplace(key, it, inserted, hash); + if (inserted) { + alphaMap[minHash % alphaMap.size()] = min->count; + min->key = key; + min->count = alpha + increment; + min->error = alpha + error; + it->second = min; + percolate(min); + } + + return min; + } + + /* + * Parallel Space Saving reduction and combine step from: + * https://arxiv.org/pdf/1401.0702.pdf + */ + void merge(const SpaceSaving & rhs) + { + UInt64 m1 = 0, m2 = 0; + if (size() == capacity()) { + m1 = counterList.back()->count; + } + if (rhs.size() == rhs.capacity()) { + m2 = rhs.counterList.back()->count; + } + + /* + * Updated algorithm to mutate current table in place + * without mutating rhs table or creating new one + * in the first step we expect that no elements overlap + * and in the second sweep we correct the error if they do. + */ + if (m2 > 0) { + for (auto c : counterList) { + c->count += m2; + c->error += m2; + } + } + + // The list is sorted in descending order, we have to scan in reverse + for (auto c : boost::adaptors::reverse(rhs.counterList)) { + if (counterMap.find(c->key) != counterMap.end()) { + // Subtract m2 previously added, guaranteed not negative + insert(c->key, c->count - m2, c->error - m2); + } else { + // Counters not monitored in S1 + insert(c->key, c->count + m1, c->error + m1); + } + } + } + + std::vector topK(size_t k) const + { + std::vector res; + for (auto c : counterList) { + res.push_back(*c); + if (res.size() == k) { + break; + } + } + return res; + } + + void write(DB::WriteBuffer & wb) const + { + DB::writeVarUInt(size(), wb); + for (auto c : counterList) { + c->write(wb); + } + for (auto a : alphaMap) { + DB::writeVarUInt(a, wb); + } + } + + void read(DB::ReadBuffer & rb) + { + destroyElements(); + size_t count = 0; + DB::readVarUInt(count, rb); + + for (size_t i = 0; i < count; ++i) { + auto c = new Counter(); + c->read(rb); + push(c); + } + + for (size_t i = 0; i < capacity() * 6; ++i) { + UInt64 alpha = 0; + DB::readVarUInt(alpha, rb); + alphaMap.push_back(alpha); + } + } + +protected: + void push(Counter * c) { + c->slot = counterList.size(); + counterList.push_back(c); + counterMap[c->key] = c; + percolate(c); + } + + // This is equivallent to one step of bubble sort + void percolate(Counter * c) { + while (c->slot > 0) { + auto next = counterList[c->slot - 1]; + if (*c > *next) { + std::swap(next->slot, c->slot); + std::swap(counterList[next->slot], counterList[c->slot]); + } else { + break; + } + } + } + +private: + void destroyElements() { + for (auto c : counterList) { + delete c; + } + counterMap.clear(); + counterList.clear(); + alphaMap.clear(); + } + + HashMap counterMap; + std::vector counterList; + std::vector alphaMap; + size_t cap; +}; + +}; \ No newline at end of file diff --git a/dbms/src/Common/tests/CMakeLists.txt b/dbms/src/Common/tests/CMakeLists.txt index 3b8f53b307c..072d5547301 100644 --- a/dbms/src/Common/tests/CMakeLists.txt +++ b/dbms/src/Common/tests/CMakeLists.txt @@ -54,3 +54,6 @@ target_link_libraries (thread_pool dbms) add_executable (array_cache array_cache.cpp) target_link_libraries (array_cache dbms) + +add_executable (space_saving space_saving.cpp) +target_link_libraries (space_saving dbms) diff --git a/dbms/src/Common/tests/space_saving.cpp b/dbms/src/Common/tests/space_saving.cpp new file mode 100644 index 00000000000..5b37b94f43b --- /dev/null +++ b/dbms/src/Common/tests/space_saving.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include + +#include +#include + +int main(int argc, char ** argv) +{ + { + using Cont = DB::SpaceSaving; + Cont first(10); + + /* Test biased insertion */ + + for (int i = 0; i < 200; ++i) { + first.insert(i); + int k = i % 5; // Bias towards 0-4 + first.insert(k); + } + + /* Test whether the biased elements are retained */ + + std::map expect; + for (int i = 0; i < 5; ++i) { + expect[i] = 41; + } + + for (auto x : first.topK(5)) { + if (expect[x.key] != x.count) { + std::cerr << "key: " << x.key << " value: " << x.count << " expected: " << expect[x.key] << std::endl; + } else { + std::cout << "key: " << x.key << " value: " << x.count << std::endl; + } + expect.erase(x.key); + } + + if (!expect.empty()) { + std::cerr << "expected to find all heavy hitters" << std::endl; + } + + /* Create another table and test merging */ + + Cont second(10); + for (int i = 0; i < 200; ++i) { + first.insert(i); + } + + for (int i = 0; i < 5; ++i) { + expect[i] = 42; + } + + first.merge(second); + + for (auto x : first.topK(5)) { + if (expect[x.key] != x.count) { + std::cerr << "key: " << x.key << " value: " << x.count << " expected: " << expect[x.key] << std::endl; + } else { + std::cout << "key: " << x.key << " value: " << x.count << std::endl; + } + expect.erase(x.key); + } + } + + { + /* Same test for string keys */ + + using Cont = DB::SpaceSaving; + Cont cont(10); + + std::vector refs; + + for (int i = 0; i < 400; ++i) { + refs.push_back(std::to_string(i)); + cont.insert(StringRef(refs.back())); + refs.push_back(std::to_string(i % 5)); // Bias towards 0-4 + cont.insert(StringRef(refs.back())); + } + + // The hashing is going to be more lossy + // Expect at least ~ 10% count + std::map expect; + for (int i = 0; i < 5; ++i) { + expect[std::to_string(i)] = 38; + } + + for (auto x : cont.topK(5)) { + auto key = x.key.toString(); + if (x.count < expect[key]) { + std::cerr << "key: " << key << " value: " << x.count << " expected: " << expect[key] << std::endl; + } else { + std::cout << "key: " << key << " value: " << x.count << std::endl; + } + expect.erase(key); + } + + if (!expect.empty()) { + std::cerr << "expected to find all heavy hitters" << std::endl; + abort(); + } + } + + return 0; +} diff --git a/dbms/src/IO/WriteHelpers.h b/dbms/src/IO/WriteHelpers.h index 0604a9179e6..f94d0600ab4 100644 --- a/dbms/src/IO/WriteHelpers.h +++ b/dbms/src/IO/WriteHelpers.h @@ -583,6 +583,7 @@ inline typename std::enable_if::value, void>::type writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); } inline void writeBinary(const String & x, WriteBuffer & buf) { writeStringBinary(x, buf); } +inline void writeBinary(const StringRef & x, WriteBuffer & buf) { writeStringBinary(x, buf); } inline void writeBinary(const uint128 & x, WriteBuffer & buf) { writePODBinary(x, buf); } inline void writeBinary(const LocalDate & x, WriteBuffer & buf) { writePODBinary(x, buf); } inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); } diff --git a/dbms/tests/queries/0_stateless/00453_top_k.reference b/dbms/tests/queries/0_stateless/00453_top_k.reference new file mode 100644 index 00000000000..0b5c06820e8 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00453_top_k.reference @@ -0,0 +1 @@ +[0,1,2,3,4,5,6,7,8,9] \ No newline at end of file diff --git a/dbms/tests/queries/0_stateless/00453_top_k.sql b/dbms/tests/queries/0_stateless/00453_top_k.sql new file mode 100644 index 00000000000..1f79a8c5393 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00453_top_k.sql @@ -0,0 +1 @@ +SELECT topK(10)(n) FROM (SELECT if(number % 100 < 10, number % 10, number) AS n FROM system.numbers LIMIT 100000); \ No newline at end of file diff --git a/website/reference_en.html b/website/reference_en.html index 63fd353ca6b..f616ab306eb 100644 --- a/website/reference_en.html +++ b/website/reference_en.html @@ -6418,6 +6418,17 @@ Usage example: Problem: Generate a report that shows only keywords that produced at least 5 unique users. Solution: Write in the query GROUP BY SearchPhrase HAVING uniqUpTo(4)(UserID) >= 5 +==topK(N)(x)== + +Returns the K most frequent argument values as an array sorted by their relative frequency. + +Recommended for use with small Ns, up to 10. The maximum N value is 65536. + +For the state of an aggregate function, it uses approximately the amount of memory equal to K * (the size of the key + 16) for counters, and 48 * N bytes for alpha value map. + +Usage example: +Problem: Generate a report that shows top 5 frequent queries. +Solution: Write in the query SELECT topK(5)(SearchPhrase) ==Aggregate function combinators== diff --git a/website/reference_ru.html b/website/reference_ru.html index c6d0b76800a..59a9ceb7ca7 100644 --- a/website/reference_ru.html +++ b/website/reference_ru.html @@ -6534,6 +6534,17 @@ cond1, cond2 ... - от одного до 32 аргументов типа UInt8 Задача: показывать в отчёте только поисковые фразы, по которым было хотя бы 5 уникальных посетителей. Решение: пишем в запросе %%GROUP BY SearchPhrase HAVING uniqUpTo(4)(UserID) >= 5%% +==topK(N)(x)== + +Returns the K most frequent argument values as an array sorted by their relative frequency. + +Recommended for use with small Ns, up to 10. The maximum N value is 65536. + +For the state of an aggregate function, it uses approximately the amount of memory equal to K * (the size of the key + 16) for counters, and 48 * N bytes for alpha value map. + +Usage example: +Problem: Generate a report that shows top 5 frequent queries. +Solution: Write in the query SELECT topK(5)(SearchPhrase) ==Комбинаторы агрегатных функций== From 9a937591e5641f8f7f27910ea8d2ba23db0f22e8 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 4 May 2017 14:56:13 +0300 Subject: [PATCH 14/76] Try fix freebsd 11-STABLE OCbuild --- dbms/src/AggregateFunctions/AggregateFunctionSequenceMatch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionSequenceMatch.h b/dbms/src/AggregateFunctions/AggregateFunctionSequenceMatch.h index cb5c55adc92..bb1c1a8b103 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionSequenceMatch.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionSequenceMatch.h @@ -286,7 +286,7 @@ private: ParserString dot_p("."); ParserNumber number_p; - auto pos = pattern.data(); + const char * pos = pattern.data(); const auto begin = pos; const auto end = pos + pattern.size(); From 1474de179c9f170687170063bac8b60d1a532f2a Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 4 May 2017 22:40:51 +0300 Subject: [PATCH 15/76] CastTypeBlockInputStream: hotfix: sometimes columns in sample blocks and stream blocks does not match --- dbms/src/DataStreams/CastTypeBlockInputStream.cpp | 13 ++++++++++--- dbms/src/DataStreams/CastTypeBlockInputStream.h | 2 ++ dbms/tests/queries/0_stateless/00428_partition.sql | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/dbms/src/DataStreams/CastTypeBlockInputStream.cpp b/dbms/src/DataStreams/CastTypeBlockInputStream.cpp index a72f759492d..c8c7696fb16 100644 --- a/dbms/src/DataStreams/CastTypeBlockInputStream.cpp +++ b/dbms/src/DataStreams/CastTypeBlockInputStream.cpp @@ -41,10 +41,17 @@ Block CastTypeBlockInputStream::readImpl() if (!block || cast_types.empty()) return block; - Block res; - size_t s = block.columns(); + size_t block_size = block.columns(); - for (size_t i = 0; i < s; ++i) + if (block_size != cast_types.size()) + { + LOG_ERROR(log, "Number of columns do not match, skipping cast"); + return block; + } + + Block res; + + for (size_t i = 0; i < block_size; ++i) { const auto & elem = block.getByPosition(i); diff --git a/dbms/src/DataStreams/CastTypeBlockInputStream.h b/dbms/src/DataStreams/CastTypeBlockInputStream.h index d7c5b2560c1..2f8c6adfb31 100644 --- a/dbms/src/DataStreams/CastTypeBlockInputStream.h +++ b/dbms/src/DataStreams/CastTypeBlockInputStream.h @@ -2,6 +2,7 @@ #include +#include #include #include @@ -34,6 +35,7 @@ private: const Context & context; std::vector> cast_types; std::vector> cast_functions; /// Used to perform type conversions. + Logger * log = &Logger::get("CastTypeBlockInputStream"); }; } diff --git a/dbms/tests/queries/0_stateless/00428_partition.sql b/dbms/tests/queries/0_stateless/00428_partition.sql index 7ff9bbd7c19..365f0ba5c4b 100644 --- a/dbms/tests/queries/0_stateless/00428_partition.sql +++ b/dbms/tests/queries/0_stateless/00428_partition.sql @@ -1,4 +1,5 @@ -- Not found column date in block. There are only columns: x. +drop table if exists test.partition_428; create table test.partition_428 (date MATERIALIZED toDate(0), x UInt64, sample_key MATERIALIZED intHash64(x)) ENGINE=MergeTree(date,sample_key,(date,x,sample_key),8192); insert into test.partition_428 ( x ) VALUES ( now() ); insert into test.partition_428 ( x ) VALUES ( now()+1 ); From 6c34f27e3b4b1ce7578aed9f64d8971340d1a303 Mon Sep 17 00:00:00 2001 From: proller Date: Fri, 5 May 2017 03:23:32 +0300 Subject: [PATCH 16/76] Another freebsd fix, update freebsd build doc --- dbms/src/Storages/ColumnsDescription.cpp | 2 +- doc/build_freebsd.sh | 43 +++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index 207f4f4cddc..c663643c049 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -104,7 +104,7 @@ ColumnsDescription ColumnsDescription::parse(const String & str) ASTPtr default_expr; Expected expected{}; - auto begin = default_expr_str.data(); + const char * begin = default_expr_str.data(); const auto end = begin + default_expr_str.size(); const char * max_parsed_pos = begin; if (!expr_parser.parse(begin, end, default_expr, max_parsed_pos, expected)) diff --git a/doc/build_freebsd.sh b/doc/build_freebsd.sh index 92fd419323d..230e1793449 100755 --- a/doc/build_freebsd.sh +++ b/doc/build_freebsd.sh @@ -1,35 +1,46 @@ #!/bin/sh -# How to build ClickHouse under freebsd 11+ -# [temporary solution before port created] +# How to build ClickHouse under freebsd 11+ + +# Variant 1: Use pkg: +# pkg install databases/clickhouse + +# Variant 2: Use ports: +# make -C /usr/ports/databases/clickhouse install clean + +# Run server: +# echo clickhouse_enable="YES" >> /etc/rc.conf.local +# service clickhouse restart + + +# Variant 3: Manual build: # pkg install -y curl sudo # curl https://raw.githubusercontent.com/yandex/ClickHouse/master/doc/build_freebsd.sh | sh -# install compiler and libs -sudo pkg install git cmake bash mysql57-client icu libltdl unixODBC google-perftools +# install compiler and libs +sudo pkg install devel/git devel/cmake shells/bash devel/icu devel/libltdl databases/unixODBC devel/google-perftools devel/libzookeeper devel/libdouble-conversion archivers/zstd archivers/liblz4 devel/sparsehash devel/re2 -# install testing only stuff if you want: -sudo pkg install python py27-lxml py27-termcolor curl perl5 +# install testing only stuff if you want: +sudo pkg install lang/python devel/py-lxml devel/py-termcolor ftp/curl perl5 -# Checkout ClickHouse sources +# If you want ODBC support: Check UNIXODBC option: +# make -C /usr/ports/devel/poco config reinstall + +# Checkout ClickHouse sources git clone https://github.com/yandex/ClickHouse.git -# Build! +# Build! mkdir -p ClickHouse/build cd ClickHouse/build -cmake .. -DUSE_INTERNAL_GPERFTOOLS_LIBRARY=0 -# WIP: variant with libs from ports: -# sudo pkg install devel/boost-libs devel/libzookeeper devel/libdouble-conversion archivers/zstd archivers/liblz4 devel/sparsehash devel/re2 -# Check UNIXODBC option: -# make -C /usr/ports/devel/poco config reinstall -# cmake .. -DUNBUNDLED=1 -DUSE_STATIC_LIBRARIES=0 -DNO_WERROR=1 +cmake .. -DUNBUNDLED=1 -DUSE_STATIC_LIBRARIES=0 -DNO_WERROR=1 -DUSE_INTERNAL_BOOST_LIBRARY=1 +# build with boost 1.64 from ports temporary broken make -C dbms/src/Server -j $(nproc || sysctl -n hw.ncpu || echo 2) cd ../.. -# run server: +# Run server: # ClickHouse/build/dbms/src/Server/clickhouse --server --config-file=ClickHouse/dbms/src/Server/config.xml & -# run client: +# Run client: # ClickHouse/build/dbms/src/Server/clickhouse --client From 9bcece79f9b357748dffce82e708b9a434449052 Mon Sep 17 00:00:00 2001 From: proller Date: Fri, 5 May 2017 17:14:49 +0300 Subject: [PATCH 17/76] tests: dont stop on errors by default --- dbms/tests/clickhouse-test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbms/tests/clickhouse-test b/dbms/tests/clickhouse-test index 9be8227d5b6..c285b3299db 100755 --- a/dbms/tests/clickhouse-test +++ b/dbms/tests/clickhouse-test @@ -160,7 +160,7 @@ def main(args): report_testcase.append(stderr_element) print(stderr) - if 'Connection refused' in stderr or 'Attempt to read after eof' in stderr: + if args.stop and ('Connection refused' in stderr or 'Attempt to read after eof' in stderr): SERVER_DIED = True elif stderr: @@ -235,6 +235,7 @@ if __name__ == '__main__': group.add_argument('--no-zookeeper', action = 'store_false', default = None, dest = 'zookeeper', help = 'Do not run zookeeper related tests') group.add_argument('--shard', action = 'store_true', default = None, dest = 'shard', help = 'Run sharding related tests (required to clickhouse-server listen 127.0.0.2 127.0.0.3)') group.add_argument('--no-shard', action = 'store_false', default = None, dest = 'shard', help = 'Do not run shard related tests') + group.add_argument('--stop', action = 'store_true', default = None, dest = 'stop', help = 'Stop on network errors ') args = parser.parse_args() From b1f1096f2795328b596f68e5d8016f0a963d6639 Mon Sep 17 00:00:00 2001 From: proller Date: Fri, 5 May 2017 17:50:05 +0300 Subject: [PATCH 18/76] tests: correct Connection refused detection (#766) --- dbms/tests/clickhouse-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/clickhouse-test b/dbms/tests/clickhouse-test index c285b3299db..5cb094333fe 100755 --- a/dbms/tests/clickhouse-test +++ b/dbms/tests/clickhouse-test @@ -160,7 +160,7 @@ def main(args): report_testcase.append(stderr_element) print(stderr) - if args.stop and ('Connection refused' in stderr or 'Attempt to read after eof' in stderr): + if args.stop and ('Connection refused' in stderr or 'Attempt to read after eof' in stderr) and not 'Received exception from server' in stderr: SERVER_DIED = True elif stderr: From 9d4c814b127982f5294275aedb08ce406f9a31dc Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 5 May 2017 14:17:04 -0700 Subject: [PATCH 19/76] Aggregate function topK: style modifications [#CLICKHOUSE-2]. --- dbms/src/Common/SpaceSaving.h | 213 +++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 93 deletions(-) diff --git a/dbms/src/Common/SpaceSaving.h b/dbms/src/Common/SpaceSaving.h index 4f11ebc3bbe..273599e3f1b 100644 --- a/dbms/src/Common/SpaceSaving.h +++ b/dbms/src/Common/SpaceSaving.h @@ -30,65 +30,69 @@ template > class SpaceSaving { public: - struct Counter { + using Self = SpaceSaving; + + struct Counter + { Counter() {} Counter(const TKey & k, UInt64 c = 0, UInt64 e = 0) : key(k), slot(0), count(c), error(e) {} - void write(DB::WriteBuffer & wb) const + void write(WriteBuffer & wb) const { - DB::writeBinary(key, wb); - DB::writeVarUInt(count, wb); - DB::writeVarUInt(error, wb); + writeBinary(key, wb); + writeVarUInt(count, wb); + writeVarUInt(error, wb); } - void read(DB::ReadBuffer & rb) + void read(ReadBuffer & rb) { - DB::readBinary(key, rb); - DB::readVarUInt(count, rb); - DB::readVarUInt(error, rb); + readBinary(key, rb); + readVarUInt(count, rb); + readVarUInt(error, rb); } // greater() taking slot error into account - bool operator >(const Counter &b) const + bool operator> (const Counter & b) const { return (count > b.count) || (count == b.count && error < b.error); } TKey key; size_t slot; - UInt64 count, error; + UInt64 count; + UInt64 error; }; - // Suggested constants in the paper "Finding top-k elements in data streams", chap 6. equation (24) - SpaceSaving(size_t c = 10) : counterMap(), counterList(), alphaMap(6 * c), cap(c) {} + SpaceSaving(size_t c = 10) : alpha_map(ALPHA_MAP_ELEMENTS_PER_COUNTER * c), m_capacity(c) {} ~SpaceSaving() { destroyElements(); } inline size_t size() const { - return counterList.size(); + return counter_list.size(); } inline size_t capacity() const { - return cap; + return m_capacity; } - void resize(size_t c) + void resize(size_t new_capacity) { - counterList.reserve(c); - alphaMap.resize(c * 6); - cap = c; + counter_list.reserve(new_capacity); + alpha_map.resize(new_capacity * ALPHA_MAP_ELEMENTS_PER_COUNTER); + m_capacity = new_capacity; } Counter * insert(const TKey & key, UInt64 increment = 1, UInt64 error = 0) { // Increase weight of a key that already exists // It uses hashtable for both value mapping as a presence test (c_i != 0) - auto hash = counterMap.hash(key); - auto it = counterMap.find(key, hash); - if (it != counterMap.end()) { + auto hash = counter_map.hash(key); + auto it = counter_map.find(key, hash); + if (it != counter_map.end()) + { auto c = it->second; c->count += increment; c->error += error; @@ -97,32 +101,36 @@ public: } // Key doesn't exist, but can fit in the top K - if (size() < capacity()) { + if (size() < capacity()) + { auto c = new Counter(key, increment, error); push(c); return c; } - auto min = counterList.back(); - auto & alpha = alphaMap[hash % alphaMap.size()]; - if (alpha + increment < min->count) { + auto min = counter_list.back(); + auto & alpha = alpha_map[hash % alpha_map.size()]; + if (alpha + increment < min->count) + { alpha += increment; return nullptr; } // Erase the current minimum element - auto minHash = counterMap.hash(min->key); - it = counterMap.find(min->key, minHash); - if (it != counterMap.end()) { + auto minHash = counter_map.hash(min->key); + it = counter_map.find(min->key, minHash); + if (it != counter_map.end()) + { auto cell = it.getPtr(); cell->setZero(); } // Replace minimum with newly inserted element bool inserted = false; - counterMap.emplace(key, it, inserted, hash); - if (inserted) { - alphaMap[minHash % alphaMap.size()] = min->count; + counter_map.emplace(key, it, inserted, hash); + if (inserted) + { + alpha_map[minHash % alpha_map.size()] = min->count; min->key = key; min->count = alpha + increment; min->error = alpha + error; @@ -137,14 +145,19 @@ public: * Parallel Space Saving reduction and combine step from: * https://arxiv.org/pdf/1401.0702.pdf */ - void merge(const SpaceSaving & rhs) + void merge(const Self & rhs) { - UInt64 m1 = 0, m2 = 0; - if (size() == capacity()) { - m1 = counterList.back()->count; + UInt64 m1 = 0; + UInt64 m2 = 0; + + if (size() == capacity()) + { + m1 = counter_list.back()->count; } - if (rhs.size() == rhs.capacity()) { - m2 = rhs.counterList.back()->count; + + if (rhs.size() == rhs.capacity()) + { + m2 = rhs.counter_list.back()->count; } /* @@ -153,21 +166,27 @@ public: * in the first step we expect that no elements overlap * and in the second sweep we correct the error if they do. */ - if (m2 > 0) { - for (auto c : counterList) { - c->count += m2; - c->error += m2; + if (m2 > 0) + { + for (auto counter : counter_list) + { + counter->count += m2; + counter->error += m2; } } // The list is sorted in descending order, we have to scan in reverse - for (auto c : boost::adaptors::reverse(rhs.counterList)) { - if (counterMap.find(c->key) != counterMap.end()) { + for (auto counter : boost::adaptors::reverse(rhs.counter_list)) + { + if (counter_map.find(counter->key) != counter_map.end()) + { // Subtract m2 previously added, guaranteed not negative - insert(c->key, c->count - m2, c->error - m2); - } else { + insert(counter->key, counter->count - m2, counter->error - m2); + } + else + { // Counters not monitored in S1 - insert(c->key, c->count + m1, c->error + m1); + insert(counter->key, counter->count + m1, counter->error + m1); } } } @@ -175,80 +194,88 @@ public: std::vector topK(size_t k) const { std::vector res; - for (auto c : counterList) { - res.push_back(*c); - if (res.size() == k) { + for (auto counter : counter_list) + { + res.push_back(*counter); + if (res.size() == k) break; - } } return res; } - void write(DB::WriteBuffer & wb) const + void write(WriteBuffer & wb) const { - DB::writeVarUInt(size(), wb); - for (auto c : counterList) { - c->write(wb); - } - for (auto a : alphaMap) { - DB::writeVarUInt(a, wb); - } + writeVarUInt(size(), wb); + for (auto counter : counter_list) + counter->write(wb); + for (auto alpha : alpha_map) + writeVarUInt(alpha, wb); } - void read(DB::ReadBuffer & rb) + void read(ReadBuffer & rb) { destroyElements(); size_t count = 0; - DB::readVarUInt(count, rb); + readVarUInt(count, rb); - for (size_t i = 0; i < count; ++i) { - auto c = new Counter(); - c->read(rb); - push(c); + for (size_t i = 0; i < count; ++i) + { + auto counter = new Counter(); + counter->read(rb); + push(counter); } - for (size_t i = 0; i < capacity() * 6; ++i) { + for (size_t i = 0; i < m_capacity * ALPHA_MAP_ELEMENTS_PER_COUNTER; ++i) + { UInt64 alpha = 0; - DB::readVarUInt(alpha, rb); - alphaMap.push_back(alpha); + readVarUInt(alpha, rb); + alpha_map.push_back(alpha); } } protected: - void push(Counter * c) { - c->slot = counterList.size(); - counterList.push_back(c); - counterMap[c->key] = c; - percolate(c); + void push(Counter * counter) + { + counter->slot = counter_list.size(); + counter_list.push_back(counter); + counter_map[counter->key] = counter; + percolate(counter); } // This is equivallent to one step of bubble sort - void percolate(Counter * c) { - while (c->slot > 0) { - auto next = counterList[c->slot - 1]; - if (*c > *next) { - std::swap(next->slot, c->slot); - std::swap(counterList[next->slot], counterList[c->slot]); - } else { - break; + void percolate(Counter * counter) + { + while (counter->slot > 0) + { + auto next = counter_list[counter->slot - 1]; + if (*counter > *next) + { + std::swap(next->slot, counter->slot); + std::swap(counter_list[next->slot], counter_list[counter->slot]); } + else + break; } } private: - void destroyElements() { - for (auto c : counterList) { - delete c; - } - counterMap.clear(); - counterList.clear(); - alphaMap.clear(); + void destroyElements() + { + for (auto counter : counter_list) + delete counter; + + counter_map.clear(); + counter_list.clear(); + alpha_map.clear(); } - HashMap counterMap; - std::vector counterList; - std::vector alphaMap; - size_t cap; + HashMap counter_map; + std::vector counter_list; + std::vector alpha_map; + size_t m_capacity; + + // Suggested constants in the paper "Finding top-k elements in data streams", chap 6. equation (24) + enum { ALPHA_MAP_ELEMENTS_PER_COUNTER = 6 }; }; -}; \ No newline at end of file +}; From aa629d0f7eaa4bd9ac16ef0be3ff8d4e100d4af7 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 5 May 2017 14:25:53 -0700 Subject: [PATCH 20/76] Minor modification [#CLICKHOUSE-2]. --- dbms/src/Server/Server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 01f7a0ea7b6..7a0389d93b6 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -480,7 +480,7 @@ int Server::main(const std::vector & args) for (const auto & listen_host : listen_hosts) { /// For testing purposes, user may omit tcp_port or http_port or https_port in configuration file. - try + try { /// HTTP if (config().has("http_port")) @@ -617,7 +617,7 @@ int Server::main(const std::vector & args) LOG_DEBUG( log, "Closed connections." << (current_connections ? " But " + std::to_string(current_connections) + " remains." - + " Tip: To increase wait time add to config: 60 ." : "")); + " Tip: To increase wait time add to config: 60" : "")); main_config_reloader.reset(); users_config_reloader.reset(); From d3e6321967dd82defd0dce86582b4fd050331e3d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 5 May 2017 16:36:02 -0700 Subject: [PATCH 21/76] AggregateFunctionTopK: minor modifications [#CLICKHOUSE-2]. --- .../AggregateFunctions/AggregateFunctionTopK.h | 3 +-- dbms/src/Common/SpaceSaving.h | 16 +++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h index b93780d127e..0e2400c8d04 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h @@ -72,9 +72,8 @@ public: void addImpl(AggregateDataPtr place, const IColumn & column, size_t row_num, Arena *) const { auto & set = this->data(place).value; - if (set.capacity() != reserved) { + if (set.capacity() != reserved) set.resize(reserved); - } set.insert(static_cast &>(column).getData()[row_num]); } diff --git a/dbms/src/Common/SpaceSaving.h b/dbms/src/Common/SpaceSaving.h index 273599e3f1b..f1973d9b823 100644 --- a/dbms/src/Common/SpaceSaving.h +++ b/dbms/src/Common/SpaceSaving.h @@ -85,7 +85,7 @@ public: m_capacity = new_capacity; } - Counter * insert(const TKey & key, UInt64 increment = 1, UInt64 error = 0) + void insert(const TKey & key, UInt64 increment = 1, UInt64 error = 0) { // Increase weight of a key that already exists // It uses hashtable for both value mapping as a presence test (c_i != 0) @@ -97,7 +97,7 @@ public: c->count += increment; c->error += error; percolate(c); - return c; + return; } // Key doesn't exist, but can fit in the top K @@ -105,7 +105,7 @@ public: { auto c = new Counter(key, increment, error); push(c); - return c; + return; } auto min = counter_list.back(); @@ -113,12 +113,12 @@ public: if (alpha + increment < min->count) { alpha += increment; - return nullptr; + return; } // Erase the current minimum element - auto minHash = counter_map.hash(min->key); - it = counter_map.find(min->key, minHash); + auto min_hash = counter_map.hash(min->key); + it = counter_map.find(min->key, min_hash); if (it != counter_map.end()) { auto cell = it.getPtr(); @@ -130,15 +130,13 @@ public: counter_map.emplace(key, it, inserted, hash); if (inserted) { - alpha_map[minHash % alpha_map.size()] = min->count; + alpha_map[min_hash % alpha_map.size()] = min->count; min->key = key; min->count = alpha + increment; min->error = alpha + error; it->second = min; percolate(min); } - - return min; } /* From fac00792f954b7a9b436925f6cb5cc3a8356796e Mon Sep 17 00:00:00 2001 From: proller Date: Fri, 5 May 2017 23:39:25 +0300 Subject: [PATCH 22/76] Move most AggregateFunctions to separate lib, use AggregateFunctionFactory as singletone, rename lib storages_system->clickhouse_storages_system --- dbms/CMakeLists.txt | 28 +++++++++- .../AggregateFunctionFactory.cpp | 37 ------------- .../AggregateFunctionFactory.h | 3 +- dbms/src/AggregateFunctions/CMakeLists.txt | 27 ++++++++++ .../registerAggregateFunctions.cpp | 52 +++++++++++++++++++ .../registerAggregateFunctions.h | 8 +++ .../Analyzers/TypeAndConstantInference.cpp | 2 +- dbms/src/Analyzers/tests/CMakeLists.txt | 10 ++-- dbms/src/Client/CMakeLists.txt | 2 +- dbms/src/Client/Client.cpp | 2 + dbms/src/DataStreams/tests/CMakeLists.txt | 8 +-- dbms/src/DataTypes/DataTypeFactory.cpp | 2 +- dbms/src/Functions/FunctionsArray.cpp | 2 +- dbms/src/Interpreters/Context.cpp | 2 - dbms/src/Interpreters/Context.h | 1 - dbms/src/Interpreters/ExpressionAnalyzer.cpp | 4 +- dbms/src/Interpreters/tests/CMakeLists.txt | 2 +- dbms/src/Server/CMakeLists.txt | 4 +- dbms/src/Server/LocalServer.cpp | 2 + dbms/src/Server/Server.cpp | 3 ++ dbms/src/Storages/StorageFactory.cpp | 2 +- dbms/src/Storages/System/CMakeLists.txt | 2 +- .../System/StorageSystemFunctions.cpp | 2 +- dbms/src/Storages/tests/CMakeLists.txt | 2 +- 24 files changed, 145 insertions(+), 64 deletions(-) create mode 100644 dbms/src/AggregateFunctions/CMakeLists.txt create mode 100644 dbms/src/AggregateFunctions/registerAggregateFunctions.cpp create mode 100644 dbms/src/AggregateFunctions/registerAggregateFunctions.h diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index 1ba41dca53c..28c0753a157 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -44,7 +44,6 @@ include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake) add_headers_and_sources(dbms src/TableFunctions) add_headers_and_sources(dbms src/Parsers) add_headers_and_sources(dbms src/Analyzers) -add_headers_and_sources(dbms src/AggregateFunctions) add_headers_and_sources(dbms src/Core) add_headers_and_sources(dbms src/DataStreams) add_headers_and_sources(dbms src/DataTypes) @@ -70,6 +69,33 @@ list (APPEND dbms_headers ${CONFIG_VERSION} ${CONFIG_COMMON}) list (APPEND dbms_sources src/Functions/IFunction.cpp src/Functions/FunctionFactory.cpp src/Functions/DataTypeTraits.cpp) list (APPEND dbms_headers src/Functions/IFunction.h src/Functions/FunctionFactory.h src/Functions/DataTypeTraits.h) +list (APPEND dbms_sources + src/AggregateFunctions/AggregateFunctionFactory.cpp + src/AggregateFunctions/AggregateFunctionState.cpp + src/AggregateFunctions/AggregateFunctionFactory.cpp + src/AggregateFunctions/AggregateFunctionState.cpp + src/AggregateFunctions/AggregateFunctionArray.cpp + src/AggregateFunctions/AggregateFunctionNull.cpp + src/AggregateFunctions/AggregateFunctionForEach.cpp + src/AggregateFunctions/AggregateFunctionIf.cpp + src/AggregateFunctions/AggregateFunctionMerge.cpp + src/AggregateFunctions/AggregateFunctionCount.cpp +) + +list (APPEND dbms_headers + src/AggregateFunctions/IAggregateFunction.h + src/AggregateFunctions/AggregateFunctionFactory.h + src/AggregateFunctions/AggregateFunctionState.h + src/AggregateFunctions/AggregateFunctionFactory.h + src/AggregateFunctions/AggregateFunctionState.h + src/AggregateFunctions/AggregateFunctionArray.h + src/AggregateFunctions/AggregateFunctionNull.h + src/AggregateFunctions/AggregateFunctionForEach.h + src/AggregateFunctions/AggregateFunctionIf.h + src/AggregateFunctions/AggregateFunctionMerge.h + src/AggregateFunctions/AggregateFunctionCount.h +) + list(REMOVE_ITEM dbms_sources src/Client/Client.cpp diff --git a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp index a4325c45e7e..5cd9d88f85b 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionFactory.cpp @@ -30,25 +30,6 @@ std::string trimRight(const std::string & in, const char * suffix) } -void registerAggregateFunctionAvg(AggregateFunctionFactory & factory); -void registerAggregateFunctionCount(AggregateFunctionFactory & factory); -void registerAggregateFunctionGroupArray(AggregateFunctionFactory & factory); -void registerAggregateFunctionGroupUniqArray(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantileExact(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantileExactWeighted(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantileDeterministic(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantileTiming(AggregateFunctionFactory & factory); -void registerAggregateFunctionsQuantileTDigest(AggregateFunctionFactory & factory); -void registerAggregateFunctionsSequenceMatch(AggregateFunctionFactory & factory); -void registerAggregateFunctionsMinMaxAny(AggregateFunctionFactory & factory); -void registerAggregateFunctionsStatistics(AggregateFunctionFactory & factory); -void registerAggregateFunctionSum(AggregateFunctionFactory & factory); -void registerAggregateFunctionsUniq(AggregateFunctionFactory & factory); -void registerAggregateFunctionUniqUpTo(AggregateFunctionFactory & factory); -void registerAggregateFunctionTopK(AggregateFunctionFactory & factory); -void registerAggregateFunctionDebug(AggregateFunctionFactory & factory); - AggregateFunctionPtr createAggregateFunctionArray(AggregateFunctionPtr & nested); AggregateFunctionPtr createAggregateFunctionForEach(AggregateFunctionPtr & nested); AggregateFunctionPtr createAggregateFunctionIf(AggregateFunctionPtr & nested); @@ -61,24 +42,6 @@ AggregateFunctionPtr createAggregateFunctionCountNotNull(const DataTypes & argum AggregateFunctionFactory::AggregateFunctionFactory() { - registerAggregateFunctionAvg(*this); - registerAggregateFunctionCount(*this); - registerAggregateFunctionGroupArray(*this); - registerAggregateFunctionGroupUniqArray(*this); - registerAggregateFunctionsQuantile(*this); - registerAggregateFunctionsQuantileExact(*this); - registerAggregateFunctionsQuantileExactWeighted(*this); - registerAggregateFunctionsQuantileDeterministic(*this); - registerAggregateFunctionsQuantileTiming(*this); - registerAggregateFunctionsQuantileTDigest(*this); - registerAggregateFunctionsSequenceMatch(*this); - registerAggregateFunctionsMinMaxAny(*this); - registerAggregateFunctionsStatistics(*this); - registerAggregateFunctionSum(*this); - registerAggregateFunctionsUniq(*this); - registerAggregateFunctionUniqUpTo(*this); - registerAggregateFunctionTopK(*this); - registerAggregateFunctionDebug(*this); } diff --git a/dbms/src/AggregateFunctions/AggregateFunctionFactory.h b/dbms/src/AggregateFunctions/AggregateFunctionFactory.h index ade5f84065e..6ab27a22b3b 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionFactory.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionFactory.h @@ -2,6 +2,7 @@ #include #include +#include namespace DB @@ -14,7 +15,7 @@ using DataTypes = std::vector; /** Creates an aggregate function by name. */ -class AggregateFunctionFactory final +class AggregateFunctionFactory final : public Singleton { friend class StorageSystemFunctions; diff --git a/dbms/src/AggregateFunctions/CMakeLists.txt b/dbms/src/AggregateFunctions/CMakeLists.txt new file mode 100644 index 00000000000..8e2f0368f99 --- /dev/null +++ b/dbms/src/AggregateFunctions/CMakeLists.txt @@ -0,0 +1,27 @@ +include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake) +add_headers_and_sources(clickhouse_aggregate_functions .) + +list(REMOVE_ITEM clickhouse_aggregate_functions_sources + AggregateFunctionFactory.cpp + AggregateFunctionState.cpp + AggregateFunctionArray.cpp + AggregateFunctionNull.cpp + AggregateFunctionForEach.cpp + AggregateFunctionIf.cpp + AggregateFunctionMerge.cpp + AggregateFunctionCount.cpp +) + +list(REMOVE_ITEM clickhouse_aggregate_functions_headers + AggregateFunction.h + AggregateFunctionFactory.h + AggregateFunctionState.h + AggregateFunctionArray.h + AggregateFunctionNull.h + AggregateFunctionForEach.h + AggregateFunctionIf.h + AggregateFunctionMerge.h + AggregateFunctionCount.h +) + +add_library(clickhouse_aggregate_functions ${clickhouse_aggregate_functions_sources}) diff --git a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp new file mode 100644 index 00000000000..e690af7eb83 --- /dev/null +++ b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp @@ -0,0 +1,52 @@ +#include + +#include + +namespace DB +{ + +void registerAggregateFunctionAvg(AggregateFunctionFactory & factory); +void registerAggregateFunctionCount(AggregateFunctionFactory & factory); +void registerAggregateFunctionGroupArray(AggregateFunctionFactory & factory); +void registerAggregateFunctionGroupUniqArray(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantileExact(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantileExactWeighted(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantileDeterministic(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantileTiming(AggregateFunctionFactory & factory); +void registerAggregateFunctionsQuantileTDigest(AggregateFunctionFactory & factory); +void registerAggregateFunctionsSequenceMatch(AggregateFunctionFactory & factory); +void registerAggregateFunctionsMinMaxAny(AggregateFunctionFactory & factory); +void registerAggregateFunctionsStatistics(AggregateFunctionFactory & factory); +void registerAggregateFunctionSum(AggregateFunctionFactory & factory); +void registerAggregateFunctionsUniq(AggregateFunctionFactory & factory); +void registerAggregateFunctionUniqUpTo(AggregateFunctionFactory & factory); +void registerAggregateFunctionTopK(AggregateFunctionFactory & factory); +void registerAggregateFunctionDebug(AggregateFunctionFactory & factory); + + +void registerAggregateFunctions() +{ + auto & factory = AggregateFunctionFactory::instance(); + + registerAggregateFunctionAvg(factory); + registerAggregateFunctionCount(factory); + registerAggregateFunctionGroupArray(factory); + registerAggregateFunctionGroupUniqArray(factory); + registerAggregateFunctionsQuantile(factory); + registerAggregateFunctionsQuantileExact(factory); + registerAggregateFunctionsQuantileExactWeighted(factory); + registerAggregateFunctionsQuantileDeterministic(factory); + registerAggregateFunctionsQuantileTiming(factory); + registerAggregateFunctionsQuantileTDigest(factory); + registerAggregateFunctionsSequenceMatch(factory); + registerAggregateFunctionsMinMaxAny(factory); + registerAggregateFunctionsStatistics(factory); + registerAggregateFunctionSum(factory); + registerAggregateFunctionsUniq(factory); + registerAggregateFunctionUniqUpTo(factory); + registerAggregateFunctionTopK(factory); + registerAggregateFunctionDebug(factory); +} + +} diff --git a/dbms/src/AggregateFunctions/registerAggregateFunctions.h b/dbms/src/AggregateFunctions/registerAggregateFunctions.h new file mode 100644 index 00000000000..2a2e0bb7d3f --- /dev/null +++ b/dbms/src/AggregateFunctions/registerAggregateFunctions.h @@ -0,0 +1,8 @@ +#pragma once + +namespace DB +{ + +void registerAggregateFunctions(); + +} diff --git a/dbms/src/Analyzers/TypeAndConstantInference.cpp b/dbms/src/Analyzers/TypeAndConstantInference.cpp index 0b227b0f8cc..39b85811f56 100644 --- a/dbms/src/Analyzers/TypeAndConstantInference.cpp +++ b/dbms/src/Analyzers/TypeAndConstantInference.cpp @@ -165,7 +165,7 @@ void processFunction(const String & column_name, ASTPtr & ast, TypeAndConstantIn } /// Aggregate function. - if (AggregateFunctionPtr aggregate_function_ptr = context.getAggregateFunctionFactory().tryGet(function->name, argument_types)) + if (AggregateFunctionPtr aggregate_function_ptr = AggregateFunctionFactory::instance().tryGet(function->name, argument_types)) { /// NOTE Not considering aggregate function parameters in type inference. It could become needed in future. /// Note that aggregate function could never be constant expression. diff --git a/dbms/src/Analyzers/tests/CMakeLists.txt b/dbms/src/Analyzers/tests/CMakeLists.txt index 512d955e038..42fcdc54e5e 100644 --- a/dbms/src/Analyzers/tests/CMakeLists.txt +++ b/dbms/src/Analyzers/tests/CMakeLists.txt @@ -2,22 +2,22 @@ add_executable(collect_aliases collect_aliases.cpp) target_link_libraries(collect_aliases dbms) add_executable(collect_tables collect_tables.cpp) -target_link_libraries(collect_tables dbms storages_system) +target_link_libraries(collect_tables dbms clickhouse_storages_system) add_executable(analyze_columns analyze_columns.cpp) -target_link_libraries(analyze_columns dbms storages_system) +target_link_libraries(analyze_columns dbms clickhouse_storages_system) add_executable(type_and_constant_inference type_and_constant_inference.cpp) -target_link_libraries(type_and_constant_inference storages_system clickhouse_functions dbms) +target_link_libraries(type_and_constant_inference clickhouse_storages_system clickhouse_functions dbms) add_executable(analyze_result_of_query analyze_result_of_query.cpp) -target_link_libraries(analyze_result_of_query dbms storages_system) +target_link_libraries(analyze_result_of_query dbms clickhouse_storages_system) add_executable(translate_positional_arguments translate_positional_arguments.cpp) target_link_libraries(translate_positional_arguments dbms) add_executable(optimize_group_order_limit_by optimize_group_order_limit_by.cpp) -target_link_libraries(optimize_group_order_limit_by dbms storages_system) +target_link_libraries(optimize_group_order_limit_by dbms clickhouse_storages_system) add_executable(analyze_lambdas analyze_lambdas.cpp) target_link_libraries(analyze_lambdas dbms) diff --git a/dbms/src/Client/CMakeLists.txt b/dbms/src/Client/CMakeLists.txt index 999a46a0826..da5dc27cdb5 100644 --- a/dbms/src/Client/CMakeLists.txt +++ b/dbms/src/Client/CMakeLists.txt @@ -1,5 +1,5 @@ add_library (clickhouse-client Client.cpp) -target_link_libraries (clickhouse-client dbms ${LINE_EDITING_LIBS} ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries (clickhouse-client dbms clickhouse_aggregate_functions ${LINE_EDITING_LIBS} ${Boost_PROGRAM_OPTIONS_LIBRARY}) install (FILES config.xml DESTINATION ${CLICKHOUSE_ETC_DIR}/clickhouse-client COMPONENT clickhouse-client) add_library (clickhouse-benchmark Benchmark.cpp) diff --git a/dbms/src/Client/Client.cpp b/dbms/src/Client/Client.cpp index 7e4ad1a7607..530301cabd4 100644 --- a/dbms/src/Client/Client.cpp +++ b/dbms/src/Client/Client.cpp @@ -46,6 +46,7 @@ #include #include #include +#include /// http://en.wikipedia.org/wiki/ANSI_escape_code @@ -191,6 +192,7 @@ private: #undef EXTRACT_LIMIT registerFunctions(); + registerAggregateFunctions(); } diff --git a/dbms/src/DataStreams/tests/CMakeLists.txt b/dbms/src/DataStreams/tests/CMakeLists.txt index 405e2b1a4d6..2a07e8d9b72 100644 --- a/dbms/src/DataStreams/tests/CMakeLists.txt +++ b/dbms/src/DataStreams/tests/CMakeLists.txt @@ -9,7 +9,7 @@ add_executable (block_row_transforms block_row_transforms.cpp ${SRCS}) target_link_libraries (block_row_transforms dbms) add_executable (expression_stream expression_stream.cpp ${SRCS}) -target_link_libraries (expression_stream dbms storages_system) +target_link_libraries (expression_stream dbms clickhouse_storages_system) add_executable (block_tab_separated_streams block_tab_separated_streams.cpp ${SRCS}) target_link_libraries (block_tab_separated_streams dbms) @@ -18,7 +18,7 @@ add_executable (native_streams native_streams.cpp ${SRCS}) target_link_libraries (native_streams dbms) add_executable (filter_stream filter_stream.cpp ${SRCS}) -target_link_libraries (filter_stream dbms storages_system) +target_link_libraries (filter_stream dbms clickhouse_storages_system) add_executable (filter_stream_hitlog filter_stream_hitlog.cpp ${SRCS}) target_link_libraries (filter_stream_hitlog dbms) @@ -30,7 +30,7 @@ add_executable (aggregating_stream aggregating_stream.cpp ${SRCS}) target_link_libraries (aggregating_stream dbms) add_executable (union_stream union_stream.cpp ${SRCS}) -target_link_libraries (union_stream dbms storages_system) +target_link_libraries (union_stream dbms clickhouse_storages_system) add_executable (union_stream2 union_stream2.cpp ${SRCS}) target_link_libraries (union_stream2 dbms) @@ -39,7 +39,7 @@ add_executable (collapsing_sorted_stream collapsing_sorted_stream.cpp ${SRCS}) target_link_libraries (collapsing_sorted_stream dbms) add_executable (fork_streams fork_streams.cpp ${SRCS}) -target_link_libraries (fork_streams dbms storages_system) +target_link_libraries (fork_streams dbms clickhouse_storages_system) add_executable (glue_streams glue_streams.cpp ${SRCS}) target_link_libraries (glue_streams dbms) diff --git a/dbms/src/DataTypes/DataTypeFactory.cpp b/dbms/src/DataTypes/DataTypeFactory.cpp index 3fb29ca5089..0630f4907f1 100644 --- a/dbms/src/DataTypes/DataTypeFactory.cpp +++ b/dbms/src/DataTypes/DataTypeFactory.cpp @@ -180,7 +180,7 @@ DataTypePtr DataTypeFactory::get(const String & name) const if (function_name.empty()) throw Exception("Logical error: empty name of aggregate function passed", ErrorCodes::LOGICAL_ERROR); - function = AggregateFunctionFactory().get(function_name, argument_types); + function = AggregateFunctionFactory::instance().get(function_name, argument_types); if (!params_row.empty()) function->setParameters(params_row); function->setArguments(argument_types); diff --git a/dbms/src/Functions/FunctionsArray.cpp b/dbms/src/Functions/FunctionsArray.cpp index d2c83cb30e6..76a5c1cc2d2 100644 --- a/dbms/src/Functions/FunctionsArray.cpp +++ b/dbms/src/Functions/FunctionsArray.cpp @@ -2818,7 +2818,7 @@ void FunctionArrayReduce::getReturnTypeAndPrerequisitesImpl( } } - aggregate_function = AggregateFunctionFactory().get(aggregate_function_name, argument_types); + aggregate_function = AggregateFunctionFactory::instance().get(aggregate_function_name, argument_types); if (has_parameters) aggregate_function->setParameters(params_row); diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index b57639e9bf6..54550f94003 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -104,7 +104,6 @@ struct ContextShared String flags_path; /// Databases databases; /// List of databases and tables in them. TableFunctionFactory table_function_factory; /// Table functions. - AggregateFunctionFactory aggregate_function_factory; /// Aggregate functions. FormatFactory format_factory; /// Formats. mutable std::shared_ptr embedded_dictionaries; /// Metrica's dictionaeis. Have lazy initialization. mutable std::shared_ptr external_dictionaries; @@ -211,7 +210,6 @@ Context::~Context() = default; const TableFunctionFactory & Context::getTableFunctionFactory() const { return shared->table_function_factory; } -const AggregateFunctionFactory & Context::getAggregateFunctionFactory() const { return shared->aggregate_function_factory; } InterserverIOHandler & Context::getInterserverIOHandler() { return shared->interserver_io_handler; } std::unique_lock Context::getLock() const diff --git a/dbms/src/Interpreters/Context.h b/dbms/src/Interpreters/Context.h index fa0d1b7b8b1..579f7c31b50 100644 --- a/dbms/src/Interpreters/Context.h +++ b/dbms/src/Interpreters/Context.h @@ -187,7 +187,6 @@ public: void setSetting(const String & name, const std::string & value); const TableFunctionFactory & getTableFunctionFactory() const; - const AggregateFunctionFactory & getAggregateFunctionFactory() const; const EmbeddedDictionaries & getEmbeddedDictionaries() const; const ExternalDictionaries & getExternalDictionaries() const; void tryCreateEmbeddedDictionaries() const; diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index 9bf69cf0541..dd59e96b4a4 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -883,7 +883,7 @@ void ExpressionAnalyzer::normalizeTreeImpl( { node->kind = ASTFunction::LAMBDA_EXPRESSION; } - else if (context.getAggregateFunctionFactory().isAggregateFunctionName(node->name)) + else if (AggregateFunctionFactory::instance().isAggregateFunctionName(node->name)) { node->kind = ASTFunction::AGGREGATE_FUNCTION; } @@ -2077,7 +2077,7 @@ void ExpressionAnalyzer::getAggregates(const ASTPtr & ast, ExpressionActionsPtr aggregate.argument_names[i] = name; } - aggregate.function = context.getAggregateFunctionFactory().get(node->name, types); + aggregate.function = AggregateFunctionFactory::instance().get(node->name, types); if (node->parameters) { diff --git a/dbms/src/Interpreters/tests/CMakeLists.txt b/dbms/src/Interpreters/tests/CMakeLists.txt index 3fdce76f906..c143dc3fc94 100644 --- a/dbms/src/Interpreters/tests/CMakeLists.txt +++ b/dbms/src/Interpreters/tests/CMakeLists.txt @@ -8,7 +8,7 @@ add_executable (create_query create_query.cpp) target_link_libraries (create_query dbms) add_executable (select_query select_query.cpp) -target_link_libraries (select_query dbms storages_system) +target_link_libraries (select_query dbms clickhouse_storages_system) add_executable (aggregate aggregate.cpp) target_link_libraries (aggregate dbms) diff --git a/dbms/src/Server/CMakeLists.txt b/dbms/src/Server/CMakeLists.txt index 7335b1d874b..3449db60e1a 100644 --- a/dbms/src/Server/CMakeLists.txt +++ b/dbms/src/Server/CMakeLists.txt @@ -8,10 +8,10 @@ add_library(clickhouse-server StatusFile.cpp ReplicasStatusHandler.cpp ) -target_link_libraries(clickhouse-server daemon storages_system clickhouse_functions) +target_link_libraries(clickhouse-server daemon clickhouse_storages_system clickhouse_functions clickhouse_aggregate_functions) add_library(clickhouse-local LocalServer.cpp) -target_link_libraries(clickhouse-local dbms clickhouse_functions) +target_link_libraries(clickhouse-local dbms clickhouse_functions clickhouse_aggregate_functions) add_library(clickhouse-extract-from-config ExtractFromConfig.cpp) target_link_libraries(clickhouse-extract-from-config dbms) diff --git a/dbms/src/Server/LocalServer.cpp b/dbms/src/Server/LocalServer.cpp index ff22dd84bba..507bd503aa7 100644 --- a/dbms/src/Server/LocalServer.cpp +++ b/dbms/src/Server/LocalServer.cpp @@ -22,6 +22,7 @@ #include #include "StatusFile.h" #include +#include namespace DB @@ -266,6 +267,7 @@ try /// Don't initilaize DateLUT registerFunctions(); + registerAggregateFunctions(); /// Maybe useless if (config().has("macros")) diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 7a0389d93b6..9ef1a22ee94 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -39,6 +39,8 @@ #endif #include +#include + namespace DB { @@ -212,6 +214,7 @@ int Server::main(const std::vector & args) Logger * log = &logger(); registerFunctions(); + registerAggregateFunctions(); /** Context contains all that query execution is dependent: * settings, available functions, data types, aggregate functions, databases... diff --git a/dbms/src/Storages/StorageFactory.cpp b/dbms/src/Storages/StorageFactory.cpp index 0639c700a82..2ecb5c46ddd 100644 --- a/dbms/src/Storages/StorageFactory.cpp +++ b/dbms/src/Storages/StorageFactory.cpp @@ -153,7 +153,7 @@ static void appendGraphitePattern(const Context & context, else if (key == "function") { /// TODO Not only Float64 - pattern.function = context.getAggregateFunctionFactory().get( + pattern.function = AggregateFunctionFactory::instance().get( config.getString(config_element + ".function"), { std::make_shared() }); } else if (startsWith(key, "retention")) diff --git a/dbms/src/Storages/System/CMakeLists.txt b/dbms/src/Storages/System/CMakeLists.txt index 49deb422b83..dae153e4fb1 100644 --- a/dbms/src/Storages/System/CMakeLists.txt +++ b/dbms/src/Storages/System/CMakeLists.txt @@ -1,4 +1,4 @@ include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake) add_headers_and_sources(storages_system .) -add_library(storages_system ${storages_system_headers} ${storages_system_sources}) +add_library(clickhouse_storages_system ${storages_system_headers} ${storages_system_sources}) diff --git a/dbms/src/Storages/System/StorageSystemFunctions.cpp b/dbms/src/Storages/System/StorageSystemFunctions.cpp index e9c7075f11f..98cf8cbe9be 100644 --- a/dbms/src/Storages/System/StorageSystemFunctions.cpp +++ b/dbms/src/Storages/System/StorageSystemFunctions.cpp @@ -49,7 +49,7 @@ BlockInputStreams StorageSystemFunctions::read( column_is_aggregate.column->insert(UInt64(0)); } - const auto & aggregate_functions = context.getAggregateFunctionFactory().aggregate_functions; + const auto & aggregate_functions = AggregateFunctionFactory::instance().aggregate_functions; for (const auto & it : aggregate_functions) { column_name.column->insert(it.first); diff --git a/dbms/src/Storages/tests/CMakeLists.txt b/dbms/src/Storages/tests/CMakeLists.txt index bd0897f969d..663ea09be6e 100644 --- a/dbms/src/Storages/tests/CMakeLists.txt +++ b/dbms/src/Storages/tests/CMakeLists.txt @@ -1,7 +1,7 @@ include_directories (${CMAKE_CURRENT_BINARY_DIR}) add_executable (system_numbers system_numbers.cpp) -target_link_libraries (system_numbers dbms storages_system) +target_link_libraries (system_numbers dbms clickhouse_storages_system) add_executable (storage_log storage_log.cpp) target_link_libraries (storage_log dbms) From 0c72259c3c0bcb3a22e79044c6d22a75075e9a6d Mon Sep 17 00:00:00 2001 From: Dmitry Bilunov Date: Fri, 5 May 2017 18:03:04 +0300 Subject: [PATCH 23/76] mongodb: Avoid compiling DB::authenticate() function unless it is needed --- dbms/src/Dictionaries/MongoDBDictionarySource.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbms/src/Dictionaries/MongoDBDictionarySource.cpp b/dbms/src/Dictionaries/MongoDBDictionarySource.cpp index 4f8b599ae0e..f9108c43803 100644 --- a/dbms/src/Dictionaries/MongoDBDictionarySource.cpp +++ b/dbms/src/Dictionaries/MongoDBDictionarySource.cpp @@ -32,6 +32,7 @@ namespace ErrorCodes static const size_t max_block_size = 8192; +#if POCO_VERSION < 0x01070800 /// See https://pocoproject.org/forum/viewtopic.php?f=10&t=6326&p=11426&hilit=mongodb+auth#p11485 static void authenticate(Poco::MongoDB::Connection & connection, const std::string & database, const std::string & user, const std::string & password) @@ -117,6 +118,7 @@ static void authenticate(Poco::MongoDB::Connection & connection, } } } +#endif MongoDBDictionarySource::MongoDBDictionarySource( From 11ec4c627dec30a7e4f6f5b1f480b7249aa38ad3 Mon Sep 17 00:00:00 2001 From: Dmitry Bilunov Date: Fri, 5 May 2017 18:12:21 +0300 Subject: [PATCH 24/76] IO/CompressedWriteBuffer: support new LZ4 library --- dbms/src/IO/CompressedWriteBuffer.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dbms/src/IO/CompressedWriteBuffer.cpp b/dbms/src/IO/CompressedWriteBuffer.cpp index ba6fbe8307a..eb00b400196 100644 --- a/dbms/src/IO/CompressedWriteBuffer.cpp +++ b/dbms/src/IO/CompressedWriteBuffer.cpp @@ -70,15 +70,18 @@ void CompressedWriteBuffer::nextImpl() compressed_buffer[0] = static_cast(CompressionMethodByte::LZ4); if (method == CompressionMethod::LZ4) - compressed_size = header_size + LZ4_compress( + compressed_size = header_size + LZ4_compress_default( working_buffer.begin(), &compressed_buffer[header_size], - uncompressed_size); + uncompressed_size, + LZ4_COMPRESSBOUND(uncompressed_size)); else - compressed_size = header_size + LZ4_compressHC( + compressed_size = header_size + LZ4_compress_HC( working_buffer.begin(), &compressed_buffer[header_size], - uncompressed_size); + uncompressed_size, + LZ4_COMPRESSBOUND(uncompressed_size), + 0); UInt32 compressed_size_32 = compressed_size; UInt32 uncompressed_size_32 = uncompressed_size; From 6b9fbd2095b8b887f458ff276391364759f05414 Mon Sep 17 00:00:00 2001 From: kmeaw Date: Sat, 6 May 2017 11:29:08 +0300 Subject: [PATCH 25/76] Update lz4 library to the latest stable version (1.7.5, 2016-11-28) --- contrib/liblz4/include/lz4/lz4.h | 385 +++++++++----- contrib/liblz4/include/lz4/lz4hc.h | 255 +++++---- contrib/liblz4/src/lz4.c | 815 ++++++++++++++--------------- contrib/liblz4/src/lz4hc.c | 381 +++++++------- 4 files changed, 957 insertions(+), 879 deletions(-) diff --git a/contrib/liblz4/include/lz4/lz4.h b/contrib/liblz4/include/lz4/lz4.h index 3e740022561..0aae19c9a73 100644 --- a/contrib/liblz4/include/lz4/lz4.h +++ b/contrib/liblz4/include/lz4/lz4.h @@ -1,7 +1,7 @@ /* - LZ4 - Fast LZ compression algorithm - Header File - Copyright (C) 2011-2015, Yann Collet. + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -29,34 +29,79 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ -#pragma once +#ifndef LZ4_H_2983827168210 +#define LZ4_H_2983827168210 #if defined (__cplusplus) extern "C" { #endif -/* - * lz4.h provides block compression functions, and gives full buffer control to programmer. - * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), - * and can let the library handle its own memory, please use lz4frame.h instead. +/* --- Dependency --- */ +#include /* size_t */ + + +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Decompressing an lz4-compressed block also requires metadata (such as compressed size). + Each application is free to encode such metadata in whichever way it wants. + + An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md), + take care of encoding standard metadata alongside LZ4-compressed blocks. + If your application requires interoperability, it's recommended to use it. + A library is provided to take care of it, see lz4frame.h. */ -/************************************** -* Version -**************************************/ +/*^*************************************************************** +* Export parameters +*****************************************************************/ +/* +* LZ4_DLL_EXPORT : +* Enable exporting of functions when building a Windows DLL +*/ +#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) +# define LZ4LIB_API __declspec(dllexport) +#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) +# define LZ4LIB_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define LZ4LIB_API +#endif + + +/*========== Version =========== */ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ -#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) -int LZ4_versionNumber (void); +#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ -/************************************** +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) + +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str +#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) + +LZ4LIB_API int LZ4_versionNumber (void); +LZ4LIB_API const char* LZ4_versionString (void); + + +/*-************************************ * Tuning parameter **************************************/ -/* +/*! * LZ4_MEMORY_USAGE : * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) * Increasing memory usage improves compression ratio @@ -66,15 +111,10 @@ int LZ4_versionNumber (void); #define LZ4_MEMORY_USAGE 14 -/************************************** +/*-************************************ * Simple Functions **************************************/ - -int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); -int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); - -/* -LZ4_compress_default() : +/*! LZ4_compress_default() : Compresses 'sourceSize' bytes from buffer 'source' into already allocated 'dest' buffer of size 'maxDestSize'. Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). @@ -86,9 +126,10 @@ LZ4_compress_default() : sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails + or 0 if compression fails */ +LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); -LZ4_decompress_safe() : +/*! LZ4_decompress_safe() : compressedSize : is the precise full size of the compressed block. maxDecompressedSize : is the size of destination buffer, which must be already allocated. return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) @@ -97,15 +138,16 @@ LZ4_decompress_safe() : This function is protected against buffer overflow exploits, including malicious data packets. It never writes outside output buffer, nor reads outside input buffer. */ +LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); -/************************************** +/*-************************************ * Advanced Functions **************************************/ #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) -/* +/*! LZ4_compressBound() : Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) This function is primarily useful for memory allocation purposes (destination buffer size). @@ -115,9 +157,9 @@ LZ4_compressBound() : return : maximum output size in a "worst case" scenario or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) */ -int LZ4_compressBound(int inputSize); +LZ4LIB_API int LZ4_compressBound(int inputSize); -/* +/*! LZ4_compress_fast() : Same as LZ4_compress_default(), but allows to select an "acceleration" factor. The larger the acceleration value, the faster the algorithm, but also the lesser the compression. @@ -125,21 +167,21 @@ LZ4_compress_fast() : An acceleration value of "1" is the same as regular LZ4_compress_default() Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. */ -int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); +LZ4LIB_API int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); -/* +/*! LZ4_compress_fast_extState() : Same compression function, just using an externally allocated memory space to store compression state. Use LZ4_sizeofState() to know how much memory must be allocated, and allocate it on 8-bytes boundaries (using malloc() typically). Then, provide it as 'void* state' to compression function. */ -int LZ4_sizeofState(void); -int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); +LZ4LIB_API int LZ4_sizeofState(void); +LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); -/* +/*! LZ4_compress_destSize() : Reverse the logic, by compressing as much data as possible from 'source' buffer into already allocated buffer 'dest' of size 'targetDestSize'. @@ -150,10 +192,10 @@ LZ4_compress_destSize() : return : Nb bytes written into 'dest' (necessarily <= targetDestSize) or 0 if compression fails */ -int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); +LZ4LIB_API int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); -/* +/*! LZ4_decompress_fast() : originalSize : is the original and therefore uncompressed size return : the number of bytes read from the source buffer (in other words, the compressed size) @@ -164,9 +206,9 @@ LZ4_decompress_fast() : However, it does not provide any protection against intentionally modified data stream (malicious input). Use this function in trusted environment only (data to decode comes from a trusted source). */ -int LZ4_decompress_fast (const char* source, char* dest, int originalSize); +LZ4LIB_API int LZ4_decompress_fast (const char* source, char* dest, int originalSize); -/* +/*! LZ4_decompress_safe_partial() : This function decompress a compressed block of size 'compressedSize' at position 'source' into destination buffer 'dest' of size 'maxDecompressedSize'. @@ -178,98 +220,73 @@ LZ4_decompress_safe_partial() : If the source stream is detected malformed, the function will stop decoding and return a negative result. This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets */ -int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); +LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); -/*********************************************** +/*-********************************************* * Streaming Compression Functions ***********************************************/ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) -/* - * LZ4_stream_t - * information structure to track an LZ4 stream. - * important : init this structure content before first use ! - * note : only allocated directly the structure if you are statically linking LZ4 - * If you are using liblz4 as a DLL, please use below construction methods instead. +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ + +/*! LZ4_createStream() and LZ4_freeStream() : + * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. + * LZ4_freeStream() releases its memory. */ -typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; +LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); +LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); -/* - * LZ4_resetStream - * Use this function to init an allocated LZ4_stream_t structure +/*! LZ4_resetStream() : + * An LZ4_stream_t structure can be allocated once and re-used multiple times. + * Use this function to init an allocated `LZ4_stream_t` structure and start a new compression. */ -void LZ4_resetStream (LZ4_stream_t* streamPtr); +LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); -/* - * LZ4_createStream will allocate and initialize an LZ4_stream_t structure - * LZ4_freeStream releases its memory. - * In the context of a DLL (liblz4), please use these methods rather than the static struct. - * They are more future proof, in case of a change of LZ4_stream_t size. +/*! LZ4_loadDict() : + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed. + * Return : dictionary size, in bytes (necessarily <= 64 KB) */ -LZ4_stream_t* LZ4_createStream(void); -int LZ4_freeStream (LZ4_stream_t* streamPtr); +LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); -/* - * LZ4_loadDict - * Use this function to load a static dictionary into LZ4_stream. - * Any previous data will be forgotten, only 'dictionary' will remain in memory. - * Loading a size of 0 is allowed. - * Return : dictionary size, in bytes (necessarily <= 64 KB) +/*! LZ4_compress_fast_continue() : + * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. + * Important : Previous data blocks are assumed to still be present and unmodified ! + * 'dst' buffer must be already allocated. + * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. */ -int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); +LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); -/* - * LZ4_compress_fast_continue - * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. - * Important : Previous data blocks are assumed to still be present and unmodified ! - * 'dst' buffer must be already allocated. - * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. - * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. */ -int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); - -/* - * LZ4_saveDict - * If previously compressed data block is not guaranteed to remain available at its memory location - * save it into a safer place (char* safeBuffer) - * Note : you don't need to call LZ4_loadDict() afterwards, - * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() - * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error - */ -int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); +LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); -/************************************************ +/*-********************************************** * Streaming Decompression Functions +* Bufferless synchronous API ************************************************/ +typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defined later) */ -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) -typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; -/* - * LZ4_streamDecode_t - * information structure to track an LZ4 stream. - * init this structure content using LZ4_setStreamDecode or memset() before first use ! - * - * In the context of a DLL (liblz4) please prefer usage of construction methods below. - * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. - * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure - * LZ4_freeStreamDecode releases its memory. +/* creation / destruction of streaming decompression tracking structure */ +LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); +LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/*! LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * Setting a size of 0 is allowed (same effect as reset). + * @return : 1 if OK, 0 if error */ -LZ4_streamDecode_t* LZ4_createStreamDecode(void); -int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); +LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary. - * Setting a size of 0 is allowed (same effect as reset). - * Return : 1 if OK, 0 if error - */ -int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); - -/* -*_continue() : +/*! +LZ4_decompress_*_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) In the case of a ring buffers, decoding buffer must be either : @@ -285,35 +302,120 @@ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dicti Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, and indicate where it is saved using LZ4_setStreamDecode() */ -int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); -int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); +LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); -/* -Advanced decoding functions : -*_usingDict() : - These decoding functions work the same as - a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() - They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. -*/ -int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); -int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); +/*! LZ4_decompress_*_usingDict() : + * These decoding functions work the same as + * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue() + * They are stand-alone, and don't need an LZ4_streamDecode_t structure. + */ +LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); +/*^********************************************** + * !!!!!! STATIC LINKING ONLY !!!!!! + ***********************************************/ +/*-************************************ + * Private definitions + ************************************** + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. + * Using these definitions will expose code to API and/or ABI break in future versions of the library. + **************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ -/************************************** +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +#include + +typedef struct { + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; +} LZ4_stream_t_internal; + +typedef struct { + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#else + +typedef struct { + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned int initCheck; + const unsigned char* dictionary; + unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ + unsigned int dictSize; +} LZ4_stream_t_internal; + +typedef struct { + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#endif + +/*! + * LZ4_stream_t : + * information structure to track an LZ4 stream. + * init this structure before first use. + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +union LZ4_stream_u { + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_stream_t */ + + +/*! + * LZ4_streamDecode_t : + * information structure to track an LZ4 stream during decompression. + * init this structure using LZ4_setStreamDecode (or memset()) before first use + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +union LZ4_streamDecode_u { + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_streamDecode_t */ + + +/*=************************************ * Obsolete Functions **************************************/ -/* Deprecate Warnings */ -/* Should these warnings messages be a problem, +/* Deprecation warnings */ +/* Should these warnings be a problem, it is generally possible to disable them, - with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual for example. - You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ -#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK -# define LZ4_DEPRECATE_WARNING_DEFBLOCK + typically with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */ +#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ +#else # define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# if (LZ4_GCC_VERSION >= 405) || defined(__clang__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LZ4_DEPRECATED(message) [[deprecated(message)]] +# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) # define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) # elif (LZ4_GCC_VERSION >= 301) # define LZ4_DEPRECATED(message) __attribute__((deprecated)) @@ -323,20 +425,19 @@ int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalS # pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") # define LZ4_DEPRECATED(message) # endif -#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ +#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ /* Obsolete compression functions */ -/* These functions are planned to start generate warnings by r131 approximately */ -int LZ4_compress (const char* source, char* dest, int sourceSize); -int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); -int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); -int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); -int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); -int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress (const char* source, char* dest, int sourceSize); +LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); /* Obsolete decompression functions */ /* These function names are completely deprecated and must no longer be used. - They are only provided here for compatibility with older programs. + They are only provided in lz4.c for compatibility with older programs. - LZ4_uncompress is the same as LZ4_decompress_fast - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe These function prototypes are now disabled; uncomment them only if you really need them. @@ -358,3 +459,5 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress #if defined (__cplusplus) } #endif + +#endif /* LZ4_H_2983827168210 */ diff --git a/contrib/liblz4/include/lz4/lz4hc.h b/contrib/liblz4/include/lz4/lz4hc.h index 431f7c87c86..1036fd0bf5c 100644 --- a/contrib/liblz4/include/lz4/lz4hc.h +++ b/contrib/liblz4/include/lz4/lz4hc.h @@ -1,7 +1,7 @@ /* LZ4 HC - High Compression Mode of LZ4 Header File - Copyright (C) 2011-2015, Yann Collet. + Copyright (C) 2011-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without @@ -28,107 +28,92 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 + - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ -#pragma once - +#ifndef LZ4_HC_H_19834876238432 +#define LZ4_HC_H_19834876238432 #if defined (__cplusplus) extern "C" { #endif -/***************************** -* Includes -*****************************/ -#include /* size_t */ +/* --- Dependency --- */ +/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ +#include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ -/************************************** -* Block Compression -**************************************/ -int LZ4_compress_HC (const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel); -/* -LZ4_compress_HC : - Destination buffer 'dst' must be already allocated. - Compression completion is guaranteed if 'dst' buffer is sized to handle worst circumstances (data not compressible) - Worst size evaluation is provided by function LZ4_compressBound() (see "lz4.h") - srcSize : Max supported value is LZ4_MAX_INPUT_SIZE (see "lz4.h") - compressionLevel : Recommended values are between 4 and 9, although any value between 0 and 16 will work. - 0 means "use default value" (see lz4hc.c). - Values >16 behave the same as 16. - return : the number of bytes written into buffer 'dst' - or 0 if compression fails. -*/ +/* --- Useful constants --- */ +#define LZ4HC_CLEVEL_MIN 3 +#define LZ4HC_CLEVEL_DEFAULT 9 +#define LZ4HC_CLEVEL_OPT_MIN 11 +#define LZ4HC_CLEVEL_MAX 12 + + +/*-************************************ + * Block Compression + **************************************/ +/*! LZ4_compress_HC() : + * Compress data from `src` into `dst`, using the more powerful but slower "HC" algorithm. + * `dst` must be already allocated. + * Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see "lz4.h") + * Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see "lz4.h") + * `compressionLevel` : Recommended values are between 4 and 9, although any value between 1 and LZ4HC_MAX_CLEVEL will work. + * Values >LZ4HC_MAX_CLEVEL behave the same as LZ4HC_MAX_CLEVEL. + * @return : the number of bytes written into 'dst' + * or 0 if compression fails. + */ +LZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel); /* Note : - Decompression functions are provided within LZ4 source code (see "lz4.h") (BSD license) -*/ + * Decompression functions are provided within "lz4.h" (BSD license) + */ -int LZ4_sizeofStateHC(void); -int LZ4_compress_HC_extStateHC(void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel); -/* -LZ4_compress_HC_extStateHC() : - Use this function if you prefer to manually allocate memory for compression tables. - To know how much memory must be allocated for the compression tables, use : - int LZ4_sizeofStateHC(); - - Allocated memory must be aligned on 8-bytes boundaries (which a normal malloc() will do properly). - - The allocated memory can then be provided to the compression functions using 'void* state' parameter. - LZ4_compress_HC_extStateHC() is equivalent to previously described function. - It just uses externally allocated memory for stateHC. -*/ +/*! LZ4_compress_HC_extStateHC() : + * Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`. + * `state` size is provided by LZ4_sizeofStateHC(). + * Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() will do properly). + */ +LZ4LIB_API int LZ4_compress_HC_extStateHC(void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel); +LZ4LIB_API int LZ4_sizeofStateHC(void); -/************************************** -* Streaming Compression -**************************************/ -#define LZ4_STREAMHCSIZE 262192 -#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t)) -typedef struct { size_t table[LZ4_STREAMHCSIZE_SIZET]; } LZ4_streamHC_t; -/* - LZ4_streamHC_t - This structure allows static allocation of LZ4 HC streaming state. - State must then be initialized using LZ4_resetStreamHC() before first use. +/*-************************************ + * Streaming Compression + * Bufferless synchronous API + **************************************/ + typedef union LZ4_streamHC_u LZ4_streamHC_t; /* incomplete type (defined later) */ - Static allocation should only be used in combination with static linking. - If you want to use LZ4 as a DLL, please use construction functions below, which are future-proof. -*/ +/*! LZ4_createStreamHC() and LZ4_freeStreamHC() : + * These functions create and release memory for LZ4 HC streaming state. + * Newly created states are automatically initialized. + * Existing states can be re-used several times, using LZ4_resetStreamHC(). + * These methods are API and ABI stable, they can be used in combination with a DLL. + */ +LZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void); +LZ4LIB_API int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr); +LZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel); +LZ4LIB_API int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize); -LZ4_streamHC_t* LZ4_createStreamHC(void); -int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr); -/* - These functions create and release memory for LZ4 HC streaming state. - Newly created states are already initialized. - Existing state space can be re-used anytime using LZ4_resetStreamHC(). - If you use LZ4 as a DLL, use these functions instead of static structure allocation, - to avoid size mismatch between different versions. -*/ +LZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize); -void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel); -int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize); - -int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize); - -int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize); +LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize); /* These functions compress data in successive blocks of any size, using previous blocks as dictionary. One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks. - There is an exception for ring buffers, which can be smaller 64 KB. - Such case is automatically detected and correctly handled by LZ4_compress_HC_continue(). + There is an exception for ring buffers, which can be smaller than 64 KB. + Ring buffers scenario is automatically detected and handled by LZ4_compress_HC_continue(). Before starting compression, state must be properly initialized, using LZ4_resetStreamHC(). A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional). Then, use LZ4_compress_HC_continue() to compress each successive block. - It works like LZ4_compress_HC(), but use previous memory blocks as dictionary to improve compression. Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression. - As a reminder, size 'dst' buffer to handle worst cases, using LZ4_compressBound(), to ensure success of compression operation. + 'dst' buffer should be sized to handle worst case scenarios, using LZ4_compressBound(), to ensure operation success. If, for any reason, previous data blocks can't be preserved unmodified in memory during next compression block, you must save it to a safer memory space, using LZ4_saveDictHC(). @@ -136,50 +121,102 @@ int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSi */ +/*-****************************************** + * !!!!! STATIC LINKING ONLY !!!!! + *******************************************/ -/************************************** + /*-************************************* + * PRIVATE DEFINITIONS : + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_streamHC_t`. + * Using these definitions makes the code vulnerable to potential API break when upgrading LZ4 + **************************************/ +#define LZ4HC_DICTIONARY_LOGSIZE 17 +#define LZ4HC_MAXD (1<= 199901L) /* C99 */) +#include + +typedef struct +{ + uint32_t hashTable[LZ4HC_HASHTABLESIZE]; + uint16_t chainTable[LZ4HC_MAXD]; + const uint8_t* end; /* next block here to continue on current prefix */ + const uint8_t* base; /* All index relative to this position */ + const uint8_t* dictBase; /* alternate base for extDict */ + uint8_t* inputBuffer; /* deprecated */ + uint32_t dictLimit; /* below that point, need extDict */ + uint32_t lowLimit; /* below that point, no more dict */ + uint32_t nextToUpdate; /* index from which to continue dictionary update */ + uint32_t searchNum; /* only for optimal parser */ + uint32_t compressionLevel; +} LZ4HC_CCtx_internal; + +#else + +typedef struct +{ + unsigned int hashTable[LZ4HC_HASHTABLESIZE]; + unsigned short chainTable[LZ4HC_MAXD]; + const unsigned char* end; /* next block here to continue on current prefix */ + const unsigned char* base; /* All index relative to this position */ + const unsigned char* dictBase; /* alternate base for extDict */ + unsigned char* inputBuffer; /* deprecated */ + unsigned int dictLimit; /* below that point, need extDict */ + unsigned int lowLimit; /* below that point, no more dict */ + unsigned int nextToUpdate; /* index from which to continue dictionary update */ + unsigned int searchNum; /* only for optimal parser */ + unsigned int compressionLevel; +} LZ4HC_CCtx_internal; + +#endif + +#define LZ4_STREAMHCSIZE (4*LZ4HC_HASHTABLESIZE + 2*LZ4HC_MAXD + 56) /* 393268 */ +#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t)) +union LZ4_streamHC_u { + size_t table[LZ4_STREAMHCSIZE_SIZET]; + LZ4HC_CCtx_internal internal_donotuse; +}; /* previously typedef'd to LZ4_streamHC_t */ +/* + LZ4_streamHC_t : + This structure allows static allocation of LZ4 HC streaming state. + State must be initialized using LZ4_resetStreamHC() before first use. + + Static allocation shall only be used in combination with static linking. + When invoking LZ4 from a DLL, use create/free functions instead, which are API and ABI stable. +*/ + + +/*-************************************ * Deprecated Functions **************************************/ -/* Deprecate Warnings */ -/* Should these warnings messages be a problem, - it is generally possible to disable them, - with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual for example. - You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ -#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK -# define LZ4_DEPRECATE_WARNING_DEFBLOCK -# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# if (LZ4_GCC_VERSION >= 405) || defined(__clang__) -# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (LZ4_GCC_VERSION >= 301) -# define LZ4_DEPRECATED(message) __attribute__((deprecated)) -# elif defined(_MSC_VER) -# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) -# else -# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") -# define LZ4_DEPRECATED(message) -# endif -#endif // LZ4_DEPRECATE_WARNING_DEFBLOCK +/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */ -/* compression functions */ -/* these functions are planned to trigger warning messages by r131 approximately */ -int LZ4_compressHC (const char* source, char* dest, int inputSize); -int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); -int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel); -int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); -int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize); -int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); -int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel); -int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); -int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize); -int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize); +/* deprecated compression functions */ +/* these functions will trigger warning messages in future releases */ +LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC (const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize); -/* Streaming functions following the older model; should no longer be used */ +/* Deprecated Streaming functions using older model; should no longer be used */ LZ4_DEPRECATED("use LZ4_createStreamHC() instead") void* LZ4_createHC (char* inputBuffer); LZ4_DEPRECATED("use LZ4_saveDictHC() instead") char* LZ4_slideInputBufferHC (void* LZ4HC_Data); LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") int LZ4_freeHC (void* LZ4HC_Data); -LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel); -LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel); +LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); LZ4_DEPRECATED("use LZ4_createStreamHC() instead") int LZ4_sizeofStreamStateHC(void); LZ4_DEPRECATED("use LZ4_resetStreamHC() instead") int LZ4_resetStreamStateHC(void* state, char* inputBuffer); @@ -187,3 +224,5 @@ LZ4_DEPRECATED("use LZ4_resetStreamHC() instead") int LZ4_resetStreamStateHC( #if defined (__cplusplus) } #endif + +#endif /* LZ4_HC_H_19834876238432 */ diff --git a/contrib/liblz4/src/lz4.c b/contrib/liblz4/src/lz4.c index 47f3200bed2..143c36e1a74 100644 --- a/contrib/liblz4/src/lz4.c +++ b/contrib/liblz4/src/lz4.c @@ -1,6 +1,6 @@ /* LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2015, Yann Collet. + Copyright (C) 2011-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -28,12 +28,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ -/************************************** +/*-************************************ * Tuning parameters **************************************/ /* @@ -41,7 +41,9 @@ * Select how default compression functions will allocate memory for their hash table, * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). */ -#define HEAPMODE 0 +#ifndef HEAPMODE +# define HEAPMODE 0 +#endif /* * ACCELERATION_DEFAULT : @@ -50,9 +52,31 @@ #define ACCELERATION_DEFAULT 1 -/************************************** +/*-************************************ * CPU Feature Detection **************************************/ +/* LZ4_FORCE_MEMORY_ACCESS + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets which generate assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define LZ4_FORCE_MEMORY_ACCESS 2 +# elif defined(__INTEL_COMPILER) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define LZ4_FORCE_MEMORY_ACCESS 1 +# endif +#endif + /* * LZ4_FORCE_SW_BITCOUNT * Define this parameter if your target system or compiler does not support hardware bit count @@ -62,13 +86,14 @@ #endif -/************************************** -* Includes +/*-************************************ +* Dependency **************************************/ -#include +#include "lz4.h" +/* see also "memory routines" below */ -/************************************** +/*-************************************ * Compiler Options **************************************/ #ifdef _MSC_VER /* Visual Studio */ @@ -77,19 +102,16 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else -# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -# if defined(__GNUC__) || defined(__clang__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif +# if defined(__GNUC__) || defined(__clang__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# elif defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define FORCE_INLINE static inline # else # define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ +# endif #endif /* _MSC_VER */ -/* LZ4_GCC_VERSION is defined into lz4.h */ -#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) @@ -99,7 +121,7 @@ #define unlikely(expr) expect((expr) != 0, 0) -/************************************** +/*-************************************ * Memory routines **************************************/ #include /* malloc, calloc, free */ @@ -109,54 +131,100 @@ #define MEM_INIT memset -/************************************** +/*-************************************ * Basic Types **************************************/ -#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; + typedef uintptr_t uptrval; #else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; + typedef size_t uptrval; /* generally true, except OpenVMS-64 */ #endif +#if defined(__x86_64__) + typedef U64 reg_t; /* 64-bits in x32 mode */ +#else + typedef size_t reg_t; /* 32-bits in x32 mode */ +#endif -/************************************** +/*-************************************ * Reading and writing into memory **************************************/ -#define STEPSIZE sizeof(size_t) - -static unsigned LZ4_64bits(void) { return sizeof(void*)==8; } - static unsigned LZ4_isLittleEndian(void) { - const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; } +#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) +/* lie to the compiler about data alignment; use with caution */ + +static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } +static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } +static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } + +static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } + +#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; + +static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } + +static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } +static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } + +#else /* safe and portable access through memcpy() */ + static U16 LZ4_read16(const void* memPtr) { - U16 val16; - memcpy(&val16, memPtr, 2); - return val16; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } +static U32 LZ4_read32(const void* memPtr) +{ + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static void LZ4_write16(void* memPtr, U16 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static void LZ4_write32(void* memPtr, U32 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* LZ4_FORCE_MEMORY_ACCESS */ + + static U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) - { + if (LZ4_isLittleEndian()) { return LZ4_read16(memPtr); - } - else - { + } else { const BYTE* p = (const BYTE*)memPtr; return (U16)((U16)p[0] + (p[1]<<8)); } @@ -164,63 +232,39 @@ static U16 LZ4_readLE16(const void* memPtr) static void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) - { - memcpy(memPtr, &value, 2); - } - else - { + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { BYTE* p = (BYTE*)memPtr; p[0] = (BYTE) value; p[1] = (BYTE)(value>>8); } } -static U32 LZ4_read32(const void* memPtr) +static void LZ4_copy8(void* dst, const void* src) { - U32 val32; - memcpy(&val32, memPtr, 4); - return val32; + memcpy(dst,src,8); } -static U64 LZ4_read64(const void* memPtr) -{ - U64 val64; - memcpy(&val64, memPtr, 8); - return val64; -} - -static size_t LZ4_read_ARCH(const void* p) -{ - if (LZ4_64bits()) - return (size_t)LZ4_read64(p); - else - return (size_t)LZ4_read32(p); -} - - -static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); } - -static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); } - -/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */ +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; - BYTE* e = (BYTE*)dstEnd; + BYTE* const e = (BYTE*)dstEnd; + do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctzll((U64)val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; # endif - } - else /* 32 bits */ - { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; _BitScanForward( &r, (U32)val ); return (int)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctz((U32)val) >> 3); # else static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; # endif } - } - else /* Big Endian CPU */ - { - if (LZ4_64bits()) - { + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { # if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse64( &r, val ); return (unsigned)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clzll((U64)val) >> 3); # else unsigned r; @@ -293,14 +330,12 @@ static unsigned LZ4_NbCommonBytes (register size_t val) r += (!val); return r; # endif - } - else /* 32 bits */ - { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse( &r, (unsigned long)val ); return (unsigned)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clz((U32)val) >> 3); # else unsigned r; @@ -312,19 +347,19 @@ static unsigned LZ4_NbCommonBytes (register size_t val) } } +#define STEPSIZE sizeof(reg_t) static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { const BYTE* const pStart = pIn; - while (likely(pIn compression run slower on incompressible data */ -/************************************** +/*-************************************ * Local Structures and types **************************************/ -typedef struct { - U32 hashTable[HASH_SIZE_U32]; - U32 currentOffset; - U32 initCheck; - const BYTE* dictionary; - BYTE* bufferStart; /* obsolete, used for slideInputBuffer */ - U32 dictSize; -} LZ4_stream_t_internal; - typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; typedef enum { byPtr, byU32, byU16 } tableType_t; @@ -365,44 +387,43 @@ typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; typedef enum { full = 0, partial = 1 } earlyEnd_directive; -/************************************** +/*-************************************ * Local Utils **************************************/ int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } int LZ4_sizeofState() { return LZ4_STREAMSIZE; } - -/******************************** +/*-****************************** * Compression functions ********************************/ - -static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) +static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -static const U64 prime5bytes = 889523592379ULL; -static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) +static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - const U32 hashMask = (1<> (40 - hashLog)) & hashMask; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } -static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) +FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if (LZ4_64bits()) - return LZ4_hashSequence64(sequence, tableType); - return LZ4_hashSequence((U32)sequence, tableType); + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); } -static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); } - static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { switch (tableType) @@ -413,27 +434,30 @@ static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableTy } } -static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 h = LZ4_hashPosition(p, tableType); + U32 const h = LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } - if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ + if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ } -static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 h = LZ4_hashPosition(p, tableType); + U32 const h = LZ4_hashPosition(p, tableType); return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } + +/** LZ4_compress_generic() : + inlined, to ensure branches are decided at compilation time */ FORCE_INLINE int LZ4_compress_generic( - void* const ctx, + LZ4_stream_t_internal* const cctx, const char* const source, char* const dest, const int inputSize, @@ -444,15 +468,13 @@ FORCE_INLINE int LZ4_compress_generic( const dictIssue_directive dictIssue, const U32 acceleration) { - LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx; - const BYTE* ip = (const BYTE*) source; const BYTE* base; const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - dictPtr->dictSize; - const BYTE* const dictionary = dictPtr->dictionary; - const BYTE* const dictEnd = dictionary + dictPtr->dictSize; - const size_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* const lowRefLimit = ip - cctx->dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimit = iend - MFLIMIT; @@ -462,10 +484,9 @@ FORCE_INLINE int LZ4_compress_generic( BYTE* const olimit = op + maxOutputSize; U32 forwardH; - size_t refDelta=0; /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ switch(dict) { case noDict: @@ -474,11 +495,11 @@ FORCE_INLINE int LZ4_compress_generic( lowLimit = (const BYTE*)source; break; case withPrefix64k: - base = (const BYTE*)source - dictPtr->currentOffset; - lowLimit = (const BYTE*)source - dictPtr->dictSize; + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; break; case usingExtDict: - base = (const BYTE*)source - dictPtr->currentOffset; + base = (const BYTE*)source - cctx->currentOffset; lowLimit = (const BYTE*)source; break; } @@ -486,44 +507,38 @@ FORCE_INLINE int LZ4_compress_generic( if (inputSizehashTable, tableType, base); ip++; forwardH = LZ4_hashPosition(ip, tableType); /* Main Loop */ - for ( ; ; ) - { + for ( ; ; ) { + ptrdiff_t refDelta = 0; const BYTE* match; BYTE* token; - { - const BYTE* forwardIp = ip; + + /* Find a match */ + { const BYTE* forwardIp = ip; unsigned step = 1; unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - - /* Find a match */ do { - U32 h = forwardH; + U32 const h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); if (unlikely(forwardIp > mflimit)) goto _last_literals; - match = LZ4_getPositionOnHash(h, ctx, tableType, base); - if (dict==usingExtDict) - { - if (match<(const BYTE*)source) - { + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { refDelta = dictDelta; lowLimit = dictionary; - } - else - { + } else { refDelta = 0; lowLimit = (const BYTE*)source; - } - } + } } forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) @@ -531,18 +546,17 @@ FORCE_INLINE int LZ4_compress_generic( } /* Catch up */ - while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } + while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); token = op++; - if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) - return 0; /* Check output limit */ - if (litLength>=RUN_MASK) - { + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { int len = (int)litLength-RUN_MASK; - *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } @@ -558,41 +572,37 @@ _next_match: LZ4_writeLE16(op, (U16)(ip-match)); op+=2; /* Encode MatchLength */ - { - unsigned matchLength; + { unsigned matchCode; - if ((dict==usingExtDict) && (lowLimit==dictionary)) - { + if ((dict==usingExtDict) && (lowLimit==dictionary)) { const BYTE* limit; match += refDelta; limit = ip + (dictEnd-match); if (limit > matchlimit) limit = matchlimit; - matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchLength; - if (ip==limit) - { - unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchLength += more; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; ip += more; } - } - else - { - matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchLength; + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; } - if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) - return 0; /* Check output limit */ - if (matchLength>=ML_MASK) - { + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { *token += ML_MASK; - matchLength -= ML_MASK; - for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } - if (matchLength >= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; - } - else *token += (BYTE)(matchLength); + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); } anchor = ip; @@ -601,24 +611,19 @@ _next_match: if (ip > mflimit) break; /* Fill table */ - LZ4_putPosition(ip-2, ctx, tableType, base); + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - if (dict==usingExtDict) - { - if (match<(const BYTE*)source) - { + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { refDelta = dictDelta; lowLimit = dictionary; - } - else - { + } else { refDelta = 0; lowLimit = (const BYTE*)source; - } - } - LZ4_putPosition(ip, ctx, tableType, base); + } } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) && (match+MAX_DISTANCE>=ip) && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) @@ -630,19 +635,16 @@ _next_match: _last_literals: /* Encode Last Literals */ - { - const size_t lastRun = (size_t)(iend - anchor); - if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) - return 0; /* Check output limit */ - if (lastRun >= RUN_MASK) - { + { size_t const lastRun = (size_t)(iend - anchor); + if ( (outputLimited) && /* Check output buffer overflow */ + ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; - } - else - { + } else { *op++ = (BYTE)(lastRun<internal_donotuse; LZ4_resetStream((LZ4_stream_t*)state); if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - if (maxOutputSize >= LZ4_compressBound(inputSize)) - { + if (maxOutputSize >= LZ4_compressBound(inputSize)) { if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); else - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } - else - { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } else { if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); else - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); } } @@ -682,10 +682,10 @@ int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutp void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else LZ4_stream_t ctx; - void* ctxPtr = &ctx; + void* const ctxPtr = &ctx; #endif - int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) FREEMEM(ctxPtr); @@ -705,22 +705,21 @@ int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxO int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t ctx; - LZ4_resetStream(&ctx); if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); else - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); } -/******************************** -* destSize variant +/*-****************************** +* *_destSize() variant ********************************/ static int LZ4_compress_destSize_generic( - void* const ctx, + LZ4_stream_t_internal* const ctx, const char* const src, char* const dst, int* const srcSizePtr, @@ -752,32 +751,30 @@ static int LZ4_compress_destSize_generic( /* First Byte */ *srcSizePtr = 0; - LZ4_putPosition(ip, ctx, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); ip++; forwardH = LZ4_hashPosition(ip, tableType); /* Main Loop */ - for ( ; ; ) - { + for ( ; ; ) { const BYTE* match; BYTE* token; - { - const BYTE* forwardIp = ip; + + /* Find a match */ + { const BYTE* forwardIp = ip; unsigned step = 1; unsigned searchMatchNb = 1 << LZ4_skipTrigger; - /* Find a match */ do { U32 h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); - if (unlikely(forwardIp > mflimit)) - goto _last_literals; + if (unlikely(forwardIp > mflimit)) goto _last_literals; - match = LZ4_getPositionOnHash(h, ctx, tableType, base); + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) || (LZ4_read32(match) != LZ4_read32(ip)) ); @@ -786,18 +783,15 @@ static int LZ4_compress_destSize_generic( /* Catch up */ while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); token = op++; - if (op + ((litLength+240)/255) + litLength > oMaxLit) - { + if (op + ((litLength+240)/255) + litLength > oMaxLit) { /* Not enough space for a last match */ op--; goto _last_literals; } - if (litLength>=RUN_MASK) - { + if (litLength>=RUN_MASK) { unsigned len = litLength - RUN_MASK; *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; @@ -815,21 +809,15 @@ _next_match: LZ4_writeLE16(op, (U16)(ip-match)); op+=2; /* Encode MatchLength */ - { - size_t matchLength; + { size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - - if (op + ((matchLength+240)/255) > oMaxMatch) - { + if (op + ((matchLength+240)/255) > oMaxMatch) { /* Match description too long : reduce it */ matchLength = (15-1) + (oMaxMatch-op) * 255; } - //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH); ip += MINMATCH + matchLength; - if (matchLength>=ML_MASK) - { + if (matchLength>=ML_MASK) { *token += ML_MASK; matchLength -= ML_MASK; while (matchLength >= 255) { matchLength-=255; *op++ = 255; } @@ -845,11 +833,11 @@ _next_match: if (op > oMaxSeq) break; /* Fill table */ - LZ4_putPosition(ip-2, ctx, tableType, base); + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - LZ4_putPosition(ip, ctx, tableType, base); + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); if ( (match+MAX_DISTANCE>=ip) && (LZ4_read32(match)==LZ4_read32(ip)) ) { token=op++; *token=0; goto _next_match; } @@ -860,25 +848,20 @@ _next_match: _last_literals: /* Encode Last Literals */ - { - size_t lastRunSize = (size_t)(iend - anchor); - if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) - { + { size_t lastRunSize = (size_t)(iend - anchor); + if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { /* adapt lastRunSize to fill 'dst' */ lastRunSize = (oend-op) - 1; lastRunSize -= (lastRunSize+240)/255; } ip = anchor + lastRunSize; - if (lastRunSize >= RUN_MASK) - { + if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; - } - else - { + } else { *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */ - { + if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); - } - else - { + } else { if (*srcSizePtr < LZ4_64Klimit) - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16); + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); else - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr); + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); } } @@ -912,10 +892,10 @@ static int LZ4_compress_destSize_extState (void* state, const char* src, char* d int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (HEAPMODE) - void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else LZ4_stream_t ctxBody; - void* ctx = &ctxBody; + LZ4_stream_t* ctx = &ctxBody; #endif int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); @@ -928,7 +908,7 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe -/******************************** +/*-****************************** * Streaming functions ********************************/ @@ -952,10 +932,10 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream) } -#define HASH_UNIT sizeof(size_t) +#define HASH_UNIT sizeof(reg_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { - LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; const BYTE* p = (const BYTE*)dictionary; const BYTE* const dictEnd = p + dictSize; const BYTE* base; @@ -963,8 +943,7 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ LZ4_resetStream(LZ4_dict); - if (dictSize < (int)HASH_UNIT) - { + if (dictSize < (int)HASH_UNIT) { dict->dictionary = NULL; dict->dictSize = 0; return 0; @@ -977,8 +956,7 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) dict->dictSize = (U32)(dictEnd - p); dict->currentOffset += dict->dictSize; - while (p <= dictEnd-HASH_UNIT) - { + while (p <= dictEnd-HASH_UNIT) { LZ4_putPosition(p, dict->hashTable, byU32, base); p+=3; } @@ -990,14 +968,12 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) { if ((LZ4_dict->currentOffset > 0x80000000) || - ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ - { + ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ /* rescale hash table */ - U32 delta = LZ4_dict->currentOffset - 64 KB; + U32 const delta = LZ4_dict->currentOffset - 64 KB; const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; - for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; else LZ4_dict->hashTable[i] -= delta; } @@ -1010,7 +986,7 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; const BYTE* smallest = (const BYTE*) source; @@ -1020,10 +996,8 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; /* Check overlapping input/dictionary space */ - { - const BYTE* sourceEnd = (const BYTE*) source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) - { + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; @@ -1032,25 +1006,23 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch } /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) - { + if (dictEnd == (const BYTE*)source) { int result; if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); streamPtr->dictSize += (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; return result; } /* external dictionary mode */ - { - int result; + { int result; if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; streamPtr->currentOffset += (U32)inputSize; @@ -1062,15 +1034,15 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch /* Hidden debug function, to force external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) { - LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; int result; const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; const BYTE* smallest = dictEnd; if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; - LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); + LZ4_renormDictT(streamPtr, smallest); - result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; @@ -1080,10 +1052,17 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* } +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { - LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; - const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; @@ -1098,14 +1077,14 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) -/******************************* +/*-***************************** * Decompression functions *******************************/ -/* - * This generic decompression function cover all use cases. - * It shall be instantiated several times, using different sets of directives - * Note that it is essential this generic function is really inlined, - * in order to remove useless branches during compilation optimization. +/*! LZ4_decompress_generic() : + * This generic decompression function cover all use cases. + * It shall be instantiated several times, using different sets of directives + * Note that it is important this generic function is really inlined, + * in order to remove useless branches during compilation optimization. */ FORCE_INLINE int LZ4_decompress_generic( const char* const source, @@ -1117,7 +1096,7 @@ FORCE_INLINE int LZ4_decompress_generic( int partialDecoding, /* full, partial */ int targetOutputSize, /* only used if partialDecoding==partial */ int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest if dict == noDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) @@ -1133,53 +1112,45 @@ FORCE_INLINE int LZ4_decompress_generic( const BYTE* const lowLimit = lowPrefix - dictSize; const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; - const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; + const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; const int safeDecode = (endOnInput==endOnInputSize); const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); /* Special cases */ - if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - - /* Main Loop */ - while (1) - { - unsigned token; + /* Main Loop : decode sequences */ + while (1) { size_t length; const BYTE* match; + size_t offset; /* get literal length */ - token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) - { + unsigned const token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) { unsigned s; - do - { + do { s = *ip++; length += s; - } - while (likely((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-COPYLENGTH))) + if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) { - if (partialDecoding) - { + if (partialDecoding) { if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } - else - { + } else { if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ } @@ -1192,84 +1163,76 @@ FORCE_INLINE int LZ4_decompress_generic( ip += length; op = cpy; /* get offset */ - match = cpy - LZ4_readLE16(ip); ip+=2; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ /* get matchlength */ length = token & ML_MASK; - if (length == ML_MASK) - { + if (length == ML_MASK) { unsigned s; - do - { - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + do { s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; length += s; } while (s==255); - if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ } length += MINMATCH; /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) - { + if ((dict==usingExtDict) && (match < lowPrefix)) { if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - if (length <= (size_t)(lowPrefix-match)) - { + if (length <= (size_t)(lowPrefix-match)) { /* match can be copied as a single segment from external dictionary */ - match = dictEnd - (lowPrefix-match); - memmove(op, match, length); op += length; - } - else - { - /* match encompass external dictionary and current segment */ - size_t copySize = (size_t)(lowPrefix-match); + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; memcpy(op, dictEnd - copySize, copySize); op += copySize; - copySize = length - copySize; - if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */ - { - BYTE* const endOfMatch = op + copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; - } - else - { - memcpy(op, lowPrefix, copySize); - op += copySize; - } - } + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } continue; } - /* copy repeated sequence */ + /* copy match within block */ cpy = op + length; - if (unlikely((op-match)<8)) - { - const size_t dec64 = dec64table[op-match]; + if (unlikely(offset<8)) { + const int dec64 = dec64table[offset]; op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; - match += dec32table[op-match]; - LZ4_copy4(op+4, match); - op += 8; match -= dec64; - } else { LZ4_copy8(op, match); op+=8; match+=8; } + match += dec32table[offset]; + memcpy(op+4, match, 4); + match -= dec64; + } else { LZ4_copy8(op, match); match+=8; } + op += 8; - if (unlikely(cpy>oend-12)) - { - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */ - if (op < oend-8) - { - LZ4_wildCopy(op, match, oend-8); - match += (oend-8) - op; - op = oend-8; + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; } while (op16) LZ4_wildCopy(op+8, match+8, cpy); } - else - LZ4_wildCopy(op, match, cpy); op=cpy; /* correction */ } @@ -1301,15 +1264,7 @@ int LZ4_decompress_fast(const char* source, char* dest, int originalSize) } -/* streaming decompression functions */ - -typedef struct -{ - const BYTE* externalDict; - size_t extDictSize; - const BYTE* prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; +/*===== streaming decompression functions =====*/ /* * If you prefer dynamic allocation methods, @@ -1328,16 +1283,16 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) return 0; } -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary +/*! + * LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. * This function is not necessary if previous data is still available where it was decoded. * Loading a size of 0 is allowed (same effect as no dictionary). * Return : 1 if OK, 0 if error */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; lz4sd->prefixSize = (size_t) dictSize; lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; lz4sd->externalDict = NULL; @@ -1354,20 +1309,17 @@ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dicti */ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE*)dest) - { + if (lz4sd->prefixEnd == (BYTE*)dest) { result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += result; lz4sd->prefixEnd += result; - } - else - { + } else { lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, @@ -1383,22 +1335,19 @@ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE*)dest) - { + if (lz4sd->prefixEnd == (BYTE*)dest) { result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += originalSize; lz4sd->prefixEnd += originalSize; - } - else - { + } else { lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); @@ -1422,8 +1371,7 @@ FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest { if (dictSize==0) return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); - if (dictStart+dictSize == dest) - { + if (dictStart+dictSize == dest) { if (dictSize >= (int)(64 KB - 1)) return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); @@ -1448,7 +1396,7 @@ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compres } -/*************************************************** +/*=************************************************* * Obsolete Functions ***************************************************/ /* obsolete compression functions */ @@ -1473,29 +1421,29 @@ int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } -static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base) +static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) { - MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); - lz4ds->bufferStart = base; + MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); + lz4ds->internal_donotuse.bufferStart = base; } int LZ4_resetStreamState(void* state, char* inputBuffer) { - if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer); + if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); return 0; } void* LZ4_create (char* inputBuffer) { - void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer); + LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); + LZ4_init (lz4ds, (BYTE*)inputBuffer); return lz4ds; } char* LZ4_slideInputBuffer (void* LZ4_Data) { - LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data; + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); return (char*)(ctx->bufferStart + dictSize); } @@ -1513,4 +1461,3 @@ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int origin } #endif /* LZ4_COMMONDEFS_ONLY */ - diff --git a/contrib/liblz4/src/lz4hc.c b/contrib/liblz4/src/lz4hc.c index 8cc1a3398da..5d4ea3e6328 100644 --- a/contrib/liblz4/src/lz4hc.c +++ b/contrib/liblz4/src/lz4hc.c @@ -1,6 +1,6 @@ /* LZ4 HC - High Compression Mode of LZ4 - Copyright (C) 2011-2015, Yann Collet. + Copyright (C) 2011-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -28,27 +28,36 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 + - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ +/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ - -/************************************** +/* ************************************* * Tuning Parameter -**************************************/ -static const int LZ4HC_compressionLevel_default = 9; +***************************************/ + +/*! + * HEAPMODE : + * Select how default compression function will allocate workplace memory, + * in stack (0:fastest), or in heap (1:requires malloc()). + * Since workplace is rather large, heap mode is recommended. + */ +#ifndef LZ4HC_HEAPMODE +# define LZ4HC_HEAPMODE 1 +#endif -/************************************** -* Includes -**************************************/ -#include +/* ************************************* +* Dependency +***************************************/ +#include "lz4hc.h" -/************************************** +/* ************************************* * Local Compiler Options -**************************************/ +***************************************/ #if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wunused-function" #endif @@ -58,52 +67,24 @@ static const int LZ4HC_compressionLevel_default = 9; #endif -/************************************** +/* ************************************* * Common LZ4 definition -**************************************/ +***************************************/ #define LZ4_COMMONDEFS_ONLY #include "lz4.c" -/************************************** +/* ************************************* * Local Constants -**************************************/ -#define DICTIONARY_LOGSIZE 16 -#define MAXD (1<> ((MINMATCH*8)-HASH_LOG)) -//#define DELTANEXTU16(p) chainTable[(p) & MAXD_MASK] /* flexible, MAXD dependent */ +#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG)) +#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */ #define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } @@ -113,7 +94,7 @@ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr) /************************************** * HC Compression **************************************/ -static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start) +static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start) { MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); @@ -127,21 +108,20 @@ static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start) /* Update chains up to ip (excluded) */ -FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip) +FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) { - U16* chainTable = hc4->chainTable; - U32* HashTable = hc4->hashTable; + U16* const chainTable = hc4->chainTable; + U32* const hashTable = hc4->hashTable; const BYTE* const base = hc4->base; - const U32 target = (U32)(ip - base); + U32 const target = (U32)(ip - base); U32 idx = hc4->nextToUpdate; - while(idx < target) - { - U32 h = LZ4HC_hashPtr(base+idx); - size_t delta = idx - HashTable[h]; + while (idx < target) { + U32 const h = LZ4HC_hashPtr(base+idx); + size_t delta = idx - hashTable[h]; if (delta>MAX_DISTANCE) delta = MAX_DISTANCE; DELTANEXTU16(idx) = (U16)delta; - HashTable[h] = idx; + hashTable[h] = idx; idx++; } @@ -149,7 +129,7 @@ FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip) } -FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* Index table will be updated */ +FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLimit, const BYTE** matchpos, const int maxNbAttempts) @@ -161,7 +141,6 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* I const U32 dictLimit = hc4->dictLimit; const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); U32 matchIndex; - const BYTE* match; int nbAttempts=maxNbAttempts; size_t ml=0; @@ -169,24 +148,19 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* I LZ4HC_Insert(hc4, ip); matchIndex = HashTable[LZ4HC_hashPtr(ip)]; - while ((matchIndex>=lowLimit) && (nbAttempts)) - { + while ((matchIndex>=lowLimit) && (nbAttempts)) { nbAttempts--; - if (matchIndex >= dictLimit) - { - match = base + matchIndex; + if (matchIndex >= dictLimit) { + const BYTE* const match = base + matchIndex; if (*(match+ml) == *(ip+ml) && (LZ4_read32(match) == LZ4_read32(ip))) { - size_t mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH; + size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH; if (mlt > ml) { ml = mlt; *matchpos = match; } } - } - else - { - match = dictBase + matchIndex; - if (LZ4_read32(match) == LZ4_read32(ip)) - { + } else { + const BYTE* const match = dictBase + matchIndex; + if (LZ4_read32(match) == LZ4_read32(ip)) { size_t mlt; const BYTE* vLimit = ip + (dictLimit - matchIndex); if (vLimit > iLimit) vLimit = iLimit; @@ -204,7 +178,7 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* I FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( - LZ4HC_Data_Structure* hc4, + LZ4HC_CCtx_internal* hc4, const BYTE* const ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, @@ -229,38 +203,32 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( LZ4HC_Insert(hc4, ip); matchIndex = HashTable[LZ4HC_hashPtr(ip)]; - while ((matchIndex>=lowLimit) && (nbAttempts)) - { + while ((matchIndex>=lowLimit) && (nbAttempts)) { nbAttempts--; - if (matchIndex >= dictLimit) - { + if (matchIndex >= dictLimit) { const BYTE* matchPtr = base + matchIndex; - if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) - if (LZ4_read32(matchPtr) == LZ4_read32(ip)) - { + if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) { + if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); int back = 0; - while ((ip+back>iLowLimit) + while ((ip+back > iLowLimit) && (matchPtr+back > lowPrefixPtr) && (ip[back-1] == matchPtr[back-1])) back--; mlt -= back; - if (mlt > longest) - { + if (mlt > longest) { longest = (int)mlt; *matchpos = matchPtr+back; *startpos = ip+back; } } - } - else - { - const BYTE* matchPtr = dictBase + matchIndex; - if (LZ4_read32(matchPtr) == LZ4_read32(ip)) - { + } + } else { + const BYTE* const matchPtr = dictBase + matchIndex; + if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { size_t mlt; int back=0; const BYTE* vLimit = ip + (dictLimit - matchIndex); @@ -320,8 +288,15 @@ FORCE_INLINE int LZ4HC_encodeSequence ( /* Encode MatchLength */ length = (int)(matchLength-MINMATCH); if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */ - if (length>=(int)ML_MASK) { *token+=ML_MASK; length-=ML_MASK; for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } if (length > 254) { length-=255; *(*op)++ = 255; } *(*op)++ = (BYTE)length; } - else *token += (BYTE)(length); + if (length>=(int)ML_MASK) { + *token += ML_MASK; + length -= ML_MASK; + for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } + if (length > 254) { length-=255; *(*op)++ = 255; } + *(*op)++ = (BYTE)length; + } else { + *token += (BYTE)(length); + } /* Prepare next loop */ *ip += matchLength; @@ -330,18 +305,18 @@ FORCE_INLINE int LZ4HC_encodeSequence ( return 0; } +#include "lz4opt.h" -static int LZ4HC_compress_generic ( - void* ctxvoid, - const char* source, - char* dest, - int inputSize, - int maxOutputSize, - int compressionLevel, +static int LZ4HC_compress_hashChain ( + LZ4HC_CCtx_internal* const ctx, + const char* const source, + char* const dest, + int const inputSize, + int const maxOutputSize, + unsigned maxNbAttempts, limitedOutput_directive limit ) { - LZ4HC_Data_Structure* ctx = (LZ4HC_Data_Structure*) ctxvoid; const BYTE* ip = (const BYTE*) source; const BYTE* anchor = ip; const BYTE* const iend = ip + inputSize; @@ -351,28 +326,22 @@ static int LZ4HC_compress_generic ( BYTE* op = (BYTE*) dest; BYTE* const oend = op + maxOutputSize; - unsigned maxNbAttempts; int ml, ml2, ml3, ml0; - const BYTE* ref=NULL; - const BYTE* start2=NULL; - const BYTE* ref2=NULL; - const BYTE* start3=NULL; - const BYTE* ref3=NULL; + const BYTE* ref = NULL; + const BYTE* start2 = NULL; + const BYTE* ref2 = NULL; + const BYTE* start3 = NULL; + const BYTE* ref3 = NULL; const BYTE* start0; const BYTE* ref0; - /* init */ - if (compressionLevel > g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel; - if (compressionLevel < 1) compressionLevel = LZ4HC_compressionLevel_default; - maxNbAttempts = 1 << (compressionLevel-1); ctx->end += inputSize; ip++; /* Main Loop */ - while (ip < mflimit) - { + while (ip < mflimit) { ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts); if (!ml) { ip++; continue; } @@ -383,19 +352,16 @@ static int LZ4HC_compress_generic ( _Search2: if (ip+ml < mflimit) - ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2, maxNbAttempts); + ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, maxNbAttempts); else ml2 = ml; - if (ml2 == ml) /* No better match */ - { + if (ml2 == ml) { /* No better match */ if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0; continue; } - if (start0 < ip) - { - if (start2 < ip + ml0) /* empirical */ - { + if (start0 < ip) { + if (start2 < ip + ml0) { /* empirical */ ip = start0; ref = ref0; ml = ml0; @@ -403,8 +369,7 @@ _Search2: } /* Here, start0==ip */ - if ((start2 - ip) < 3) /* First Match too small : removed */ - { + if ((start2 - ip) < 3) { /* First Match too small : removed */ ml = ml2; ip = start2; ref =ref2; @@ -417,15 +382,13 @@ _Search3: * ml2 > ml1, and * ip1+3 <= ip2 (usually < ip1+ml1) */ - if ((start2 - ip) < OPTIMAL_ML) - { + if ((start2 - ip) < OPTIMAL_ML) { int correction; int new_ml = ml; if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH; correction = new_ml - (int)(start2 - ip); - if (correction > 0) - { + if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; @@ -437,8 +400,7 @@ _Search3: ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts); else ml3 = ml2; - if (ml3 == ml2) /* No better match : 2 sequences to encode */ - { + if (ml3 == ml2) { /* No better match : 2 sequences to encode */ /* ip & ref are known; Now for ml */ if (start2 < ip+ml) ml = (int)(start2 - ip); /* Now, encode 2 sequences */ @@ -448,18 +410,14 @@ _Search3: continue; } - if (start3 < ip+ml+3) /* Not enough space for match 2 : remove it */ - { - if (start3 >= (ip+ml)) /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ - { - if (start2 < ip+ml) - { + if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */ + if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ + if (start2 < ip+ml) { int correction = (int)(ip+ml - start2); start2 += correction; ref2 += correction; ml2 -= correction; - if (ml2 < MINMATCH) - { + if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; @@ -487,23 +445,18 @@ _Search3: * OK, now we have 3 ascending matches; let's write at least the first one * ip & ref are known; Now for ml */ - if (start2 < ip+ml) - { - if ((start2 - ip) < (int)ML_MASK) - { + if (start2 < ip+ml) { + if ((start2 - ip) < (int)ML_MASK) { int correction; if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH; correction = ml - (int)(start2 - ip); - if (correction > 0) - { + if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } - } - else - { + } else { ml = (int)(start2 - ip); } } @@ -521,8 +474,7 @@ _Search3: } /* Encode Last Literals */ - { - int lastRun = (int)(iend - anchor); + { int lastRun = (int)(iend - anchor); if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } else *op++ = (BYTE)(lastRun< 9) { + switch (compressionLevel) { + case 10: return LZ4HC_compress_hashChain(ctx, source, dest, inputSize, maxOutputSize, 1 << (16-1), limit); + case 11: ctx->searchNum = LZ4HC_getSearchNum(compressionLevel); return LZ4HC_compress_optimal(ctx, source, dest, inputSize, maxOutputSize, limit, 128, 0); + default: + case 12: ctx->searchNum = LZ4HC_getSearchNum(compressionLevel); return LZ4HC_compress_optimal(ctx, source, dest, inputSize, maxOutputSize, limit, LZ4_OPT_NUM, 1); + } + } + return LZ4HC_compress_hashChain(ctx, source, dest, inputSize, maxOutputSize, 1 << (compressionLevel-1), limit); +} + + +int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); } int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel) { + LZ4HC_CCtx_internal* ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */ - LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)src); + LZ4HC_init (ctx, (const BYTE*)src); if (maxDstSize < LZ4_compressBound(srcSize)) - return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput); + return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput); else - return LZ4HC_compress_generic (state, src, dst, srcSize, maxDstSize, compressionLevel, noLimit); + return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, noLimit); } int LZ4_compress_HC(const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel) { - LZ4HC_Data_Structure state; - return LZ4_compress_HC_extStateHC(&state, src, dst, srcSize, maxDstSize, compressionLevel); +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); +#else + LZ4_streamHC_t state; + LZ4_streamHC_t* const statePtr = &state; +#endif + int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, maxDstSize, compressionLevel); +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + free(statePtr); +#endif + return cSize; } @@ -566,32 +559,38 @@ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_st /* initialization */ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) { - LZ4_STATIC_ASSERT(sizeof(LZ4HC_Data_Structure) <= sizeof(LZ4_streamHC_t)); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */ - ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->base = NULL; - ((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->compressionLevel = (unsigned)compressionLevel; + LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */ + LZ4_streamHCPtr->internal_donotuse.base = NULL; + LZ4_streamHCPtr->internal_donotuse.compressionLevel = (unsigned)compressionLevel; + LZ4_streamHCPtr->internal_donotuse.searchNum = LZ4HC_getSearchNum(compressionLevel); } int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) { - LZ4HC_Data_Structure* ctxPtr = (LZ4HC_Data_Structure*) LZ4_streamHCPtr; - if (dictSize > 64 KB) - { + LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse; + if (dictSize > 64 KB) { dictionary += dictSize - 64 KB; dictSize = 64 KB; } LZ4HC_init (ctxPtr, (const BYTE*)dictionary); - if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3)); ctxPtr->end = (const BYTE*)dictionary + dictSize; + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) + LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); + else + if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); return dictSize; } /* compression */ -static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newBlock) +static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) { - if (ctxPtr->end >= ctxPtr->base + 4) - LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) + LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); + else + if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ + /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ ctxPtr->lowLimit = ctxPtr->dictLimit; ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base); @@ -601,34 +600,29 @@ static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newB ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ } -static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr, +static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize, limitedOutput_directive limit) { + LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse; /* auto-init if forgotten */ - if (ctxPtr->base == NULL) - LZ4HC_init (ctxPtr, (const BYTE*) source); + if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) source); /* Check overflow */ - if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) - { + if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) { size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit; if (dictSize > 64 KB) dictSize = 64 KB; - - LZ4_loadDictHC((LZ4_streamHC_t*)ctxPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); + LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); } /* Check if blocks follow each other */ - if ((const BYTE*)source != ctxPtr->end) - LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source); + if ((const BYTE*)source != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source); /* Check overlapping input/dictionary space */ - { - const BYTE* sourceEnd = (const BYTE*) source + inputSize; - const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; - const BYTE* dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; - if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd)) - { + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; + const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; + if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd)) { if (sourceEnd > dictEnd) sourceEnd = dictEnd; ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; @@ -641,9 +635,9 @@ static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr, int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize) { if (maxOutputSize < LZ4_compressBound(inputSize)) - return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput); + return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput); else - return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit); + return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit); } @@ -651,14 +645,13 @@ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* sourc int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) { - LZ4HC_Data_Structure* streamPtr = (LZ4HC_Data_Structure*)LZ4_streamHCPtr; - int prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); + LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; + int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); if (dictSize > 64 KB) dictSize = 64 KB; if (dictSize < 4) dictSize = 0; if (dictSize > prefixSize) dictSize = prefixSize; memmove(safeBuffer, streamPtr->end - dictSize, dictSize); - { - U32 endIndex = (U32)(streamPtr->end - streamPtr->base); + { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base); streamPtr->end = (const BYTE*)safeBuffer + dictSize; streamPtr->base = streamPtr->end - endIndex; streamPtr->dictLimit = endIndex - dictSize; @@ -672,8 +665,8 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS /*********************************** * Deprecated Functions ***********************************/ +/* These functions currently generate deprecation warnings */ /* Deprecated compression functions */ -/* These functions are planned to start generate warnings by r131 approximately */ int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); } int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); } int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } @@ -687,45 +680,41 @@ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, /* Deprecated streaming functions */ -/* These functions currently generate deprecation warnings */ int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; } int LZ4_resetStreamStateHC(void* state, char* inputBuffer) { + LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */ - LZ4HC_init((LZ4HC_Data_Structure*)state, (const BYTE*)inputBuffer); - ((LZ4HC_Data_Structure*)state)->inputBuffer = (BYTE*)inputBuffer; + LZ4HC_init(ctx, (const BYTE*)inputBuffer); + ctx->inputBuffer = (BYTE*)inputBuffer; return 0; } void* LZ4_createHC (char* inputBuffer) { - void* hc4 = ALLOCATOR(1, sizeof(LZ4HC_Data_Structure)); + LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t)); if (hc4 == NULL) return NULL; /* not enough memory */ - LZ4HC_init ((LZ4HC_Data_Structure*)hc4, (const BYTE*)inputBuffer); - ((LZ4HC_Data_Structure*)hc4)->inputBuffer = (BYTE*)inputBuffer; + LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer); + hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer; return hc4; } -int LZ4_freeHC (void* LZ4HC_Data) -{ - FREEMEM(LZ4HC_Data); - return (0); -} +int LZ4_freeHC (void* LZ4HC_Data) { FREEMEM(LZ4HC_Data); return 0; } int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel) { - return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, compressionLevel, noLimit); + return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, 0, compressionLevel, noLimit); } int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel) { - return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput); + return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput); } char* LZ4_slideInputBufferHC(void* LZ4HC_Data) { - LZ4HC_Data_Structure* hc4 = (LZ4HC_Data_Structure*)LZ4HC_Data; - int dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB); + LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; + int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB); return (char*)(hc4->inputBuffer + dictSize); } From f33494ffe279c12d3b66b8e9163a40f9cd4542c1 Mon Sep 17 00:00:00 2001 From: ivanzhukov Date: Sun, 7 May 2017 00:04:38 +0300 Subject: [PATCH 26/76] Add missing liblz4 header file --- contrib/liblz4/CMakeLists.txt | 4 +- contrib/liblz4/include/lz4/lz4opt.h | 361 ++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 contrib/liblz4/include/lz4/lz4opt.h diff --git a/contrib/liblz4/CMakeLists.txt b/contrib/liblz4/CMakeLists.txt index bce214ca215..033b923e8e3 100644 --- a/contrib/liblz4/CMakeLists.txt +++ b/contrib/liblz4/CMakeLists.txt @@ -5,4 +5,6 @@ add_library (lz4 src/lz4hc.c include/lz4/lz4.h - include/lz4/lz4hc.h) + include/lz4/lz4hc.h + include/lz4/lz4opt.h) + diff --git a/contrib/liblz4/include/lz4/lz4opt.h b/contrib/liblz4/include/lz4/lz4opt.h new file mode 100644 index 00000000000..b346eba87f1 --- /dev/null +++ b/contrib/liblz4/include/lz4/lz4opt.h @@ -0,0 +1,361 @@ +/* + lz4opt.h - Optimal Mode of LZ4 + Copyright (C) 2015-2017, Przemyslaw Skibinski + Note : this file is intended to be included within lz4hc.c + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +#define LZ4_OPT_NUM (1<<12) + + +typedef struct { + int off; + int len; +} LZ4HC_match_t; + +typedef struct { + int price; + int off; + int mlen; + int litlen; +} LZ4HC_optimal_t; + + +/* price in bytes */ +FORCE_INLINE size_t LZ4HC_literalsPrice(size_t litlen) +{ + size_t price = litlen; + if (litlen >= (size_t)RUN_MASK) + price += 1 + (litlen-RUN_MASK)/255; + return price; +} + + +/* requires mlen >= MINMATCH */ +FORCE_INLINE size_t LZ4HC_sequencePrice(size_t litlen, size_t mlen) +{ + size_t price = 2 + 1; /* 16-bit offset + token */ + + price += LZ4HC_literalsPrice(litlen); + + if (mlen >= (size_t)(ML_MASK+MINMATCH)) + price+= 1 + (mlen-(ML_MASK+MINMATCH))/255; + + return price; +} + + +/*-************************************* +* Binary Tree search +***************************************/ +FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches ( + LZ4HC_CCtx_internal* ctx, + const BYTE* const ip, + const BYTE* const iHighLimit, + size_t best_mlen, + LZ4HC_match_t* matches, + int* matchNum) +{ + U16* const chainTable = ctx->chainTable; + U32* const HashTable = ctx->hashTable; + const BYTE* const base = ctx->base; + const U32 dictLimit = ctx->dictLimit; + const U32 current = (U32)(ip - base); + const U32 lowLimit = (ctx->lowLimit + MAX_DISTANCE > current) ? ctx->lowLimit : current - (MAX_DISTANCE - 1); + const BYTE* const dictBase = ctx->dictBase; + const BYTE* match; + int nbAttempts = ctx->searchNum; + int mnum = 0; + U16 *ptr0, *ptr1, delta0, delta1; + U32 matchIndex; + size_t matchLength = 0; + U32* HashPos; + + if (ip + MINMATCH > iHighLimit) return 1; + + /* HC4 match finder */ + HashPos = &HashTable[LZ4HC_hashPtr(ip)]; + matchIndex = *HashPos; + *HashPos = current; + + ptr0 = &DELTANEXTMAXD(current*2+1); + ptr1 = &DELTANEXTMAXD(current*2); + delta0 = delta1 = (U16)(current - matchIndex); + + while ((matchIndex < current) && (matchIndex>=lowLimit) && (nbAttempts)) { + nbAttempts--; + if (matchIndex >= dictLimit) { + match = base + matchIndex; + matchLength = LZ4_count(ip, match, iHighLimit); + } else { + const BYTE* vLimit = ip + (dictLimit - matchIndex); + match = dictBase + matchIndex; + if (vLimit > iHighLimit) vLimit = iHighLimit; + matchLength = LZ4_count(ip, match, vLimit); + if ((ip+matchLength == vLimit) && (vLimit < iHighLimit)) + matchLength += LZ4_count(ip+matchLength, base+dictLimit, iHighLimit); + } + + if (matchLength > best_mlen) { + best_mlen = matchLength; + if (matches) { + if (matchIndex >= dictLimit) + matches[mnum].off = (int)(ip - match); + else + matches[mnum].off = (int)(ip - (base + matchIndex)); /* virtual matchpos */ + matches[mnum].len = (int)matchLength; + mnum++; + } + if (best_mlen > LZ4_OPT_NUM) break; + } + + if (ip+matchLength >= iHighLimit) /* equal : no way to know if inf or sup */ + break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */ + + if (*(ip+matchLength) < *(match+matchLength)) { + *ptr0 = delta0; + ptr0 = &DELTANEXTMAXD(matchIndex*2); + if (*ptr0 == (U16)-1) break; + delta0 = *ptr0; + delta1 += delta0; + matchIndex -= delta0; + } else { + *ptr1 = delta1; + ptr1 = &DELTANEXTMAXD(matchIndex*2+1); + if (*ptr1 == (U16)-1) break; + delta1 = *ptr1; + delta0 += delta1; + matchIndex -= delta1; + } + } + + *ptr0 = (U16)-1; + *ptr1 = (U16)-1; + if (matchNum) *matchNum = mnum; + /* if (best_mlen > 8) return best_mlen-8; */ + if (!matchNum) return 1; + return 1; +} + + +FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const BYTE* const ip, const BYTE* const iHighLimit) +{ + const BYTE* const base = ctx->base; + const U32 target = (U32)(ip - base); + U32 idx = ctx->nextToUpdate; + while(idx < target) + idx += LZ4HC_BinTree_InsertAndGetAllMatches(ctx, base+idx, iHighLimit, 8, NULL, NULL); +} + + +/** Tree updater, providing best match */ +FORCE_INLINE int LZ4HC_BinTree_GetAllMatches ( + LZ4HC_CCtx_internal* ctx, + const BYTE* const ip, const BYTE* const iHighLimit, + size_t best_mlen, LZ4HC_match_t* matches, const int fullUpdate) +{ + int mnum = 0; + if (ip < ctx->base + ctx->nextToUpdate) return 0; /* skipped area */ + if (fullUpdate) LZ4HC_updateBinTree(ctx, ip, iHighLimit); + best_mlen = LZ4HC_BinTree_InsertAndGetAllMatches(ctx, ip, iHighLimit, best_mlen, matches, &mnum); + ctx->nextToUpdate = (U32)(ip - ctx->base + best_mlen); + return mnum; +} + + +#define SET_PRICE(pos, ml, offset, ll, cost) \ +{ \ + while (last_pos < pos) { opt[last_pos+1].price = 1<<30; last_pos++; } \ + opt[pos].mlen = (int)ml; \ + opt[pos].off = (int)offset; \ + opt[pos].litlen = (int)ll; \ + opt[pos].price = (int)cost; \ +} + + +static int LZ4HC_compress_optimal ( + LZ4HC_CCtx_internal* ctx, + const char* const source, + char* dest, + int inputSize, + int maxOutputSize, + limitedOutput_directive limit, + size_t sufficient_len, + const int fullUpdate + ) +{ + LZ4HC_optimal_t opt[LZ4_OPT_NUM + 1]; /* this uses a bit too much stack memory to my taste ... */ + LZ4HC_match_t matches[LZ4_OPT_NUM + 1]; + + const BYTE* ip = (const BYTE*) source; + const BYTE* anchor = ip; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = (iend - LASTLITERALS); + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + maxOutputSize; + + /* init */ + if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; + ctx->end += inputSize; + ip++; + + /* Main Loop */ + while (ip < mflimit) { + size_t const llen = ip - anchor; + size_t last_pos = 0; + size_t match_num, cur, best_mlen, best_off; + memset(opt, 0, sizeof(LZ4HC_optimal_t)); /* memset only the first one */ + + match_num = LZ4HC_BinTree_GetAllMatches(ctx, ip, matchlimit, MINMATCH-1, matches, fullUpdate); + if (!match_num) { ip++; continue; } + + if ((size_t)matches[match_num-1].len > sufficient_len) { + /* good enough solution : immediate encoding */ + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto encode; + } + + /* set prices using matches at position = 0 */ + { size_t matchNb; + for (matchNb = 0; matchNb < match_num; matchNb++) { + size_t mlen = (matchNb>0) ? (size_t)matches[matchNb-1].len+1 : MINMATCH; + best_mlen = matches[matchNb].len; /* necessarily < sufficient_len < LZ4_OPT_NUM */ + for ( ; mlen <= best_mlen ; mlen++) { + size_t const cost = LZ4HC_sequencePrice(llen, mlen) - LZ4HC_literalsPrice(llen); + SET_PRICE(mlen, mlen, matches[matchNb].off, 0, cost); /* updates last_pos and opt[pos] */ + } } } + + if (last_pos < MINMATCH) { ip++; continue; } /* note : on clang at least, this test improves performance */ + + /* check further positions */ + opt[0].mlen = opt[1].mlen = 1; + for (cur = 1; cur <= last_pos; cur++) { + const BYTE* const curPtr = ip + cur; + + /* establish baseline price if cur is literal */ + { size_t price, litlen; + if (opt[cur-1].mlen == 1) { + /* no match at previous position */ + litlen = opt[cur-1].litlen + 1; + if (cur > litlen) { + price = opt[cur - litlen].price + LZ4HC_literalsPrice(litlen); + } else { + price = LZ4HC_literalsPrice(llen + litlen) - LZ4HC_literalsPrice(llen); + } + } else { + litlen = 1; + price = opt[cur - 1].price + LZ4HC_literalsPrice(1); + } + + if (price < (size_t)opt[cur].price) + SET_PRICE(cur, 1 /*mlen*/, 0 /*off*/, litlen, price); /* note : increases last_pos */ + } + + if (cur == last_pos || curPtr >= mflimit) break; + + match_num = LZ4HC_BinTree_GetAllMatches(ctx, curPtr, matchlimit, MINMATCH-1, matches, fullUpdate); + if ((match_num > 0) && (size_t)matches[match_num-1].len > sufficient_len) { + /* immediate encoding */ + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto encode; + } + + /* set prices using matches at position = cur */ + { size_t matchNb; + for (matchNb = 0; matchNb < match_num; matchNb++) { + size_t ml = (matchNb>0) ? (size_t)matches[matchNb-1].len+1 : MINMATCH; + best_mlen = (cur + matches[matchNb].len < LZ4_OPT_NUM) ? + (size_t)matches[matchNb].len : LZ4_OPT_NUM - cur; + + for ( ; ml <= best_mlen ; ml++) { + size_t ll, price; + if (opt[cur].mlen == 1) { + ll = opt[cur].litlen; + if (cur > ll) + price = opt[cur - ll].price + LZ4HC_sequencePrice(ll, ml); + else + price = LZ4HC_sequencePrice(llen + ll, ml) - LZ4HC_literalsPrice(llen); + } else { + ll = 0; + price = opt[cur].price + LZ4HC_sequencePrice(0, ml); + } + + if (cur + ml > last_pos || price < (size_t)opt[cur + ml].price) { + SET_PRICE(cur + ml, ml, matches[matchNb].off, ll, price); + } } } } + } /* for (cur = 1; cur <= last_pos; cur++) */ + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + +encode: /* cur, last_pos, best_mlen, best_off must be set */ + opt[0].mlen = 1; + while (1) { /* from end to beginning */ + size_t const ml = opt[cur].mlen; + int const offset = opt[cur].off; + opt[cur].mlen = (int)best_mlen; + opt[cur].off = (int)best_off; + best_mlen = ml; + best_off = offset; + if (ml > cur) break; /* can this happen ? */ + cur -= ml; + } + + /* encode all recorded sequences */ + cur = 0; + while (cur < last_pos) { + int const ml = opt[cur].mlen; + int const offset = opt[cur].off; + if (ml == 1) { ip++; cur++; continue; } + cur += ml; + if ( LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ip - offset, limit, oend) ) return 0; + } + } /* while (ip < mflimit) */ + + /* Encode Last Literals */ + { int lastRun = (int)(iend - anchor); + if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun< Date: Mon, 8 May 2017 08:06:04 +0300 Subject: [PATCH 27/76] Fixed some ERRORS and WARNINGS during RU docs build. (#772) * Initial commit if EN docs * Part of EN documentation * Full queries section * External data * Table engines * System tables * Table functions * Formats * Data types * Operators * Functions * Dictionaries * Settings * Configuration files * Access rights * Quotas * Fixed few formatting errors * Fixed few formatting errors * Fixed few formatting errors * FIX: "WARNING: Title underline too short." during build RU docs. * FIX: "WARNING: Title underline too short." during build RU docs. --- doc/presentations | 1 - docs/ru/agg_functions/index.rst | 58 ++++----- docs/ru/data_types/enum.rst | 2 + docs/ru/dicts/external_dicts.rst | 11 +- docs/ru/external_data.rst | 3 + docs/ru/formats/jsoncompact.rst | 1 + docs/ru/formats/jsoneachrow.rst | 4 +- docs/ru/formats/prettynoescapes.rst | 4 +- docs/ru/formats/tabseparated.rst | 1 + docs/ru/formats/tskv.rst | 1 + docs/ru/functions/array_functions.rst | 30 ++--- docs/ru/functions/array_join.rst | 2 +- docs/ru/functions/bit_functions.rst | 2 +- docs/ru/functions/comparison_functions.rst | 6 +- docs/ru/functions/conditional_functions.rst | 2 +- docs/ru/functions/date_time_functions.rst | 2 + docs/ru/functions/encoding_functions.rst | 14 +-- docs/ru/functions/ext_dict_functions.rst | 20 ++-- docs/ru/functions/hash_functions.rst | 20 ++-- docs/ru/functions/higher_order_functions.rst | 18 +-- docs/ru/functions/in_functions.rst | 8 +- docs/ru/functions/ip_address_functions.rst | 12 +- docs/ru/functions/json_functions.rst | 18 +-- docs/ru/functions/math_functions.rst | 34 +++--- docs/ru/functions/other_functions.rst | 44 +++---- docs/ru/functions/random_functions.rst | 4 +- docs/ru/functions/rounding_functions.rst | 14 +-- .../functions/splitting_merging_functions.rst | 10 +- .../ru/functions/string_replace_functions.rst | 2 + .../functions/type_conversion_functions.rst | 1 + docs/ru/functions/url_functions.rst | 41 +++---- docs/ru/functions/ym_dict_functions.rst | 23 ++-- docs/ru/getting_started.rst | 34 ++++-- docs/ru/interfaces/cli.rst | 8 +- docs/ru/introduction/distinctive_features.rst | 18 +-- docs/ru/introduction/performance.rst | 10 +- .../introduction/possible_silly_questions.rst | 4 +- docs/ru/introduction/use_case.rst | 2 +- docs/ru/introduction/what_is_clickhouse.rst | 8 +- docs/ru/introduction/ya_metrika_task.rst | 2 +- docs/ru/query_language/index.rst | 2 +- docs/ru/query_language/queries.rst | 111 +++++++++++++----- docs/ru/query_language/syntax.rst | 7 +- docs/ru/settings/query_complexity.rst | 68 +++++------ docs/ru/settings/settings.rst | 50 ++++---- docs/ru/system_tables/index.rst | 2 +- docs/ru/system_tables/system.clusters.rst | 2 + docs/ru/system_tables/system.columns.rst | 1 + docs/ru/system_tables/system.dictionaries.rst | 1 + docs/ru/system_tables/system.functions.rst | 1 + docs/ru/system_tables/system.merges.rst | 1 + docs/ru/system_tables/system.parts.rst | 1 + docs/ru/system_tables/system.processes.rst | 1 + docs/ru/system_tables/system.replicas.rst | 1 + docs/ru/system_tables/system.settings.rst | 1 + docs/ru/system_tables/system.zookeeper.rst | 1 + docs/ru/table_engines/buffer.rst | 4 +- docs/ru/table_engines/distributed.rst | 3 +- docs/ru/table_engines/join.rst | 1 + docs/ru/table_engines/merge.rst | 1 + docs/ru/table_engines/mergetree.rst | 2 + docs/ru/table_engines/replication.rst | 4 +- docs/ru/table_engines/summingmergetree.rst | 1 + docs/ru/table_functions/remote.rst | 5 + 64 files changed, 450 insertions(+), 321 deletions(-) delete mode 160000 doc/presentations diff --git a/doc/presentations b/doc/presentations deleted file mode 160000 index b0b67a13a5a..00000000000 --- a/doc/presentations +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0b67a13a5ab20eac11496393acbe1e6c4f9c925 diff --git a/docs/ru/agg_functions/index.rst b/docs/ru/agg_functions/index.rst index ff9b9f50e53..a27e575b8d7 100644 --- a/docs/ru/agg_functions/index.rst +++ b/docs/ru/agg_functions/index.rst @@ -28,7 +28,7 @@ min(x) Вычисляет минимум. max(x) ------ +------ Вычисляет максимум. argMin(arg, val) @@ -36,11 +36,11 @@ argMin(arg, val) Вычисляет значение arg при минимальном значении val. Если есть несколько разных значений arg для минимальных значений val, то выдаётся первое попавшееся из таких значений. argMax(arg, val) ---------------- +---------------- Вычисляет значение arg при максимальном значении val. Если есть несколько разных значений arg для максимальных значений val, то выдаётся первое попавшееся из таких значений. sum(x) -------- +------ Вычисляет сумму. Работает только для чисел. @@ -60,7 +60,7 @@ uniq(x) Результат детерминирован (не зависит от порядка выполнения запроса). uniqCombined(x) --------------- +--------------- Приближённо вычисляет количество различных значений аргумента. Работает для чисел, строк, дат, дат-с-временем, для нескольких аргументов и аргументов-кортежей. Используется комбинация трёх алгоритмов: массив, хэш-таблица и HyperLogLog с таблицей коррекции погрешности. Расход памяти в несколько раз меньше, чем у функции uniq, а точность в несколько раз выше. Скорость работы чуть ниже, чем у функции uniq, но иногда может быть даже выше - в случае распределённых запросов, в которых по сети передаётся большое количество состояний агрегации. Максимальный размер состояния составляет 96 KiB (HyperLogLog из 217 6-битовых ячеек). @@ -87,7 +87,7 @@ uniqExact(x) Функция uniqExact расходует больше оперативки, чем функция uniq, так как размер состояния неограниченно растёт по мере роста количества различных значений. groupArray(x) ------------- +------------- Составляет массив из значений аргумента. Значения в массив могут быть добавлены в любом (недетерминированном) порядке. @@ -117,7 +117,7 @@ quantile(level)(x) При использовании нескольких функций quantile (и аналогичных) с разными уровнями в запросе, внутренние состояния не объединяются (то есть, запрос работает менее эффективно, чем мог бы). В этом случае, используйте функцию quantiles (и аналогичные). quantileDeterministic(level)(x, determinator) --------------- +--------------------------------------------- Работает аналогично функции quantile, но, в отличие от неё, результат является детерминированным и не зависит от порядка выполнения запроса. Для этого, функция принимает второй аргумент - "детерминатор". Это некоторое число, хэш от которого используется вместо генератора случайных чисел в алгоритме reservoir sampling. Для правильной работы функции, одно и то же значение детерминатора не должно встречаться слишком часто. В качестве детерминатора вы можете использовать идентификатор события, идентификатор посетителя и т. п. @@ -125,7 +125,7 @@ quantileDeterministic(level)(x, determinator) Не используйте эту функцию для рассчёта таймингов. Для этого есть более подходящая функции - quantileTiming. quantileTiming(level)(x) ---------------- +------------------------ Вычисляет квантиль уровня level с фиксированной точностью. Работает для чисел. Предназначена для расчёта квантилей от времени загрузки страницы в миллисекундах. @@ -146,22 +146,22 @@ quantileTiming(level)(x) Для своей задачи (расчёт квантилей времени загрузки страниц), использование этой функции эффективнее и результат точнее, чем для функции quantile. quantileTimingWeighted(level)(x, weight) ---------------- +---------------------------------------- Отличается от функции medianTiming наличием второго аргумента - "веса". Вес - неотрицательное целое число. Результат считается так же, как если бы в функцию medianTiming значение x было передано weight количество раз. quantileExact(level)(x) ------------- +----------------------- Вычисляет квантиль уровня level точно. Для этого, все переданные значения складываются в массив, который затем частично сортируется. Поэтому, функция потребляет O(n) памяти, где n - количество переданных значений. Впрочем, для случая маленького количества значений, функция весьма эффективна. quantileExactWeighted(level)(x, weight) ----------------- +--------------------------------------- Вычисляет квантиль уровня level точно. При этом, каждое значение учитывается с весом weight - как будто оно присутствует weight раз. Аргументы функции можно рассматривать как гистограммы, где значению x соответствует "столбик" гистограммы высоты weight, а саму функцию можно рассматривать как суммирование гистограмм. В качестве алгоритма используется хэш-таблица. Из-за этого, в случае, если передаваемые значения часто повторяются, функция потребляет меньше оперативки, чем quantileExact. Вы можете использовать эту функцию вместо quantileExact, указав в качестве веса число 1. quantileTDigest(level)(x) -------------- +------------------------- Вычисляет квантиль уровня level приближённо, с использованием алгоритма t-digest. Максимальная погрешность составляет 1%. Расход памяти на состояние пропорционален логарифму от количества переданных значений. Производительность функции ниже quantile, quantileTiming. По соотношению размера состояния и точности, функция существенно лучше, чем quantile. @@ -173,11 +173,11 @@ median Для всех quantile-функций, также присутствуют соответствующие median-функции: median, medianDeterministic, medianTiming, medianTimingWeighted, medianExact, medianExactWeighted, medianTDigest. Они являются синонимами и их поведение ничем не отличается. quantiles(level1, level2, ...)(x) ---------------- +--------------------------------- Для всех quantile-функций, также присутствуют соответствующие quantiles-функции: quantiles, quantilesDeterministic, quantilesTiming, quantilesTimingWeighted, quantilesExact, quantilesExactWeighted, quantilesTDigest. Эти функции за один проход вычисляют все квантили перечисленных уровней и возвращают массив вычисленных значений. varSamp(x) --------- +---------- Вычисляет величину Σ((x - x̅)2) / (n - 1), где n - размер выборки, x̅ - среднее значение x. Она представляет собой несмещённую оценку дисперсии случайной величины, если переданные в функцию значения являются выборкой этой случайной величины. @@ -191,35 +191,35 @@ varPop(x) То есть, дисперсию для множества значений. Возвращает Float64. stddevSamp(x) ------------ +------------- Результат равен квадратному корню от varSamp(x). stddevPop(x) ---------- +------------ Результат равен квадратному корню от varPop(x). covarSamp(x, y) ----------- +--------------- Вычисляет величину Σ((x - x̅)(y - y̅)) / (n - 1). Возвращает Float64. В случае, когда n <= 1, возвращается +∞. covarPop(x, y) ----------- +-------------- Вычисляет величину Σ((x - x̅)(y - y̅)) / n. corr(x, y) ---------- +---------- Вычисляет коэффициент корреляции Пирсона: Σ((x - x̅)(y - y̅)) / sqrt(Σ((x - x̅)2) * Σ((y - y̅)2)). Параметрические агрегатные функции -================ +================================== Некоторые агрегатные функции могут принимать не только столбцы-аргументы (по которым производится свёртка), но и набор параметров - констант для инициализации. Синтаксис - две пары круглых скобок вместо одной. Первая - для параметров, вторая - для аргументов. sequenceMatch(pattern)(time, cond1, cond2, ...) ------------- +----------------------------------------------- Сопоставление с образцом для цепочки событий. ``pattern`` - строка, содержащая шаблон для сопоставления. Шаблон похож на регулярное выражение. @@ -237,6 +237,7 @@ sequenceMatch(pattern)(time, cond1, cond2, ...) Это вырожденный пример. Его можно записать с помощью других агрегатных функций: :: + minIf(EventTime, URL LIKE '%company%') < maxIf(EventTime, URL LIKE '%cart%'). Но в более сложных случаях, такого решения нет. @@ -258,12 +259,12 @@ sequenceMatch(pattern)(time, cond1, cond2, ...) События, произошедшие в одну секунду, могут оказаться в цепочке в произвольном порядке. От этого может зависеть результат работы функции. sequenceCount(pattern)(time, cond1, cond2, ...) ------------------- +----------------------------------------------- Аналогично функции sequenceMatch, но возвращает не факт наличия цепочки событий, а UInt64 - количество найденных цепочек. Цепочки ищутся без перекрытия. То есть, следующая цепочка может начаться только после окончания предыдущей. uniqUpTo(N)(x) -------------- +-------------- Вычисляет количество различных значений аргумента, если оно меньше или равно N. В случае, если количество различных значений аргумента больше N, возвращает N + 1. @@ -278,16 +279,17 @@ uniqUpTo(N)(x) Пример применения: :: + Задача: показывать в отчёте только поисковые фразы, по которым было хотя бы 5 уникальных посетителей. Решение: пишем в запросе GROUP BY SearchPhrase HAVING uniqUpTo(4)(UserID) >= 5 Комбинаторы агрегатных функций -======================= +============================== К имени агрегатной функции может быть приписан некоторый суффикс. При этом, работа агрегатной функции некоторым образом модифицируется. Существуют комбинаторы If и Array. Смотрите разделы ниже. Комбинатор -If. Условные агрегатные функции ---------------------- +------------------------------------------- К имени любой агрегатной функции может быть приписан суффикс -If. В этом случае, агрегатная функция принимает ещё один дополнительный аргумент - условие (типа UInt8). Агрегатная функция будет обрабатывать только те строки, для которых условие сработало. Если условие ни разу не сработало - возвращается некоторое значение по умолчанию (обычно - нули, пустые строки). Примеры: ``sumIf(column, cond)``, ``countIf(cond)``, ``avgIf(x, cond)``, ``quantilesTimingIf(level1, level2)(x, cond)``, ``argMinIf(arg, val, cond)`` и т. п. @@ -296,7 +298,7 @@ uniqUpTo(N)(x) Например, в Яндекс.Метрике, условные агрегатные функции используются для реализации функциональности сравнения сегментов. Комбинатор -Array. Агрегатные функции для аргументов-массивов ------------------ +------------------------------------------------------------- К имени любой агрегатной функции может быть приписан суффикс -Array. В этом случае, агрегатная функция вместо аргументов типов T принимает аргументы типов Array(T) (массивы). Если агрегатная функция принимает несколько аргументов, то это должны быть массивы одинаковых длин. При обработке массивов, агрегатная функция работает, как исходная агрегатная функция по всем элементам массивов. Пример 1: ``sumArray(arr)`` - просуммировать все элементы всех массивов arr. В данном примере можно было бы написать проще: ``sum(arraySum(arr))``. @@ -306,13 +308,13 @@ uniqUpTo(N)(x) Комбинаторы -If и -Array можно сочетать. При этом, должен сначала идти Array, а потом If. Примеры: uniqArrayIf(arr, cond), quantilesTimingArrayIf(level1, level2)(arr, cond). Из-за такого порядка получается, что аргумент cond не должен быть массивом. Комбинатор -State. ------------- +------------------ В случае применения этого комбинатора, агрегатная функция возвращает не готовое значение (например, в случае функции uniq - количество уникальных значений), а промежуточное состояние агрегации (например, в случае функции uniq - хэш-таблицу для рассчёта количества уникальных значений), которое имеет тип AggregateFunction(...) и может использоваться для дальнейшей обработки или может быть сохранено в таблицу для последующей доагрегации - смотрите разделы "AggregatingMergeTree" и "функции для работы с промежуточными состояниями агрегации". Комбинатор -Merge. ------------- +------------------ В случае применения этого комбинатора, агрегатная функция будет принимать в качестве аргумента промежуточное состояние агрегации, доагрегировать (объединять вместе) эти состояния, и возвращать готовое значение. Комбинатор -MergeState. ----------------- +----------------------- Выполняет слияние промежуточных состояний агрегации, аналогично комбинатору -Merge, но возвращает не готовое значение, а промежуточное состояние агрегации, аналогично комбинатору -State. diff --git a/docs/ru/data_types/enum.rst b/docs/ru/data_types/enum.rst index 3df8bc318e2..4eb28c13977 100644 --- a/docs/ru/data_types/enum.rst +++ b/docs/ru/data_types/enum.rst @@ -5,7 +5,9 @@ Enum8 или Enum16. Представляет собой конечное мно Пример: :: + Enum8('hello' = 1, 'world' = 2) + - тип данных с двумя возможными значениями - 'hello' и 'world'. Для каждого из значений прописывается число в диапазоне -128..127 для ``Enum8`` или в диапазоне -32768..32767 для ``Enum16``. Все строки должны быть разными, числа - тоже. Разрешена пустая строка. При указании такого типа (в определении таблицы), числа могут идти не подряд и в произвольном порядке. При этом, порядок не имеет значения. diff --git a/docs/ru/dicts/external_dicts.rst b/docs/ru/dicts/external_dicts.rst index 70df8850eec..94dcffa13e5 100644 --- a/docs/ru/dicts/external_dicts.rst +++ b/docs/ru/dicts/external_dicts.rst @@ -155,20 +155,21 @@ flat Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. hashed -------- +------ В виде хэш-таблиц. Слегка менее эффективный способ. Словарь тоже загружается в оперативку целиком, и может содержать произвольное количество элементов с произвольными идентификаторами. На практике, имеет смысл использовать до десятков миллионов элементов, пока хватает оперативки. Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. cache -------- +----- Наименее эффективный способ. Подходит, если словарь не помещается в оперативку. Представляет собой кэш из фиксированного количества ячеек, в которых могут быть расположены часто используемые данные. Поддерживается источник MySQL, ClickHouse, executable, http; источник-файл не поддерживается. При поиске в словаре, сначала просматривается кэш. На каждый блок данных, все не найденные в кэше ключи (или устаревшие ключи) собираются в пачку, и с этой пачкой делается запрос к источнику вида SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...). Затем полученные данные записываются в кэш. range_hashed --------- +------------ В таблице прописаны какие-то данные для диапазонов дат, для каждого ключа. Дать возможность доставать эти данные для заданного ключа, для заданной даты. Пример: в таблице записаны скидки для каждого рекламодателя в виде: :: + id рекламодателя дата начала действия скидки дата конца величина 123 2015-01-01 2015-01-15 0.15 123 2015-01-16 2015-01-31 0.25 @@ -255,12 +256,12 @@ range_hashed complex_key_hashed ----------------- +------------------ Для использования с составными ключами. Аналогичен hashed. complex_key_cache ----------- +----------------- Для использования с составными ключами. Аналогичен cache. diff --git a/docs/ru/external_data.rst b/docs/ru/external_data.rst index 17f0598f718..d134b3ba723 100644 --- a/docs/ru/external_data.rst +++ b/docs/ru/external_data.rst @@ -11,6 +11,7 @@ ClickHouse позволяет отправить на сервер данные, В клиенте командной строки, может быть указана секция параметров вида :: + --external --file=... [--name=...] [--format=...] [--types=...|--structure=...] Таких секций может быть несколько - по числу передаваемых таблиц. @@ -31,6 +32,7 @@ ClickHouse позволяет отправить на сервер данные, Примеры: :: + echo -ne "1\n2\n3\n" | clickhouse-client --query="SELECT count() FROM test.visits WHERE TraficSourceID IN _data" --external --file=- --types=Int8 849897 cat /etc/passwd | sed 's/:/\t/g' | clickhouse-client --query="SELECT shell, count() AS c FROM passwd GROUP BY shell ORDER BY c DESC" --external --file=- --name=passwd --structure='login String, unused String, uid UInt16, gid UInt16, comment String, home String, shell String' @@ -44,6 +46,7 @@ ClickHouse позволяет отправить на сервер данные, Пример: :: + cat /etc/passwd | sed 's/:/\t/g' > passwd.tsv curl -F 'passwd=@passwd.tsv;' 'http://localhost:8123/?query=SELECT+shell,+count()+AS+c+FROM+passwd+GROUP+BY+shell+ORDER+BY+c+DESC&passwd_structure=login+String,+unused+String,+uid+UInt16,+gid+UInt16,+comment+String,+home+String,+shell+String' diff --git a/docs/ru/formats/jsoncompact.rst b/docs/ru/formats/jsoncompact.rst index f9bd21b8924..5b4d5d8c1ad 100644 --- a/docs/ru/formats/jsoncompact.rst +++ b/docs/ru/formats/jsoncompact.rst @@ -5,6 +5,7 @@ JSONCompact Пример: :: + { "meta": [ diff --git a/docs/ru/formats/jsoneachrow.rst b/docs/ru/formats/jsoneachrow.rst index 37dc5f72792..3a2e4de347f 100644 --- a/docs/ru/formats/jsoneachrow.rst +++ b/docs/ru/formats/jsoneachrow.rst @@ -2,7 +2,9 @@ JSONEachRow ----------- Выводит данные в виде отдельных JSON объектов для каждой строки (newline delimited JSON). -:: + +.. code-block:: json + {"SearchPhrase":"","count()":"8267016"} {"SearchPhrase":"интерьер ванной комнаты","count()":"2166"} {"SearchPhrase":"яндекс","count()":"1655"} diff --git a/docs/ru/formats/prettynoescapes.rst b/docs/ru/formats/prettynoescapes.rst index b0ef87e88b2..9bceae0d0d3 100644 --- a/docs/ru/formats/prettynoescapes.rst +++ b/docs/ru/formats/prettynoescapes.rst @@ -4,7 +4,9 @@ PrettyNoEscapes Отличается от Pretty тем, что не используются ANSI-escape последовательности. Это нужно для отображения этого формата в браузере, а также при использовании утилиты командной строки watch. Пример: -:: + +.. code-block:: bash + watch -n1 "clickhouse-client --query='SELECT * FROM system.events FORMAT PrettyCompactNoEscapes'" Для отображения в браузере, вы можете использовать HTTP интерфейс. diff --git a/docs/ru/formats/tabseparated.rst b/docs/ru/formats/tabseparated.rst index fe9503aeec7..09112eccfe0 100644 --- a/docs/ru/formats/tabseparated.rst +++ b/docs/ru/formats/tabseparated.rst @@ -18,6 +18,7 @@ TabSeparated Строки выводятся с экранированием спец-символов с помощью обратного слеша. При выводе, используются следующие escape-последовательности: ``\b``, ``\f``, ``\r``, ``\n``, ``\t``, ``\0``, ``\'``, ``\\``. При парсинге, также поддерживаются последовательности ``\a``, ``\v``, а также ``\xHH`` (hex escape-последовательности) и любые последовательности вида ``\c``, где ``c`` - любой символ - такие последовательности преобразуется в ``c``. Таким образом, при чтении поддерживаются форматы, где перевод строки может быть записан как ``\n`` и как ``\`` и перевод строки. Например, строка ``Hello world``, где между словами вместо пробела стоит перевод строки, может быть считана в любом из следующих вариантов: :: + Hello\nworld Hello\ diff --git a/docs/ru/formats/tskv.rst b/docs/ru/formats/tskv.rst index 868b10c6d31..4fb1d76e70e 100644 --- a/docs/ru/formats/tskv.rst +++ b/docs/ru/formats/tskv.rst @@ -3,6 +3,7 @@ TSKV Похож на TabSeparated, но выводит значения в формате name=value. Имена экранируются так же, как строки в формате TabSeparated и, дополнительно, экранируется также символ =. :: + SearchPhrase= count()=8267016 SearchPhrase=интерьер ванной комнаты count()=2166 SearchPhrase=яндекс count()=1655 diff --git a/docs/ru/functions/array_functions.rst b/docs/ru/functions/array_functions.rst index f475b3f2eab..bb817b50ddb 100644 --- a/docs/ru/functions/array_functions.rst +++ b/docs/ru/functions/array_functions.rst @@ -20,38 +20,38 @@ length Функция также работает для строк. emptyArrayUInt8, emptyArrayUInt16, emptyArrayUInt32, emptyArrayUInt64 -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ emptyArrayInt8, emptyArrayInt16, emptyArrayInt32, emptyArrayInt64 -~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ emptyArrayFloat32, emptyArrayFloat64 -~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ emptyArrayDate, emptyArrayDateTime -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ emptyArrayString -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~ Принимает ноль аргументов и возвращает пустой массив соответствующего типа. emptyArrayToSingle -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Принимает пустой массив и возвращает массив из одного элемента, равного значению по умолчанию. range(N) -~~~~~~~ +~~~~~~~~ Возвращает массив чисел от 0 до N-1. На всякий случай, если на блок данных, создаются массивы суммарной длины больше 100 000 000 элементов, то кидается исключение. array(x1, ...), оператор [x1, ...] -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Создаёт массив из аргументов функции. Аргументы должны быть константами и иметь типы, для которых есть наименьший общий тип. Должен быть передан хотя бы один аргумент, так как иначе непонятно, какого типа создавать массив. То есть, с помощью этой функции невозможно создать пустой массив (для этого используйте функции emptyArray*, описанные выше). Возвращает результат типа Array(T), где T - наименьший общий тип от переданных аргументов. arrayElement(arr, n), оператор arr[n] -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Достаёт элемент с индексом n из массива arr. n должен быть любым целочисленным типом. Индексы в массиве начинаются с единицы. @@ -62,21 +62,21 @@ n должен быть любым целочисленным типом. - иначе, возвращается некоторое значение по умолчанию (0 для чисел, пустая строка для строк и т. п.). has(arr, elem) -~~~~~~~~~~~ +~~~~~~~~~~~~~~ Проверяет наличие элемента elem в массиве arr. Возвращает 0, если элемента в массиве нет, или 1, если есть. elem должен быть константой. indexOf(arr, x) -~~~~~~~~~~ +~~~~~~~~~~~~~~~ Возвращает индекс элемента x (начиная с 1), если он есть в массиве, или 0, если его нет. countEqual(arr, x) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Возвращает количество элементов массива, равных x. Эквивалентно arrayCount(elem -> elem = x, arr). arrayEnumerate(arr) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ Возвращает массив [1, 2, 3, ..., length(arr)] Эта функция обычно используется совместно с ARRAY JOIN. Она позволяет, после применения ARRAY JOIN, посчитать что-либо только один раз для каждого массива. Пример: @@ -114,7 +114,7 @@ arrayEnumerate(arr) Также эта функция может быть использована в функциях высшего порядка. Например, с её помощью можно достать индексы массива для элементов, удовлетворяющих некоторому условию. arrayEnumerateUniq(arr, ...) -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Возвращает массив, такого же размера, как исходный, где для каждого элемента указано, какой он по счету среди элементов с таким же значением. Например: arrayEnumerateUniq([10, 20, 10, 30]) = [1, 1, 2, 1]. @@ -171,5 +171,5 @@ arrayUniq(arr, ...) Если необходимо получить список уникальных элементов массива, можно воспользоваться arrayReduce('groupUniqArray', arr). arrayJoin(arr) -~~~~~~~~ +~~~~~~~~~~~~~~ Особенная функция. Смотрите раздел "Функция arrayJoin". diff --git a/docs/ru/functions/array_join.rst b/docs/ru/functions/array_join.rst index 6302776490d..0d2a805a006 100644 --- a/docs/ru/functions/array_join.rst +++ b/docs/ru/functions/array_join.rst @@ -1,5 +1,5 @@ Функция arrayJoin ---------------- +----------------- Это совсем необычная функция. Обычные функции не изменяют множество строк, а лишь изменяют значения в каждой строке (map). diff --git a/docs/ru/functions/bit_functions.rst b/docs/ru/functions/bit_functions.rst index c5712800ba1..dbd36ade77e 100644 --- a/docs/ru/functions/bit_functions.rst +++ b/docs/ru/functions/bit_functions.rst @@ -21,4 +21,4 @@ bitShiftLeft(a, b) ~~~~~~~~~~~~~~~~~~ bitShiftRight(a, b) -~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ru/functions/comparison_functions.rst b/docs/ru/functions/comparison_functions.rst index e25ea67853e..d590dceafe1 100644 --- a/docs/ru/functions/comparison_functions.rst +++ b/docs/ru/functions/comparison_functions.rst @@ -1,5 +1,5 @@ Функции сравнения ------------------- +----------------- Функции сравнения возвращают всегда 0 или 1 (UInt8). @@ -30,7 +30,7 @@ greater, оператор > ~~~~~~~~~~~~~~~~~~~ lessOrEquals, оператор <= -~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~ greaterOrEquals, оператор >= -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ru/functions/conditional_functions.rst b/docs/ru/functions/conditional_functions.rst index 3ebea48120a..dbebf7c2610 100644 --- a/docs/ru/functions/conditional_functions.rst +++ b/docs/ru/functions/conditional_functions.rst @@ -2,6 +2,6 @@ ------------- if(cond, then, else), оператор cond ? then : else -~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Возвращает then, если cond != 0 или else, если cond = 0. cond должно иметь тип UInt8, а then и else должны иметь тип, для которого есть наименьший общий тип. diff --git a/docs/ru/functions/date_time_functions.rst b/docs/ru/functions/date_time_functions.rst index c20f24aed8b..72586480efa 100644 --- a/docs/ru/functions/date_time_functions.rst +++ b/docs/ru/functions/date_time_functions.rst @@ -6,6 +6,7 @@ Все функции по работе с датой и временем, для которых это имеет смысл, могут принимать второй, необязательный аргумент - имя часового пояса. Пример: Asia/Yekaterinburg. В этом случае, они используют не локальный часовой пояс (по умолчанию), а указанный. .. code-block:: sql + SELECT toDateTime('2016-06-15 23:00:00') AS time, toDate(time) AS date_local, @@ -15,6 +16,7 @@ ┌────────────────time─┬─date_local─┬─date_yekat─┬─time_samoa──────────┐ │ 2016-06-15 23:00:00 │ 2016-06-15 │ 2016-06-16 │ 2016-06-15 09:00:00 │ └─────────────────────┴────────────┴────────────┴─────────────────────┘ + Поддерживаются только часовые пояса, отличающиеся от UTC на целое число часов. toYear diff --git a/docs/ru/functions/encoding_functions.rst b/docs/ru/functions/encoding_functions.rst index 4116952b674..139585d11e6 100644 --- a/docs/ru/functions/encoding_functions.rst +++ b/docs/ru/functions/encoding_functions.rst @@ -1,27 +1,27 @@ Функции кодирования --------- +------------------- hex -~~~~~ +~~~ Принимает строку, число, дату или дату-с-временем. Возвращает строку, содержащую шестнадцатеричное представление аргумента. Используются заглавные буквы A-F. Не используются префиксы 0x и суффиксы h. Для строк просто все байты кодируются в виде двух шестнадцатеричных цифр. Числа выводятся в big endian ("человеческом") формате. Для чисел вырезаются старшие нули, но только по целым байтам. Например, hex(1) = '01'. Даты кодируются как число дней с начала unix-эпохи. Даты-с-временем кодируются как число секунд с начала unix-эпохи. unhex(str) -~~~~~~~ +~~~~~~~~~~ Принимает строку, содержащую произвольное количество шестнадцатеричных цифр, и возвращает строку, содержащую соответствующие байты. Поддерживаются как строчные, так и заглавные буквы A-F. Число шестнадцатеричных цифр не обязано быть чётным. Если оно нечётное - последняя цифра интерпретируется как младшая половинка байта 00-0F. Если строка-аргумент содержит что-либо кроме шестнадцатеричных цифр, то будет возвращён какой-либо implementation-defined результат (не кидается исключение). Если вы хотите преобразовать результат в число, то вы можете использовать функции reverse и reinterpretAsType. UUIDStringToNum(str) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ Принимает строку, содержащую 36 символов в формате 123e4567-e89b-12d3-a456-426655440000, и возвращает в виде набора байт в FixedString(16). UUIDNumToString(str) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ Принимает значение типа FixedString(16). Возвращает строку из 36 символов в текстовом виде. bitmaskToList(num) -~~~~~~~ +~~~~~~~~~~~~~~~~~~ Принимает целое число. Возвращает строку, содержащую список степеней двойки, в сумме дающих исходное число; по возрастанию, в текстовом виде, через запятую, без пробелов. bitmaskToArray(num) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ Принимает целое число. Возвращает массив чисел типа UInt64, содержащий степени двойки, в сумме дающих исходное число; числа в массиве идут по возрастанию. diff --git a/docs/ru/functions/ext_dict_functions.rst b/docs/ru/functions/ext_dict_functions.rst index 9fd1d7f130a..0e27687efe3 100644 --- a/docs/ru/functions/ext_dict_functions.rst +++ b/docs/ru/functions/ext_dict_functions.rst @@ -1,21 +1,21 @@ Функции для работы с внешними словарями -------- +--------------------------------------- Подробнее смотрите в разделе "Внешние словари". dictGetUInt8, dictGetUInt16, dictGetUInt32, dictGetUInt64 -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dictGetInt8, dictGetInt16, dictGetInt32, dictGetInt64 -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dictGetFloat32, dictGetFloat64 -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dictGetDate, dictGetDateTime -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dictGetString -~~~~~~ +~~~~~~~~~~~~~ ``dictGetT('dict_name', 'attr_name', id)`` - получить из словаря dict_name значение атрибута attr_name по ключу id. ``dict_name`` и ``attr_name`` - константные строки. @@ -23,21 +23,21 @@ dictGetString Если ключа ``id`` нет в словаре - вернуть значение по умолчанию, заданное в описании словаря. dictGetTOrDefault -~~~~~~~~ +~~~~~~~~~~~~~~~~~ ``dictGetT('dict_name', 'attr_name', id, default)`` Аналогично функциям dictGetT, но значение по умолчанию берётся из последнего аргумента функции. dictIsIn -~~~~~~ +~~~~~~~~ ``dictIsIn('dict_name', child_id, ancestor_id)`` - для иерархического словаря dict_name - узнать, находится ли ключ child_id внутри ancestor_id (или совпадает с ancestor_id). Возвращает UInt8. dictGetHierarchy -~~~~~~~~ +~~~~~~~~~~~~~~~~ ``dictGetHierarchy('dict_name', id)`` - для иерархического словаря dict_name - вернуть массив ключей словаря, начиная с id и продолжая цепочкой родительских элементов. Возвращает Array(UInt64). dictHas -~~~~~~ +~~~~~~~ ``dictHas('dict_name', id)`` - проверить наличие ключа в словаре. Возвращает значение типа UInt8, равное 0, если ключа нет и 1, если ключ есть. diff --git a/docs/ru/functions/hash_functions.rst b/docs/ru/functions/hash_functions.rst index 58765bb2671..cf1c188fb90 100644 --- a/docs/ru/functions/hash_functions.rst +++ b/docs/ru/functions/hash_functions.rst @@ -1,10 +1,10 @@ Функции хэширования -------------- +------------------- Функции хэширования могут использоваться для детерминированного псевдослучайного разбрасывания элементов. halfMD5 -~~~~~~ +~~~~~~~ Вычисляет MD5 от строки. Затем берёт первые 8 байт от хэша и интерпретирует их как UInt64 в big endian. Принимает аргумент типа String. Возвращает UInt64. Функция работает достаточно медленно (5 миллионов коротких строк в секунду на одном процессорном ядре). @@ -17,20 +17,20 @@ MD5 Если вы хотите получить такой же результат, как выдаёт утилита md5sum, напишите lower(hex(MD5(s))). sipHash64 -~~~~~~~ +~~~~~~~~~ Вычисляет SipHash от строки. Принимает аргумент типа String. Возвращает UInt64. SipHash - криптографическая хэш-функция. Работает быстрее чем MD5 не менее чем в 3 раза. Подробнее смотрите по ссылке: https://131002.net/siphash/ sipHash128 -~~~~~ +~~~~~~~~~~ Вычисляет SipHash от строки. Принимает аргумент типа String. Возвращает FixedString(16). Отличается от sipHash64 тем, что финальный xor-folding состояния делается только до 128 бит. cityHash64 -~~~~~ +~~~~~~~~~~ Вычисляет CityHash64 от строки или похожую хэш-функцию для произвольного количества аргументов произвольного типа. Если аргумент имеет тип String, то используется CityHash. Это быстрая некриптографическая хэш-функция неплохого качества для строк. Если аргумент имеет другой тип, то используется implementation specific быстрая некриптографическая хэш-функция неплохого качества. @@ -38,12 +38,12 @@ cityHash64 Например, так вы можете вычислить чексумму всей таблицы с точностью до порядка строк: ``SELECT sum(cityHash64(*)) FROM table``. intHash32 -~~~~~ +~~~~~~~~~ Вычисляет 32-битный хэш-код от целого числа любого типа. Это сравнительно быстрая некриптографическая хэш-функция среднего качества для чисел. intHash64 -~~~~~ +~~~~~~~~~ Вычисляет 64-битный хэш-код от целого числа любого типа. Работает быстрее, чем intHash32. Качество среднее. @@ -51,17 +51,17 @@ SHA1 ~~~~ SHA224 -~~~~~ +~~~~~~ SHA256 -~~~~~ +~~~~~~ Вычисляет SHA-1, SHA-224, SHA-256 от строки и возвращает полученный набор байт в виде FixedString(20), FixedString(28), FixedString(32). Функция работает достаточно медленно (SHA-1 - примерно 5 миллионов коротких строк в секунду на одном процессорном ядре, SHA-224 и SHA-256 - примерно 2.2 миллионов). Рекомендуется использовать эти функции лишь в тех случаях, когда вам нужна конкретная хэш-функция и вы не можете её выбрать. Даже в этих случаях, рекомендуется применять функцию оффлайн - заранее вычисляя значения при вставке в таблицу, вместо того, чтобы применять её при SELECT-ах. URLHash(url[, N]) -~~~~~~~~ +~~~~~~~~~~~~~~~~~ Быстрая некриптографическая хэш-функция неплохого качества для строки, полученной из URL путём некоторой нормализации. ``URLHash(s)`` - вычислить хэш от строки без одного завершающего символа ``/``, ``?`` или ``#`` на конце, если такой там есть. ``URLHash(s, N)`` - вычислить хэш от строки до N-го уровня в иерархии URL, без одного завершающего символа ``/``, ``?`` или ``#`` на конце, если такой там есть. diff --git a/docs/ru/functions/higher_order_functions.rst b/docs/ru/functions/higher_order_functions.rst index 6e4eaf43420..6162a269514 100644 --- a/docs/ru/functions/higher_order_functions.rst +++ b/docs/ru/functions/higher_order_functions.rst @@ -2,7 +2,7 @@ ----------------------- Оператор ->, функция lambda(params, expr) -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Позволяет описать лямбда-функцию для передачи в функцию высшего порядка. Слева от стрелочки стоит формальный параметр - произвольный идентификатор, или несколько формальных параметров - произвольные идентификаторы в кортеже. Справа от стрелочки стоит выражение, в котором могут использоваться эти формальные параметры, а также любые столбцы таблицы. Примеры: ``x -> 2 * x, str -> str != Referer.`` @@ -14,11 +14,11 @@ Для всех функций кроме arrayMap, arrayFilter, первый аргумент (лямбда-функция) может отсутствовать. В этом случае, подразумевается тождественное отображение. arrayMap(func, arr1, ...) -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть массив, полученный из исходного применением функции func к каждому элементу массива arr. arrayFilter(func, arr1, ...) -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть массив, содержащий только те элементы массива arr1, для которых функция func возвращает не 0. Примеры: @@ -43,25 +43,25 @@ arrayFilter(func, arr1, ...) └─────┘ arrayCount([func,] arr1, ...) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть количество элементов массива arr, для которых функция func возвращает не 0. Если func не указана - вернуть количество ненулевых элементов массива. arrayExists([func,] arr1, ...) -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть 1, если существует хотя бы один элемент массива arr, для которого функция func возвращает не 0. Иначе вернуть 0. arrayAll([func,] arr1, ...) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть 1, если для всех элементов массива arr, функция func возвращает не 0. Иначе вернуть 0. arraySum([func,] arr1, ...) -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть сумму значений функции func. Если функция не указана - просто вернуть сумму элементов массива. arrayFirst(func, arr1, ...) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть первый элемент массива arr1, для которого функция func возвращает не 0. arrayFirstIndex(func, arr1, ...) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть индекс первого элемента массива arr1, для которого функция func возвращает не 0. diff --git a/docs/ru/functions/in_functions.rst b/docs/ru/functions/in_functions.rst index 5e17c634c4e..a826c94b175 100644 --- a/docs/ru/functions/in_functions.rst +++ b/docs/ru/functions/in_functions.rst @@ -1,18 +1,18 @@ Функции для реализации оператора IN. ---------------- +------------------------------------ in, notIn, globalIn, globalNotIn -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Смотрите раздел "Операторы IN". tuple(x, y, ...), оператор (x, y, ...) -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Функция, позволяющая сгруппировать несколько столбцов. Для столбцов, имеющих типы T1, T2, ... возвращает кортеж типа Tuple(T1, T2, ...), содержащий эти столбцы. Выполнение функции ничего не стоит. Кортежи обычно используются как промежуточное значение в качестве аргумента операторов IN, или для создания списка формальных параметров лямбда-функций. Кортежи не могут быть записаны в таблицу. tupleElement(tuple, n), оператор x.N -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Функция, позволяющая достать столбец из кортежа. N - индекс столбца начиная с 1. N должно быть константой. N должно быть целым строго положительным числом не большим размера кортежа. Выполнение функции ничего не стоит. diff --git a/docs/ru/functions/ip_address_functions.rst b/docs/ru/functions/ip_address_functions.rst index b872dee1ef5..ab5986af39c 100644 --- a/docs/ru/functions/ip_address_functions.rst +++ b/docs/ru/functions/ip_address_functions.rst @@ -1,16 +1,16 @@ Функции для работы с IP-адресами -------------------------- +-------------------------------- IPv4NumToString(num) -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ Принимает число типа UInt32. Интерпретирует его, как IPv4-адрес в big endian. Возвращает строку, содержащую соответствующий IPv4-адрес в формате A.B.C.D (числа в десятичной форме через точки). IPv4StringToNum(s) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Функция, обратная к IPv4NumToString. Если IPv4 адрес в неправильном формате, то возвращает 0. IPv4NumToStringClassC(num) -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~ Похоже на IPv4NumToString, но вместо последнего октета используется xxx. Пример: @@ -41,7 +41,7 @@ IPv4NumToStringClassC(num) В связи с тем, что использование xxx весьма необычно, это может быть изменено в дальнейшем, и вам не следует полагаться на конкретный вид этого фрагмента. IPv6NumToString(x) -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Принимает значение типа FixedString(16), содержащее IPv6-адрес в бинарном виде. Возвращает строку, содержащую этот адрес в текстовом виде. IPv6-mapped IPv4 адреса выводится в формате ::ffff:111.222.33.44. Примеры: @@ -96,6 +96,6 @@ IPv6-mapped IPv4 адреса выводится в формате ::ffff:111.22 └────────────────────────────┴────────┘ IPv6StringToNum(s) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Функция, обратная к IPv6NumToString. Если IPv6 адрес в неправильном формате, то возвращает строку из нулевых байт. HEX может быть в любом регистре. diff --git a/docs/ru/functions/json_functions.rst b/docs/ru/functions/json_functions.rst index 3f628d302c4..175a6c65c66 100644 --- a/docs/ru/functions/json_functions.rst +++ b/docs/ru/functions/json_functions.rst @@ -1,5 +1,5 @@ Функции для работы с JSON. -------------------- +-------------------------- В Яндекс.Метрике пользователями передаётся JSON в качестве параметров визитов. Для работы с таким JSON-ом, реализованы некоторые функции. (Хотя в большинстве случаев, JSON-ы дополнительно обрабатываются заранее, и полученные значения кладутся в отдельные столбцы в уже обработанном виде.) Все эти функции исходят из сильных допущений о том, каким может быть JSON, и при этом стараются почти ничего не делать. Делаются следующие допущения: @@ -9,40 +9,42 @@ #. В JSON-е нет пробельных символов вне строковых литералов. visitParamHas(params, name) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Проверить наличие поля с именем name. visitParamExtractUInt(params, name) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Распарсить UInt64 из значения поля с именем name. Если поле строковое - попытаться распарсить число из начала строки. Если такого поля нет, или если оно есть, но содержит не число, то вернуть 0. visitParamExtractInt(params, name) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Аналогично для Int64. visitParamExtractFloat(params, name) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Аналогично для Float64. visitParamExtractBool(params, name) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Распарсить значение true/false. Результат - UInt8. visitParamExtractRaw(params, name) -~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Вернуть значение поля, включая разделители. Примеры: :: + visitParamExtractRaw('{"abc":"\\n\\u0000"}', 'abc') = '"\\n\\u0000"' visitParamExtractRaw('{"abc":{"def":[1,2,3]}}', 'abc') = '{"def":[1,2,3]}' visitParamExtractString(params, name) -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Распарсить строку в двойных кавычках. У значения убирается экранирование. Если убрать экранированные символы не удалось, то возвращается пустая строка. Примеры: :: + visitParamExtractString('{"abc":"\\n\\u0000"}', 'abc') = '\n\0' visitParamExtractString('{"abc":"\\u263a"}', 'abc') = '☺' visitParamExtractString('{"abc":"\\u263"}', 'abc') = '' diff --git a/docs/ru/functions/math_functions.rst b/docs/ru/functions/math_functions.rst index f033cb5f0e7..a30780a8e0f 100644 --- a/docs/ru/functions/math_functions.rst +++ b/docs/ru/functions/math_functions.rst @@ -1,9 +1,9 @@ Математические функции ---------------- +---------------------- Все функции возвращают число типа Float64. Точность результата близка к максимально возможной, но результат может не совпадать с наиболее близким к соответствующему вещественному числу машинно представимым числом. e() -~~~~ +~~~ Принимает ноль аргументов, возвращает число типа Float64, близкое к числу e. pi() @@ -11,7 +11,7 @@ pi() Принимает ноль аргументов, возвращает число типа Float64, близкое к числу π. exp(x) -~~~~~ +~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к экспоненте от аргумента. log(x) @@ -23,19 +23,19 @@ exp2(x) Принимает числовой аргумент, возвращает число типа Float64, близкое к 2x. log2(x) -~~~~~ +~~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к двоичному логарифму от аргумента. exp10(x) -~~~~~~~ +~~~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к 10x. log10(x) -~~~~~~~ +~~~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к десятичному логарифму от аргумента. sqrt(x) -~~~~~~~~ +~~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к квадратному корню от аргумента. cbrt(x) @@ -43,7 +43,7 @@ cbrt(x) Принимает числовой аргумент, возвращает число типа Float64, близкое к кубическому корню от аргумента. erf(x) -~~~~~~~ +~~~~~~ Если x неотрицательно, то erf(x / σ√2) - вероятность того, что случайная величина, имеющая нормальное распределение со среднеквадратичным отклонением σ, принимает значение, отстоящее от мат. ожидания больше чем на x. @@ -58,23 +58,23 @@ erf(x) └─────────────────────────┘ erfc(x) -~~~~~~ +~~~~~~~ Принимает числовой аргумент, возвращает число типа Float64, близкое к 1 - erf(x), но без потери точности для больших x. lgamma(x) -~~~~~~~ +~~~~~~~~~ Логарифм от гамма функции. tgamma(x) -~~~~~~ +~~~~~~~~~ Гамма функция. sin(x) -~~~~~ +~~~~~~ Синус. cos(x) -~~~~~ +~~~~~~ Косинус. tan(x) @@ -82,17 +82,17 @@ tan(x) Тангенс. asin(x) -~~~~~~ +~~~~~~~ Арксинус. acos(x) -~~~~~~ +~~~~~~~ Арккосинус. atan(x) -~~~~~ +~~~~~~~ Арктангенс. pow(x, y) -~~~~~~~ +~~~~~~~~~ xy. diff --git a/docs/ru/functions/other_functions.rst b/docs/ru/functions/other_functions.rst index 7e4fff51a0b..ff73662d971 100644 --- a/docs/ru/functions/other_functions.rst +++ b/docs/ru/functions/other_functions.rst @@ -1,64 +1,64 @@ Прочие функции -------------- +-------------- hostName() -~~~~~~~ +~~~~~~~~~~ Возвращает строку - имя хоста, на котором эта функция была выполнена. При распределённой обработке запроса, это будет имя хоста удалённого сервера, если функция выполняется на удалённом сервере. visibleWidth(x) -~~~~~~~~~ +~~~~~~~~~~~~~~~ Вычисляет приблизительную ширину при выводе значения в текстовом (tab-separated) виде на консоль. Функция используется системой для реализации Pretty форматов. toTypeName(x) -~~~~~~~~ +~~~~~~~~~~~~~ Возвращает строку, содержащую имя типа переданного аргумента. blockSize() -~~~~~~~~ +~~~~~~~~~~~ Получить размер блока. В ClickHouse выполнение запроса всегда идёт по блокам (наборам кусочков столбцов). Функция позволяет получить размер блока, для которого её вызвали. materialize(x) -~~~~~~~~ +~~~~~~~~~~~~~~ Превращает константу в полноценный столбец, содержащий только одно значение. В ClickHouse полноценные столбцы и константы представлены в памяти по-разному. Функции по-разному работают для аргументов-констант и обычных аргументов (выполняется разный код), хотя результат почти всегда должен быть одинаковым. Эта функция предназначена для отладки такого поведения. ignore(...) -~~~~~~~ +~~~~~~~~~~~ Принимает любые аргументы, всегда возвращает 0. При этом, аргумент всё равно вычисляется. Это может использоваться для бенчмарков. sleep(seconds) -~~~~~~~~~ +~~~~~~~~~~~~~~ Спит seconds секунд на каждый блок данных. Можно указать как целое число, так и число с плавающей запятой. currentDatabase() -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~ Возвращает имя текущей базы данных. Эта функция может использоваться в параметрах движка таблицы в запросе CREATE TABLE там, где нужно указать базу данных. isFinite(x) -~~~~~~~ +~~~~~~~~~~~ Принимает Float32 или Float64 и возвращает UInt8, равный 1, если аргумент не бесконечный и не NaN, иначе 0. isInfinite(x) -~~~~~~~ +~~~~~~~~~~~~~ Принимает Float32 или Float64 и возвращает UInt8, равный 1, если аргумент бесконечный, иначе 0. Отметим, что в случае NaN возвращается 0. isNaN(x) -~~~~~ +~~~~~~~~ Принимает Float32 или Float64 и возвращает UInt8, равный 1, если аргумент является NaN, иначе 0. hasColumnInTable('database', 'table', 'column') -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Принимает константные строки - имя базы данных, имя таблицы и название столбца. Возвращает константное выражение типа UInt8, равное 1, если есть столбец, иначе 0. Функция кидает исключение, если таблица не существует. Для элементов вложенной структуры данных функция проверяет существование столбца. Для самой же вложенной структуры данных функция возвращает 0. bar -~~~~~ +~~~ Позволяет построить unicode-art диаграмму. ``bar(x, min, max, width)`` - рисует полосу ширины пропорциональной (x - min) и равной width символов при x == max. @@ -107,7 +107,7 @@ bar └────┴────────┴────────────────────┘ transform -~~~~~~~ +~~~~~~~~~ Преобразовать значение согласно явно указанному отображению одних элементов на другие. Имеется два варианта функции: @@ -187,7 +187,7 @@ transform └────────────────┴─────────┘ formatReadableSize(x) -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ Принимает размер (число байт). Возвращает округленный размер с суффиксом (KiB, MiB и т.д.) в виде строки. Пример: @@ -206,27 +206,27 @@ formatReadableSize(x) └────────────────┴────────────┘ least(a, b) -~~~~~~ +~~~~~~~~~~~ Возвращает наименьшее значение из a и b. greatest(a, b) -~~~~~~~~ +~~~~~~~~~~~~~~ Возвращает наибольшее значение из a и b. uptime() -~~~~~~ +~~~~~~~~ Возвращает аптайм сервера в секундах. version() -~~~~~~~ +~~~~~~~~~ Возвращает версию сервера в виде строки. rowNumberInAllBlocks() -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~ Возвращает порядковый номер строки в блоке данных. Функция учитывает только задействованные блоки данных. runningDifference(x) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~ Считает разницу между последовательными значениями строк в блоке данных. Возвращает 0 для первой строки и разницу с предыдущей строкой для каждой последующей строки. diff --git a/docs/ru/functions/random_functions.rst b/docs/ru/functions/random_functions.rst index 3f3e71ffc10..1334c0efe75 100644 --- a/docs/ru/functions/random_functions.rst +++ b/docs/ru/functions/random_functions.rst @@ -1,5 +1,5 @@ Функции генерации псевдослучайных чисел ----------------------- +--------------------------------------- Используются некриптографические генераторы псевдослучайных чисел. Все функции принимают ноль аргументов или один аргумент. @@ -12,6 +12,6 @@ rand Используется linear congruential generator. rand64 -~~~~ +~~~~~~ Возвращает псевдослучайное число типа UInt64, равномерно распределённое среди всех чисел типа UInt64. Используется linear congruential generator. diff --git a/docs/ru/functions/rounding_functions.rst b/docs/ru/functions/rounding_functions.rst index 272cd10bd19..3d421ab5af2 100644 --- a/docs/ru/functions/rounding_functions.rst +++ b/docs/ru/functions/rounding_functions.rst @@ -1,8 +1,8 @@ Функции округления ----------------- +------------------ floor(x[, N]) -~~~~~~~ +~~~~~~~~~~~~~ Возвращает наибольшее круглое число, которое меньше или равно, чем x. Круглым называется число, кратное 1 / 10N или ближайшее к нему число соответствующего типа данных, если 1 / 10N не представимо точно. N - целочисленная константа, не обязательный параметр. По умолчанию - ноль, что означает - округлять до целого числа. @@ -15,25 +15,25 @@ N может быть отрицательным. В случае переполнения при округлении (например, floor(-128, -1)), возвращается implementation specific результат. ceil(x[, N]) -~~~~~~ +~~~~~~~~~~~~ Возвращает наименьшее круглое число, которое больше или равно, чем x. В остальном, аналогично функции floor, см. выше. round(x[, N]) -~~~~~~~ +~~~~~~~~~~~~~ Возвращает ближайшее к num круглое число, которое может быть меньше или больше или равно x. Если x находится посередине от ближайших круглых чисел, то возвращается какое-либо одно из них (implementation specific). Число -0. может считаться или не считаться круглым (implementation specific). В остальном, аналогично функциям floor и ceil, см. выше. roundToExp2(num) -~~~~~~~~ +~~~~~~~~~~~~~~~~ Принимает число. Если число меньше единицы - возвращает 0. Иначе округляет число вниз до ближайшей (целой неотрицательной) степени двух. roundDuration(num) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Принимает число. Если число меньше единицы - возвращает 0. Иначе округляет число вниз до чисел из набора: 1, 10, 30, 60, 120, 180, 240, 300, 600, 1200, 1800, 3600, 7200, 18000, 36000. Эта функция специфична для Яндекс.Метрики и предназначена для реализации отчёта по длительности визита. roundAge(num) -~~~~~~~ +~~~~~~~~~~~~~ Принимает число. Если число меньше 18 - возвращает 0. Иначе округляет число вниз до чисел из набора: 18, 25, 35, 45. Эта функция специфична для Яндекс.Метрики и предназначена для реализации отчёта по возрасту посетителей. diff --git a/docs/ru/functions/splitting_merging_functions.rst b/docs/ru/functions/splitting_merging_functions.rst index eb85635b3c7..08764489756 100644 --- a/docs/ru/functions/splitting_merging_functions.rst +++ b/docs/ru/functions/splitting_merging_functions.rst @@ -1,23 +1,23 @@ Функции разбиения и слияния строк и массивов ----------------- +-------------------------------------------- splitByChar(separator, s) -~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~ Разбивает строку на подстроки, используя в качестве разделителя separator. separator должен быть константной строкой из ровно одного символа. Возвращается массив выделенных подстрок. Могут выделяться пустые подстроки, если разделитель идёт в начале или в конце строки, или если идёт более одного разделителя подряд. splitByString(separator, s) -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ То же самое, но использует строку из нескольких символов в качестве разделителя. Строка должна быть непустой. arrayStringConcat(arr[, separator]) -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Склеивает строки, перечисленные в массиве, с разделителем separator. separator - необязательный параметр, константная строка, по умолчанию равен пустой строке. Возвращается строка. alphaTokens(s) -~~~~~~~~~~ +~~~~~~~~~~~~~~ Выделяет подстроки из подряд идущих байт из диапазонов a-z и A-Z. Возвращается массив выделенных подстрок. diff --git a/docs/ru/functions/string_replace_functions.rst b/docs/ru/functions/string_replace_functions.rst index 9c0892f04b0..7a99b4d5c8f 100644 --- a/docs/ru/functions/string_replace_functions.rst +++ b/docs/ru/functions/string_replace_functions.rst @@ -53,6 +53,7 @@ replaceRegexpAll(haystack, pattern, replacement) То же самое, но делается замена всех вхождений. Пример: .. code-block:: sql + SELECT replaceRegexpAll('Hello, World!', '.', '\\0\\0') AS res ┌─res────────────────────────┐ @@ -63,6 +64,7 @@ replaceRegexpAll(haystack, pattern, replacement) Пример: .. code-block:: sql + SELECT replaceRegexpAll('Hello, World!', '^', 'here: ') AS res ┌─res─────────────────┐ diff --git a/docs/ru/functions/type_conversion_functions.rst b/docs/ru/functions/type_conversion_functions.rst index 2269c608e42..51e5e66b39c 100644 --- a/docs/ru/functions/type_conversion_functions.rst +++ b/docs/ru/functions/type_conversion_functions.rst @@ -28,6 +28,7 @@ toString Форматы даты и даты-с-временем для функций toDate/toDateTime определены следующим образом: :: + YYYY-MM-DD YYYY-MM-DD hh:mm:ss diff --git a/docs/ru/functions/url_functions.rst b/docs/ru/functions/url_functions.rst index 040c0d23ae1..0b6f18d6f1a 100644 --- a/docs/ru/functions/url_functions.rst +++ b/docs/ru/functions/url_functions.rst @@ -16,19 +16,19 @@ domain Возвращает домен. domainWithoutWWW -"""""""""""" +"""""""""""""""" Возвращает домен, удалив не более одного 'www.' с начала, если есть. topLevelDomain -""""""""""" +"""""""""""""" Возвращает домен верхнего уровня. Пример: .ru. firstSignificantSubdomain -"""""""""""""" +""""""""""""""""""""""""" Возвращает "первый существенный поддомен". Это понятие является нестандартным и специфично для Яндекс.Метрики. Первый существенный поддомен - это домен второго уровня, если он не равен одному из com, net, org, co, или домен третьего уровня, иначе. Например, firstSignificantSubdomain('https://news.yandex.ru/') = 'yandex', firstSignificantSubdomain('https://news.yandex.com.tr/') = 'yandex'. Список "несущественных" доменов второго уровня и другие детали реализации могут изменяться в будущем. cutToFirstSignificantSubdomain -"""""""""""""""" +"""""""""""""""""""""""""""""" Возвращает часть домена, включающую поддомены верхнего уровня до "первого существенного поддомена" (см. выше). Например, ``cutToFirstSignificantSubdomain('https://news.yandex.com.tr/') = 'yandex.com.tr'``. @@ -38,42 +38,43 @@ path Возвращает путь. Пример: ``/top/news.html`` Путь не включает в себя query string. pathFull -""""""" +"""""""" То же самое, но включая query string и fragment. Пример: /top/news.html?page=2#comments queryString -""""""""" +""""""""""" Возвращает query-string. Пример: page=1&lr=213. query-string не включает в себя начальный знак вопроса, а также # и всё, что после #. fragment -"""""" +"""""""" Возвращает fragment identifier. fragment не включает в себя начальный символ решётки. queryStringAndFragment -""""""""" +"""""""""""""""""""""" Возвращает query string и fragment identifier. Пример: страница=1#29390. extractURLParameter(URL, name) -""""""""" +"""""""""""""""""""""""""""""" Возвращает значение параметра name в URL, если такой есть; или пустую строку, иначе; если параметров с таким именем много - вернуть первый попавшийся. Функция работает при допущении, что имя параметра закодировано в URL в точности таким же образом, что и в переданном аргументе. extractURLParameters(URL) -"""""""""" +""""""""""""""""""""""""" Возвращает массив строк вида name=value, соответствующих параметрам URL. Значения никак не декодируются. extractURLParameterNames(URL) -"""""""" +""""""""""""""""""""""""""""" Возвращает массив строк вида name, соответствующих именам параметров URL. Значения никак не декодируются. URLHierarchy(URL) -""""""""" +""""""""""""""""" Возвращает массив, содержащий URL, обрезанный с конца по символам /, ? в пути и query-string. Подряд идущие символы-разделители считаются за один. Резка производится в позиции после всех подряд идущих символов-разделителей. Пример: URLPathHierarchy(URL) -"""""""" +""""""""""""""""""""" То же самое, но без протокола и хоста в результате. Элемент / (корень) не включается. Пример: Функция используется для реализации древовидных отчётов по URL в Яндекс.Метрике. :: + URLPathHierarchy('https://example.com/browse/CONV-6788') = [ '/browse/', @@ -81,7 +82,7 @@ URLPathHierarchy(URL) ] decodeURLComponent(URL) -""""""""""" +""""""""""""""""""""""" Возвращает декодированный URL. Пример: @@ -93,26 +94,26 @@ decodeURLComponent(URL) │ http://127.0.0.1:8123/?query=SELECT 1; │ └────────────────────────────────────────┘ -Функции, удаляющие часть из URL-а. +Функции, удаляющие часть из URL-а ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Если в URL-е нет ничего похожего, то URL остаётся без изменений. cutWWW -""""" +"""""" Удаляет не более одного 'www.' с начала домена URL-а, если есть. cutQueryString -"""""" +"""""""""""""" Удаляет query string. Знак вопроса тоже удаляется. cutFragment -"""""""" +""""""""""" Удаляет fragment identifier. Символ решётки тоже удаляется. cutQueryStringAndFragment -"""""""""" +""""""""""""""""""""""""" Удаляет query string и fragment identifier. Знак вопроса и символ решётки тоже удаляются. cutURLParameter(URL, name) -"""""""""" +"""""""""""""""""""""""""" Удаляет параметр URL с именем name, если такой есть. Функция работает при допущении, что имя параметра закодировано в URL в точности таким же образом, что и в переданном аргументе. diff --git a/docs/ru/functions/ym_dict_functions.rst b/docs/ru/functions/ym_dict_functions.rst index b21d670bd2b..ef412381246 100644 --- a/docs/ru/functions/ym_dict_functions.rst +++ b/docs/ru/functions/ym_dict_functions.rst @@ -1,11 +1,11 @@ Функции для работы со словарями Яндекс.Метрики ----------------- +---------------------------------------------- Чтобы указанные ниже функции работали, в конфиге сервера должны быть указаны пути и адреса для получения всех словарей Яндекс.Метрики. Словари загружаются при первом вызове любой из этих функций. Если справочники не удаётся загрузить - будет выкинуто исключение. О том, как создать справочники, смотрите в разделе "Словари". Множественные геобазы -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ ClickHouse поддерживает работу одновременно с несколькими альтернативными геобазами (иерархиями регионов), для того чтобы можно было поддержать разные точки зрения о принадлежности регионов странам. В конфиге clickhouse-server указывается файл с иерархией регионов: @@ -21,16 +21,17 @@ ClickHouse поддерживает работу одновременно с н Во все функции по работе с регионами, в конце добавлен один необязательный аргумент - ключ словаря. Далее он обозначен как geobase. Пример: :: + regionToCountry(RegionID) - использует словарь по умолчанию: /opt/geo/regions_hierarchy.txt; regionToCountry(RegionID, '') - использует словарь по умолчанию: /opt/geo/regions_hierarchy.txt; regionToCountry(RegionID, 'ua') - использует словарь для ключа ua: /opt/geo/regions_hierarchy_ua.txt; regionToCity(id[, geobase]) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Принимает число типа UInt32 - идентификатор региона из геобазы Яндекса. Если регион является городом или входит в некоторый город, то возвращает идентификатор региона - соответствующего города. Иначе возвращает 0. regionToArea(id[, geobase]) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Переводит регион в область (тип в геобазе - 5). В остальном, аналогично функции regionToCity. .. code-block:: sql @@ -58,7 +59,7 @@ regionToArea(id[, geobase]) └──────────────────────────────────────────────────────┘ regionToDistrict(id[, geobase]) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Переводит регион в федеральный округ (тип в геобазе - 4). В остальном, аналогично функции regionToCity. .. code-block:: sql @@ -86,34 +87,34 @@ regionToDistrict(id[, geobase]) └──────────────────────────────────────────────────────────┘ regionToCountry(id[, geobase]) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Переводит регион в страну. В остальном, аналогично функции regionToCity. Пример: ``regionToCountry(toUInt32(213)) = 225`` - преобразовали Москву (213) в Россию (225). regionToContinent(id[, geobase]) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Переводит регион в континент. В остальном, аналогично функции regionToCity. Пример: ``regionToContinent(toUInt32(213)) = 10001`` - преобразовали Москву (213) в Евразию (10001). regionToPopulation(id[, geobase]) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Получает население для региона. Население может быть прописано в файлах с геобазой. Смотрите в разделе "Встроенные словари". Если для региона не прописано население, возвращается 0. В геобазе Яндекса, население может быть прописано для дочерних регионов, но не прописано для родительских. regionIn(lhs, rhs[, geobase]) -~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Проверяет принадлежность региона lhs региону rhs. Возвращает число типа UInt8, равное 1, если принадлежит и 0, если не принадлежит. Отношение рефлексивное - любой регион принадлежит также самому себе. regionHierarchy(id[, geobase]) -~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Принимает число типа UInt32 - идентификатор региона из геобазы Яндекса. Возвращает массив идентификаторов регионов, состоящий из переданного региона и всех родителей по цепочке. Пример: ``regionHierarchy(toUInt32(213)) = [213,1,3,225,10001,10000]``. regionToName(id[, lang]) -~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~ Принимает число типа UInt32 - идентификатор региона из геобазы Яндекса. Вторым аргументом может быть передана строка - название языка. Поддерживаются языки ru, en, ua, uk, by, kz, tr. Если второй аргумент отсутствует - используется язык ru. Если язык не поддерживается - кидается исключение. Возвращает строку - название региона на соответствующем языке. Если региона с указанным идентификатором не существует - возвращается пустая строка. ``ua`` и ``uk`` обозначают одно и то же - украинский язык. diff --git a/docs/ru/getting_started.rst b/docs/ru/getting_started.rst index 95b76f9f0f1..18cee873721 100644 --- a/docs/ru/getting_started.rst +++ b/docs/ru/getting_started.rst @@ -2,18 +2,20 @@ ============= Системные требования ------------------ +-------------------- Система некроссплатформенная. Требуется ОС Linux Ubuntu не более старая, чем Precise (12.04); архитектура x86_64 с поддержкой набора инструкций SSE 4.2. Для проверки наличия SSE 4.2, выполните: -:: + +.. code-block:: bash + grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported" Рекомендуется использовать Ubuntu Trusty или Ubuntu Xenial или Ubuntu Precise. Терминал должен работать в кодировке UTF-8 (как по умолчанию в Ubuntu). Установка ------------------ +--------- В целях тестирования и разработки, система может быть установлена на один сервер или на рабочий компьютер. @@ -22,12 +24,14 @@ Пропишите в `/etc/apt/sources.list` (или в отдельный файл `/etc/apt/sources.list.d/clickhouse.list`) репозитории: :: + deb http://repo.yandex.ru/clickhouse/trusty stable main На других версиях Ubuntu, замените `trusty` на `xenial` или `precise`. Затем выполните: :: + sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E0C56BD4 # optional sudo apt-get update sudo apt-get install clickhouse-client clickhouse-server-common @@ -48,11 +52,13 @@ ClickHouse содержит настройки ограничения досту Вы можете собрать пакеты и установить их. Также вы можете использовать программы без установки пакетов. :: + Клиент: dbms/src/Client/ Сервер: dbms/src/Server/ Для сервера создаёте директории с данными, например: :: + /opt/clickhouse/data/default/ /opt/clickhouse/metadata/default/ @@ -69,10 +75,12 @@ Gentoo overlay: https://github.com/kmeaw/clickhouse-overlay Запуск -------- +------ Для запуска сервера (в качестве демона), выполните: -:: + +.. code-block:: bash + sudo service clickhouse-server start Смотрите логи в директории `/var/log/clickhouse-server/` @@ -80,25 +88,33 @@ Gentoo overlay: https://github.com/kmeaw/clickhouse-overlay Если сервер не стартует - проверьте правильность конфигурации в файле `/etc/clickhouse-server/config.xml` Также можно запустить сервер из консоли: -:: + +.. code-block:: bash + clickhouse-server --config-file=/etc/clickhouse-server/config.xml При этом, лог будет выводиться в консоль - удобно для разработки. Если конфигурационный файл лежит в текущей директории, то указывать параметр --config-file не требуется - по умолчанию будет использован файл ./config.xml Соединиться с сервером можно с помощью клиента командной строки: -:: + +.. code-block:: bash + clickhouse-client Параметры по умолчанию обозначают - соединяться с localhost:9000, от имени пользователя default без пароля. Клиент может быть использован для соединения с удалённым сервером. Пример: -:: + +.. code-block:: bash + clickhouse-client --host=example.com Подробнее смотри раздел "Клиент командной строки". Проверим работоспособность системы: -:: + +.. code-block:: bash + milovidov@milovidov-Latitude-E6320:~/work/metrica/src/dbms/src/Client$ ./clickhouse-client ClickHouse client version 0.0.18749. Connecting to localhost:9000. diff --git a/docs/ru/interfaces/cli.rst b/docs/ru/interfaces/cli.rst index 999a2552044..cd51b2c7ea9 100644 --- a/docs/ru/interfaces/cli.rst +++ b/docs/ru/interfaces/cli.rst @@ -1,7 +1,9 @@ Клиент командной строки ----------------------- Для работы из командной строки вы можете использовать clickhouse-client: -:: + +.. code-block:: bash + $ clickhouse-client ClickHouse client version 0.0.26176. Connecting to localhost:9000. @@ -50,7 +52,9 @@ Аналогично HTTP интерфейсу, при использовании одновременно параметра query и отправке данных в stdin, запрос составляется из конкатенации параметра query, перевода строки, и данных в stdin. Это удобно для больших INSERT запросов. Примеры использования клиента для вставки данных: -:: + +.. code-block:: bash + echo -ne "1, 'some text', '2016-08-14 00:00:00'\n2, 'some more text', '2016-08-14 00:00:01'" | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV"; cat <<_EOF | clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV"; diff --git a/docs/ru/introduction/distinctive_features.rst b/docs/ru/introduction/distinctive_features.rst index 55e2eaca1d9..0f160a5880a 100644 --- a/docs/ru/introduction/distinctive_features.rst +++ b/docs/ru/introduction/distinctive_features.rst @@ -1,5 +1,5 @@ Отличительные возможности ClickHouse -=================================== +==================================== 1. По-настоящему столбцовая СУБД. --------------------------------- @@ -22,12 +22,12 @@ Большие запросы естественным образом распараллеливаются. 5. Распределённая обработка запроса на многих серверах. ------------------------------------------------ +------------------------------------------------------- Почти все перечисленные ранее столбцовые СУБД не поддерживают распределённую обработку запроса. В ClickHouse данные могут быть расположены на разных шардах. Каждый шард может представлять собой группу реплик, которые используются для отказоустойчивости. Запрос будет выполнен на всех шардах параллельно. Это делается прозрачно для пользователя. 6. Поддержка SQL. ---------------- +----------------- Если вы знаете, что такое стандартный SQL, то говорить о поддержке SQL всё-таки нельзя. Не поддерживаются NULL-ы. Все функции названы по-другому. Тем не менее, это - декларативный язык запросов на основе SQL и во многих случаях не отличимый от SQL. @@ -35,29 +35,29 @@ Зависимые подзапросы не поддерживаются. 7. Векторный движок. ------------------ +-------------------- Данные не только хранятся по столбцам, но и обрабатываются по векторам - кусочкам столбцов. За счёт этого достигается высокая эффективность по CPU. 8. Обновление данных в реальном времени. ------------------------ +---------------------------------------- ClickHouse поддерживает таблицы с первичным ключом. Для того, чтобы можно было быстро выполнять запросы по диапазону первичного ключа, данные инкрементально сортируются с помощью merge дерева. За счёт этого, поддерживается постоянное добавление данных в таблицу. Блокировки при добавлении данных отсутствуют. 9. Наличие индексов. ------------------ +-------------------- Наличие первичного ключа позволяет, например, вынимать данные для конкретных клиентов (счётчиков Метрики), для заданного диапазона времени, с низкими задержками - менее десятков миллисекунд. 10. Подходит для онлайн запросов. ------------------- +--------------------------------- Это позволяет использовать систему в качестве бэкенда для веб-интерфейса. Низкие задержки позволяют не откладывать выполнение запроса, а выполнять его в момент загрузки страницы интерфейса Яндекс.Метрики. То есть, в режиме онлайн. 11. Поддержка приближённых вычислений. ------------------ +-------------------------------------- #. Система содержит агрегатные функции для приближённого вычисления количества различных значений, медианы и квантилей. #. Поддерживается возможность выполнить запрос на основе части (выборки) данных и получить приближённый результат. При этом, с диска будет считано пропорционально меньше данных. #. Поддерживается возможность выполнить агрегацию не для всех ключей, а для ограниченного количества первых попавшихся ключей. При выполнении некоторых условий на распределение ключей в данных, это позволяет получить достаточно точный результат с использованием меньшего количества ресурсов. 14. Репликация данных, поддержка целостности данных на репликах. ------------------ +---------------------------------------------------------------- Используется асинхронная multimaster репликация. После записи на любую доступную реплику, данные распространяются на все остальные реплики. Система поддерживает полную идентичность данных на разных репликах. Восстановление после сбоя осуществляется автоматически, а в сложных случаях - "по кнопке". Подробнее смотрите раздел "Репликация данных". diff --git a/docs/ru/introduction/performance.rst b/docs/ru/introduction/performance.rst index 24f635eb9a5..c3b9cf225f7 100644 --- a/docs/ru/introduction/performance.rst +++ b/docs/ru/introduction/performance.rst @@ -1,21 +1,21 @@ Производительность -=================== +================== По результатам внутреннего тестирования, ClickHouse обладает наиболее высокой производительностью (как наиболее высоким throughput на длинных запросах, так и наиболее низкой latency на коротких запросах), при соответствующем сценарии работы, среди доступных для тестирования систем подобного класса. Результаты тестирования можно посмотреть на отдельной странице. Пропускная способность при обработке одного большого запроса -------------------------------- +------------------------------------------------------------ Пропускную способность можно измерять в строчках в секунду и в мегабайтах в секунду. При условии, что данные помещаются в page cache, не слишком сложный запрос обрабатывается на современном железе со скоростью около 2-10 GB/sec. несжатых данных на одном сервере (в простейшем случае скорость может достигать 30 GB/sec). Если данные не помещаются в page cache, то скорость работы зависит от скорости дисковой подсистемы и коэффициента сжатия данных. Например, если дисковая подсистема позволяет читать данные со скоростью 400 MB/sec., а коэффициент сжатия данных составляет 3, то скорость будет около 1.2GB/sec. Для получения скорости в строчках в секунду, следует поделить скорость в байтах в секунду на суммарный размер используемых в запросе столбцов. Например, если вынимаются столбцы на 10 байт, то скорость будет в районе 100-200 млн. строчек в секунду. При распределённой обработке запроса, скорость обработки запроса растёт почти линейно, но только при условии, что в результате агрегации или при сортировке получается не слишком большое множество строчек. Задержки при обработке коротких запросов. --------------------- +----------------------------------------- Если запрос использует первичный ключ, и выбирает для обработки не слишком большое количество строчек (сотни тысяч), и использует не слишком большое количество столбцов, то вы можете рассчитывать на latency менее 50 миллисекунд (от единиц миллисекунд в лучшем случае), при условии, что данные помещаются в page cache. Иначе latency вычисляется из количества seek-ов. Если вы используйте вращающиеся диски, то на не слишком сильно нагруженной системе, latency вычисляется по формуле: seek time (10 мс.) * количество столбцов в запросе * количество кусков с данными. Пропускная способность при обработке большого количества коротких запросов. --------------------- +--------------------------------------------------------------------------- При тех же условиях, ClickHouse может обработать несколько сотен (до нескольких тысяч в лучшем случае) запросов в секунду на одном сервере. Так как такой сценарий работы не является типичным для аналитических СУБД, рекомендуется рассчитывать не более чем на 100 запросов в секунду. Производительность при вставке данных. ------------------- +-------------------------------------- Данные рекомендуется вставлять пачками не менее 1000 строк или не более одного запроса в секунду. При вставке в таблицу типа MergeTree из tab-separated дампа, скорость вставки будет в районе 50-200 МБ/сек. Если вставляются строчки размером около 1 КБ, то скорость будет в районе 50 000 - 200 000 строчек в секунду. Если строчки маленькие - производительность в строчках в секунду будет выше (на данных БК - > 500 000 строк в секунду, на данных Graphite - > 1 000 000 строк в секунду). Для увеличения производительности, можно производить несколько запросов INSERT параллельно - при этом производительность растёт линейно. diff --git a/docs/ru/introduction/possible_silly_questions.rst b/docs/ru/introduction/possible_silly_questions.rst index 80f075ba501..22d0f6bf372 100644 --- a/docs/ru/introduction/possible_silly_questions.rst +++ b/docs/ru/introduction/possible_silly_questions.rst @@ -1,8 +1,8 @@ Возможные глупые вопросы ------------------------ +------------------------ 1. Почему бы не использовать системы типа map-reduce? -""""""""""""""""""" +""""""""""""""""""""""""""""""""""""""""""""""""""""" Системами типа map-reduce будем называть системы распределённых вычислений, в которых операция reduce сделана на основе распределённой сортировки. Таким образом, к ним относятся YAMR, Hadoop, YT. diff --git a/docs/ru/introduction/use_case.rst b/docs/ru/introduction/use_case.rst index 94c11fb9c85..9dde13d7230 100644 --- a/docs/ru/introduction/use_case.rst +++ b/docs/ru/introduction/use_case.rst @@ -1,5 +1,5 @@ Использование в Яндекс.Метрике и других отделах Яндекса ------------------------------------------- +------------------------------------------------------- В Яндекс.Метрике ClickHouse используется для нескольких задач. Основная задача - построение отчётов в режиме онлайн по неагрегированным данным. Для решения этой задачи используется кластер из 374 серверов, хранящий более 20,3 триллионов строк в базе данных. Объём сжатых данных, без учёта дублирования и репликации, составляет около 2 ПБ. Объём несжатых данных (в формате tsv) составил бы, приблизительно, 17 ПБ. diff --git a/docs/ru/introduction/what_is_clickhouse.rst b/docs/ru/introduction/what_is_clickhouse.rst index 46b8187e6db..6864b5e51f8 100644 --- a/docs/ru/introduction/what_is_clickhouse.rst +++ b/docs/ru/introduction/what_is_clickhouse.rst @@ -5,15 +5,17 @@ ClickHouse - столбцовая СУБД для OLAP (Columnar DBMS). В обычной, "строковой" СУБД, данные хранятся в таком порядке: :: + 5123456789123456789 1 Евробаскет - Греция - Босния и Герцеговина - example.com 1 2011-09-01 01:03:02 6274717 1294101174 11409 612345678912345678 0 33 6 http://www.example.com/basketball/team/123/match/456789.html http://www.example.com/basketball/team/123/match/987654.html 0 1366 768 32 10 3183 0 0 13 0\0 1 1 0 0 2011142 -1 0 0 01321 613 660 2011-09-01 08:01:17 0 0 0 0 utf-8 1466 0 0 0 5678901234567890123 277789954 0 0 0 0 0 5234985259563631958 0 Консалтинг, налогообложение, бухгалтерский учет, право 1 2011-09-01 01:03:02 6320881 2111222333 213 6458937489576391093 0 3 2 http://www.example.ru/ 0 800 600 16 10 2 153.1 0 0 10 63 1 1 0 0 2111678 000 0 588 368 240 2011-09-01 01:03:17 4 0 60310 0 windows-1251 1466 0 000 778899001 0 0 0 0 0 -... + ... То есть, значения, относящиеся к одной строке, хранятся рядом. Примеры строковых СУБД: MySQL, Postgres, MS SQL Server и т. п. В столбцовых СУБД, данные хранятся в таком порядке: :: + WatchID: 5385521489354350662 5385521490329509958 5385521489953706054 5385521490476781638 5385521490583269446 5385521490218868806 5385521491437850694 5385521491090174022 5385521490792669254 5385521490420695110 5385521491532181574 5385521491559694406 5385521491459625030 5385521492275175494 5385521492781318214 5385521492710027334 5385521492955615302 5385521493708759110 5385521494506434630 5385521493104611398 JavaEnable: 1 0 1 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 Title: Yandex Announcements - Investor Relations - Yandex Yandex — Contact us — Moscow Yandex — Mission Ru Yandex — History — History of Yandex Yandex Financial Releases - Investor Relations - Yandex Yandex — Locations Yandex Board of Directors - Corporate Governance - Yandex Yandex — Technologies @@ -58,7 +60,9 @@ ClickHouse - столбцовая СУБД для OLAP (Columnar DBMS). Для примера, для запроса "посчитать количество записей для каждой рекламной системы", требуется прочитать один столбец "идентификатор рекламной системы", который занимает 1 байт в несжатом виде. Если большинство переходов было не с рекламных систем, то можно рассчитывать хотя бы на десятикратное сжатие этого столбца. При использовании быстрого алгоритма сжатия, возможно разжатие данных со скоростью более нескольких гигабайт несжатых данных в секунду. То есть, такой запрос может выполняться со скоростью около нескольких миллиардов строк в секунду на одном сервере. На практике, такая скорость действительно достигается. Пример: -:: + +.. code-block:: bash + milovidov@████████.yandex.ru:~$ clickhouse-client ClickHouse client version 0.0.52053. Connecting to localhost:9000. diff --git a/docs/ru/introduction/ya_metrika_task.rst b/docs/ru/introduction/ya_metrika_task.rst index cb4dfa8759a..b3ade1fa7a3 100644 --- a/docs/ru/introduction/ya_metrika_task.rst +++ b/docs/ru/introduction/ya_metrika_task.rst @@ -5,7 +5,7 @@ На данный момент (апрель 2014), каждый день в Яндекс.Метрику поступает около 12 миллиардов событий (хитов и кликов мыши). Все эти события должны быть сохранены для возможности строить произвольные отчёты. Один запрос может потребовать просканировать сотни миллионов строк за время не более нескольких секунд, или миллионы строк за время не более нескольких сотен миллисекунд. Агрегированные и неагрегированные данные -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Существует мнение, что для того, чтобы эффективно считать статистику, данные нужно агрегировать, так как это позволяет уменьшить объём данных. Но агрегированные данные являются очень ограниченным решением, по следующим причинам: diff --git a/docs/ru/query_language/index.rst b/docs/ru/query_language/index.rst index a4676e7aa99..06ba229309c 100644 --- a/docs/ru/query_language/index.rst +++ b/docs/ru/query_language/index.rst @@ -1,5 +1,5 @@ Язык запросов -========== +============= .. toctree:: :glob: diff --git a/docs/ru/query_language/queries.rst b/docs/ru/query_language/queries.rst index a7e801bcfc8..db7de94dd05 100644 --- a/docs/ru/query_language/queries.rst +++ b/docs/ru/query_language/queries.rst @@ -4,7 +4,9 @@ CREATE DATABASE ~~~~~~~~~~~~~~~ Создание базы данных db_name -:: + +.. code-block:: sql + CREATE DATABASE [IF NOT EXISTS] db_name ``База данных`` - это просто директория для таблиц. @@ -13,7 +15,9 @@ CREATE DATABASE CREATE TABLE ~~~~~~~~~~~~ Запрос ``CREATE TABLE`` может иметь несколько форм. -:: + +.. code-block:: sql + CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ( name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], @@ -26,11 +30,15 @@ CREATE TABLE Описание столбца, это ``name type``, в простейшем случае. Пример: ``RegionID UInt32``. Также могут быть указаны выражения для значений по умолчанию - смотрите ниже. -:: + +.. code-block:: sql + CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] Создаёт таблицу с такой же структурой, как другая таблица. Можно указать другой движок для таблицы. Если движок не указан, то будет выбран такой же движок, как у таблицы ``db2.name2``. -:: + +.. code-block:: sql + CREATE [TEMPORARY] TABLE [IF NOT EXISTS] [db.]name ENGINE = engine AS SELECT ... Создаёт таблицу со структурой, как результат запроса ``SELECT``, с движком engine, и заполняет её данными из SELECT-а. @@ -86,20 +94,31 @@ CREATE TABLE CREATE VIEW ~~~~~~~~~~~~ -``CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ...`` + +.. code-block:: sql + + CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ... Создаёт представление. Представления бывают двух видов - обычные и материализованные (MATERIALIZED). Обычные представления не хранят никаких данных, а всего лишь производят чтение из другой таблицы. То есть, обычное представление - не более чем сохранённый запрос. При чтении из представления, этот сохранённый запрос, используется в качестве подзапроса в секции FROM. Для примера, пусть вы создали представление: -:: + +.. code-block:: sql + CREATE VIEW view AS SELECT ... + и написали запрос: -:: + +.. code-block:: sql + SELECT a, b, c FROM view + Этот запрос полностью эквивалентен использованию подзапроса: -:: + +.. code-block:: sql + SELECT a, b, c FROM (SELECT ...) Материализованные (MATERIALIZED) представления хранят данные, преобразованные соответствующим запросом SELECT. @@ -130,12 +149,16 @@ ATTACH DROP ~~~~ Запрос имеет два вида: ``DROP DATABASE`` и ``DROP TABLE``. -:: + +.. code-block:: sql + DROP DATABASE [IF EXISTS] db Удаляет все таблицы внутри базы данных db, а затем саму базу данных db. Если указано ``IF EXISTS`` - не выдавать ошибку, если база данных не существует. -:: + +.. code-block:: sql + DROP TABLE [IF EXISTS] [db.]name Удаляет таблицу. @@ -144,7 +167,9 @@ DROP DETACH ~~~~~~ Удаляет из сервера информацию о таблице `name`. Сервер перестаёт знать о существовании таблицы. -:: + +.. code-block:: sql + DETACH TABLE [IF EXISTS] [db.]name Но ни данные, ни метаданные таблицы не удаляются. При следующем запуске сервера, сервер прочитает метаданные и снова узнает о таблице. @@ -155,7 +180,9 @@ DETACH RENAME ~~~~~~ Переименовывает одну или несколько таблиц. -:: + +.. code-block:: sql + RENAME TABLE [db11.]name11 TO [db12.]name12, [db21.]name21 TO [db22.]name22, ... Все таблицы переименовываются под глобальной блокировкой. Переименовывание таблицы является лёгкой операцией. Если вы указали после TO другую базу данных, то таблица будет перенесена в эту базу данных. При этом, директории с базами данных должны быть расположены в одной файловой системе (иначе возвращается ошибка). @@ -167,14 +194,18 @@ ALTER Манипуляции со столбцами """""""""""""""""""""""" Изменение структуры таблицы. -:: + +.. code-block:: sql + ALTER TABLE [db].name ADD|DROP|MODIFY COLUMN ... В запросе указывается список из одного или более действий через запятую. Каждое действие - операция над столбцом. Существуют следующие действия: -:: + +.. code-block:: sql + ADD COLUMN name [type] [default_expr] [AFTER name_after] Добавляет в таблицу новый столбец с именем name, типом type и выражением для умолчания ``default_expr`` (смотрите раздел "Значения по умолчанию"). Если указано ``AFTER name_after`` (имя другого столбца), то столбец добавляется (в список столбцов таблицы) после указанного. Иначе, столбец добавляется в конец таблицы. Внимательный читатель может заметить, что отсутствует возможность добавить столбец в начало таблицы. Для цепочки действий, name_after может быть именем столбца, который добавляется в одном из предыдущих действий. @@ -240,7 +271,9 @@ ALTER Куском (part) в таблице называется часть данных одной партиции, отсортированная по первичному ключу. Чтобы посмотреть набор кусков и партиций таблицы, можно воспользоваться системной таблицей ``system.parts``: -:: + +.. code-block:: sql + SELECT * FROM system.parts WHERE active ``active`` - учитывать только активные куски. Неактивными являются, например, исходные куски оставшиеся после слияния в более крупный кусок - такие куски удаляются приблизительно через 10 минут после слияния. @@ -248,7 +281,9 @@ ALTER Другой способ посмотреть набор кусков и партиций - зайти в директорию с данными таблицы. Директория с данными - ``/var/lib/clickhouse/data/database/table/``, где ``/var/lib/clickhouse/`` - путь к данным ClickHouse, database - имя базы данных, table - имя таблицы. Пример: -:: + +.. code-block:: bash + $ ls -l /var/lib/clickhouse/data/test/visits/ total 48 drwxrwxrwx 2 clickhouse clickhouse 20480 мая 13 02:58 20140317_20140323_2_2_0 @@ -260,9 +295,9 @@ ALTER Рассмотрим по порядку имя первого куска: ``20140317_20140323_2_2_0``. * ``20140317`` - минимальная дата данных куска - * ``20140323`` - максимальная дата данных куска .. |br| raw:: html - * ``2`` - минимальный номер блока данных .. |br| raw:: html - * ``2`` - максимальный номер блока данных .. |br| raw:: html + * ``20140323`` - максимальная дата данных куска + * ``2`` - минимальный номер блока данных + * ``2`` - максимальный номер блока данных * ``0`` - уровень куска - глубина дерева слияний, которыми он образован Каждый кусок относится к одной партиции и содержит данные только за один месяц. @@ -273,8 +308,10 @@ ALTER Для реплицируемых таблиц, набор кусков нельзя менять в любом случае. Директория ``detached`` содержит куски, не используемые сервером - отцепленные от таблицы с помощью запроса ``ALTER ... DETACH``. Также в эту директорию переносятся куски, признанные повреждёнными, вместо их удаления. Вы можете в любое время добавлять, удалять, модифицировать данные в директории detached - сервер не будет об этом знать, пока вы не сделаете запрос ``ALTER TABLE ... ATTACH``. -:: -ALTER TABLE [db.]table DETACH PARTITION 'name' + +.. code-block:: sql + + ALTER TABLE [db.]table DETACH PARTITION 'name' Перенести все данные для партиции с именем name в директорию detached и забыть про них. Имя партиции указывается в формате YYYYMM. Оно может быть указано в одинарных кавычках или без них. @@ -282,11 +319,15 @@ ALTER TABLE [db.]table DETACH PARTITION 'name' После того, как запрос будет выполнен, вы можете самостоятельно сделать что угодно с данными в директории detached, например, удалить их из файловой системы, или ничего не делать. Запрос реплицируется - данные будут перенесены в директорию detached и забыты на всех репликах. Запрос может быть отправлен только на реплику-лидер. Вы можете узнать, является ли реплика лидером, сделав SELECT в системную таблицу system.replicas. Или, проще, вы можете выполнить запрос на всех репликах, и на всех кроме одной, он кинет исключение. -:: + +.. code-block:: sql + ALTER TABLE [db.]table DROP PARTITION 'name' Аналогично операции ``DETACH``. Удалить данные из таблицы. Куски с данными будут помечены как неактивные и будут полностью удалены примерно через 10 минут. Запрос реплицируется - данные будут удалены на всех репликах. -:: + +.. code-block:: sql + ALTER TABLE [db.]table ATTACH PARTITION|PART 'name' Добавить данные в таблицу из директории detached. @@ -296,7 +337,9 @@ ALTER TABLE [db.]table DETACH PARTITION 'name' Запрос реплицируется. Каждая реплика проверяет, если ли данные в директории detached. Если данные есть - проверяет их целостность, проверяет их соответствие данным на сервере-инициаторе запроса, и если всё хорошо, то добавляет их. Если нет, то скачивает данные с реплики-инициатора запроса, или с другой реплики, на которой уже добавлены эти данные. То есть, вы можете разместить данные в директории detached на одной реплике и, с помощью запроса ALTER ... ATTACH добавить их в таблицу на всех репликах. -:: + +.. code-block:: sql + ALTER TABLE [db.]table FREEZE PARTITION 'name' Создаёт локальный бэкап одной или нескольких партиций. В качестве имени может быть указано полное имя партиции (например, 201403) или его префикс (например, 2014) - тогда бэкап будет создан для всех соответствующих партиций. @@ -337,7 +380,9 @@ ALTER TABLE [db.]table DETACH PARTITION 'name' Бэкапы защищают от человеческих ошибок (случайно удалили данные, удалили не те данные или не на том кластере, испортили данные). Для баз данных большого объёма, бывает затруднительно копировать бэкапы на удалённые серверы. В этих случаях, для защиты от человеческой ошибки, можно держать бэкап на том же сервере (он будет лежать в ``/var/lib/clickhouse/shadow/``). -:: + +.. code-block:: sql + ALTER TABLE [db.]table FETCH PARTITION 'name' FROM 'path-in-zookeeper' Запрос работает только для реплицируемых таблиц. @@ -415,7 +460,10 @@ SHOW PROCESSLIST Запрос полностью аналогичен запросу: ``SELECT * FROM system.processes [INTO OUTFILE filename] [FORMAT format]``. Полезный совет (выполните в консоли): -``watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'"`` + +.. code-block:: bash + + watch -n1 "clickhouse-client --query='SHOW PROCESSLIST'" SHOW CREATE TABLE ~~~~~~~~~~~~~~~~~ @@ -1265,7 +1313,7 @@ n и m должны быть неотрицательными целыми чи │ 2014-03-23 │ 0.648416 │ └────────────┴──────────┘ -- за каждый день после 17 марта считаем долю хитов, сделанных посетителями, которые заходили на сайт 17 марта. +за каждый день после 17 марта считаем долю хитов, сделанных посетителями, которые заходили на сайт 17 марта. Подзапрос в секции IN на одном сервере всегда выполняется только один раз. Зависимых подзапросов не существует. Распределённые подзапросы @@ -1287,11 +1335,15 @@ n и m должны быть неотрицательными целыми чи Например, запрос -``SELECT uniq(UserID) FROM distributed_table`` +.. code-block:: sql + + SELECT uniq(UserID) FROM distributed_table будет отправлен на все удалённые серверы в виде -``SELECT uniq(UserID) FROM local_table`` +.. code-block:: sql + + SELECT uniq(UserID) FROM local_table`` , выполнен параллельно на каждом из них до стадии, позволяющей объединить промежуточные результаты; затем промежуточные результаты вернутся на сервер-инициатор запроса, будут на нём объединены, и финальный результат будет отправлен клиенту. @@ -1322,6 +1374,7 @@ n и m должны быть неотрицательными целыми чи Этот запрос будет отправлен на все удалённые серверы в виде .. code-block:: sql + SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34) На каждом удалённом сервере начнёт выполняться подзапрос. Так как в подзапросе используется распределённая таблица, то подзапрос будет, на каждом удалённом сервере, снова отправлен на каждый удалённый сервер, в виде diff --git a/docs/ru/query_language/syntax.rst b/docs/ru/query_language/syntax.rst index 770333e4d2b..73545b6c56e 100644 --- a/docs/ru/query_language/syntax.rst +++ b/docs/ru/query_language/syntax.rst @@ -4,7 +4,9 @@ В системе есть два вида парсеров: полноценный парсер SQL (recursive descent parser) и парсер форматов данных (быстрый потоковый парсер). Во всех случаях кроме запроса INSERT, используется только полноценный парсер SQL. В запросе INSERT используется оба парсера: -:: + +.. code-block:: sql + INSERT INTO t VALUES (1, 'Hello, world'), (2, 'abc'), (3, 'def') Фрагмент ``INSERT INTO t VALUES`` парсится полноценным парсером, а данные ``(1, 'Hello, world'), (2, 'abc'), (3, 'def')`` - быстрым потоковым парсером. @@ -86,7 +88,8 @@ Синонимы ~~~~~~~~ В запросе SELECT, в выражениях могут быть указаны синонимы с помощью ключевого слова AS. Слева от AS стоит любое выражение. Справа от AS стоит идентификатор - имя для синонима. В отличие от стандартного SQL, синонимы могут объявляться не только на верхнем уровне выражений: -:: +.. code-block:: sql + SELECT (1 AS n) + 2, n В отличие от стандартного SQL, синонимы могут использоваться во всех секциях запроса, а не только ``SELECT``. diff --git a/docs/ru/settings/query_complexity.rst b/docs/ru/settings/query_complexity.rst index 48c2adb1e37..7de814db6a1 100644 --- a/docs/ru/settings/query_complexity.rst +++ b/docs/ru/settings/query_complexity.rst @@ -1,5 +1,5 @@ Ограничения на сложность запроса -===================== +================================ Ограничения на сложность запроса - часть настроек. Используются, чтобы обеспечить более безопасное исполнение запросов из пользовательского интерфейса. Почти все ограничения действуют только на SELECT-ы. @@ -16,7 +16,7 @@ ``any (только для group_by_overflow_mode)`` - продолжить агрегацию по ключам, которые успели войти в набор, но не добавлять новые ключи в набор. readonly -------- +-------- При значении 0 можно выполнять любые запросы. При значении 1 можно выполнять только запросы на чтение (например, SELECT и SHOW). Запросы на запись и изменение настроек (INSERT, SET) запрещены. При значении 2 можно выполнять запросы на чтение (SELECT, SHOW) и изменение настроек (SET). @@ -26,7 +26,7 @@ readonly При использовании метода GET HTTP интерфейса, автоматически выставляется readonly = 1. То есть, для запросов, модифицирующие данные, можно использовать только метод POST. Сам запрос при этом можно отправлять как в теле POST-а, так и в параметре URL. max_memory_usage --------------- +---------------- Максимальное количество потребляемой памяти при выполнении запроса на одном сервере. По умолчанию - 10 GB. Настройка не учитывает объём свободной памяти или общий объём памяти на машине. @@ -41,134 +41,134 @@ max_memory_usage Потребление оперативки не полностью учитывается для состояний агрегатных функций min, max, any, anyLast, argMin, argMax от аргументов String и Array. max_rows_to_read ---------------- +---------------- Следующие ограничения могут проверяться на каждый блок (а не на каждую строку). То есть, ограничения могут быть немного нарушены. При выполнении запроса в несколько потоков, следующие ограничения действуют в каждом потоке по-отдельности. Максимальное количество строчек, которое можно прочитать из таблицы при выполнении запроса. max_bytes_to_read -------------- +----------------- Максимальное количество байт (несжатых данных), которое можно прочитать из таблицы при выполнении запроса. read_overflow_mode -------------- +------------------ Что делать, когда количество прочитанных данных превысило одно из ограничений: throw или break. По умолчанию: throw. max_rows_to_group_by -------------- +-------------------- Максимальное количество уникальных ключей, получаемых в процессе агрегации. Позволяет ограничить потребление оперативки при агрегации. group_by_overflow_mode ---------------- +---------------------- Что делать, когда количество уникальных ключей при агрегации превысило ограничение: throw, break или any. По умолчанию: throw. Использование значения any позволяет выполнить GROUP BY приближённо. Качество такого приближённого вычисления сильно зависит от статистических свойств данных. max_rows_to_sort --------------- +---------------- Максимальное количество строк до сортировки. Позволяет ограничить потребление оперативки при сортировке. max_bytes_to_sort -------------- +----------------- Максимальное количество байт до сортировки. sort_overflow_mode ------------- +------------------ Что делать, если количество строк, полученное перед сортировкой, превысило одно из ограничений: throw или break. По умолчанию: throw. max_result_rows -------------- +--------------- Ограничение на количество строк результата. Проверяются также для подзапросов и на удалённых серверах при выполнении части распределённого запроса. max_result_bytes -------------- +---------------- Ограничение на количество байт результата. Аналогично. result_overflow_mode --------------- +-------------------- Что делать, если объём результата превысил одно из ограничений: throw или break. По умолчанию: throw. Использование break по смыслу похоже на LIMIT. max_execution_time --------------- +------------------ Максимальное время выполнения запроса в секундах. На данный момент не проверяется при одной из стадий сортировки а также при слиянии и финализации агрегатных функций. timeout_overflow_mode ---------------- +--------------------- Что делать, если запрос выполняется дольше max_execution_time: throw или break. По умолчанию: throw. min_execution_speed --------------- +------------------- Минимальная скорость выполнения запроса в строчках в секунду. Проверяется на каждый блок данных по истечении timeout_before_checking_execution_speed. Если скорость выполнения запроса оказывается меньше, то кидается исключение. timeout_before_checking_execution_speed ---------------- +--------------------------------------- Проверять, что скорость выполнения запроса не слишком низкая (не меньше min_execution_speed), после прошествия указанного времени в секундах. max_columns_to_read --------------- +------------------- Максимальное количество столбцов, которых можно читать из таблицы в одном запросе. Если запрос требует чтения большего количества столбцов - кинуть исключение. max_temporary_columns ----------------- +--------------------- Максимальное количество временных столбцов, которых необходимо одновременно держать в оперативке, в процессе выполнения запроса, включая константные столбцы. Если временных столбцов оказалось больше - кидается исключение. max_temporary_non_const_columns ---------------------- +------------------------------- То же самое, что и max_temporary_columns, но без учёта столбцов-констант. Стоит заметить, что столбцы-константы довольно часто образуются в процессе выполнения запроса, но расходуют примерно нулевое количество вычислительных ресурсов. max_subquery_depth -------------- +------------------ Максимальная вложенность подзапросов. Если подзапросы более глубокие - кидается исключение. По умолчанию: 100. max_pipeline_depth ------------ +------------------ Максимальная глубина конвейера выполнения запроса. Соответствует количеству преобразований, которое проходит каждый блок данных в процессе выполнения запроса. Считается в пределах одного сервера. Если глубина конвейера больше - кидается исключение. По умолчанию: 1000. max_ast_depth ------------ +------------- Максимальная вложенность синтаксического дерева запроса. Если превышена - кидается исключение. На данный момент, проверяются не во время парсинга а уже после парсинга запроса. То есть, во время парсинга может быть создано слишком глубокое синтаксическое дерево, но запрос не будет выполнен. По умолчанию: 1000. max_ast_elements ------------ +---------------- Максимальное количество элементов синтаксического дерева запроса. Если превышено - кидается исключение. Аналогично, проверяется уже после парсинга запроса. По умолчанию: 10 000. max_rows_in_set ----------- +--------------- Максимальное количество строчек для множества в секции IN, создаваемого из подзапроса. max_bytes_in_set ------------ +---------------- Максимальное количество байт (несжатых данных), занимаемое множеством в секции IN, создаваемым из подзапроса. set_overflow_mode ------------ +----------------- Что делать, когда количество данных превысило одно из ограничений: throw или break. По умолчанию: throw. max_rows_in_distinct ------------ +-------------------- Максимальное количество различных строчек при использовании DISTINCT. max_bytes_in_distinct --------------- +--------------------- Максимальное количество байт, занимаемых хэш-таблицей, при использовании DISTINCT. distinct_overflow_mode ------------- +---------------------- Что делать, когда количество данных превысило одно из ограничений: throw или break. По умолчанию: throw. max_rows_to_transfer ------------ +-------------------- Максимальное количество строчек, которых можно передать на удалённый сервер или сохранить во временную таблицу, при использовании GLOBAL IN. max_bytes_to_transfer ------------ +--------------------- Максимальное количество байт (несжатых данных), которых можно передать на удалённый сервер или сохранить во временную таблицу, при использовании GLOBAL IN. transfer_overflow_mode ---------- +---------------------- Что делать, когда количество данных превысило одно из ограничений: throw или break. По умолчанию: throw. diff --git a/docs/ru/settings/settings.rst b/docs/ru/settings/settings.rst index 093394c3af7..022cf1d2656 100644 --- a/docs/ru/settings/settings.rst +++ b/docs/ru/settings/settings.rst @@ -41,13 +41,13 @@ max_threads Чем меньше ``max_threads``, тем меньше будет использоваться оперативки. max_compress_block_size ------------ +----------------------- Максимальный размер блоков не сжатых данных перед сжатием при записи в таблицу. По умолчанию - 1 048 576 (1 MiB). При уменьшении размера, незначительно уменьшается коэффициент сжатия, незначительно возрастает скорость сжатия и разжатия за счёт кэш-локальности, и уменьшается потребление оперативки. Как правило, не имеет смысла менять эту настройку. Не путайте блоки для сжатия (кусок памяти, состоящий из байт) и блоки для обработки запроса (пачка строк из таблицы). min_compress_block_size --------------- +----------------------- Для таблиц типа *MergeTree. В целях уменьшения задержек при обработке запросов, блок сжимается при записи следующей засечки, если его размер не меньше min_compress_block_size. По умолчанию - 65 536. Реальный размер блока, если несжатых данных меньше max_compress_block_size, будет не меньше этого значения и не меньше объёма данных на одну засечку. @@ -61,35 +61,35 @@ min_compress_block_size Как правило, не имеет смысла менять эту настройку. max_query_size ------------ +-------------- Максимальный кусок запроса, который будет считан в оперативку для разбора парсером языка SQL. Запрос INSERT также содержит данные для INSERT-а, которые обрабатываются отдельным, потоковым парсером (расходующим O(1) оперативки), и не учитываются в этом ограничении. ``По умолчанию - 256 KiB.`` interactive_delay -------------- +----------------- Интервал в микросекундах для проверки, не запрошена ли остановка выполнения запроса, и отправки прогресса. По умолчанию - 100 000 (проверять остановку запроса и отправлять прогресс десять раз в секунду). connect_timeout ------------ +--------------- receive_timeout ---------- +--------------- send_timeout ---------- +------------ Таймауты в секундах на сокет, по которому идёт общение с клиентом. ``По умолчанию - 10, 300, 300.`` poll_interval ----------- +------------- Блокироваться в цикле ожидания запроса в сервере на указанное количество секунд. ``По умолчанию - 10.`` max_distributed_connections ----------------- +--------------------------- Максимальное количество одновременных соединений с удалёнными серверами при распределённой обработке одного запроса к одной таблице типа Distributed. Рекомендуется выставлять не меньше, чем количество серверов в кластере. ``По умолчанию - 100.`` @@ -97,36 +97,36 @@ max_distributed_connections Следующие параметры имеют значение только на момент создания таблицы типа Distributed (и при запуске сервера), поэтому их не имеет смысла менять в рантайме. distributed_connections_pool_size -------------------- +--------------------------------- Максимальное количество одновременных соединений с удалёнными серверами при распределённой обработке всех запросов к одной таблице типа Distributed. Рекомендуется выставлять не меньше, чем количество серверов в кластере. ``По умолчанию - 128.`` connect_timeout_with_failover_ms ----------------- +-------------------------------- Таймаут в миллисекундах на соединение с удалённым сервером, для движка таблиц Distributed, если используются секции shard и replica в описании кластера. В случае неуспеха, делается несколько попыток соединений с разными репликами. ``По умолчанию - 50.`` connections_with_failover_max_tries ----------------- +----------------------------------- Максимальное количество попыток соединения с каждой репликой, для движка таблиц Distributed. ``По умолчанию - 3`` extremes ------ +-------- Считать ли экстремальные значения (минимумы и максимумы по столбцам результата запроса). Принимает 0 или 1. По умолчанию - 0 (выключено). Подробнее смотрите раздел "Экстремальные значения". use_uncompressed_cache ----------- +---------------------- Использовать ли кэш разжатых блоков. Принимает 0 или 1. По умолчанию - 0 (выключено). Кэш разжатых блоков (только для таблиц семейства MergeTree) позволяет существенно уменьшить задержки и увеличить пропускную способность при обработке большого количества коротких запросов. Включите эту настройку для пользователей, от которых идут частые короткие запросы. Также обратите внимание на конфигурационный параметр uncompressed_cache_size (настраивается только в конфигурационном файле) - размер кэша разжатых блоков. По умолчанию - 8 GiB. Кэш разжатых блоков заполняется по мере надобности; наиболее невостребованные данные автоматически удаляются. Для запросов, читающих хоть немного приличный объём данных (миллион строк и больше), кэш разжатых блоков автоматически выключается, чтобы оставить место для действительно мелких запросов. Поэтому, можно держать настройку use_uncompressed_cache всегда выставленной в 1. replace_running_query ------------ +--------------------- При использовании HTTP-интерфейса, может быть передан параметр query_id - произвольная строка, являющаяся идентификатором запроса. Если в этот момент, уже существует запрос от того же пользователя с тем же query_id, то поведение определяется параметром replace_running_query. @@ -137,16 +137,16 @@ replace_running_query Эта настройка, выставленная в 1, используется в Яндекс.Метрике для реализации suggest-а значений для условий сегментации. После ввода очередного символа, если старый запрос ещё не выполнился, его следует отменить. load_balancing ------------ +-------------- На какие реплики (среди живых реплик) предпочитать отправлять запрос (при первой попытке) при распределённой обработке запроса. random (по умолчанию) -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ Для каждой реплики считается количество ошибок. Запрос отправляется на реплику с минимальным числом ошибок, а если таких несколько, то на случайную из них. Недостатки: не учитывается близость серверов; если на репликах оказались разные данные, то вы будете получать так же разные данные. nearest_hostname -~~~~~~~~~ +~~~~~~~~~~~~~~~~ Для каждой реплики считается количество ошибок. Каждые 5 минут, число ошибок целочисленно делится на 2 - таким образом, обеспечивается расчёт числа ошибок за недавнее время с экспоненциальным сглаживанием. Если есть одна реплика с минимальным числом ошибок (то есть, на других репликах недавно были ошибки) - запрос отправляется на неё. Если есть несколько реплик с одинаковым минимальным числом ошибок, то запрос отправляется на реплику, имя хоста которой в конфигурационном файле минимально отличается от имени хоста сервера (по количеству отличающихся символов на одинаковых позициях, до минимальной длины обеих имён хостов). Для примера, example01-01-1 и example01-01-2.yandex.ru отличаются в одной позиции, а example01-01-1 и example01-02-2 - в двух. @@ -156,7 +156,7 @@ nearest_hostname Также можно сделать предположение, что при отправке запроса на один и тот же сервер, в случае отсутствия сбоев, распределённый запрос будет идти тоже на одни и те же серверы. То есть, даже если на репликах расположены разные данные, запрос будет возвращать в основном одинаковые результаты. in_order -~~~~~~~ +~~~~~~~~ Реплики перебираются в таком порядке, в каком они указаны. Количество ошибок не имеет значения. Этот способ подходит для тех случаев, когда вы точно знаете, какая реплика предпочтительнее. @@ -166,19 +166,19 @@ totals_mode Смотрите раздел "Модификатор WITH TOTALS". totals_auto_threshold --------------- +--------------------- Порог для ``totals_mode = 'auto'``. Смотрите раздел "Модификатор WITH TOTALS". default_sample ----------- +-------------- Число с плавающей запятой от 0 до 1. По умолчанию - 1. Позволяет выставить коэффициент сэмплирования по умолчанию для всех запросов SELECT. (Для таблиц, не поддерживающих сэмплирование, будет кидаться исключение.) Если равно 1 - сэмплирование по умолчанию не делается. max_parallel_replicas ---------------- +--------------------- Максимальное количество используемых реплик каждого шарда при выполнении запроса. Для консистентности (чтобы получить разные части одного и того же разбиения), эта опция работает только при заданном ключе сэмплирования. Отставание реплик не контролируется. @@ -191,7 +191,7 @@ compile В случае, если эта часть конвейера была скомпилирована, запрос может работать быстрее, за счёт разворачивания коротких циклов и инлайнинга вызовов агрегатных функций. Максимальный прирост производительности (до четырёх раз в редких случаях) достигается на запросах с несколькими простыми агрегатными функциями. Как правило, прирост производительности незначителен. В очень редких случаях возможно замедление выполнения запроса. min_count_to_compile ---------------- +-------------------- После скольких раз, когда скомпилированный кусок кода мог пригодиться, выполнить его компиляцию. По умолчанию - 3. В случае, если значение равно нулю, то компиляция выполняется синхронно, и запрос будет ждать окончания процесса компиляции перед продолжением выполнения. Это можно использовать для тестирования, иначе используйте значения, начиная с 1. Как правило, компиляция занимает по времени около 5-10 секунд. В случае, если значение равно 1 или больше, компиляция выполняется асинхронно, в отдельном потоке. При готовности результата, он сразу же будет использован, в том числе, уже выполняющимися в данный момент запросами. @@ -200,10 +200,10 @@ min_count_to_compile Результаты компиляции сохраняются в директории build в виде .so файлов. Количество результатов компиляции не ограничено, так как они не занимают много места. При перезапуске сервера, старые результаты будут использованы, за исключением случая обновления сервера - тогда старые результаты удаляются. input_format_skip_unknown_fields ----------------- +-------------------------------- Если значение истинно, то при выполнении INSERT из входных данных пропускаются (не рассматриваются) колонки с неизвестными именами, иначе в данной ситуации будет сгенерировано исключение. Работает для форматов JSONEachRow и TSKV. output_format_json_quote_64bit_integers ------------------ +--------------------------------------- Если значение истинно, то при использовании JSON* форматов UInt64 и Int64 числа выводятся в кавычках (из соображений совместимости с большинством реализаций JavaScript), иначе - без кавычек. diff --git a/docs/ru/system_tables/index.rst b/docs/ru/system_tables/index.rst index 37afe3c55bf..72085f0ac05 100644 --- a/docs/ru/system_tables/index.rst +++ b/docs/ru/system_tables/index.rst @@ -1,5 +1,5 @@ Системные таблицы -========== +================= Системные таблицы используются для реализации части функциональности системы, а также предоставляют доступ к информации о работе системы. Вы не можете удалить системную таблицу (хотя можете сделать DETACH). diff --git a/docs/ru/system_tables/system.clusters.rst b/docs/ru/system_tables/system.clusters.rst index 1bdd4f7dc1f..4e3e6538107 100644 --- a/docs/ru/system_tables/system.clusters.rst +++ b/docs/ru/system_tables/system.clusters.rst @@ -3,7 +3,9 @@ system.clusters Содержит информацию о доступных в конфигурационном файле кластерах и серверах, которые в них входят. Столбцы: + :: + cluster String - имя кластера shard_num UInt32 - номер шарда в кластере, начиная с 1 shard_weight UInt32 - относительный вес шарда при записи данных diff --git a/docs/ru/system_tables/system.columns.rst b/docs/ru/system_tables/system.columns.rst index 295ffc0ae84..afc46b60820 100644 --- a/docs/ru/system_tables/system.columns.rst +++ b/docs/ru/system_tables/system.columns.rst @@ -4,6 +4,7 @@ system.columns Содержит информацию о столбцах всех таблиц. С помощью этой таблицы можно получить информацию аналогично запросу ``DESCRIBE TABLE``, но для многих таблиц сразу. :: + database String - имя базы данных, в которой находится таблица table String - имя таблицы name String - имя столбца diff --git a/docs/ru/system_tables/system.dictionaries.rst b/docs/ru/system_tables/system.dictionaries.rst index 9d7664a4888..da4fc9a662c 100644 --- a/docs/ru/system_tables/system.dictionaries.rst +++ b/docs/ru/system_tables/system.dictionaries.rst @@ -5,6 +5,7 @@ system.dictionaries Столбцы: :: + name String - имя словаря type String - тип словаря: Flat, Hashed, Cache origin String - путь к конфигурационному файлу, в котором описан словарь diff --git a/docs/ru/system_tables/system.functions.rst b/docs/ru/system_tables/system.functions.rst index b04b6875c27..c823ea9026a 100644 --- a/docs/ru/system_tables/system.functions.rst +++ b/docs/ru/system_tables/system.functions.rst @@ -5,5 +5,6 @@ system.functions Столбцы: :: + name String - имя функции is_aggregate UInt8 - является ли функция агрегатной diff --git a/docs/ru/system_tables/system.merges.rst b/docs/ru/system_tables/system.merges.rst index 88ea0531ace..7ce370a12fb 100644 --- a/docs/ru/system_tables/system.merges.rst +++ b/docs/ru/system_tables/system.merges.rst @@ -4,6 +4,7 @@ system.merges Столбцы: :: + database String - имя базы данных, в которой находится таблица table String - имя таблицы elapsed Float64 - время в секундах, прошедшее от начала выполнения слияния diff --git a/docs/ru/system_tables/system.parts.rst b/docs/ru/system_tables/system.parts.rst index 4a3bf36fe2d..177f469cbe9 100644 --- a/docs/ru/system_tables/system.parts.rst +++ b/docs/ru/system_tables/system.parts.rst @@ -4,6 +4,7 @@ system.parts Столбцы: :: + database String - имя базы данных, в которой находится таблица, к которой относится кусок table String - имя таблицы, к которой относится кусок engine String - имя движка таблицы, без параметров diff --git a/docs/ru/system_tables/system.processes.rst b/docs/ru/system_tables/system.processes.rst index 733794f9aee..d2feeb5882e 100644 --- a/docs/ru/system_tables/system.processes.rst +++ b/docs/ru/system_tables/system.processes.rst @@ -4,6 +4,7 @@ system.processes Эта системная таблица используется для реализации запроса ``SHOW PROCESSLIST``. Столбцы: :: + user String - имя пользователя, который задал запрос. При распределённой обработке запроса, относится к пользователю, с помощью которого сервер-инициатор запроса отправил запрос на данный сервер, а не к имени пользователя, который задал распределённый запрос на сервер-инициатор запроса. address String - IP-адрес, с которого задан запрос. При распределённой обработке запроса, аналогично. diff --git a/docs/ru/system_tables/system.replicas.rst b/docs/ru/system_tables/system.replicas.rst index 71c3e562c23..6a1f80d7284 100644 --- a/docs/ru/system_tables/system.replicas.rst +++ b/docs/ru/system_tables/system.replicas.rst @@ -37,6 +37,7 @@ system.replicas Столбцы: :: + database: имя БД table: имя таблицы engine: имя движка таблицы diff --git a/docs/ru/system_tables/system.settings.rst b/docs/ru/system_tables/system.settings.rst index b0e9c9ff757..bf4728a2ca7 100644 --- a/docs/ru/system_tables/system.settings.rst +++ b/docs/ru/system_tables/system.settings.rst @@ -6,6 +6,7 @@ system.settings Столбцы: :: + name String - имя настройки value String - значение настройки changed UInt8 - была ли настройка явно задана в конфиге или изменена явным образом diff --git a/docs/ru/system_tables/system.zookeeper.rst b/docs/ru/system_tables/system.zookeeper.rst index 6cc1b25161b..c9a0e6787fc 100644 --- a/docs/ru/system_tables/system.zookeeper.rst +++ b/docs/ru/system_tables/system.zookeeper.rst @@ -10,6 +10,7 @@ system.zookeeper Столбцы: :: + name String - имя узла path String - путь к узлу value String - значение узла diff --git a/docs/ru/table_engines/buffer.rst b/docs/ru/table_engines/buffer.rst index 45d6c6f16f2..4e328aff839 100644 --- a/docs/ru/table_engines/buffer.rst +++ b/docs/ru/table_engines/buffer.rst @@ -3,6 +3,7 @@ Buffer Буферизует записываемые данные в оперативке, периодически сбрасывая их в другую таблицу. При чтении, производится чтение данных одновременно из буфера и из другой таблицы. :: + Buffer(database, table, num_layers, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes) Параметры движка: @@ -20,7 +21,8 @@ min_bytes, max_bytes - условие на количество байт в бу Условия для сброса данных учитываются отдельно для каждого из num_layers буферов. Например, если num_layers = 16 и max_bytes = 100000000, то максимальный расход оперативки будет 1.6 GB. Пример: -:: +.. code-block:: sql + CREATE TABLE merge.hits_buffer AS merge.hits ENGINE = Buffer(merge, hits, 16, 10, 100, 10000, 1000000, 10000000, 100000000) Создаём таблицу merge.hits_buffer такой же структуры как merge.hits и движком Buffer. При записи в эту таблицу, данные буферизуются в оперативке и, в дальнейшем, записываются в таблицу merge.hits. Создаётся 16 буферов. Данные, имеющиеся в каждом из них будут сбрасываться, если прошло сто секунд, или записан миллион строк, или записано сто мегабайт данных; или если одновременно прошло десять секунд и записано десять тысяч строк и записано десять мегабайт данных. Для примера, если записана всего лишь одна строка, то через сто секунд она будет сброшена в любом случае. А если записано много строк, то они будут сброшены раньше. diff --git a/docs/ru/table_engines/distributed.rst b/docs/ru/table_engines/distributed.rst index 94da814ab00..c6d62994579 100644 --- a/docs/ru/table_engines/distributed.rst +++ b/docs/ru/table_engines/distributed.rst @@ -6,9 +6,10 @@ Distributed Движок Distributed принимает параметры: имя кластера в конфигурационном файле сервера, имя удалённой базы данных, имя удалённой таблицы, а также (не обязательно) ключ шардирования. Пример: :: + Distributed(logs, default, hits[, sharding_key]) -- данные будут читаться со всех серверов кластера logs, из таблицы default.hits, расположенной на каждом сервере кластера. +данные будут читаться со всех серверов кластера logs, из таблицы default.hits, расположенной на каждом сервере кластера. Данные не только читаются, но и частично (настолько, насколько это возможно) обрабатываются на удалённых серверах. Например, при запросе с GROUP BY, данные будут агрегированы на удалённых серверах, промежуточные состояния агрегатных функций будут отправлены на запросивший сервер; затем данные будут доагрегированы. diff --git a/docs/ru/table_engines/join.rst b/docs/ru/table_engines/join.rst index 600233a1de5..946e8191c45 100644 --- a/docs/ru/table_engines/join.rst +++ b/docs/ru/table_engines/join.rst @@ -3,6 +3,7 @@ Join Представляет собой подготовленную структуру данных для JOIN-а, постоянно находящуюся в оперативке. :: + Join(ANY|ALL, LEFT|INNER, k1[, k2, ...]) Параметры движка: ``ANY|ALL`` - строгость, ``LEFT|INNER`` - тип. diff --git a/docs/ru/table_engines/merge.rst b/docs/ru/table_engines/merge.rst index a2f81db37e4..95b6494ef9f 100644 --- a/docs/ru/table_engines/merge.rst +++ b/docs/ru/table_engines/merge.rst @@ -5,6 +5,7 @@ Merge Чтение автоматически распараллеливается. Запись в таблицу не поддерживается. При чтении будут использованы индексы тех таблиц, из которых реально идёт чтение, если они существуют. Движок Merge принимает параметры: имя базы данных и регулярное выражение для таблиц. Пример: :: + Merge(hits, '^WatchLog') - данные будут читаться из таблиц в базе hits, имена которых соответствуют регулярному выражению '``^WatchLog``'. diff --git a/docs/ru/table_engines/mergetree.rst b/docs/ru/table_engines/mergetree.rst index 1b9b93fc3f3..94f0eb3d98e 100644 --- a/docs/ru/table_engines/mergetree.rst +++ b/docs/ru/table_engines/mergetree.rst @@ -8,10 +8,12 @@ MergeTree Пример без поддержки сэмплирования: :: + MergeTree(EventDate, (CounterID, EventDate), 8192) Пример с поддержкой сэмплирования: :: + MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192) В таблице типа MergeTree обязательно должен быть отдельный столбец, содержащий дату. В этом примере, это - столбец EventDate. Тип столбца с датой - обязательно Date (а не DateTime). diff --git a/docs/ru/table_engines/replication.rst b/docs/ru/table_engines/replication.rst index c834bf3f351..0684ddcb600 100644 --- a/docs/ru/table_engines/replication.rst +++ b/docs/ru/table_engines/replication.rst @@ -74,6 +74,7 @@ ReplicatedSummingMergeTree Пример: :: + ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/hits', '{replica}', EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID), EventTime), 8192) Как видно в примере, эти параметры могут содержать подстановки в фигурных скобках. Подставляемые значения достаются из конфигурационного файла, из секции macros. Пример: @@ -123,7 +124,8 @@ ReplicatedSummingMergeTree Если обнаруживается, что локальный набор данных слишком сильно отличается от ожидаемого, то срабатывает защитный механизм - сервер сообщает об этом в лог и отказывается запускаться. Это сделано, так как такой случай может свидетельствовать об ошибке конфигурации - например, если реплика одного шарда была случайно сконфигурирована, как реплика другого шарда. Тем не менее, пороги защитного механизма поставлены довольно низкими, и такая ситуация может возникнуть и при обычном восстановлении после сбоя. В этом случае, восстановление делается полуавтоматически - "по кнопке". Для запуска восстановления, создайте в ZooKeeper узел ``/path_to_table/replica_name/flags/force_restore_data`` с любым содержимым или выполните команду для восстановления всех реплицируемых таблиц: -:: +.. code-block:: bash + sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data Затем запустите сервер. При старте, сервер удалит эти флаги и запустит восстановление. diff --git a/docs/ru/table_engines/summingmergetree.rst b/docs/ru/table_engines/summingmergetree.rst index 7620b5042a5..8d993c53c9a 100644 --- a/docs/ru/table_engines/summingmergetree.rst +++ b/docs/ru/table_engines/summingmergetree.rst @@ -29,6 +29,7 @@ SummingMergeTree Примеры: :: + [(1, 100)] + [(2, 150)] -> [(1, 100), (2, 150)] [(1, 100)] + [(1, 150)] -> [(1, 250)] [(1, 100)] + [(1, 150), (2, 150)] -> [(1, 250), (2, 150)] diff --git a/docs/ru/table_functions/remote.rst b/docs/ru/table_functions/remote.rst index 541f418cce4..6901bc53679 100644 --- a/docs/ru/table_functions/remote.rst +++ b/docs/ru/table_functions/remote.rst @@ -17,6 +17,7 @@ remote Примеры: :: + example01-01-1 example01-01-1:9000 localhost @@ -28,14 +29,17 @@ remote Пример: :: + example01-01-1,example01-02-1 Часть выражения может быть указана в фигурных скобках. Предыдущий пример может быть записан следующим образом: :: + example01-0{1,2}-1 В фигурных скобках может быть указан диапазон (неотрицательных целых) чисел через две точки. В этом случае, диапазон раскрывается в множество значений, генерирующих адреса шардов. Если запись первого числа начинается с нуля, то значения формируются с таким же выравниванием нулями. Предыдущий пример может быть записан следующим образом: :: + example01-{01..02}-1 При наличии нескольких пар фигурных скобок, генерируется прямое произведение соответствующих множеств. @@ -44,6 +48,7 @@ remote Пример: :: + example01-{01..02}-{1|2} В этом примере указано два шарда, в каждом из которых имеется две реплики. From 46db454562999676352eaa964ca3e88ed5f99c27 Mon Sep 17 00:00:00 2001 From: f1yegor Date: Sun, 7 May 2017 22:25:26 +0200 Subject: [PATCH 28/76] translate comments --- dbms/src/Common/AIO.h | 2 +- dbms/src/Common/Allocator.cpp | 16 +- dbms/src/Common/Allocator.h | 20 +- dbms/src/Common/ArenaWithFreeLists.h | 38 ++-- dbms/src/Common/AutoArray.h | 66 +++---- .../src/Common/CombinedCardinalityEstimator.h | 12 +- dbms/src/Common/CompactArray.h | 46 ++--- dbms/src/Common/ConcurrentBoundedQueue.h | 6 +- dbms/src/Common/CounterInFile.h | 26 +-- dbms/src/Common/Exception.h | 8 +- dbms/src/Common/ExternalTable.h | 48 ++--- dbms/src/Common/FileChecker.h | 8 +- dbms/src/Common/HashTable/ClearableHashSet.h | 18 +- dbms/src/Common/HashTable/Hash.h | 44 ++--- dbms/src/Common/HashTable/HashMap.h | 34 ++-- dbms/src/Common/HashTable/HashTable.h | 180 +++++++++--------- dbms/src/Common/HashTable/SmallTable.h | 44 ++--- dbms/src/Common/HashTable/TwoLevelHashTable.h | 40 ++-- dbms/src/Common/HyperLogLogBiasEstimator.h | 28 +-- .../HyperLogLogWithSmallSetOptimization.h | 12 +- dbms/src/Common/Increment.h | 36 ++-- dbms/src/Common/Macros.h | 6 +- dbms/src/Common/MemoryTracker.h | 8 +- dbms/src/Common/OptimizedRegularExpression.h | 26 +-- .../src/Common/OptimizedRegularExpression.inl | 30 +-- dbms/src/Common/PODArray.h | 38 ++-- dbms/src/Common/PoolBase.h | 32 ++-- dbms/src/Common/RadixSort.h | 70 +++---- dbms/src/Common/ShellCommand.h | 30 +-- dbms/src/Common/SimpleCache.h | 14 +- dbms/src/Common/SipHash.h | 34 ++-- dbms/src/Common/SmallObjectPool.h | 2 +- dbms/src/Common/StackTrace.h | 6 +- dbms/src/Common/StringSearcher.h | 12 +- dbms/src/Common/Throttler.h | 16 +- dbms/src/Common/UInt128.h | 12 +- dbms/src/Common/UnicodeBar.h | 4 +- dbms/src/Common/VirtualColumnUtils.h | 18 +- dbms/src/Common/Volnitsky.h | 74 +++---- dbms/src/Common/formatReadable.h | 6 +- dbms/src/Common/getFQDNOrHostName.h | 4 +- dbms/src/Common/isLocalAddress.h | 14 +- dbms/src/Common/localBackup.h | 14 +- dbms/src/Common/setThreadName.h | 6 +- dbms/src/Common/typeid_cast.h | 6 +- release_lib.sh | 16 +- 46 files changed, 615 insertions(+), 615 deletions(-) diff --git a/dbms/src/Common/AIO.h b/dbms/src/Common/AIO.h index 5702a8bc683..df3e22a5338 100644 --- a/dbms/src/Common/AIO.h +++ b/dbms/src/Common/AIO.h @@ -15,7 +15,7 @@ #include -/** Небольшие обёртки для асинхронного ввода-вывода. +/** Small wrappers for asynchronous I/O. */ diff --git a/dbms/src/Common/Allocator.cpp b/dbms/src/Common/Allocator.cpp index 7eca841833e..a773aaceb24 100644 --- a/dbms/src/Common/Allocator.cpp +++ b/dbms/src/Common/Allocator.cpp @@ -22,15 +22,15 @@ namespace ErrorCodes } -/** Многие современные аллокаторы (например, tcmalloc) не умеют делать mremap для realloc, - * даже в случае достаточно больших кусков памяти. - * Хотя это позволяет увеличить производительность и уменьшить потребление памяти во время realloc-а. - * Чтобы это исправить, делаем mremap самостоятельно, если кусок памяти достаточно большой. - * Порог (64 МБ) выбран достаточно большим, так как изменение адресного пространства - * довольно сильно тормозит, особенно в случае наличия большого количества потоков. - * Рассчитываем, что набор операций mmap/что-то сделать/mremap может выполняться всего лишь около 1000 раз в секунду. +/** Many modern allocators (for example, tcmalloc) do not know how to do a mremap for realloc, + * even in case of large enough chunks of memory. + * Although this allows you to increase performance and reduce memory consumption during realloc. + * To fix this, do the mremap yourself if the chunk of memory is large enough. + * The threshold (64 MB) is chosen quite large, since changing the address space is + * rather slow, especially in the case of a large number of threads. + * We expect that the set of operations mmap/something to do/mremap can only be performed about 1000 times per second. * - * PS. Также это требуется, потому что tcmalloc не может выделить кусок памяти больше 16 GB. + * PS. This is also required, because tcmalloc can not allocate a chunk of memory greater than 16 GB. */ static constexpr size_t MMAP_THRESHOLD = 64 * (1 << 20); static constexpr size_t MMAP_MIN_ALIGNMENT = 4096; diff --git a/dbms/src/Common/Allocator.h b/dbms/src/Common/Allocator.h index 8018ebbde79..8079b37cf0c 100644 --- a/dbms/src/Common/Allocator.h +++ b/dbms/src/Common/Allocator.h @@ -3,13 +3,13 @@ #include -/** Отвечает за выделение/освобождение памяти. Используется, например, в PODArray, Arena. - * Также используется в хэш-таблицах. - * Интерфейс отличается от std::allocator - * - наличием метода realloc, который для больших кусков памяти использует mremap; - * - передачей размера в метод free; - * - наличием аргумента alignment; - * - возможностью зануления памяти (используется в хэш-таблицах); +/** Responsible for allocating / freeing memory. Used, for example, in PODArray, Arena. + * Also used in hash tables. + * The interface is different from std::allocator + * - the presence of the method realloc, which for large chunks of memory uses mremap; + * - passing the size into the `free` method; + * - by the presence of the `alignment` argument; + * - the possibility of zeroing memory (used in hash tables); */ template class Allocator @@ -38,9 +38,9 @@ protected: }; -/** При использовании AllocatorWithStackMemory, размещённом на стеке, - * GCC 4.9 ошибочно делает предположение, что мы можем вызывать free от указателя на стек. - * На самом деле, комбинация условий внутри AllocatorWithStackMemory этого не допускает. +/** When using AllocatorWithStackMemory, located on the stack, + * GCC 4.9 mistakenly assumes that we can call `free` from a pointer to the stack. + * In fact, the combination of conditions inside AllocatorWithStackMemory does not allow this. */ #if !__clang__ #pragma GCC diagnostic push diff --git a/dbms/src/Common/ArenaWithFreeLists.h b/dbms/src/Common/ArenaWithFreeLists.h index 08a3c84d8ca..094b67afae5 100644 --- a/dbms/src/Common/ArenaWithFreeLists.h +++ b/dbms/src/Common/ArenaWithFreeLists.h @@ -8,40 +8,40 @@ namespace DB { -/** В отличие от Arena, позволяет освобождать (для последующего повторного использования) - * выделенные ранее (не обязательно только что) куски памяти. - * Для этого, запрашиваемый размер округляется вверх до степени двух - * (или до 8, если меньше; или используется выделение памяти вне Arena, если размер больше 65536). - * При освобождении памяти, для каждого размера (всего 14 вариантов: 8, 16... 65536), - * поддерживается односвязный список свободных блоков. - * При аллокации, мы берём голову списка свободных блоков, - * либо, если список пуст - выделяем новый блок, используя Arena. +/** Unlike Arena, allows you to release (for later re-use) + * previously allocated (not necessarily just recently) chunks of memory. + * For this, the requested size is rounded up to the power of two + * (or up to 8, if less, or using memory allocation outside Arena if the size is greater than 65536). + * When freeing memory, for each size (14 options in all: 8, 16 ... 65536), + * a one-link list of free blocks is kept track. + * When allocating, we take the head of the list of free blocks, + * or, if the list is empty - allocate a new block using Arena. */ class ArenaWithFreeLists : private Allocator, private boost::noncopyable { private: - /// Если блок свободен, то в его начале хранится указатель на следующий свободный блок, либо nullptr, если свободных блоков больше нет. - /// Если блок используется, то в нём хранятся какие-то данные. + /// If the block is free, then the pointer to the next free block is stored at its beginning, or nullptr, if there are no more free blocks. + /// If the block is used, then some data is stored in it. union Block { Block * next; char data[0]; }; - /// Максимальный размер куска памяти, который выделяется с помощью Arena. Иначе используем Allocator напрямую. + /// The maximum size of a piece of memory that is allocated with Arena. Otherwise, we use Allocator directly. static constexpr size_t max_fixed_block_size = 65536; - /// Получить индекс в массиве freelist-ов для заданного размера. + /// Get the index in the freelist array for the specified size. static size_t findFreeListIndex(const size_t size) { return size <= 8 ? 2 : bitScanReverse(size - 1); } - /// Для выделения блоков не слишком большого размера используется Arena. + /// Arena is used to allocate blocks that are not too large. Arena pool; - /// Списки свободных блоков. Каждый элемент указывает на голову соответствующего списка, либо равен nullptr. - /// Первые два элемента не используются, а предназначены для упрощения арифметики. + /// Lists of free blocks. Each element points to the head of the corresponding list, or is nullptr. + /// The first two elements are not used, but are intended to simplify arithmetic. Block * free_lists[16] {}; public: @@ -60,10 +60,10 @@ public: /// find list of required size const auto list_idx = findFreeListIndex(size); - /// Если есть свободный блок. + /// If there is a free block. if (auto & free_block_ptr = free_lists[list_idx]) { - /// Возьмём его. И поменяем голову списка на следующий элемент списка. + /// Let's take it. And change the head of the list to the next item in the list. const auto res = free_block_ptr->data; free_block_ptr = free_block_ptr->next; return res; @@ -81,14 +81,14 @@ public: /// find list of required size const auto list_idx = findFreeListIndex(size); - /// Вставим освобождённый блок в голову списка. + /// Insert the released block into the head of the list. auto & free_block_ptr = free_lists[list_idx]; const auto old_head = free_block_ptr; free_block_ptr = reinterpret_cast(ptr); free_block_ptr->next = old_head; } - /// Размер выделенного пула в байтах + /// Size of the allocated pool in bytes size_t size() const { return pool.size(); diff --git a/dbms/src/Common/AutoArray.h b/dbms/src/Common/AutoArray.h index 60246b4d1b2..2f1f3d28cf9 100644 --- a/dbms/src/Common/AutoArray.h +++ b/dbms/src/Common/AutoArray.h @@ -8,30 +8,30 @@ namespace DB { -/** Массив (почти) неизменяемого размера: - * размер задаётся в конструкторе; - * метод resize приводит к удалению старых данных и нужен лишь для того, - * чтобы можно было сначала создать пустой объект, используя конструктор по-умолчанию, - * а потом уже определиться с размером. +/** An array of (almost) unchangable size: + * the size is specified in the constructor; + * `resize` method removes old data, and necessary only for + * so that you can first create an empty object using the default constructor, + * and then decide on the size. * - * Есть возможность не инициализировать элементы по-умолчанию, а создавать их inplace. - * Деструкторы элементов вызываются автоматически. + * There is a possibility to not initialize elements by default, but create them inplace. + * Member destructors are called automatically. * - * sizeof равен размеру одного указателя. + * `sizeof` is equal to the size of one pointer. * - * Не exception-safe. - * Копирование не поддерживается. Перемещение опустошает исходный объект. - * То есть, использовать этот массив во многих случаях неудобно. + * Not exception-safe. + * Copying is not supported. Moving empties the original object. + * That is, it is inconvenient to use this array in many cases. * - * Предназначен для ситуаций, в которых создаётся много массивов одинакового небольшого размера, - * но при этом размер не известен во время компиляции. - * Также даёт существенное преимущество в случаях, когда важно, чтобы sizeof был минимальным. - * Например, если массивы кладутся в open-addressing хэш-таблицу с inplace хранением значений (как HashMap) + * Designed for situations in which many arrays of the same small size are created, + * but the size is not known at compile time. + * Also gives a significant advantage in cases where it is important that `sizeof` is minimal. + * For example, if arrays are put in an open-addressing hash table with inplace storage of values ​​(like HashMap) * - * В этом случае, по сравнению с std::vector: - * - для массивов размером в 1 элемент - преимущество примерно в 2 раза; - * - для массивов размером в 5 элементов - преимущество примерно в 1.5 раза - * (в качестве T использовались DB::Field, содержащие UInt64 и String); + * In this case, compared to std::vector: + * - for arrays of 1 element size - an advantage of about 2 times; + * - for arrays of 5 elements - an advantage of about 1.5 times + * (DB::Field, containing UInt64 and String, used as T); */ const size_t empty_auto_array_helper = 0; @@ -42,7 +42,7 @@ template class AutoArray { public: - /// Для отложенного создания. + /// For deferred creation. AutoArray() { setEmpty(); @@ -53,16 +53,16 @@ public: init(size_, false); } - /** Не будут вызваны конструкторы по-умолчанию для элементов. - * В этом случае, вы должны вставить все элементы с помощью функции place и placement new, - * так как для них потом будут вызваны деструкторы. + /** The default constructors for elements will not be called. + * In this case, you must insert all elements using the `place` and `placement new` functions, + * since destructors are then called for them. */ AutoArray(size_t size_, const DontInitElemsTag & tag) { init(size_, true); } - /** Инициализирует все элементы копирующим конструктором с параметром value. + /** Initializes all elements with a copy constructor with the `value` parameter. */ AutoArray(size_t size_, const T & value) { @@ -74,7 +74,7 @@ public: } } - /** resize удаляет все существующие элементы. + /** `resize` removes all existing items. */ void resize(size_t size_, bool dont_init_elems = false) { @@ -82,7 +82,7 @@ public: init(size_, dont_init_elems); } - /** Премещение. + /** Preposition. */ AutoArray(AutoArray && src) { @@ -125,10 +125,10 @@ public: setEmpty(); } - /** Можно читать и модифицировать элементы с помощью оператора [] - * только если элементы были инициализированы - * (то есть, в конструктор не был передан DontInitElemsTag, - * или вы их инициализировали с помощью place и placement new). + /** You can read and modify elements using the [] operator + * only if items were initialized + * (that is, into the constructor was not passed DontInitElemsTag, + * or you initialized them using `place` and `placement new`). */ T & operator[](size_t i) { @@ -140,9 +140,9 @@ public: return elem(i); } - /** Получить кусок памяти, в котором должен быть расположен элемент. - * Функция предназначена, чтобы инициализировать элемент, - * который ещё не был инициализирован: + /** Get the piece of memory in which the element should be located. + * The function is intended to initialize an element, + * which has not yet been initialized * new (arr.place(i)) T(args); */ char * place(size_t i) diff --git a/dbms/src/Common/CombinedCardinalityEstimator.h b/dbms/src/Common/CombinedCardinalityEstimator.h index e89b62699f6..82c2951e44a 100644 --- a/dbms/src/Common/CombinedCardinalityEstimator.h +++ b/dbms/src/Common/CombinedCardinalityEstimator.h @@ -23,9 +23,9 @@ static inline ContainerType max(const ContainerType & lhs, const ContainerType & } -/** Для маленького количества ключей - массив фиксированного размера "на стеке". - * Для среднего - выделяется HashSet. - * Для большого - выделяется HyperLogLog. +/** For a small number of keys - an array of fixed size "on the stack." + * For the average, HashSet is allocated. + * For large, HyperLogLog is allocated. */ template < @@ -146,7 +146,7 @@ public: getContainer().merge(rhs.getContainer()); } - /// Можно вызывать только для пустого объекта. + /// You can only call for an empty object. void read(DB::ReadBuffer & in) { UInt8 v; @@ -171,8 +171,8 @@ public: { auto container_type = getContainerType(); - /// Если readAndMerge вызывается с пустым состоянием, просто десериализуем - /// состояние задано в качестве параметра. + /// If readAndMerge is called with an empty state, just deserialize + /// the state is specified as a parameter. if ((container_type == details::ContainerType::SMALL) && small.empty()) { read(in); diff --git a/dbms/src/Common/CompactArray.h b/dbms/src/Common/CompactArray.h index c53fb4d5b7b..db07f90a644 100644 --- a/dbms/src/Common/CompactArray.h +++ b/dbms/src/Common/CompactArray.h @@ -15,11 +15,11 @@ namespace ErrorCodes } -/** Компактный массив для хранения данных, размер content_width, в битах, которых составляет - * меньше одного байта. Вместо того, чтобы хранить каждое значение в отдельный - * байт, что приводит к растрате 37.5% пространства для content_width=5, CompactArray хранит - * смежные content_width-битные значения в массиве байтов, т.е. фактически CompactArray - * симулирует массив content_width-битных значений. +/** Compact array for data storage, size `content_width`, in bits, of which is + * less than one byte. Instead of storing each value in a separate + * bytes, which leads to a waste of 37.5% of the space for content_width = 5, CompactArray stores + * adjacent `content_width`-bit values ​​in the byte array, that is actually CompactArray + * simulates an array of `content_width`-bit values. */ template class __attribute__ ((packed)) CompactArray final @@ -76,12 +76,12 @@ public: } private: - /// число байт в битсете + /// number of bytes in bitset static constexpr size_t BITSET_SIZE = (static_cast(bucket_count) * content_width + 7) / 8; UInt8 bitset[BITSET_SIZE] = { 0 }; }; -/** Класс для последовательного чтения ячеек из компактного массива на диске. +/** A class for sequentially reading cells from a compact array on a disk. */ template class CompactArray::Reader final @@ -135,7 +135,7 @@ public: return true; } - /** Вернуть текущий номер ячейки и соответствующее содержание. + /** Return the current cell number and the corresponding content. */ inline std::pair get() const { @@ -150,26 +150,26 @@ public: private: ReadBuffer & in; - /// Физическое расположение текущей ячейки. + /// The physical location of the current cell. Locus locus; - /// Текущая позиция в файле в виде номера ячейки. + /// The current position in the file as a cell number. BucketIndex current_bucket_index = 0; - /// Количество прочитанных байтов. + /// The number of bytes read. size_t read_count = 0; - /// Содержание в текущей позиции. + /// The content in the current position. UInt8 value_l; UInt8 value_r; /// bool is_eof = false; - /// Влезает ли ячейка полностью в один байт? + /// Does the cell fully fit into one byte? bool fits_in_byte; }; -/** Структура Locus содержит необходимую информацию, чтобы найти для каждой ячейки - * соответствующие байт и смещение, в битах, от начала ячейки. Поскольку в общем - * случае размер одного байта не делится на размер одной ячейки, возможны случаи, - * когда одна ячейка перекрывает два байта. Поэтому структура Locus содержит две - * пары (индекс, смещение). +/** The `Locus` structure contains the necessary information to find for each cell + * the corresponding byte and offset, in bits, from the beginning of the cell. Since in general + * case the size of one byte is not divisible by the size of one cell, cases possible + * when one cell overlaps two bytes. Therefore, the `Locus` structure contains two + * pairs (index, offset). */ template class CompactArray::Locus final @@ -190,13 +190,13 @@ public: { if ((index_l == index_r) || (index_l == (BITSET_SIZE - 1))) { - /// Ячейка полностью влезает в один байт. + /// The cell completely fits into one byte. *content_l &= ~(((1 << content_width) - 1) << offset_l); *content_l |= content << offset_l; } else { - /// Ячейка перекрывает два байта. + /// The cell overlaps two bytes. size_t left = 8 - offset_l; *content_l &= ~(((1 << left) - 1) << offset_l); @@ -230,13 +230,13 @@ private: UInt8 ALWAYS_INLINE read(UInt8 value_l) const { - /// Ячейка полностью влезает в один байт. + /// The cell completely fits into one byte. return (value_l >> offset_l) & ((1 << content_width) - 1); } UInt8 ALWAYS_INLINE read(UInt8 value_l, UInt8 value_r) const { - /// Ячейка перекрывает два байта. + /// The cell overlaps two bytes. return ((value_l >> offset_l) & ((1 << (8 - offset_l)) - 1)) | ((value_r & ((1 << offset_r) - 1)) << (8 - offset_l)); } @@ -250,7 +250,7 @@ private: UInt8 * content_l; UInt8 * content_r; - /// Проверки + /// Checks static_assert((content_width > 0) && (content_width < 8), "Invalid parameter value"); static_assert(bucket_count <= (std::numeric_limits::max() / content_width), "Invalid parameter value"); }; diff --git a/dbms/src/Common/ConcurrentBoundedQueue.h b/dbms/src/Common/ConcurrentBoundedQueue.h index cbcfd1b5eb8..9b9a80dd9f1 100644 --- a/dbms/src/Common/ConcurrentBoundedQueue.h +++ b/dbms/src/Common/ConcurrentBoundedQueue.h @@ -38,9 +38,9 @@ namespace detail } }; -/** Очень простая thread-safe очередь ограниченной длины. - * Если пытаться вынуть элемент из пустой очереди, то поток блокируется, пока очередь не станет непустой. - * Если пытаться вставить элемент в переполненную очередь, то поток блокируется, пока в очереди не появится элемент. +/** A very simple thread-safe queue of limited length. + * If you try to pop an item from an empty queue, the thread is blocked until the queue becomes nonempty. + * If you try to push an element into an overflowed queue, the thread is blocked until space appears in the queue. */ template class ConcurrentBoundedQueue diff --git a/dbms/src/Common/CounterInFile.h b/dbms/src/Common/CounterInFile.h index 3ff4d9aeb67..99320a1fbfd 100644 --- a/dbms/src/Common/CounterInFile.h +++ b/dbms/src/Common/CounterInFile.h @@ -22,24 +22,24 @@ #define SMALL_READ_WRITE_BUFFER_SIZE 16 -/** Хранит в файле число. - * Предназначен для редких вызовов (не рассчитан на производительность). +/** Stores a number in the file. + * Designed for rare calls (not designed for performance). */ class CounterInFile { public: - /// path - имя файла, включая путь + /// path - the name of the file, including the path CounterInFile(const std::string & path_) : path(path_) {} - /** Добавить delta к числу в файле и вернуть новое значение. - * Если параметр create_if_need не установлен в true, то - * в файле уже должно быть записано какое-нибудь число (если нет - создайте файл вручную с нулём). + /** Add `delta` to the number in the file and return the new value. + * If the `create_if_need` parameter is not set to true, then + * the file should already have a number written (if not - create the file manually with zero). * - * Для защиты от race condition-ов между разными процессами, используются файловые блокировки. - * (Но при первом создании файла race condition возможен, так что лучше создать файл заранее.) + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) * - * locked_callback вызывается при заблокированном файле со счетчиком. В него передается новое значение. - * locked_callback можно использовать, чтобы делать что-нибудь атомарно с увеличением счетчика (например, переименовывать файлы). + * `locked_callback` is called when the counter file is locked. A new value is passed to it. + * `locked_callback` can be used to do something atomically with incrementing the counter (for example, renaming files). */ template Int64 add(Int64 delta, Callback && locked_callback, bool create_if_need = false) @@ -74,7 +74,7 @@ public: } catch (const DB::Exception & e) { - /// Более понятное сообщение об ошибке. + /// A more understandable error message. if (e.code() == DB::ErrorCodes::CANNOT_READ_ALL_DATA || e.code() == DB::ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) throw DB::Exception("File " + path + " is empty. You must fill it manually with appropriate value.", e.code()); else @@ -118,13 +118,13 @@ public: return path; } - /// Изменить путь к файлу. + /// Change the path to the file. void setPath(std::string path_) { path = path_; } - // Не thread-safe и не синхронизирован между процессами. + // Not thread-safe and not synchronized between processes. void fixIfBroken(UInt64 value) { bool file_exists = Poco::File(path).exists(); diff --git a/dbms/src/Common/Exception.h b/dbms/src/Common/Exception.h index aa3f4544b74..edac971d65b 100644 --- a/dbms/src/Common/Exception.h +++ b/dbms/src/Common/Exception.h @@ -35,7 +35,7 @@ public: DB::Exception * clone() const override { return new DB::Exception(*this); } void rethrow() const override { throw *this; } - /// Дописать к существующему сообщению что-нибудь ещё. + /// Add something to the existing message. void addMessage(const std::string & arg) { extendedMessage(arg); } const StackTrace & getStackTrace() const { return trace; } @@ -45,7 +45,7 @@ private: }; -/// Содержит дополнительный член saved_errno. См. функцию throwFromErrno. +/// Contains an additional member `saved_errno`. See the throwFromErrno function. class ErrnoException : public Exception { public: @@ -73,8 +73,8 @@ using Exceptions = std::vector; void throwFromErrno(const std::string & s, int code = 0, int the_errno = errno); -/** Попробовать записать исключение в лог (и забыть про него). - * Можно использовать в деструкторах в блоке catch (...). +/** Try to write an exception to the log (and forget about it). + * Can be used in destructors in the catch block (...). */ void tryLogCurrentException(const char * log_name, const std::string & start_of_message = ""); void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_message = ""); diff --git a/dbms/src/Common/ExternalTable.h b/dbms/src/Common/ExternalTable.h index e275ce2e37f..257431a5d15 100644 --- a/dbms/src/Common/ExternalTable.h +++ b/dbms/src/Common/ExternalTable.h @@ -25,16 +25,16 @@ namespace ErrorCodes } -/// Базовый класс содержащий основную информацию о внешней таблице и -/// основные функции для извлечения этой информации из текстовых полей. +/// The base class containing the basic information about external table and +/// basic functions for extracting this information from text fields. class BaseExternalTable { public: - std::string file; /// Файл с данными или '-' если stdin - std::string name; /// Имя таблицы - std::string format; /// Название формата хранения данных + std::string file; /// File with data or '-' if stdin + std::string name; /// The name of the table + std::string format; /// Name of the data storage format - /// Описание структуры таблицы: (имя столбца, имя типа данных) + /// Description of the table structure: (column name, data type name) std::vector > structure; std::unique_ptr read_buffer; @@ -42,10 +42,10 @@ public: virtual ~BaseExternalTable() {}; - /// Инициализировать read_buffer в зависимости от источника данных. По умолчанию не делает ничего. + /// Initialize read_buffer, depending on the data source. By default, does nothing. virtual void initReadBuffer() {}; - /// Инициализировать sample_block по структуре таблицы сохраненной в structure + /// Initialize sample_block according to the structure of the table stored in the `structure` virtual void initSampleBlock(const Context & context) { const DataTypeFactory & data_type_factory = DataTypeFactory::instance(); @@ -60,7 +60,7 @@ public: } } - /// Получить данные таблицы - пару (поток с содержимым таблицы, имя таблицы) + /// Get the table data - a pair (a thread with the contents of the table, the name of the table) virtual ExternalTableData getData(const Context & context) { initReadBuffer(); @@ -71,7 +71,7 @@ public: } protected: - /// Очистить всю накопленную информацию + /// Clear all accumulated information void clean() { name = ""; @@ -82,7 +82,7 @@ protected: read_buffer.reset(); } - /// Функция для отладочного вывода информации + /// Function for debugging information output void write() { std::cerr << "file " << file << std::endl; @@ -100,7 +100,7 @@ protected: return res; } - /// Построить вектор structure по текстовому полю structure + /// Construct the `structure` vector from the text field `structure` virtual void parseStructureFromStructureField(const std::string & argument) { std::vector vals = split(argument, " ,"); @@ -112,7 +112,7 @@ protected: structure.emplace_back(vals[i], vals[i + 1]); } - /// Построить вектор structure по текстовому полю types + /// Construct the `structure` vector from the text field `types` virtual void parseStructureFromTypesField(const std::string & argument) { std::vector vals = split(argument, " ,"); @@ -123,7 +123,7 @@ protected: }; -/// Парсинг внешей таблицы, используемый в tcp клиенте. +/// Parsing of external table used in the tcp client. class ExternalTable : public BaseExternalTable { public: @@ -135,7 +135,7 @@ public: read_buffer = std::make_unique(file); } - /// Извлечение параметров из variables_map, которая строится по командной строке клиента + /// Extract parameters from variables_map, which is built on the client command line ExternalTable(const boost::program_options::variables_map & external_options) { if (external_options.count("file")) @@ -162,9 +162,9 @@ public: } }; -/// Парсинг внешей таблицы, используемый при отправке таблиц через http -/// Функция handlePart будет вызываться для каждой переданной таблицы, -/// поэтому так же необходимо вызывать clean в конце handlePart. +/// Parsing of external table used when sending tables via http +/// The `handlePart` function will be called for each table passed, + /// so it's also necessary to call `clean` at the end of the `handlePart`. class ExternalTablesHandler : public Poco::Net::PartHandler, BaseExternalTable { public: @@ -174,15 +174,15 @@ public: void handlePart(const Poco::Net::MessageHeader & header, std::istream & stream) { - /// Буфер инициализируется здесь, а не в виртуальной функции initReadBuffer + /// The buffer is initialized here, not in the virtual function initReadBuffer read_buffer = std::make_unique(stream); - /// Извлекаем коллекцию параметров из MessageHeader + /// Retrieve a collection of parameters from MessageHeader Poco::Net::NameValueCollection content; std::string label; Poco::Net::MessageHeader::splitParameters(header.get("Content-Disposition"), label, content); - /// Получаем параметры + /// Get parameters name = content.get("name", "_data"); format = params.get(name + "_format", "TabSeparated"); @@ -195,13 +195,13 @@ public: ExternalTableData data = getData(context); - /// Создаем таблицу + /// Create table NamesAndTypesListPtr columns = std::make_shared(sample_block.getColumnsList()); StoragePtr storage = StorageMemory::create(data.second, columns); context.addExternalTable(data.second, storage); BlockOutputStreamPtr output = storage->write(ASTPtr(), context.getSettingsRef()); - /// Записываем данные + /// Write data data.first->readPrefix(); output->writePrefix(); while(Block block = data.first->read()) @@ -210,7 +210,7 @@ public: output->writeSuffix(); names.push_back(name); - /// Подготавливаемся к приему следующего файла, для этого очищаем всю полученную информацию + /// We are ready to receive the next file, for this we clear all the information received clean(); } diff --git a/dbms/src/Common/FileChecker.h b/dbms/src/Common/FileChecker.h index aa1cb601125..4b44b7ede7b 100644 --- a/dbms/src/Common/FileChecker.h +++ b/dbms/src/Common/FileChecker.h @@ -8,11 +8,11 @@ namespace DB { -/// хранит размеры всех столбцов, и может проверять не побились ли столбцы +/// stores the sizes of all columns, and can check whether the columns are corrupted class FileChecker { private: - /// Имя файла -> размер. + /// File name -> size. using Map = std::map; public: @@ -23,7 +23,7 @@ public: void update(const Poco::File & file); void update(const Files::const_iterator & begin, const Files::const_iterator & end); - /// Проверяем файлы, параметры которых указаны в sizes.json + /// Check the files whose parameters are specified in sizes.json bool check() const; private: @@ -35,7 +35,7 @@ private: std::string files_info_path; std::string tmp_files_info_path; - /// Данные из файла читаются лениво. + /// The data from the file is read lazily. Map map; bool initialized = false; diff --git a/dbms/src/Common/HashTable/ClearableHashSet.h b/dbms/src/Common/HashTable/ClearableHashSet.h index e0939d43071..25f64fd3c1e 100644 --- a/dbms/src/Common/HashTable/ClearableHashSet.h +++ b/dbms/src/Common/HashTable/ClearableHashSet.h @@ -4,12 +4,12 @@ #include -/** Хеш-таблица, позволяющая очищать таблицу за O(1). - * Еще более простая, чем HashSet: Key и Mapped должны быть POD-типами. +/** A hash table that allows you to clear the table in O(1). + * Even simpler than HashSet: Key and Mapped must be POD-types. * - * Вместо этого класса можно было бы просто использовать в HashSet в качестве ключа пару <версия, ключ>, - * но тогда таблица накапливала бы все ключи, которые в нее когда-либо складывали, и неоправданно росла. - * Этот класс идет на шаг дальше и считает ключи со старой версией пустыми местами в хеш-таблице. + * Instead of this class, you could just use the couple in the HashSet as the key + * but then the table would accumulate all the keys that it ever stored, and it was unreasonably growing. + * This class goes a step further and considers the keys with the old version empty in the hash table. */ @@ -17,11 +17,11 @@ struct ClearableHashSetState { UInt32 version = 1; - /// Сериализация, в бинарном и текстовом виде. + /// Serialization, in binary and text form. void write(DB::WriteBuffer & wb) const { DB::writeBinary(version, wb); } void writeText(DB::WriteBuffer & wb) const { DB::writeText(version, wb); } - /// Десериализация, в бинарном и текстовом виде. + /// Deserialization, in binary and text form. void read(DB::ReadBuffer & rb) { DB::readBinary(version, rb); } void readText(DB::ReadBuffer & rb) { DB::readText(version, rb); } }; @@ -38,10 +38,10 @@ struct ClearableHashTableCell : public BaseCell bool isZero(const State & state) const { return version != state.version; } static bool isZero(const Key & key, const State & state) { return false; } - /// Установить значение ключа в ноль. + /// Set the key value to zero. void setZero() { version = 0; } - /// Нужно ли хранить нулевой ключ отдельно (то есть, могут ли в хэш-таблицу вставить нулевой ключ). + /// Do I need to store the zero key separately (that is, can a zero key be inserted into the hash table). static constexpr bool need_zero_value_storage = false; ClearableHashTableCell() {} diff --git a/dbms/src/Common/HashTable/Hash.h b/dbms/src/Common/HashTable/Hash.h index ed3bc228b65..8733aee136e 100644 --- a/dbms/src/Common/HashTable/Hash.h +++ b/dbms/src/Common/HashTable/Hash.h @@ -3,12 +3,12 @@ #include -/** Хэш функции, которые лучше чем тривиальная функция std::hash. - * (при агрегации по идентификатору посетителя, прирост производительности более чем в 5 раз) +/** Hash functions that are better than the trivial function std::hash. + * (when aggregated by the visitor ID, the performance increase is more than 5 times) */ -/** Взято из MurmurHash. - * Быстрее, чем intHash32 при вставке в хэш-таблицу UInt64 -> UInt64, где ключ - идентификатор посетителя. +/** Taken from MurmurHash. + * Faster than intHash32 when inserting into the hash table UInt64 -> UInt64, where the key is the visitor ID. */ inline DB::UInt64 intHash64(DB::UInt64 x) { @@ -21,12 +21,12 @@ inline DB::UInt64 intHash64(DB::UInt64 x) return x; } -/** CRC32C является не очень качественной в роли хэш функции, - * согласно avalanche и bit independence тестам, а также малым количеством бит, - * но может вести себя хорошо при использовании в хэш-таблицах, - * за счёт высокой скорости (latency 3 + 1 такт, througput 1 такт). - * Работает только при поддержке SSE 4.2. - * Используется asm вместо интринсика, чтобы не обязательно было собирать весь проект с -msse4. +/** CRC32C is not very high-quality as a hash function, + * according to avalanche and bit independence tests, as well as a small number of bits, + * but can behave well when used in hash tables, + * due to high speed (latency 3 + 1 clock cycle, throughput 1 clock cycle). + * Works only with SSE 4.2 support. + * Used asm instead of intrinsics, so you do not have to build the entire project with -msse4. */ inline DB::UInt64 intHashCRC32(DB::UInt64 x) { @@ -35,7 +35,7 @@ inline DB::UInt64 intHashCRC32(DB::UInt64 x) asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x)); return crc; #else - /// На других платформах используем не обязательно CRC32. NOTE Это может сбить с толку. + /// On other platforms we do not need CRC32. NOTE This can be confusing. return intHash64(x); #endif } @@ -117,7 +117,7 @@ DEFINE_HASH(DB::Float64) #undef DEFINE_HASH -/// Разумно использовать для UInt8, UInt16 при достаточном размере хэш-таблицы. +/// It is reasonable to use for UInt8, UInt16 with sufficient hash table size. struct TrivialHash { template @@ -128,17 +128,17 @@ struct TrivialHash }; -/** Сравнительно неплохая некриптографическая хэш функция из UInt64 в UInt32. - * Но хуже (и по качеству и по скорости), чем просто срезка intHash64. - * Взята отсюда: http://www.concentric.net/~ttwang/tech/inthash.htm +/** A relatively good non-cryptic hash function from UInt64 to UInt32. + * But worse (both in quality and speed) than just cutting intHash64. + * Taken from here: http://www.concentric.net/~ttwang/tech/inthash.htm * - * Немного изменена по сравнению с функцией по ссылке: сдвиги вправо случайно заменены на цикличесвие сдвиги вправо. - * Это изменение никак не повлияло на результаты тестов smhasher. + * Slightly changed compared to the function by link: shifts to the right are accidentally replaced by a cyclic shift to the right. + * This change did not affect the smhasher test results. * - * Рекомендуется для разных задач использовать разные salt. - * А то был случай, что в БД значения сортировались по хэшу (для некачественного псевдослучайного разбрасывания), - * а в другом месте, в агрегатной функции, в хэш таблице использовался такой же хэш, - * в результате чего, эта агрегатная функция чудовищно тормозила из-за коллизий. + * It is recommended to use different salt for different tasks. + * That was the case that in the database values ​​were sorted by hash (for low-quality pseudo-random spread), + * and in another place, in the aggregate function, the same hash was used in the hash table, + * as a result, this aggregate function was monstrously slowed due to collisions. */ template inline DB::UInt32 intHash32(DB::UInt64 key) @@ -156,7 +156,7 @@ inline DB::UInt32 intHash32(DB::UInt64 key) } -/// Для контейнеров. +/// For containers. template struct IntHash32 { diff --git a/dbms/src/Common/HashTable/HashMap.h b/dbms/src/Common/HashTable/HashMap.h index 438022f7c02..f6608a9158f 100644 --- a/dbms/src/Common/HashTable/HashMap.h +++ b/dbms/src/Common/HashTable/HashMap.h @@ -13,7 +13,7 @@ struct NoInitTag {}; -/// Пара, которая не инициализирует элементы, если не нужно. +/// A pair that does not initialize the elements, if not needed. template struct PairNoInit { @@ -60,18 +60,18 @@ struct HashMapCell bool isZero(const State & state) const { return isZero(value.first, state); } static bool isZero(const Key & key, const State & state) { return ZeroTraits::check(key); } - /// Установить значение ключа в ноль. + /// Set the key value to zero. void setZero() { ZeroTraits::set(value.first); } - /// Нужно ли хранить нулевой ключ отдельно (то есть, могут ли в хэш-таблицу вставить нулевой ключ). + /// Do I need to store the zero key separately (that is, can a zero key be inserted into the hash table). static constexpr bool need_zero_value_storage = true; - /// Является ли ячейка удалённой. + /// Whether the cell is removed. bool isDeleted() const { return false; } void setMapped(const value_type & value_) { value.second = value_.second; } - /// Сериализация, в бинарном и текстовом виде. + /// Serialization, in binary and text form. void write(DB::WriteBuffer & wb) const { DB::writeBinary(value.first, wb); @@ -85,7 +85,7 @@ struct HashMapCell DB::writeDoubleQuoted(value.second, wb); } - /// Десериализация, в бинарном и текстовом виде. + /// Deserialization, in binary and text form. void read(DB::ReadBuffer & rb) { DB::readBinary(value.first, rb); @@ -141,19 +141,19 @@ public: bool inserted; this->emplace(x, it, inserted); - /** Может показаться, что инициализация не обязательна для POD-типов (или __has_trivial_constructor), - * так как кусок памяти для хэш-таблицы изначально инициализирован нулями. - * Но, на самом деле, пустая ячейка может быть не инициализирована нулями в следующих случаях: - * - ZeroValueStorage (в нём зануляется только ключ); - * - после ресайза и переноса части ячеек в новую половину хэш-таблицы, у старых ячеек, тоже зануляется только ключ. + /** It may seem that initialization is not necessary for POD-types (or __has_trivial_constructor), + * since the hash table memory is initially initialized with zeros. + * But, in fact, an empty cell may not be initialized with zeros in the following cases: + * - ZeroValueStorage (it only zeros the key); + * - after resizing and moving a part of the cells to the new half of the hash table, the old cells also have only the key to zero. * - * По производительности, разницы почти всегда нет, за счёт того, что it->second как правило присваивается сразу - * после вызова operator[], и так как operator[] инлайнится, компилятор убирает лишнюю инициализацию. + * On performance, there is almost always no difference, due to the fact that it->second is usually assigned immediately + * after calling `operator[]`, and since `operator[]` is inlined, the compiler removes unnecessary initialization. * - * Иногда из-за инициализации, производительность даже растёт. Это происходит в коде вида ++map[key]. - * Когда мы делаем инициализацию, то для новых ячеек, достаточно сразу сделать store 1. - * А если бы мы не делали инициализацию, то не смотря на то, что в ячейке был ноль, - * компилятор не может об этом догадаться, и генерирует код load, increment, store. + * Sometimes due to initialization, the performance even grows. This occurs in code like `++map[key]`. + * When we do the initialization, for new cells, it's enough to make `store 1` right away. + * And if we did not initialize, then even though there was zero in the cell, + * the compiler can not guess about this, and generates the `load`, `increment`, `store` code. */ if (inserted) new(&it->second) mapped_type(); diff --git a/dbms/src/Common/HashTable/HashTable.h b/dbms/src/Common/HashTable/HashTable.h index 50ffb4058b2..224c39f26ed 100644 --- a/dbms/src/Common/HashTable/HashTable.h +++ b/dbms/src/Common/HashTable/HashTable.h @@ -44,27 +44,27 @@ namespace ErrorCodes } -/** Состояние хэш-таблицы, которое влияет на свойства её ячеек. - * Используется в качестве параметра шаблона. - * Например, существует реализация мгновенно-очищаемой хэш-таблицы - ClearableHashMap. - * Для неё, в каждой ячейке хранится номер версии, и в самой хэш-таблице - текущая версия. - * При очистке, просто увеличивается текущая версия; все ячейки с несовпадающей версией считаются пустыми. - * Другой пример: для приближённого рассчёта количества уникальных посетителей, есть хэш-таблица UniquesHashSet. - * В ней имеется понятие "степень". При каждом переполнении, ячейки с ключами, не делящимися на соответствующую степень двух, удаляются. +/** The state of the hash table that affects the properties of its cells. + * Used as a template parameter. + * For example, there is an implementation of an instantly cleared hash table - ClearableHashMap. + * For it, each cell holds the version number, and in the hash table itself is the current version. + * When cleaning, the current version simply increases; All cells with a mismatching version are considered empty. + * Another example: for an approximate calculation of the number of unique visitors, there is a hash table for UniquesHashSet. + * It has the concept of "degree". At each overflow, cells with keys that do not divide by the corresponding power of the two are deleted. */ struct HashTableNoState { - /// Сериализация, в бинарном и текстовом виде. + /// Serialization, in binary and text form. void write(DB::WriteBuffer & wb) const {} void writeText(DB::WriteBuffer & wb) const {} - /// Десериализация, в бинарном и текстовом виде. + /// Deserialization, in binary and text form. void read(DB::ReadBuffer & rb) {} void readText(DB::ReadBuffer & rb) {} }; -/// Эти функции могут быть перегружены для пользовательских типов. +/// These functions can be overloaded for custom types. namespace ZeroTraits { @@ -77,11 +77,11 @@ void set(T & x) { x = 0; } }; -/** Compile-time интерфейс ячейки хэш-таблицы. - * Разные ячейки используются для реализации разных хэш-таблиц. - * Ячейка должна содержать ключ. - * Также может содержать значение и произвольные дополнительные данные - * (пример: запомненное значение хэш-функции; номер версии для ClearableHashMap). +/** Compile-time cell interface of the hash table. + * Different cells are used to implement different hash tables. + * The cell must contain a key. + * It can also contain a value and arbitrary additional data + * (example: the stored hash value; version number for ClearableHashMap). */ template struct HashTableCell @@ -93,89 +93,89 @@ struct HashTableCell HashTableCell() {} - /// Создать ячейку с заданным ключём / ключём и значением. + /// Create a cell with the given key / key and value. HashTableCell(const Key & key_, const State & state) : key(key_) {} /// HashTableCell(const value_type & value_, const State & state) : key(value_) {} - /// Получить то, что будет value_type контейнера. + /// Get what the value_type of the container will be. value_type & getValue() { return key; } const value_type & getValue() const { return key; } - /// Получить ключ. + /// Get the key. static Key & getKey(value_type & value) { return value; } static const Key & getKey(const value_type & value) { return value; } - /// Равны ли ключи у ячеек. + /// Are the keys at the cells equal? bool keyEquals(const Key & key_) const { return key == key_; } bool keyEquals(const Key & key_, size_t hash_) const { return key == key_; } - /// Если ячейка умеет запоминать в себе значение хэш-функции, то запомнить его. + /// If the cell can remember the value of the hash function, then remember it. void setHash(size_t hash_value) {} - /// Если ячейка умеет запоминать в себе значение хэш-функции, то вернуть запомненное значение. - /// Оно должно быть хотя бы один раз вычислено до этого. - /// Если запоминание значения хэш-функции не предусмотрено, то просто вычислить хэш. + /// If the cell can store the hash value in itself, then return the stored value. + /// It must be at least once calculated before. + /// If storing the hash value is not provided, then just compute the hash. size_t getHash(const Hash & hash) const { return hash(key); } - /// Является ли ключ нулевым. В основном буфере, ячейки с нулевым ключём, считаются пустыми. - /// Если нулевые ключи могут быть вставлены в таблицу, то ячейка для нулевого ключа хранится отдельно, не в основном буфере. - /// Нулевые ключи должны быть такими, что занулённый кусок памяти представляет собой нулевой ключ. + /// Whether the key is zero. In the main buffer, cells with a zero key are considered empty. + /// If zero keys can be inserted into the table, then the cell for the zero key is stored separately, not in the main buffer. + /// Zero keys must be such that the zeroed-down piece of memory is a zero key. bool isZero(const State & state) const { return isZero(key, state); } static bool isZero(const Key & key, const State & state) { return ZeroTraits::check(key); } - /// Установить значение ключа в ноль. + /// Set the key value to zero. void setZero() { ZeroTraits::set(key); } - /// Нужно ли хранить нулевой ключ отдельно (то есть, могут ли в хэш-таблицу вставить нулевой ключ). + /// Do I need to store the zero key separately (that is, can a zero key be inserted into the hash table). static constexpr bool need_zero_value_storage = true; - /// Является ли ячейка удалённой. + /// Whether the cell is deleted. bool isDeleted() const { return false; } - /// Установить отображаемое значение, если есть (для HashMap), в соответствующиее из value. + /// Set the displayed value, if any (for HashMap), to the corresponding `value`. void setMapped(const value_type & value) {} - /// Сериализация, в бинарном и текстовом виде. + /// Serialization, in binary and text form. void write(DB::WriteBuffer & wb) const { DB::writeBinary(key, wb); } void writeText(DB::WriteBuffer & wb) const { DB::writeDoubleQuoted(key, wb); } - /// Десериализация, в бинарном и текстовом виде. + /// Deserialization, in binary and text form. void read(DB::ReadBuffer & rb) { DB::readBinary(key, rb); } void readText(DB::ReadBuffer & rb) { DB::writeDoubleQuoted(key, rb); } }; -/** Определяет размер хэш-таблицы, а также когда и во сколько раз её надо ресайзить. +/** Determines the size of the hash table, and when and how many times it should be resized. */ template struct HashTableGrower { - /// Состояние этой структуры достаточно, чтобы получить размер буфера хэш-таблицы. + /// The state of this structure is enough to get the buffer size of the hash table. UInt8 size_degree = initial_size_degree; - /// Размер хэш-таблицы в ячейках. + /// The size of the hash table in the cells. size_t bufSize() const { return 1 << size_degree; } size_t maxFill() const { return 1 << (size_degree - 1); } size_t mask() const { return bufSize() - 1; } - /// Из значения хэш-функции получить номер ячейки в хэш-таблице. + /// From the hash value, get the cell number in the hash table. size_t place(size_t x) const { return x & mask(); } - /// Следующая ячейка в цепочке разрешения коллизий. + /// The next cell in the collision resolution chain. size_t next(size_t pos) const { ++pos; return pos & mask(); } - /// Является ли хэш-таблица достаточно заполненной. Нужно увеличить размер хэш-таблицы, или удалить из неё что-нибудь ненужное. + /// Whether the hash table is sufficiently full. You need to increase the size of the hash table, or remove something unnecessary from it. bool overflow(size_t elems) const { return elems > maxFill(); } - /// Увеличить размер хэш-таблицы. + /// Increase the size of the hash table. void increaseSize() { size_degree += size_degree >= 23 ? 1 : 2; } - /// Установить размер буфера по количеству элементов хэш-таблицы. Используется при десериализации хэш-таблицы. + /// Set the buffer size by the number of elements in the hash table. Used when deserializing a hash table. void set(size_t num_elems) { size_degree = num_elems <= 1 @@ -192,17 +192,17 @@ struct HashTableGrower }; -/** При использовании в качестве Grower-а, превращает хэш-таблицу в что-то типа lookup-таблицы. - * Остаётся неоптимальность - в ячейках хранятся ключи. - * Также компилятору не удаётся полностью удалить код хождения по цепочке разрешения коллизий, хотя он не нужен. - * TODO Сделать полноценную lookup-таблицу. +/** When used as a Grower, it turns a hash table into something like a lookup table. + * It remains non-optimal - the cells store the keys. + * Also, the compiler can not completely remove the code of passing through the collision resolution chain, although it is not needed. + * TODO Make a full lookup table. */ template struct HashTableFixedGrower { size_t bufSize() const { return 1 << key_bits; } size_t place(size_t x) const { return x; } - /// Тут можно было бы написать __builtin_unreachable(), но компилятор не до конца всё оптимизирует, и получается менее эффективно. + /// You could write __builtin_unreachable(), but the compiler does not optimize everything, and it turns out less efficiently. size_t next(size_t pos) const { return pos + 1; } bool overflow(size_t elems) const { return false; } @@ -212,7 +212,7 @@ struct HashTableFixedGrower }; -/** Если нужно хранить нулевой ключ отдельно - место для его хранения. */ +/** If you want to store the null key separately - a place to store it. */ template struct ZeroValueStorage; @@ -271,15 +271,15 @@ protected: using Self = HashTable; using cell_type = Cell; - size_t m_size = 0; /// Количество элементов - Cell * buf; /// Кусок памяти для всех элементов кроме элемента с ключём 0. + size_t m_size = 0; /// Amount of elements + Cell * buf; /// A piece of memory for all elements except the element with key 0. Grower grower; #ifdef DBMS_HASH_MAP_COUNT_COLLISIONS mutable size_t collisions = 0; #endif - /// Найти ячейку с тем же ключём или пустую ячейку, начиная с заданного места и далее по цепочке разрешения коллизий. + /// Find a cell with the same key or an empty cell, starting from the specified position and further along the collision resolution chain. size_t ALWAYS_INLINE findCell(const Key & x, size_t hash_value, size_t place_value) const { while (!buf[place_value].isZero(*this) && !buf[place_value].keyEquals(x, hash_value)) @@ -293,7 +293,7 @@ protected: return place_value; } - /// Найти пустую ячейку, начиная с заданного места и далее по цепочке разрешения коллизий. + /// Find an empty cell, starting with the specified position and further along the collision resolution chain. size_t ALWAYS_INLINE findEmptyCell(const Key & x, size_t hash_value, size_t place_value) const { while (!buf[place_value].isZero(*this)) @@ -323,7 +323,7 @@ protected: } - /// Увеличить размер буфера. + /// Increase the size of the buffer. void resize(size_t for_num_elems = 0, size_t for_buf_size = 0) { #ifdef DBMS_HASH_MAP_DEBUG_RESIZES @@ -332,10 +332,10 @@ protected: size_t old_size = grower.bufSize(); - /** Чтобы в случае исключения, объект остался в корректном состоянии, - * изменение переменной grower (определяющией размер буфера хэш-таблицы) - * откладываем на момент после реального изменения буфера. - * Временная переменная new_grower используется, чтобы определить новый размер. + /** In case of exception for the object to remain in the correct state, + * changing the variable `grower` (which determines the buffer size of the hash table) + * postpone for a moment after a real buffer change. + * The temporary variable `new_grower` is used to determine the new size. */ Grower new_grower = grower; @@ -354,26 +354,26 @@ protected: else new_grower.increaseSize(); - /// Расширим пространство. + /// Expand the space. buf = reinterpret_cast(Allocator::realloc(buf, getBufferSizeInBytes(), new_grower.bufSize() * sizeof(Cell))); grower = new_grower; - /** Теперь некоторые элементы может потребоваться переместить на новое место. - * Элемент может остаться на месте, или переместиться в новое место "справа", - * или переместиться левее по цепочке разрешения коллизий, из-за того, что элементы левее него были перемещены в новое место "справа". + /** Now some items may need to be moved to a new location. + * The element can stay in place, or move to a new location "on the right", + * or move to the left of the collision resolution chain, because the elements to the left of it have been moved to the new "right" location. */ size_t i = 0; for (; i < old_size; ++i) if (!buf[i].isZero(*this) && !buf[i].isDeleted()) reinsert(buf[i]); - /** Также имеется особый случай: - * если элемент должен был быть в конце старого буфера, [ x] - * но находится в начале из-за цепочки разрешения коллизий, [o x] - * то после ресайза, он сначала снова окажется не на своём месте, [ xo ] - * и для того, чтобы перенести его куда надо, - * надо будет после переноса всех элементов из старой половинки [ o x ] - * обработать ещё хвостик из цепочки разрешения коллизий сразу после неё [ o x ] + /** There is also a special case: + * if the element was to be at the end of the old buffer, [ x] + * but is at the beginning because of the collision resolution chain, [o x] + * then after resizing, it will first be out of place again, [ xo ] + * and in order to transfer it where necessary, + * after transferring all the elements from the old halves you need to [ o x ] + * process tail from the collision resolution chain immediately after it [ o x ] */ for (; !buf[i].isZero(*this) && !buf[i].isDeleted(); ++i) reinsert(buf[i]); @@ -387,30 +387,30 @@ protected: } - /** Вставить в новый буфер значение, которое было в старом буфере. - * Используется при увеличении размера буфера. + /** Paste into the new buffer the value that was in the old buffer. + * Used when increasing the buffer size. */ void reinsert(Cell & x) { size_t hash_value = x.getHash(*this); size_t place_value = grower.place(hash_value); - /// Если элемент на своём месте. + /// If the element is in its place. if (&x == &buf[place_value]) return; - /// Вычисление нового места, с учётом цепочки разрешения коллизий. + /// Compute a new location, taking into account the collision resolution chain. place_value = findCell(Cell::getKey(x.getValue()), hash_value, place_value); - /// Если элемент остался на своём месте в старой цепочке разрешения коллизий. + /// If the item remains in its place in the old collision resolution chain. if (!buf[place_value].isZero(*this)) return; - /// Копирование на новое место и зануление старого. + /// Copy to a new location and zero the old one. memcpy(&buf[place_value], &x, sizeof(x)); x.setZero(); - /// Потом на старое место могут переместиться элементы, которые раньше были в коллизии с этим. + /// Then the elements that previously were in conflict with this can move to the old place. } @@ -611,10 +611,10 @@ protected: iterator iteratorToZero() { return iteratorTo(this->zeroValue()); } - /// Если ключ нулевой - вставить его в специальное место и вернуть true. + /// If the key is zero, insert it into a special place and return true. bool ALWAYS_INLINE emplaceIfZero(Key x, iterator & it, bool & inserted) { - /// Если утверждается, что нулевой ключ не могут вставить в таблицу. + /// If it is claimed that the zero key can not be inserted into the table. if (!Cell::need_zero_value_storage) return false; @@ -638,7 +638,7 @@ protected: } - /// Только для ненулевых ключей. Найти нужное место, вставить туда ключ, если его ещё нет, вернуть итератор на ячейку. + /// Only for non-zero keys. Find the right place, insert the key there, if it does not already exist, return the iterator to the cell. void ALWAYS_INLINE emplaceNonZero(Key x, iterator & it, bool & inserted, size_t hash_value) { size_t place_value = findCell(x, hash_value, grower.place(hash_value)); @@ -664,9 +664,9 @@ protected: } catch (...) { - /** Если этого не делать, то будут проблемы. - * Ведь останется ключ, но неинициализированное mapped-значение, - * у которого, возможно, даже нельзя вызвать деструктор. + /** If you do not do it, then there will be problems. + * After all, there remains a key, but uninitialized mapped-value, + * which, perhaps, can not even be called a destructor. */ --m_size; buf[place_value].setZero(); @@ -679,7 +679,7 @@ protected: public: - /// Вставить значение. В случае хоть сколько-нибудь сложных значений, лучше используйте функцию emplace. + /// Insert a value. In the case of any more complex values, it is better to use the `emplace` function. std::pair ALWAYS_INLINE insert(const value_type & x) { std::pair res; @@ -694,14 +694,14 @@ public: } - /** Вставить ключ, - * вернуть итератор на позицию, которую можно использовать для placement new значения, - * а также флаг - был ли вставлен новый ключ. + /** Insert the key, + * return the iterator to a position that can be used for `placement new` of value, + * as well as the flag - whether a new key was inserted. * - * Вы обязаны сделать placement new значения, если был вставлен новый ключ, - * так как при уничтожении хэш-таблицы для него будет вызываться деструктор! + * You are required to make `placement new` of value ​​if you inserted a new key, + * since when destroying a hash table, it will call the destructor! * - * Пример использования: + * Example usage: * * Map::iterator it; * bool inserted; @@ -716,7 +716,7 @@ public: } - /// То же самое, но с заранее вычисленным значением хэш-функции. + /// Same, but with a precalculated value of hash function. void ALWAYS_INLINE emplace(Key x, iterator & it, bool & inserted, size_t hash_value) { if (!emplaceIfZero(x, it, inserted)) @@ -724,7 +724,7 @@ public: } - /// Скопировать ячейку из другой хэш-таблицы. Предполагается, что ячейка не нулевая, а также, что такого ключа в таблице ещё не было. + /// Copy the cell from another hash table. It is assumed that the cell is not zero, and also that there was no such key in the table yet. void ALWAYS_INLINE insertUniqueNonZero(const Cell * cell, size_t hash_value) { size_t place_value = findEmptyCell(cell->getKey(cell->getValue()), hash_value, grower.place(hash_value)); @@ -903,8 +903,8 @@ public: memset(buf, 0, grower.bufSize() * sizeof(*buf)); } - /// После выполнения этой функции, таблицу можно только уничтожить, - /// а также можно использовать методы size, empty, begin, end. + /// After executing this function, the table can only be destroyed, + /// and also you can use the methods `size`, `empty`, `begin`, `end`. void clearAndShrink() { destroyElements(); diff --git a/dbms/src/Common/HashTable/SmallTable.h b/dbms/src/Common/HashTable/SmallTable.h index 413adac0018..190bb295b2e 100644 --- a/dbms/src/Common/HashTable/SmallTable.h +++ b/dbms/src/Common/HashTable/SmallTable.h @@ -3,15 +3,15 @@ #include -/** Замена хэш-таблицы для маленького количества (единицы) ключей. - * Реализована в виде массива с линейным поиском. - * Массив расположен внутри объекта. - * Интерфейс является подмножеством интерфейса HashTable. +/** Replacement of the hash table for a small number (<10) of keys. + * Implemented as an array with linear search. + * The array is located inside the object. + * The interface is a subset of the HashTable interface. * - * Вставка возможна только если метод full возвращает false. - * При неизвестном количестве различных ключей, - * вы должны проверять, не заполнена ли таблица, - * и делать fallback в этом случае (например, использовать полноценную хэш-таблицу). + * Insert is possible only if the `full` method returns false. + * With an unknown number of different keys, + * you should check if the table is not full, + * and do a `fallback` in this case (for example, use a real hash table). */ template @@ -32,11 +32,11 @@ protected: using Self = SmallTable; using cell_type = Cell; - size_t m_size = 0; /// Количество элементов. - Cell buf[capacity]; /// Кусок памяти для всех элементов. + size_t m_size = 0; /// Amount of elements. + Cell buf[capacity]; /// A piece of memory for all elements. - /// Найти ячейку с тем же ключём или пустую ячейку, начиная с заданного места и далее по цепочке разрешения коллизий. + /// Find a cell with the same key or an empty cell, starting from the specified position and then by the collision resolution chain. const Cell * ALWAYS_INLINE findCell(const Key & x) const { const Cell * it = buf; @@ -188,8 +188,8 @@ protected: public: - /** Таблица переполнена. - * В переполненную таблицу ничего нельзя вставлять. + /** The table is full. + * You can not insert anything into the full table. */ bool full() { @@ -197,7 +197,7 @@ public: } - /// Вставить значение. В случае хоть сколько-нибудь сложных значений, лучше используйте функцию emplace. + /// Insert the value. In the case of any more complex values, it is better to use the `emplace` function. std::pair ALWAYS_INLINE insert(const value_type & x) { std::pair res; @@ -211,14 +211,14 @@ public: } - /** Вставить ключ, - * вернуть итератор на позицию, которую можно использовать для placement new значения, - * а также флаг - был ли вставлен новый ключ. + /** Insert the key, + * return the iterator to a position that can be used for `placement new` of value, + * as well as the flag - whether a new key was inserted. * - * Вы обязаны сделать placement new значения, если был вставлен новый ключ, - * так как при уничтожении хэш-таблицы для него будет вызываться деструктор! + * You have to make `placement new` of value ​​if you inserted a new key, + * since when destroying a hash table, a destructor will be called for it! * - * Пример использования: + * Example usage: * * Map::iterator it; * bool inserted; @@ -239,7 +239,7 @@ public: } - /// То же самое, но вернуть false, если переполнено. + /// Same, but return false if it's full. bool ALWAYS_INLINE tryEmplace(Key x, iterator & it, bool & inserted) { Cell * res = findCell(x); @@ -257,7 +257,7 @@ public: } - /// Скопировать ячейку из другой хэш-таблицы. Предполагается, что такого ключа в таблице ещё не было. + /// Copy the cell from another hash table. It is assumed that there was no such key in the table yet. void ALWAYS_INLINE insertUnique(const Cell * cell) { memcpy(&buf[m_size], cell, sizeof(*cell)); diff --git a/dbms/src/Common/HashTable/TwoLevelHashTable.h b/dbms/src/Common/HashTable/TwoLevelHashTable.h index 519b0db7110..d33b8b50bfe 100644 --- a/dbms/src/Common/HashTable/TwoLevelHashTable.h +++ b/dbms/src/Common/HashTable/TwoLevelHashTable.h @@ -3,21 +3,21 @@ #include -/** Двухуровневая хэш-таблица. - * Представляет собой 256 (или 1 << BITS_FOR_BUCKET) маленьких хэш-таблиц (bucket-ов первого уровня). - * Для определения, какую из них использовать, берётся один из байтов хэш-функции. +/** Two-level hash table. + * Represents 256 (or 1 << BITS_FOR_BUCKET) small hash tables (buckets of the first level). + * To determine which one to use, one of the bytes of the hash function is taken. * - * Обычно работает чуть-чуть медленнее простой хэш-таблицы. - * Тем не менее, обладает преимуществами в некоторых случаях: - * - если надо мерджить две хэш-таблицы вместе, то это можно легко распараллелить по bucket-ам; - * - лаг при ресайзах размазан, так как маленькие хэш-таблицы ресайзятся по-отдельности; - * - по идее, ресайзы кэш-локальны в большем диапазоне размеров. + * Usually works a little slower than a simple hash table. + * However, it has advantages in some cases: + * - if you need to measure two hash tables together, then you can easily parallelize them by buckets; + * - lag during resizes is spread, since the small hash tables will be resized separately; + * - in theory, the cache resize is local in a larger range of sizes. */ template struct TwoLevelHashTableGrower : public HashTableGrower { - /// Увеличить размер хэш-таблицы. + /// Increase the size of the hash table. void increaseSize() { this->size_degree += this->size_degree >= 15 ? 1 : 2; @@ -52,7 +52,7 @@ public: size_t hash(const Key & x) const { return Hash::operator()(x); } - /// NOTE Плохо для хэш-таблиц больше чем на 2^32 ячеек. + /// NOTE Bad for hash tables for more than 2^32 cells. static size_t getBucketFromHash(size_t hash_value) { return (hash_value >> (32 - BITS_FOR_BUCKET)) & MAX_BUCKET; } protected: @@ -89,13 +89,13 @@ public: TwoLevelHashTable() {} - /// Скопировать данные из другой (обычной) хэш-таблицы. У неё должна быть такая же хэш-функция. + /// Copy the data from another (normal) hash table. It should have the same hash function. template TwoLevelHashTable(const Source & src) { typename Source::const_iterator it = src.begin(); - /// Предполагается, что нулевой ключ (хранящийся отдельно) при итерировании идёт первым. + /// It is assumed that the zero key (stored separately) when iterating is first. if (it != src.end() && it.getPtr()->isZero(src)) { insert(*it); @@ -205,7 +205,7 @@ public: iterator end() { return { this, MAX_BUCKET, impls[MAX_BUCKET].end() }; } - /// Вставить значение. В случае хоть сколько-нибудь сложных значений, лучше используйте функцию emplace. + /// Insert a value. In the case of any more complex values, it is better to use the `emplace` function. std::pair ALWAYS_INLINE insert(const value_type & x) { size_t hash_value = hash(Cell::getKey(x)); @@ -220,14 +220,14 @@ public: } - /** Вставить ключ, - * вернуть итератор на позицию, которую можно использовать для placement new значения, - * а также флаг - был ли вставлен новый ключ. + /** Insert the key, + * return the iterator to a position that can be used for `placement new` value, + * as well as the flag - whether a new key was inserted. * - * Вы обязаны сделать placement new значения, если был вставлен новый ключ, - * так как при уничтожении хэш-таблицы для него будет вызываться деструктор! + * You have to make `placement new` values ​​if you inserted a new key, + * since when destroying a hash table, the destructor will be invoked for it! * - * Пример использования: + * Example usage: * * Map::iterator it; * bool inserted; @@ -242,7 +242,7 @@ public: } - /// То же самое, но с заранее вычисленным значением хэш-функции. + /// Same, but with a precalculated values of hash function. void ALWAYS_INLINE emplace(Key x, iterator & it, bool & inserted, size_t hash_value) { size_t buck = getBucketFromHash(hash_value); diff --git a/dbms/src/Common/HyperLogLogBiasEstimator.h b/dbms/src/Common/HyperLogLogBiasEstimator.h index 75116de1ce9..7d0ba470865 100644 --- a/dbms/src/Common/HyperLogLogBiasEstimator.h +++ b/dbms/src/Common/HyperLogLogBiasEstimator.h @@ -7,10 +7,10 @@ #include #include -/** Этот класс предоставляет способ, чтобы оценить погрешность результата применения алгоритма HyperLogLog. - * Эмирические наблюдения показывают, что большие погрешности возникают при E < 5 * 2^precision, где - * E - возвращаемое значение алгоритмом HyperLogLog, и precision - параметр точности HyperLogLog. - * См. "HyperLogLog in Practice: Algorithmic Engineering of a State of The Art Cardinality Estimation Algorithm". +/** This class provides a way to evaluate the error in the result of applying the HyperLogLog algorithm. + * Empirical observations show that large errors occur at E < 5 * 2^precision, where + * E is the return value of the HyperLogLog algorithm, and `precision` is the HyperLogLog precision parameter. + * See "HyperLogLog in Practice: Algorithmic Engineering of a State of the Art Cardinality Estimation Algorithm". * (S. Heule et al., Proceedings of the EDBT 2013 Conference). */ template @@ -22,14 +22,14 @@ public: return false; } - /// Предельное количество уникальных значений до которого должна примениться поправка - /// из алгоритма LinearCounting. + /// Maximum number of unique values ​​to which the correction should apply + /// from the LinearCounting algorithm. static double getThreshold() { return BiasData::getThreshold(); } - /// Вернуть оценку погрешности. + /// Return the error estimate. static double getBias(double raw_estimate) { const auto & estimates = BiasData::getRawEstimates(); @@ -52,7 +52,7 @@ public: } else { - /// Получаем оценку погрешности путём линейной интерполяции. + /// We get the error estimate by linear interpolation. size_t index = std::distance(estimates.begin(), it); double estimate1 = estimates[index - 1]; @@ -60,7 +60,7 @@ public: double bias1 = biases[index - 1]; double bias2 = biases[index]; - /// Предполагается, что условие estimate1 < estimate2 всегда выполнено. + /// It is assumed that the estimate1 < estimate2 condition is always satisfied. double slope = (bias2 - bias1) / (estimate2 - estimate1); return bias1 + slope * (raw_estimate - estimate1); @@ -68,7 +68,7 @@ public: } private: - /// Статические проверки. + /// Static checks. using TRawEstimatesRef = decltype(BiasData::getRawEstimates()); using TRawEstimates = typename std::remove_reference::type; @@ -82,10 +82,10 @@ private: "Bias estimator has inconsistent data"); }; -/** Тривиальный случай HyperLogLogBiasEstimator: употребляется, если не хотим исправить - * погрешность. Это имеет смысль при маленьких значениях параметра точности, например 5 или 12. - * Тогда применяются поправки из оригинальной версии алгоритма HyperLogLog. - * См. "HyperLogLog: The analysis of a near-optimal cardinality estimation algorithm" +/** Trivial case of HyperLogLogBiasEstimator: used if we do not want to fix + * error. This has meaning for small values ​​of the accuracy parameter, for example 5 or 12. + * Then the corrections from the original version of the HyperLogLog algorithm are applied. + * See "HyperLogLog: The analysis of a near-optimal cardinality estimation algorithm" * (P. Flajolet et al., AOFA '07: Proceedings of the 2007 International Conference on Analysis * of Algorithms) */ diff --git a/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h b/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h index faa6b90c9db..b604d82d85b 100644 --- a/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h +++ b/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h @@ -9,10 +9,10 @@ namespace DB { -/** Для маленького количества ключей - массив фиксированного размера "на стеке". - * Для большого - выделяется HyperLogLog. - * Смотрите также более практичную реализацию в CombinedCardinalityEstimator.h, - * где используется также хэш-таблица для множеств среднего размера. +/** For a small number of keys - an array of fixed size "on the stack." + * For large, HyperLogLog is allocated. + * See also the more practical implementation in CombinedCardinalityEstimator.h, + * where a hash table is also used for medium-sized sets. */ template < @@ -39,7 +39,7 @@ private: { CurrentMemoryTracker::alloc(sizeof(large)); - /// На время копирования данных из tiny, устанавливать значение large ещё нельзя (иначе оно перезатрёт часть данных). + /// At the time of copying data from `tiny`, setting the value of `large` is still not possible (otherwise it will overwrite some data). Large * tmp_large = new Large; for (const auto & x : small) @@ -99,7 +99,7 @@ public: } } - /// Можно вызывать только для пустого объекта. + /// You can only call for an empty object. void read(DB::ReadBuffer & in) { bool is_large; diff --git a/dbms/src/Common/Increment.h b/dbms/src/Common/Increment.h index fafc424073c..fc8820975fa 100644 --- a/dbms/src/Common/Increment.h +++ b/dbms/src/Common/Increment.h @@ -3,24 +3,24 @@ #include -/** Позволяет получать авто-инкрементное число, храня его в файле. - * Предназначен для редких вызовов (не рассчитан на производительность). +/** Lets you receive an auto-increment number, storing it in a file. + * Designed for rare calls (not designed for performance). */ class Increment { public: - /// path - имя файла, включая путь + /// path - the name of the file, including the path Increment(const std::string & path_) : counter(path_) {} - /** Получить следующее число. - * Если параметр create_if_need не установлен в true, то - * в файле уже должно быть записано какое-нибудь число (если нет - создайте файл вручную с нулём). + /** Get the next number. + * If the `create_if_need` parameter is not set to true, then + * the file must already have a number written (if not - create the file manually with zero). * - * Для защиты от race condition-ов между разными процессами, используются файловые блокировки. - * (Но при первом создании файла race condition возможен, так что лучше создать файл заранее.) + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) * - * locked_callback вызывается при заблокированном файле со счетчиком. В него передается новое значение. - * locked_callback можно использовать, чтобы делать что-нибудь атомарно с увеличением счетчика (например, переименовывать файлы). + * `locked_callback` is called when the counter file is locked. A new value is passed to it. + * `locked_callback` can be used to do something atomically with the increment of the counter (for example, rename files). */ template UInt64 get(Callback && locked_callback, bool create_if_need = false) @@ -33,25 +33,25 @@ public: return getBunch(1, create_if_need); } - /// Посмотреть следующее значение. + /// Peek the next value. UInt64 peek(bool create_if_need = false) { return getBunch(0, create_if_need); } - /** Получить следующее число и увеличить счетчик на count. - * Если параметр create_if_need не установлен в true, то - * в файле уже должно быть записано какое-нибудь число (если нет - создайте файл вручную с нулём). + /** Get the next number and increase the count by `count`. + * If the `create_if_need` parameter is not set to true, then + * the file should already have a number written (if not - create the file manually with zero). * - * Для защиты от race condition-ов между разными процессами, используются файловые блокировки. - * (Но при первом создании файла race condition возможен, так что лучше создать файл заранее.) + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) */ UInt64 getBunch(UInt64 count, bool create_if_need = false) { return static_cast(counter.add(static_cast(count), create_if_need) - count + 1); } - /// Изменить путь к файлу. + /// Change the path to the file. void setPath(std::string path_) { counter.setPath(path_); @@ -67,7 +67,7 @@ private: }; -/** То же самое, но без хранения в файле. +/** The same, but without storing it in a file. */ struct SimpleIncrement : private boost::noncopyable { diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index 0e6cfe94c39..dec296fcbfe 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -7,7 +7,7 @@ namespace DB { -/** Раскрывает в строке макросы из конфига. +/** Apply the macros from the config in the line. */ class Macros { @@ -15,8 +15,8 @@ public: Macros(); Macros(const Poco::Util::AbstractConfiguration & config, const String & key); - /** Заменить в строке подстроки вида {macro_name} на значение для macro_name, полученное из конфига. - * level - уровень рекурсии. + /** Replace the substring of the form {macro_name} with the value for macro_name, obtained from the config file. + * level - the level of recursion. */ String expand(const String & s, size_t level = 0) const; diff --git a/dbms/src/Common/MemoryTracker.h b/dbms/src/Common/MemoryTracker.h index df805e7f999..7066e20ee17 100644 --- a/dbms/src/Common/MemoryTracker.h +++ b/dbms/src/Common/MemoryTracker.h @@ -102,10 +102,10 @@ public: }; -/** Объект MemoryTracker довольно трудно протащить во все места, где выделяются существенные объёмы памяти. - * Поэтому, используется thread-local указатель на используемый MemoryTracker или nullptr, если его не нужно использовать. - * Этот указатель выставляется, когда в данном потоке следует отслеживать потребление памяти. - * Таким образом, его нужно всего-лишь протащить во все потоки, в которых обрабатывается один запрос. +/** The MemoryTracker object is quite difficult to drag to all places where significant amounts of memory are allocated. + * Therefore, a thread-local pointer to used MemoryTracker or nullptr is used, if it does not need to be used. + * This pointer is set when memory consumption is monitored in this thread. + * So, you just need to drag it to all the threads that handle one request. */ extern __thread MemoryTracker * current_memory_tracker; diff --git a/dbms/src/Common/OptimizedRegularExpression.h b/dbms/src/Common/OptimizedRegularExpression.h index d6a6475c1fb..3cd22ea3c15 100644 --- a/dbms/src/Common/OptimizedRegularExpression.h +++ b/dbms/src/Common/OptimizedRegularExpression.h @@ -12,20 +12,20 @@ #endif -/** Использует два способа оптимизации регулярного выражения: - * 1. Если регулярное выражение является тривиальным (сводится к поиску подстроки в строке), - * то заменяет поиск на strstr или strcasestr. - * 2. Если регулярное выражение содержит безальтернативную подстроку достаточной длины, - * то перед проверкой используется strstr или strcasestr достаточной длины; - * регулярное выражение проверяется полностью только если подстрока найдена. - * 3. В остальных случаях, используется движок re2. +/** Uses two ways to optimize a regular expression: + * 1. If the regular expression is trivial (reduces to finding a substring in a string), + * then replaces the search with strstr or strcasestr. + * 2. If the regular expression contains a non-alternative substring of sufficient length, + * then before testing, strstr or strcasestr of sufficient length is used; + * regular expression is only fully checked if a substring is found. + * 3. In other cases, the re2 engine is used. * - * Это имеет смысл, так как strstr и strcasestr в libc под Linux хорошо оптимизированы. + * This makes sense, since strstr and strcasestr in libc for Linux are well optimized. * - * Подходит, если одновременно выполнены следующие условия: - * - если в большинстве вызовов, регулярное выражение не матчится; - * - если регулярное выражение совместимо с движком re2; - * - можете использовать на свой риск, так как, возможно, не все случаи учтены. + * Suitable if the following conditions are simultaneously met: + * - if in most calls, the regular expression does not match; + * - if the regular expression is compatible with the re2 engine; + * - you can use at your own risk, since, probably, not all cases are taken into account. */ namespace OptimizedRegularExpressionDetails @@ -82,7 +82,7 @@ public: unsigned getNumberOfSubpatterns() const { return number_of_subpatterns; } - /// Получить регексп re2 или nullptr, если шаблон тривиален (для вывода в лог). + /// Get the regexp re2 or nullptr if the pattern is trivial (for output to the log). const std::unique_ptr& getRE2() const { return re2; } static void analyze(const std::string & regexp_, std::string & required_substring, bool & is_trivial, bool & required_substring_is_prefix); diff --git a/dbms/src/Common/OptimizedRegularExpression.inl b/dbms/src/Common/OptimizedRegularExpression.inl index 2689901ca99..a60ff314e7d 100644 --- a/dbms/src/Common/OptimizedRegularExpression.inl +++ b/dbms/src/Common/OptimizedRegularExpression.inl @@ -15,12 +15,12 @@ void OptimizedRegularExpressionImpl::analyze( bool & is_trivial, bool & required_substring_is_prefix) { - /** Выражение тривиально, если в нём все метасимволы эскейплены. - * Безальтернативная строка - это - * строка вне скобок, - * в которой все метасимволы эскейплены, - * а также если вне скобок нет '|', - * а также избегаются подстроки вида http:// или www. + /** The expression is trivial if all the metacharacters in it are escaped. + * The non-alternative string is + * a string outside parentheses, + * in which all metacharacters are escaped, + * and also if there are no '|' outside the brackets, + * and also avoid substrings of the form `http://` or `www`. */ const char * begin = regexp.data(); const char * pos = begin; @@ -31,7 +31,7 @@ void OptimizedRegularExpressionImpl::analyze( required_substring.clear(); bool has_alternative_on_depth_0 = false; - /// Подстрока с позицией. + /// Substring with a position. typedef std::pair Substring; typedef std::vector Substrings; @@ -66,7 +66,7 @@ void OptimizedRegularExpressionImpl::analyze( } break; default: - /// все остальные escape-последовательности не поддерживаем + /// all other escape sequences are not supported is_trivial = false; if (!last_substring->first.empty()) { @@ -157,7 +157,7 @@ void OptimizedRegularExpressionImpl::analyze( ++pos; break; - /// Квантификаторы, допускающие нулевое количество. + /// Quantifiers that allow a zero number. case '{': in_curly_braces = true; case '?': case '*': @@ -179,7 +179,7 @@ void OptimizedRegularExpressionImpl::analyze( ++pos; break; - ordinary: /// Обычный, не заэскейпленный символ. + ordinary: /// Normal, not escaped symbol. default: if (depth == 0 && !in_curly_braces && !in_square_braces) { @@ -199,8 +199,8 @@ void OptimizedRegularExpressionImpl::analyze( { if (!has_alternative_on_depth_0) { - /** Выберем безальтернативную подстроку максимальной длины, среди префиксов, - * или безальтернативную подстроку максимальной длины. + /** We choose the non-alternative substring of the maximum length, among the prefixes, + * or a non-alternative substring of maximum length. */ size_t max_length = 0; Substrings::const_iterator candidate_it = trivial_substrings.begin(); @@ -208,7 +208,7 @@ void OptimizedRegularExpressionImpl::analyze( { if (((it->second == 0 && candidate_it->second != 0) || ((it->second == 0) == (candidate_it->second == 0) && it->first.size() > max_length)) - /// Тюнинг для предметной области + /// Tuning for the domain && (it->first.size() > strlen("://") || strncmp(it->first.data(), "://", strlen("://"))) && (it->first.size() > strlen("http://") || strncmp(it->first.data(), "http", strlen("http"))) && (it->first.size() > strlen("www.") || strncmp(it->first.data(), "www", strlen("www"))) @@ -246,7 +246,7 @@ OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::str { analyze(regexp_, required_substring, is_trivial, required_substring_is_prefix); - /// Поддерживаются 3 опции + /// 3 options are supported if (options & (~(RE_CASELESS | RE_NO_CAPTURE | RE_DOT_NL))) throw Poco::Exception("OptimizedRegularExpression: Unsupported option."); @@ -257,7 +257,7 @@ OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::str number_of_subpatterns = 0; if (!is_trivial) { - /// Скомпилируем регулярное выражение re2. + /// Compile the re2 regular expression. typename RegexType::Options options; if (is_case_insensitive) diff --git a/dbms/src/Common/PODArray.h b/dbms/src/Common/PODArray.h index 2d42c1c39dc..0b46fecf5f9 100644 --- a/dbms/src/Common/PODArray.h +++ b/dbms/src/Common/PODArray.h @@ -19,33 +19,33 @@ namespace DB { -/** Динамический массив для POD-типов. - * Предназначен для небольшого количества больших массивов (а не большого количества маленьких). - * А точнее - для использования в ColumnVector. - * Отличается от std::vector тем, что не инициализирует элементы. +/** A dynamic array for POD types. + * Designed for a small number of large arrays (rather than a lot of small ones). + * To be more precise - for use in ColumnVector. + * It differs from std::vector in that it does not initialize the elements. * - * Сделан некопируемым, чтобы не было случайных копий. Скопировать данные можно с помощью метода assign. + * Made uncopable so that there are no random copies. You can copy the data using `assign` method. * - * Поддерживается только часть интерфейса std::vector. + * Only part of the std::vector interface is supported. * - * Конструктор по-умолчанию создаёт пустой объект, который не выделяет память. - * Затем выделяется память минимум в INITIAL_SIZE байт. + * The default constructor creates an empty object that does not allocate memory. + * Then the memory is allocated at least INITIAL_SIZE bytes. * - * Если вставлять элементы push_back-ом, не делая reserve, то PODArray примерно в 2.5 раза быстрее std::vector. + * If you insert elements with push_back, without making a `reserve`, then PODArray is about 2.5 times faster than std::vector. * - * Шаблонный параметр pad_right - всегда выделять в конце массива столько неиспользуемых байт. - * Может использоваться для того, чтобы делать оптимистичное чтение, запись, копирование невыровненными SIMD-инструкциями. + * The template parameter `pad_right` - always allocate at the end of the array as many unused bytes. + * Can be used to make optimistic reading, writing, copying with unaligned SIMD instructions. */ template , size_t pad_right_ = 0> class PODArray : private boost::noncopyable, private TAllocator /// empty base optimization { private: - /// Округление padding-а вверх до целого количества элементов, чтобы упростить арифметику. + /// Round padding up to an integer number of elements to simplify arithmetic. static constexpr size_t pad_right = (pad_right_ + sizeof(T) - 1) / sizeof(T) * sizeof(T); char * c_start = nullptr; char * c_end = nullptr; - char * c_end_of_storage = nullptr; /// Не включает в себя pad_right. + char * c_end_of_storage = nullptr; /// Does not include pad_right. T * t_start() { return reinterpret_cast(c_start); } T * t_end() { return reinterpret_cast(c_end); } @@ -55,10 +55,10 @@ private: const T * t_end() const { return reinterpret_cast(c_end); } const T * t_end_of_storage() const { return reinterpret_cast(c_end_of_storage); } - /// Количество памяти, занимаемое num_elements элементов. + /// The amount of memory occupied by the num_elements of the elements. static size_t byte_size(size_t num_elements) { return num_elements * sizeof(T); } - /// Минимальное количество памяти, которое нужно выделить для num_elements элементов, включая padding. + /// Minimum amount of memory to allocate for num_elements, including padding. static size_t minimum_memory_for_elements(size_t num_elements) { return byte_size(num_elements) + pad_right; } void alloc_for_num_elements(size_t num_elements) @@ -112,7 +112,7 @@ public: size_t allocated_size() const { return c_end_of_storage - c_start + pad_right; } - /// Просто typedef нельзя, так как возникает неоднозначность для конструкторов и функций assign. + /// You can not just use `typedef`, because there is ambiguity for the constructors and `assign` functions. struct iterator : public boost::iterator_adaptor { iterator() {} @@ -209,7 +209,7 @@ public: c_end = c_start + byte_size(n); } - /// Как resize, но обнуляет новые элементы. + /// Same as resize, but zeros new elements. void resize_fill(size_t n) { size_t old_size = size(); @@ -261,7 +261,7 @@ public: c_end -= byte_size(1); } - /// Не вставляйте в массив кусок самого себя. Потому что при ресайзе, итераторы на самого себя могут инвалидироваться. + /// Do not insert a piece of yourself into the array. Because with the resize, the iterators on themselves can be invalidated. template void insert(It1 from_begin, It2 from_end) { @@ -458,7 +458,7 @@ void swap(PODArray & lhs, PODArray> using PaddedPODArray = PODArray; diff --git a/dbms/src/Common/PoolBase.h b/dbms/src/Common/PoolBase.h index 5c470ada446..4b81197ee0a 100644 --- a/dbms/src/Common/PoolBase.h +++ b/dbms/src/Common/PoolBase.h @@ -8,8 +8,8 @@ #include #include -/** Класс, от которого можно унаследоваться и получить пул чего-нибудь. Используется для пулов соединений с БД. - * Наследник должен предоставить метод для создания нового объекта для помещения в пул. +/** A class from which you can inherit and get a pool of something. Used for database connection pools. + * The heir must provide a method for creating a new object to place in the pool. */ template @@ -22,7 +22,7 @@ public: private: - /** Объект с флагом, используется ли он сейчас. */ + /** The object with the flag, whether it is currently used. */ struct PooledObject { PooledObject(ObjectPtr object_, PoolBase & pool_) @@ -37,8 +37,8 @@ private: using Objects = std::vector>; - /** Помощник, который устанавливает флаг использования объекта, а в деструкторе - снимает, - * а также уведомляет о событии с помощью condvar-а. + /** The helper, which sets the flag for using the object, and in the destructor - removes, + * and also notifies the event using condvar. */ struct PoolEntryHelper { @@ -54,19 +54,19 @@ private: }; public: - /** То, что выдаётся пользователю. */ + /** What is given to the user. */ class Entry { public: friend class PoolBase; - Entry() {} /// Для отложенной инициализации. + Entry() {} /// For deferred initialization. - /** Объект Entry защищает ресурс от использования другим потоком. - * Следующие методы запрещены для rvalue, чтобы нельзя было написать подобное + /** The `Entry` object protects the resource from being used by another thread. + * The following methods are forbidden for `rvalue`, so you can not write a similar to * - * auto q = pool.Get()->query("SELECT .."); // Упс, после этой строчки Entry уничтожился - * q.execute(); // Кто-то еще может использовать этот Connection + * auto q = pool.Get()->query("SELECT .."); // Oops, after this line Entry was destroyed + * q.execute (); // Someone else can use this Connection */ Object * operator->() && = delete; const Object * operator->() const && = delete; @@ -95,7 +95,7 @@ public: virtual ~PoolBase() {} - /** Выделяет объект для работы. При timeout < 0 таймаут бесконечный. */ + /** Allocates the object for the job. With timeout < 0, the timeout is infinite. */ Entry get(Poco::Timespan::TimeDiff timeout) { std::unique_lock lock(mutex); @@ -131,13 +131,13 @@ public: } private: - /** Максимальный размер пула. */ + /** The maximum size of the pool. */ unsigned max_items; - /** Пул. */ + /** Pool. */ Objects items; - /** Блокировка для доступа к пулу. */ + /** Block to access the pool. */ std::mutex mutex; std::condition_variable available; @@ -151,7 +151,7 @@ protected: items.reserve(max_items); } - /** Создает новый объект для помещения в пул. */ + /** Creates a new object to put in the pool. */ virtual ObjectPtr allocObject() = 0; }; diff --git a/dbms/src/Common/RadixSort.h b/dbms/src/Common/RadixSort.h index 39a21a8e02f..47232b1f19d 100644 --- a/dbms/src/Common/RadixSort.h +++ b/dbms/src/Common/RadixSort.h @@ -13,18 +13,18 @@ #include -/** Поразрядная сортировка, обладает следующей функциональностью: - * Может сортировать unsigned, signed числа, а также float-ы. - * Может сортировать массив элементов фиксированной длины, которые содержат что-то ещё кроме ключа. - * Настраиваемый размер разряда. +/** Bitwise sort, has the following functionality: + * Can sort unsigned, signed numbers, and floats. + * Can sort an array of fixed length elements that contain something else besides the key. + * Customizable digit size. * * LSB, stable. - * NOTE Для некоторых приложений имеет смысл добавить MSB-radix-sort, - * а также алгоритмы radix-select, radix-partial-sort, radix-get-permutation на его основе. + * NOTE For some applications it makes sense to add MSB-radix-sort, + * as well as radix-select, radix-partial-sort, radix-get-permutation algorithms based on it. */ -/** Используется в качестве параметра шаблона. См. ниже. +/** Used as a template parameter. See below. */ struct RadixSortMallocAllocator { @@ -40,16 +40,16 @@ struct RadixSortMallocAllocator }; -/** Преобразование, которое переводит битовое представление ключа в такое целое беззнаковое число, - * что отношение порядка над ключами будет соответствовать отношению порядка над полученными беззнаковыми числами. - * Для float-ов это преобразование делает следующее: - * если выставлен знаковый бит, то переворачивает все остальные биты. - * При этом, NaN-ы оказываются больше всех нормальных чисел. +/** A transformation that transforms the bit representation of a key into an unsigned integer number, + * that the order relation over the keys will match the order relation over the obtained unsigned numbers. + * For floats this conversion does the following: + * if the signed bit is set, it flips all other bits. + * In this case, NaN-s are bigger than all normal numbers. */ template struct RadixSortFloatTransform { - /// Стоит ли записывать результат в память, или лучше делать его каждый раз заново? + /// Is it worth writing the result in memory, or is it better to do it every time again? static constexpr bool transform_is_simple = false; static KeyBits forward(KeyBits x) @@ -67,24 +67,24 @@ struct RadixSortFloatTransform template struct RadixSortFloatTraits { - using Element = Float; /// Тип элемента. Это может быть структура с ключём и ещё каким-то payload-ом. Либо просто ключ. - using Key = Float; /// Ключ, по которому нужно сортировать. - using CountType = uint32_t; /// Тип для подсчёта гистограмм. В случае заведомо маленького количества элементов, может быть меньше чем size_t. + using Element = Float; /// The type of the element. It can be a structure with a key and some other payload. Or just a key. + using Key = Float; /// The key to sort. + using CountType = uint32_t; /// Type for calculating histograms. In the case of a known small number of elements, it can be less than size_t. - /// Тип, в который переводится ключ, чтобы делать битовые операции. Это UInt такого же размера, как ключ. + /// The type to which the key is transformed to do bit operations. This UInt is the same size as the key. using KeyBits = typename std::conditional::type; - static constexpr size_t PART_SIZE_BITS = 8; /// Какими кусочками ключа в количестве бит делать один проход - перестановку массива. + static constexpr size_t PART_SIZE_BITS = 8; /// With what pieces of the key, it bits, to do one pass - reshuffle of the array. - /// Преобразования ключа в KeyBits такое, что отношение порядка над ключём соответствует отношению порядка над KeyBits. + /// Converting a key into KeyBits is such that the order relation over the key corresponds to the order relation over KeyBits. using Transform = RadixSortFloatTransform; - /// Объект с функциями allocate и deallocate. - /// Может быть использован, например, чтобы выделить память для временного массива на стеке. - /// Для этого сам аллокатор создаётся на стеке. + /// An object with the functions allocate and deallocate. + /// Can be used, for example, to allocate memory for a temporary array on the stack. + /// To do this, the allocator itself is created on the stack. using Allocator = RadixSortMallocAllocator; - /// Функция получения ключа из элемента массива. + /// The function to get the key from an array element. static Key & extractKey(Element & elem) { return elem; } }; @@ -122,7 +122,7 @@ struct RadixSortUIntTraits using Transform = RadixSortIdentityTransform; using Allocator = RadixSortMallocAllocator; - /// Функция получения ключа из элемента массива. + /// The function to get the key from an array element. static Key & extractKey(Element & elem) { return elem; } }; @@ -139,7 +139,7 @@ struct RadixSortIntTraits using Transform = RadixSortSignedTransform; using Allocator = RadixSortMallocAllocator; - /// Функция получения ключа из элемента массива. + /// The function to get the key from an array element. static Key & extractKey(Element & elem) { return elem; } }; @@ -172,19 +172,19 @@ private: public: static void execute(Element * arr, size_t size) { - /// Если массив имеет размер меньше 256, то лучше использовать другой алгоритм. + /// If the array is smaller than 256, then it is better to use another algorithm. - /// Здесь есть циклы по NUM_PASSES. Очень важно, что они разворачиваются в compile-time. + /// There are loops of NUM_PASSES. It is very important that they unfold in compile-time. - /// Для каждого из NUM_PASSES кусков бит ключа, считаем, сколько раз каждое значение этого куска встретилось. + /// For each of the NUM_PASSES bits of the key, consider how many times each value of this piece met. CountType histograms[HISTOGRAM_SIZE * NUM_PASSES] = {0}; typename Traits::Allocator allocator; - /// Будем делать несколько проходов по массиву. На каждом проходе, данные перекладываются в другой массив. Выделим этот временный массив. + /// We will do several passes through the array. On each pass, the data is transferred to another array. Let's allocate this temporary array. Element * swap_buffer = reinterpret_cast(allocator.allocate(size * sizeof(Element))); - /// Трансформируем массив и вычисляем гистограмму. + /// Transform the array and calculate the histogram. for (size_t i = 0; i < size; ++i) { if (!Traits::Transform::transform_is_simple) @@ -195,7 +195,7 @@ public: } { - /// Заменяем гистограммы на суммы с накоплением: значение в позиции i равно сумме в предыдущих позициях минус один. + /// Replace the histograms with the accumulated sums: the value in position i is the sum of the previous positions minus one. size_t sums[NUM_PASSES] = {0}; for (size_t i = 0; i < HISTOGRAM_SIZE; ++i) @@ -209,7 +209,7 @@ public: } } - /// Перекладываем элементы в порядке начиная от младшего куска бит, и далее делаем несколько проходов по количеству кусков. + /// Move the elements in the order starting from the least bit piece, and then do a few passes on the number of pieces. for (size_t j = 0; j < NUM_PASSES; ++j) { Element * writer = j % 2 ? arr : swap_buffer; @@ -219,17 +219,17 @@ public: { size_t pos = getPart(j, keyToBits(Traits::extractKey(reader[i]))); - /// Размещаем элемент на следующей свободной позиции. + /// Place the element on the next free position. auto & dest = writer[++histograms[j * HISTOGRAM_SIZE + pos]]; dest = reader[i]; - /// На последнем перекладывании, делаем обратную трансформацию. + /// On the last pass, we do the reverse transformation. if (!Traits::Transform::transform_is_simple && j == NUM_PASSES - 1) Traits::extractKey(dest) = bitsToKey(Traits::Transform::backward(keyToBits(Traits::extractKey(reader[i])))); } } - /// Если число проходов нечётное, то результирующий массив находится во временном буфере. Скопируем его на место исходного массива. + /// If the number of passes is odd, the result array is in a temporary buffer. Copy it to the place of the original array. if (NUM_PASSES % 2) memcpy(arr, swap_buffer, size * sizeof(Element)); diff --git a/dbms/src/Common/ShellCommand.h b/dbms/src/Common/ShellCommand.h index 21ccab08878..ad2f4fdd0c6 100644 --- a/dbms/src/Common/ShellCommand.h +++ b/dbms/src/Common/ShellCommand.h @@ -9,19 +9,19 @@ namespace DB { -/** Позволяет запустить команду, - * читать её stdout, stderr, писать в stdin, - * дождаться завершения. +/** Lets you run the command, + * read it stdout, stderr, write to stdin, + * wait for completion. * - * Реализация похожа на функцию popen из POSIX (посмотреть можно в исходниках libc). + * The implementation is similar to the popen function from POSIX (see libc source code). * - * Наиболее важное отличие: использует vfork вместо fork. - * Это сделано, потому что fork не работает (с ошибкой о нехватке памяти), - * при некоторых настройках overcommit-а, если размер адресного пространства процесса больше половины количества доступной памяти. - * Также, изменение memory map-ов - довольно ресурсоёмкая операция. + * The most important difference: uses vfork instead of fork. + * This is done because fork does not work (with a memory shortage error), + * with some overcommit settings, if the address space of the process is more than half the amount of available memory. + * Also, changing memory maps - a fairly resource-intensive operation. * - * Второе отличие - позволяет работать одновременно и с stdin, и с stdout, и с stderr запущенного процесса, - * а также узнать код и статус завершения. + * The second difference - allows to work simultaneously with stdin, and with stdout, and with stderr running process, + * and also find out the code and the completion status. */ class ShellCommand { @@ -34,20 +34,20 @@ private: static std::unique_ptr executeImpl(const char * filename, char * const argv[], bool pipe_stdin_only); public: - WriteBufferFromFile in; /// Если команда читает из stdin, то не забудьте вызвать in.close() после записи туда всех данных. + WriteBufferFromFile in; /// If the command reads from stdin, do not forget to call in.close() after writing all the data there. ReadBufferFromFile out; ReadBufferFromFile err; - /// Выполнить команду с использованием /bin/sh -c + /// Run the command using /bin/sh -c static std::unique_ptr execute(const std::string & command, bool pipe_stdin_only = false); - /// Выполнить исполняемый файл с указаннами аргументами. arguments - без argv[0]. + /// Run the executable with the specified arguments. `arguments` - without argv[0]. static std::unique_ptr executeDirect(const std::string & path, const std::vector & arguments); - /// Подождать завершения процесса, кинуть исключение, если код не 0 или если процесс был завершён не самостоятельно. + /// Wait for the process to end, throw an exception if the code is not 0 or if the process was not completed by itself. void wait(); - /// Подождать завершения процесса, узнать код возврата. Кинуть исключение, если процесс был завершён не самостоятельно. + /// Wait for the process to finish, see the return code. To throw an exception if the process was not completed independently. int tryWait(); }; diff --git a/dbms/src/Common/SimpleCache.h b/dbms/src/Common/SimpleCache.h index ef37ff3fdb9..b0a9d043782 100644 --- a/dbms/src/Common/SimpleCache.h +++ b/dbms/src/Common/SimpleCache.h @@ -6,13 +6,13 @@ #include -/** Простейший кэш для свободной функции. - * Можете также передать статический метод класса или лямбду без захвата. - * Размер неограничен. Значения не устаревают. - * Для синхронизации используется mutex. - * Подходит только для простейших случаев. +/** The simplest cache for a free function. + * You can also pass a static class method or lambda without capturing. + * The size is unlimited. Values ​​are not obsolete. + * To synchronize, use mutex. + * Suitable only for the simplest cases. * - * Использование: + * Usage * * SimpleCache func_cached; * std::cerr << func_cached(args...); @@ -41,7 +41,7 @@ public: return it->second; } - /// Сами вычисления делаются не под mutex-ом. + /// The calculations themselves are not done under mutex. Result res = f(std::forward(args)...); { diff --git a/dbms/src/Common/SipHash.h b/dbms/src/Common/SipHash.h index 62b76ce5ce6..f6f241df9d7 100644 --- a/dbms/src/Common/SipHash.h +++ b/dbms/src/Common/SipHash.h @@ -1,14 +1,14 @@ #pragma once -/** SipHash - быстрая криптографическая хэш функция для коротких строк. - * Взято отсюда: https://www.131002.net/siphash/ +/** SipHash is a fast cryptographic hash function for short strings. + * Taken from here: https://www.131002.net/siphash/ * - * Сделано два изменения: - * - возвращает 128 бит, а не 64; - * - сделано потоковой (можно вычислять по частям). + * Two changes are made: + * - returns 128 bits, not 64; + * - done streaming (can be calculated in parts). * - * На коротких строках (URL, поисковые фразы) более чем в 3 раза быстрее MD5 от OpenSSL. - * (~ 700 МБ/сек., 15 млн. строк в секунду) + * On short strings (URL, search phrases) more than 3 times faster than MD5 from OpenSSL. + * (~ 700 MB/sec, 15 million strings per second) */ #include @@ -33,16 +33,16 @@ private: using u64 = DB::UInt64; using u8 = DB::UInt8; - /// Состояние. + /// Status. u64 v0; u64 v1; u64 v2; u64 v3; - /// Сколько байт обработано. + /// How many bytes have been processed. u64 cnt; - /// Текущие 8 байт входных данных. + /// The current 8 bytes of input data. union { u64 current_word; @@ -51,7 +51,7 @@ private: void finalize() { - /// В последний свободный байт пишем остаток от деления длины на 256. + /// In the last free byte, we write the remainder of the division by 256. current_bytes[7] = cnt; v3 ^= current_word; @@ -67,10 +67,10 @@ private: } public: - /// Аргументы - seed. + /// Arguments - seed. SipHash(u64 k0 = 0, u64 k1 = 0) { - /// Инициализируем состояние некоторыми случайными байтами и seed-ом. + /// Initialize the state with some random bytes and seed. v0 = 0x736f6d6570736575ULL ^ k0; v1 = 0x646f72616e646f6dULL ^ k1; v2 = 0x6c7967656e657261ULL ^ k0; @@ -84,7 +84,7 @@ public: { const char * end = data + size; - /// Дообработаем остаток от предыдущего апдейта, если есть. + /// We'll finish to process the remainder of the previous update, if any. if (cnt & 7) { while (cnt & 7 && data < end) @@ -94,7 +94,7 @@ public: ++cnt; } - /// Если всё ещё не хватает байт до восьмибайтового слова. + /// If you still do not have enough bytes to an 8-byte word. if (cnt & 7) return; @@ -118,7 +118,7 @@ public: data += 8; } - /// Заполняем остаток, которого не хватает до восьмибайтового слова. + /// Pad the remainder, which is missing up to an 8-byte word. current_word = 0; switch (end - data) { @@ -133,7 +133,7 @@ public: } } - /// Получить результат в некотором виде. Это можно сделать только один раз! + /// Get the result in some form. This can only be done once! void get128(char * out) { diff --git a/dbms/src/Common/SmallObjectPool.h b/dbms/src/Common/SmallObjectPool.h index f3002f6ebcb..e53a9234ae2 100644 --- a/dbms/src/Common/SmallObjectPool.h +++ b/dbms/src/Common/SmallObjectPool.h @@ -73,7 +73,7 @@ public: free_list = block; } - /// Размер выделенного пула в байтах + /// The size of the allocated pool in bytes size_t size() const { return pool.size(); diff --git a/dbms/src/Common/StackTrace.h b/dbms/src/Common/StackTrace.h index 68822dfc019..3ac4ddb9354 100644 --- a/dbms/src/Common/StackTrace.h +++ b/dbms/src/Common/StackTrace.h @@ -6,14 +6,14 @@ #define STACK_TRACE_MAX_DEPTH 32 -/// Позволяет получить стек-трейс +/// Lets you get a stacktrace class StackTrace { public: - /// Стектрейс снимается в момент создания объекта + /// The stacktrace is captured when the object is created StackTrace(); - /// Вывести в строку + /// Print to string std::string toString() const; private: diff --git a/dbms/src/Common/StringSearcher.h b/dbms/src/Common/StringSearcher.h index 00edba6fe47..9d83d4d19f9 100644 --- a/dbms/src/Common/StringSearcher.h +++ b/dbms/src/Common/StringSearcher.h @@ -26,8 +26,8 @@ namespace ErrorCodes } -/** Варианты поиска подстроки в строке. - * В большинстве случаев, менее производительные, чем Volnitsky (см. Volnitsky.h). +/** Variants for finding a substring in a string. + * In most cases, less productive than Volnitsky (see Volnitsky.h). */ @@ -693,10 +693,10 @@ using UTF8CaseSensitiveStringSearcher = StringSearcher; using UTF8CaseInsensitiveStringSearcher = StringSearcher; -/** Используют функции из libc. - * Имеет смысл использовать для коротких строк, когда требуется дешёвая инициализация. - * Нет варианта для регистронезависимого поиска UTF-8 строк. - * Требуется, чтобы за концом строк был нулевой байт. +/** Uses functions from libc. + * It makes sense to use short strings when cheap initialization is required. + * There is no option for register-independent search for UTF-8 strings. + * It is required that the end of the lines be zero byte. */ struct LibCASCIICaseSensitiveStringSearcher diff --git a/dbms/src/Common/Throttler.h b/dbms/src/Common/Throttler.h index 6cd0175022b..75bf6490849 100644 --- a/dbms/src/Common/Throttler.h +++ b/dbms/src/Common/Throttler.h @@ -15,12 +15,12 @@ namespace ErrorCodes } -/** Позволяет ограничить скорость чего либо (в штуках в секунду) с помощью sleep. - * Особенности работы: - * - считается только средняя скорость, от момента первого вызова функции add; - * если были периоды с низкой скоростью, то в течение промежутка времени после них, скорость будет выше; +/** Allows you to limit the speed of something (in pieces per second) using sleep. + * Specifics of work: + * - only the average speed is considered, from the moment of the first call of `add` function; + * if there were periods with low speed, then during some time after them, the speed will be higher; * - * Также позволяет задать ограничение на максимальное количество в штуках. При превышении кидается исключение. + * Also allows you to set a limit on the maximum number of pieces. If you exceed, an exception is thrown. */ class Throttler { @@ -56,7 +56,7 @@ public: if (max_speed) { - /// Сколько должно было бы пройти времени, если бы скорость была равна max_speed. + /// How much time would have gone for the speed to become `max_speed`. UInt64 desired_ns = new_count * 1000000000 / max_speed; if (desired_ns > elapsed_ns) @@ -65,7 +65,7 @@ public: timespec sleep_ts; sleep_ts.tv_sec = sleep_ns / 1000000000; sleep_ts.tv_nsec = sleep_ns % 1000000000; - nanosleep(&sleep_ts, nullptr); /// NOTE Завершается раньше в случае сигнала. Это считается нормальным. + nanosleep(&sleep_ts, nullptr); /// NOTE Ends early in case of a signal. This is considered normal. } } } @@ -73,7 +73,7 @@ public: private: size_t max_speed = 0; size_t count = 0; - size_t limit = 0; /// 0 - не ограничено. + size_t limit = 0; /// 0 - not limited. const char * limit_exceeded_exception_message = nullptr; Stopwatch watch {CLOCK_MONOTONIC_COARSE}; std::mutex mutex; diff --git a/dbms/src/Common/UInt128.h b/dbms/src/Common/UInt128.h index 3df43e0a8f5..8f33c1b197b 100644 --- a/dbms/src/Common/UInt128.h +++ b/dbms/src/Common/UInt128.h @@ -9,7 +9,7 @@ namespace DB { -/// Для агрегации по SipHash или конкатенации нескольких полей. +/// For aggregation by SipHash or concatenation of several fields. struct UInt128 { /// Suppress gcc7 warnings: 'prev_key.DB::UInt128::first' may be used uninitialized in this function @@ -57,7 +57,7 @@ struct UInt128HashCRC32 #else -/// На других платформах используем не обязательно CRC32. NOTE Это может сбить с толку. +/// On other platforms we do not use CRC32. NOTE This can be confusing. struct UInt128HashCRC32 : public UInt128Hash {}; #endif @@ -71,7 +71,7 @@ inline void readBinary(UInt128 & x, ReadBuffer & buf) { readPODBinary(x, buf); } inline void writeBinary(const UInt128 & x, WriteBuffer & buf) { writePODBinary(x, buf); } -/** Используется при агрегации, для укладки большого количества ключей постоянной длины в хэш-таблицу. +/** Used for aggregation, for putting a large number of constant-length keys in a hash table. */ struct UInt256 { @@ -91,7 +91,7 @@ struct UInt256 { return a == rhs.a && b == rhs.b && c == rhs.c && d == rhs.d; - /* Так получается не лучше. + /* So it's no better. return 0xFFFF == _mm_movemask_epi8(_mm_and_si128( _mm_cmpeq_epi8( _mm_loadu_si128(reinterpret_cast(&a)), @@ -139,13 +139,13 @@ struct UInt256HashCRC32 #else -/// На других платформах используем не обязательно CRC32. NOTE Это может сбить с толку. +/// We do not need to use CRC32 on other platforms. NOTE This can be confusing. struct UInt256HashCRC32 { DefaultHash hash64; size_t operator()(UInt256 x) const { - /// TODO Это не оптимально. + /// TODO This is not optimal. return hash64(hash64(hash64(hash64(x.a) ^ x.b) ^ x.c) ^ x.d); } }; diff --git a/dbms/src/Common/UnicodeBar.h b/dbms/src/Common/UnicodeBar.h index 6182784fef7..beee179ea1d 100644 --- a/dbms/src/Common/UnicodeBar.h +++ b/dbms/src/Common/UnicodeBar.h @@ -8,7 +8,7 @@ #define UNICODE_BAR_CHAR_SIZE (strlen("█")) -/** Позволяет нарисовать unicode-art полоску, ширина которой отображается с разрешением 1/8 символа. +/** Allows you to draw a unicode-art bar whose width is displayed with a resolution of 1/8 character. */ @@ -32,7 +32,7 @@ namespace UnicodeBar return ceil(width - 1.0 / 8) * UNICODE_BAR_CHAR_SIZE; } - /// В dst должно быть место для barWidthInBytes(width) символов и завершающего нуля. + /// In `dst` there must be a space for barWidthInBytes(width) characters and a trailing zero. inline void render(double width, char * dst) { size_t floor_width = floor(width); diff --git a/dbms/src/Common/VirtualColumnUtils.h b/dbms/src/Common/VirtualColumnUtils.h index eb1cc5106b7..cbe0120ea7e 100644 --- a/dbms/src/Common/VirtualColumnUtils.h +++ b/dbms/src/Common/VirtualColumnUtils.h @@ -16,23 +16,23 @@ class Context; namespace VirtualColumnUtils { -/// Вычислить минимальный числовый суффикс, который надо добавить к строке, чтобы она не присутствовала в множестве +/// Calculate the minimum numeric suffix to add to the row so that it is not present in the set String chooseSuffix(const NamesAndTypesList & columns, const String & name); -/// Вычислить минимальный общий числовый суффикс, который надо добавить к каждой строке, -/// чтобы ни одна не присутствовала в множестве. +/// Calculate the minimum total numeric suffix to add to each row, +/// so that none is present in the set. String chooseSuffixForSet(const NamesAndTypesList & columns, const std::vector & names); -/// Добавляет в селект запрос секцию select column_name as value -/// Например select _port as 9000. +/// Adds to the select query section `select column_name as value` +/// For example select _port as 9000. void rewriteEntityInAst(ASTPtr ast, const String & column_name, const Field & value); -/// Оставить в блоке только строки, подходящие под секции WHERE и PREWHERE запроса. -/// Рассматриваются только элементы внешней конъюнкции, зависящие только от столбцов, присутствующих в блоке. -/// Возвращает true, если хоть одна строка выброшена. +/// Leave in the block only the rows that fit under the WHERE clause and the PREWHERE clause of the query. +/// Only elements of the outer conjunction are considered, depending only on the columns present in the block. +/// Returns true if at least one row is discarded. bool filterBlockWithQuery(ASTPtr query, Block & block, const Context & context); -/// Извлечь из входного потока множество значений столбца name +/// Extract from the input stream a set of `name` column values template std::multiset extractSingleValueFromBlock(const Block & block, const String & name) { diff --git a/dbms/src/Common/Volnitsky.h b/dbms/src/Common/Volnitsky.h index f0baf9ec321..8194f413e3a 100644 --- a/dbms/src/Common/Volnitsky.h +++ b/dbms/src/Common/Volnitsky.h @@ -9,24 +9,24 @@ #include -/** Поиск подстроки в строке по алгоритму Вольницкого: +/** Search for a substring in a string by Volnitsky's algorithm * http://volnitsky.com/project/str_search/ * - * haystack и needle могут содержать нулевые байты. + * `haystack` and `needle` can contain null bytes. * - * Алгоритм: - * - при слишком маленьком или слишком большом размере needle, или слишком маленьком haystack, используем std::search или memchr; - * - при инициализации, заполняем open-addressing linear probing хэш-таблицу вида: - * хэш от биграммы из needle -> позиция этой биграммы в needle + 1. - * (прибавлена единица только чтобы отличить смещение ноль от пустой ячейки) - * - в хэш-таблице ключи не хранятся, хранятся только значения; - * - биграммы могут быть вставлены несколько раз, если они встречаются в needle несколько раз; - * - при поиске, берём из haystack биграмму, которая должна соответствовать последней биграмме needle (сравниваем с конца); - * - ищем её в хэш-таблице, если нашли - достаём смещение из хэш-таблицы и сравниваем строку побайтово; - * - если сравнить не получилось - проверяем следующую ячейку хэш-таблицы из цепочки разрешения коллизий; - * - если не нашли, пропускаем в haystack почти размер needle байт; + * Algorithm: + * - if the `needle` is too small or too large, or too small `haystack`, use std::search or memchr; + * - when initializing, fill in an open-addressing linear probing hash table of the form + * hash from the bigram of needle -> the position of this bigram in needle + 1. + * (one is added only to distinguish zero offset from an empty cell) + * - the keys are not stored in the hash table, only the values ​​are stored; + * - bigrams can be inserted several times if they occur in the needle several times; + * - when searching, take from haystack bigram, which should correspond to the last bigram of needle (comparing from the end); + * - look for it in the hash table, if found - get the offset from the hash table and compare the string bytewise; + * - if it did not work, we check the next cell of the hash table from the collision resolution chain; + * - if not found, skip to haystack almost the size of the needle bytes; * - * Используется невыровненный доступ к памяти. + * Unaligned memory access is used. */ @@ -39,28 +39,28 @@ template class VolnitskyBase { protected: - using offset_t = uint8_t; /// Смещение в needle. Для основного алгоритма, длина needle не должна быть больше 255. - using ngram_t = uint16_t; /// n-грамма (2 байта). + using offset_t = uint8_t; /// Offset in the needle. For the basic algorithm, the length of the needle must not be greater than 255. + using ngram_t = uint16_t; /// n-gram (2 bytes). const UInt8 * const needle; const size_t needle_size; const UInt8 * const needle_end = needle + needle_size; - /// На сколько двигаемся, если n-грамма из haystack не нашлась в хэш-таблице. + /// For how long we move, if the n-gram from haystack is not found in the hash table. const size_t step = needle_size - sizeof(ngram_t) + 1; /** max needle length is 255, max distinct ngrams for case-sensitive is (255 - 1), case-insensitive is 4 * (255 - 1) * storage of 64K ngrams (n = 2, 128 KB) should be large enough for both cases */ - static const size_t hash_size = 64 * 1024; /// Помещается в L2-кэш. - offset_t hash[hash_size]; /// Хэш-таблица. + static const size_t hash_size = 64 * 1024; /// Fits into the L2 cache. + offset_t hash[hash_size]; /// Hash table. /// min haystack size to use main algorithm instead of fallback static constexpr auto min_haystack_size_for_algorithm = 20000; - const bool fallback; /// Нужно ли использовать fallback алгоритм. + const bool fallback; /// Do I need to use the fallback algorithm. public: - /** haystack_size_hint - ожидаемый суммарный размер haystack при вызовах search. Можно не указывать. - * Если указать его достаточно маленьким, то будет использован fallback алгоритм, - * так как считается, что тратить время на инициализацию хэш-таблицы не имеет смысла. + /** haystack_size_hint - the expected total size of the haystack for `search` calls. Can not specify. + * If you specify it small enough, the fallback algorithm will be used, + * since it is considered that it's useless to waste time initializing the hash table. */ VolnitskyBase(const char * const needle, const size_t needle_size, size_t haystack_size_hint = 0) : needle{reinterpret_cast(needle)}, needle_size{needle_size}, @@ -79,7 +79,7 @@ public: } - /// Если не найдено - возвращается конец haystack. + /// If not found, the end of the haystack is returned. const UInt8 * search(const UInt8 * const haystack, const size_t haystack_size) const { if (needle_size == 0) @@ -90,15 +90,15 @@ public: if (needle_size == 1 || fallback || haystack_size <= needle_size) return self().search_fallback(haystack, haystack_end); - /// Будем "прикладывать" needle к haystack и сравнивать n-грам из конца needle. + /// Let's "apply" the needle to the haystack and compare the n-gram from the end of the needle. const auto * pos = haystack + needle_size - sizeof(ngram_t); for (; pos <= haystack_end - needle_size; pos += step) { - /// Смотрим все ячейки хэш-таблицы, которые могут соответствовать n-граму из haystack. + /// We look at all the cells of the hash table that can correspond to the n-gram from haystack. for (size_t cell_num = toNGram(pos) % hash_size; hash[cell_num]; cell_num = (cell_num + 1) % hash_size) { - /// Когда нашли - сравниваем побайтово, используя смещение из хэш-таблицы. + /// When found - compare bytewise, using the offset from the hash table. const auto res = pos - (hash[cell_num] - 1); if (self().compare(res)) @@ -106,7 +106,7 @@ public: } } - /// Оставшийся хвостик. + /// The remaining tail. return self().search_fallback(pos - step + 1, haystack_end); } @@ -126,11 +126,11 @@ protected: void putNGramBase(const ngram_t ngram, const int offset) { - /// Кладём смещение для n-грама в соответствующую ему ячейку или ближайшую свободную. + /// Put the offset for the n-gram in the corresponding cell or the nearest free cell. size_t cell_num = ngram % hash_size; while (hash[cell_num]) - cell_num = (cell_num + 1) % hash_size; /// Поиск следующей свободной ячейки. + cell_num = (cell_num + 1) % hash_size; /// Search for the next free cell. hash[cell_num] = offset; } @@ -272,15 +272,15 @@ template <> struct VolnitskyImpl : VolnitskyBase -/// Выводит переданный размер в байтах в виде 123.45 GiB. +/// Displays the transmitted size in bytes as 123.45 GiB. void formatReadableSizeWithBinarySuffix(double value, DB::WriteBuffer & out, int precision = 2); std::string formatReadableSizeWithBinarySuffix(double value, int precision = 2); -/// Выводит переданный размер в байтах в виде 132.55 GB. +/// Displays the transmitted size in bytes as 132.55 GB. void formatReadableSizeWithDecimalSuffix(double value, DB::WriteBuffer & out, int precision = 2); std::string formatReadableSizeWithDecimalSuffix(double value, int precision = 2); -/// Выводит число в виде 123.45 billion. +/// Prints the number as 123.45 billion. void formatReadableQuantity(double value, DB::WriteBuffer & out, int precision = 2); std::string formatReadableQuantity(double value, int precision = 2); diff --git a/dbms/src/Common/getFQDNOrHostName.h b/dbms/src/Common/getFQDNOrHostName.h index 7e1c1b43040..ea796426c85 100644 --- a/dbms/src/Common/getFQDNOrHostName.h +++ b/dbms/src/Common/getFQDNOrHostName.h @@ -2,7 +2,7 @@ #include -/** Получить FQDN для локального сервера путём DNS-резолвинга hostname - аналогично вызову утилиты hostname с флагом -f. - * Если не получилось отрезолвить, то вернуть hostname - аналогично вызову утилиты hostname без флагов или uname -n. +/** Get the FQDN for the local server by resolving DNS hostname - similar to calling the hostname utility with the -f flag. + * If it does not work, return hostname - similar to calling hostname without flags or uname -n. */ const std::string & getFQDNOrHostName(); diff --git a/dbms/src/Common/isLocalAddress.h b/dbms/src/Common/isLocalAddress.h index 3bbc72b26db..d63b42dbb97 100644 --- a/dbms/src/Common/isLocalAddress.h +++ b/dbms/src/Common/isLocalAddress.h @@ -12,13 +12,13 @@ namespace Poco namespace DB { - /** Позволяет проверить, похож ли адрес на localhost. - * Цель этой проверки обычно состоит в том, чтобы сделать предположение, - * что при хождении на этот адрес через интернет, мы попадём на себя. - * Следует иметь ввиду, что эта проверка делается неточно: - * - адрес просто сравнивается с адресами сетевых интерфейсов; - * - для каждого сетевого интерфейса берётся только первый адрес; - * - не проверяются правила маршрутизации, которые влияют, через какой сетевой интерфейс мы пойдём на заданный адрес. + /** Lets you check if the address is similar to `localhost`. + * The purpose of this check is usually to make an assumption, + * that when we go to this address via the Internet, we'll get to ourselves. + * Please note that this check is not accurate: + * - the address is simply compared to the addresses of the network interfaces; + * - only the first address is taken for each network interface; + * - the routing rules that affect which network interface we go to the specified address are not checked. */ bool isLocalAddress(const Poco::Net::SocketAddress & address); diff --git a/dbms/src/Common/localBackup.h b/dbms/src/Common/localBackup.h index 25b1de4e8e5..91107294e26 100644 --- a/dbms/src/Common/localBackup.h +++ b/dbms/src/Common/localBackup.h @@ -3,14 +3,14 @@ #include -/** Создаёт локальный (в той же точке монтирования) бэкап (снэпшот) директории. +/** Creates a local (at the same mount point) backup (snapshot) directory. * - * В указанной destination-директории создаёт hard link-и на все файлы source-директории - * и во всех вложенных директориях, с сохранением (созданием) всех относительных путей; - * а также делает chown, снимая разрешение на запись. + * In the specified destination directory, it creates a hard links on all source-directory files + * and in all nested directories, with saving (creating) all relative paths; + * and also `chown`, removing the write permission. * - * Это защищает данные от случайного удаления или модификации, - * и предназначено для использования как простое средство защиты от человеческой или программной ошибки, - * но не от аппаратного сбоя. + * This protects data from accidental deletion or modification, + * and is intended to be used as a simple means of protection against a human or program error, + * but not from a hardware failure. */ void localBackup(Poco::Path source_path, Poco::Path destination_path); diff --git a/dbms/src/Common/setThreadName.h b/dbms/src/Common/setThreadName.h index 476aa47dbdf..dc6af7336e0 100644 --- a/dbms/src/Common/setThreadName.h +++ b/dbms/src/Common/setThreadName.h @@ -1,7 +1,7 @@ #pragma once -/** Устанавливает имя потока (максимальная длина - 15 байт), - * которое будет видно в ps, gdb, /proc, - * для удобства наблюдений и отладки. +/** Sets the thread name (maximum length is 15 bytes), + * which will be visible in ps, gdb, /proc, + * for convenience of observation and debugging. */ void setThreadName(const char * name); diff --git a/dbms/src/Common/typeid_cast.h b/dbms/src/Common/typeid_cast.h index e3f47870bb9..a83a414f70e 100644 --- a/dbms/src/Common/typeid_cast.h +++ b/dbms/src/Common/typeid_cast.h @@ -16,9 +16,9 @@ namespace DB } -/** Проверяет совпадение типа путём сравнения typeid-ов. - * Проверяется точное совпадение типа. То есть, cast в предка будет неуспешным. - * В остальном, ведёт себя как dynamic_cast. +/** Checks match of type by comparing typeid. + * The exact match of the type is checked. That is, cast in the ancestor will be unsuccessful. + * In the rest, behaves like a dynamic_cast. */ template typename std::enable_if::value, To>::type typeid_cast(From & from) diff --git a/release_lib.sh b/release_lib.sh index af15744fc31..65d22cfa713 100644 --- a/release_lib.sh +++ b/release_lib.sh @@ -8,8 +8,8 @@ function make_control { true } -# Генерируем номер ревизии. -# выставляются переменные окружения REVISION, AUTHOR +# Generate revision number. +# set environment variables REVISION, AUTHOR function gen_revision_author { REVISION=$(get_revision) @@ -87,8 +87,8 @@ function get_revision_author { export AUTHOR } -# Генерируем changelog из changelog.in. -# изменяет +# Generate changelog from changelog.in. +# changes # programs/CMakeLists.txt # dbms/src/CMakeLists.txt function gen_changelog { @@ -105,11 +105,11 @@ function gen_changelog { < $CHLOG.in > $CHLOG } -# Загрузка в репозитории Метрики -# рабочая директория - где лежит сам скрипт +# Upload to Metrica repository +# working directory - where script is itself function upload_debs { REVISION="$1" - # Определим репозиторий, в который надо загружать пакеты. Он соответствует версии Ubuntu. + # Determine the repository, in which you need to upload the packages. It corresponds to the version of Ubuntu. source /etc/lsb-release if [ "$DISTRIB_CODENAME" == "precise" ]; then @@ -122,7 +122,7 @@ function upload_debs { echo -e "\n\e[0;31mUnknown Ubuntu version $DISTRIB_CODENAME \e[0;0m\n" fi - # Загрузка в репозиторий Метрики. + # Upload to Metrica repository. cd ../ DUPLOAD_CONF=dupload.conf From 8e5f92f02538d11151dac0aa45a75fdfb677a11c Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 9 May 2017 15:07:35 -0400 Subject: [PATCH 29/76] Fixed translation errors, part 1 [#CLICKHOUSE-3]. --- dbms/src/Common/Allocator.cpp | 6 ++-- dbms/src/Common/ArenaWithFreeLists.h | 2 +- dbms/src/Common/AutoArray.h | 4 +-- dbms/src/Common/CompactArray.h | 2 +- dbms/src/Common/Exception.h | 2 +- dbms/src/Common/HashTable/ClearableHashSet.h | 2 +- dbms/src/Common/HashTable/Hash.h | 35 +++++++++++++------ dbms/src/Common/HashTable/HashMap.h | 2 +- dbms/src/Common/HashTable/HashTable.h | 34 +++++++++--------- dbms/src/Common/HashTable/SmallTable.h | 2 +- dbms/src/Common/HashTable/TwoLevelHashTable.h | 2 +- dbms/src/Common/HyperLogLogBiasEstimator.h | 4 +-- dbms/src/Common/SimpleCache.h | 2 +- dbms/src/Common/UInt128.h | 20 ++++++----- dbms/src/Common/Volnitsky.h | 2 +- dbms/src/Core/BlockInfo.h | 6 ++-- dbms/src/Core/Defines.h | 2 +- dbms/src/Core/StringRef.h | 10 ------ dbms/src/Core/Types.h | 2 +- .../src/DataTypes/DataTypeAggregateFunction.h | 2 +- dbms/src/DataTypes/DataTypeSet.h | 2 +- dbms/src/Databases/DatabaseCloud.h | 2 +- .../MergeTree/MergeTreeDataSelectExecutor.h | 2 +- .../MergeTree/MergedBlockOutputStream.h | 2 +- .../MergeTree/ReplicatedMergeTreeLogEntry.h | 2 +- .../ReplicatedMergeTreeRestartingThread.h | 2 +- 26 files changed, 81 insertions(+), 74 deletions(-) diff --git a/dbms/src/Common/Allocator.cpp b/dbms/src/Common/Allocator.cpp index a773aaceb24..b57ba0dd798 100644 --- a/dbms/src/Common/Allocator.cpp +++ b/dbms/src/Common/Allocator.cpp @@ -22,12 +22,12 @@ namespace ErrorCodes } -/** Many modern allocators (for example, tcmalloc) do not know how to do a mremap for realloc, +/** Many modern allocators (for example, tcmalloc) do not do a mremap for realloc, * even in case of large enough chunks of memory. * Although this allows you to increase performance and reduce memory consumption during realloc. - * To fix this, do the mremap yourself if the chunk of memory is large enough. + * To fix this, we do mremap manually if the chunk of memory is large enough. * The threshold (64 MB) is chosen quite large, since changing the address space is - * rather slow, especially in the case of a large number of threads. + * very slow, especially in the case of a large number of threads. * We expect that the set of operations mmap/something to do/mremap can only be performed about 1000 times per second. * * PS. This is also required, because tcmalloc can not allocate a chunk of memory greater than 16 GB. diff --git a/dbms/src/Common/ArenaWithFreeLists.h b/dbms/src/Common/ArenaWithFreeLists.h index 094b67afae5..4a8801ed2f1 100644 --- a/dbms/src/Common/ArenaWithFreeLists.h +++ b/dbms/src/Common/ArenaWithFreeLists.h @@ -13,7 +13,7 @@ namespace DB * For this, the requested size is rounded up to the power of two * (or up to 8, if less, or using memory allocation outside Arena if the size is greater than 65536). * When freeing memory, for each size (14 options in all: 8, 16 ... 65536), - * a one-link list of free blocks is kept track. + * a single-linked list of free blocks is kept track. * When allocating, we take the head of the list of free blocks, * or, if the list is empty - allocate a new block using Arena. */ diff --git a/dbms/src/Common/AutoArray.h b/dbms/src/Common/AutoArray.h index 2f1f3d28cf9..7b5d13d417c 100644 --- a/dbms/src/Common/AutoArray.h +++ b/dbms/src/Common/AutoArray.h @@ -26,7 +26,7 @@ namespace DB * Designed for situations in which many arrays of the same small size are created, * but the size is not known at compile time. * Also gives a significant advantage in cases where it is important that `sizeof` is minimal. - * For example, if arrays are put in an open-addressing hash table with inplace storage of values ​​(like HashMap) + * For example, if arrays are put in an open-addressing hash table with inplace storage of values (like HashMap) * * In this case, compared to std::vector: * - for arrays of 1 element size - an advantage of about 2 times; @@ -82,7 +82,7 @@ public: init(size_, dont_init_elems); } - /** Preposition. + /** Move operations. */ AutoArray(AutoArray && src) { diff --git a/dbms/src/Common/CompactArray.h b/dbms/src/Common/CompactArray.h index db07f90a644..ee4d74b3ed2 100644 --- a/dbms/src/Common/CompactArray.h +++ b/dbms/src/Common/CompactArray.h @@ -18,7 +18,7 @@ namespace ErrorCodes /** Compact array for data storage, size `content_width`, in bits, of which is * less than one byte. Instead of storing each value in a separate * bytes, which leads to a waste of 37.5% of the space for content_width = 5, CompactArray stores - * adjacent `content_width`-bit values ​​in the byte array, that is actually CompactArray + * adjacent `content_width`-bit values in the byte array, that is actually CompactArray * simulates an array of `content_width`-bit values. */ template diff --git a/dbms/src/Common/Exception.h b/dbms/src/Common/Exception.h index edac971d65b..05a40479308 100644 --- a/dbms/src/Common/Exception.h +++ b/dbms/src/Common/Exception.h @@ -74,7 +74,7 @@ void throwFromErrno(const std::string & s, int code = 0, int the_errno = errno); /** Try to write an exception to the log (and forget about it). - * Can be used in destructors in the catch block (...). + * Can be used in destructors in the catch-all block. */ void tryLogCurrentException(const char * log_name, const std::string & start_of_message = ""); void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_message = ""); diff --git a/dbms/src/Common/HashTable/ClearableHashSet.h b/dbms/src/Common/HashTable/ClearableHashSet.h index 25f64fd3c1e..4979e7ab03c 100644 --- a/dbms/src/Common/HashTable/ClearableHashSet.h +++ b/dbms/src/Common/HashTable/ClearableHashSet.h @@ -7,7 +7,7 @@ /** A hash table that allows you to clear the table in O(1). * Even simpler than HashSet: Key and Mapped must be POD-types. * - * Instead of this class, you could just use the couple in the HashSet as the key + * Instead of this class, you could just use the pair (version, key) in the HashSet as the key * but then the table would accumulate all the keys that it ever stored, and it was unreasonably growing. * This class goes a step further and considers the keys with the old version empty in the hash table. */ diff --git a/dbms/src/Common/HashTable/Hash.h b/dbms/src/Common/HashTable/Hash.h index 8733aee136e..b2733058cb7 100644 --- a/dbms/src/Common/HashTable/Hash.h +++ b/dbms/src/Common/HashTable/Hash.h @@ -4,10 +4,17 @@ /** Hash functions that are better than the trivial function std::hash. - * (when aggregated by the visitor ID, the performance increase is more than 5 times) + * + * Example: when aggregated by the visitor ID, the performance increase is more than 5 times. + * This is because of following reasons: + * - in Yandex, visitor identifier is an integer that has timestamp with seconds resolution in lower bits; + * - in typical implementation of standard library, hash function for integers is trivial and just use lower bits; + * - traffic is non-uniformly distributed across a day; + * - we are using open-addressing linear probing hash tables that are most critical to hash function quality, + * and trivial hash function gives disasterous results. */ -/** Taken from MurmurHash. +/** Taken from MurmurHash. This is Murmur finalizer. * Faster than intHash32 when inserting into the hash table UInt64 -> UInt64, where the key is the visitor ID. */ inline DB::UInt64 intHash64(DB::UInt64 x) @@ -22,20 +29,21 @@ inline DB::UInt64 intHash64(DB::UInt64 x) } /** CRC32C is not very high-quality as a hash function, - * according to avalanche and bit independence tests, as well as a small number of bits, + * according to avalanche and bit independence tests (see SMHasher software), as well as a small number of bits, * but can behave well when used in hash tables, * due to high speed (latency 3 + 1 clock cycle, throughput 1 clock cycle). * Works only with SSE 4.2 support. - * Used asm instead of intrinsics, so you do not have to build the entire project with -msse4. */ +#if __SSE4_2__ +#include +#endif + inline DB::UInt64 intHashCRC32(DB::UInt64 x) { -#if defined(__x86_64__) - DB::UInt64 crc = -1ULL; - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x)); - return crc; +#if __SSE4_2__ + return _mm_crc32_u64(-1ULL, x); #else - /// On other platforms we do not need CRC32. NOTE This can be confusing. + /// On other platforms we do not have CRC32. NOTE This can be confusing. return intHash64(x); #endif } @@ -128,7 +136,7 @@ struct TrivialHash }; -/** A relatively good non-cryptic hash function from UInt64 to UInt32. +/** A relatively good non-cryptographic hash function from UInt64 to UInt32. * But worse (both in quality and speed) than just cutting intHash64. * Taken from here: http://www.concentric.net/~ttwang/tech/inthash.htm * @@ -136,9 +144,14 @@ struct TrivialHash * This change did not affect the smhasher test results. * * It is recommended to use different salt for different tasks. - * That was the case that in the database values ​​were sorted by hash (for low-quality pseudo-random spread), + * That was the case that in the database values were sorted by hash (for low-quality pseudo-random spread), * and in another place, in the aggregate function, the same hash was used in the hash table, * as a result, this aggregate function was monstrously slowed due to collisions. + * + * NOTE Salting is far from perfect, because it commutes with first steps of calculation. + * + * NOTE As mentioned, this function is slower than intHash64. + * But occasionaly, it is faster, when written in a loop and loop is vectorized. */ template inline DB::UInt32 intHash32(DB::UInt64 key) diff --git a/dbms/src/Common/HashTable/HashMap.h b/dbms/src/Common/HashTable/HashMap.h index f6608a9158f..9068807e21f 100644 --- a/dbms/src/Common/HashTable/HashMap.h +++ b/dbms/src/Common/HashTable/HashMap.h @@ -66,7 +66,7 @@ struct HashMapCell /// Do I need to store the zero key separately (that is, can a zero key be inserted into the hash table). static constexpr bool need_zero_value_storage = true; - /// Whether the cell is removed. + /// Whether the cell was deleted. bool isDeleted() const { return false; } void setMapped(const value_type & value_) { value.second = value_.second; } diff --git a/dbms/src/Common/HashTable/HashTable.h b/dbms/src/Common/HashTable/HashTable.h index 224c39f26ed..be762733897 100644 --- a/dbms/src/Common/HashTable/HashTable.h +++ b/dbms/src/Common/HashTable/HashTable.h @@ -46,9 +46,9 @@ namespace ErrorCodes /** The state of the hash table that affects the properties of its cells. * Used as a template parameter. - * For example, there is an implementation of an instantly cleared hash table - ClearableHashMap. + * For example, there is an implementation of an instantly clearable hash table - ClearableHashMap. * For it, each cell holds the version number, and in the hash table itself is the current version. - * When cleaning, the current version simply increases; All cells with a mismatching version are considered empty. + * When clearing, the current version simply increases; All cells with a mismatching version are considered empty. * Another example: for an approximate calculation of the number of unique visitors, there is a hash table for UniquesHashSet. * It has the concept of "degree". At each overflow, cells with keys that do not divide by the corresponding power of the two are deleted. */ @@ -77,8 +77,8 @@ void set(T & x) { x = 0; } }; -/** Compile-time cell interface of the hash table. - * Different cells are used to implement different hash tables. +/** Compile-time interface for cell of the hash table. + * Different cell types are used to implement different hash tables. * The cell must contain a key. * It can also contain a value and arbitrary additional data * (example: the stored hash value; version number for ClearableHashMap). @@ -95,7 +95,7 @@ struct HashTableCell /// Create a cell with the given key / key and value. HashTableCell(const Key & key_, const State & state) : key(key_) {} -/// HashTableCell(const value_type & value_, const State & state) : key(value_) {} +/// HashTableCell(const value_type & value_, const State & state) : key(value_) {} /// Get what the value_type of the container will be. value_type & getValue() { return key; } @@ -126,13 +126,13 @@ struct HashTableCell /// Set the key value to zero. void setZero() { ZeroTraits::set(key); } - /// Do I need to store the zero key separately (that is, can a zero key be inserted into the hash table). + /// Do the hash table need to store the zero key separately (that is, can a zero key be inserted into the hash table). static constexpr bool need_zero_value_storage = true; /// Whether the cell is deleted. bool isDeleted() const { return false; } - /// Set the displayed value, if any (for HashMap), to the corresponding `value`. + /// Set the mapped value, if any (for HashMap), to the corresponding `value`. void setMapped(const value_type & value) {} /// Serialization, in binary and text form. @@ -145,7 +145,7 @@ struct HashTableCell }; -/** Determines the size of the hash table, and when and how many times it should be resized. +/** Determines the size of the hash table, and when and how much it should be resized. */ template struct HashTableGrower @@ -195,7 +195,7 @@ struct HashTableGrower /** When used as a Grower, it turns a hash table into something like a lookup table. * It remains non-optimal - the cells store the keys. * Also, the compiler can not completely remove the code of passing through the collision resolution chain, although it is not needed. - * TODO Make a full lookup table. + * TODO Make a proper lookup table. */ template struct HashTableFixedGrower @@ -212,7 +212,7 @@ struct HashTableFixedGrower }; -/** If you want to store the null key separately - a place to store it. */ +/** If you want to store the zero key separately - a place to store it. */ template struct ZeroValueStorage; @@ -272,7 +272,7 @@ protected: using cell_type = Cell; size_t m_size = 0; /// Amount of elements - Cell * buf; /// A piece of memory for all elements except the element with key 0. + Cell * buf; /// A piece of memory for all elements except the element with zero key. Grower grower; #ifdef DBMS_HASH_MAP_COUNT_COLLISIONS @@ -334,7 +334,7 @@ protected: /** In case of exception for the object to remain in the correct state, * changing the variable `grower` (which determines the buffer size of the hash table) - * postpone for a moment after a real buffer change. + * is postponed for a moment after a real buffer change. * The temporary variable `new_grower` is used to determine the new size. */ Grower new_grower = grower; @@ -410,7 +410,7 @@ protected: memcpy(&buf[place_value], &x, sizeof(x)); x.setZero(); - /// Then the elements that previously were in conflict with this can move to the old place. + /// Then the elements that previously were in collision with this can move to the old place. } @@ -638,7 +638,7 @@ protected: } - /// Only for non-zero keys. Find the right place, insert the key there, if it does not already exist, return the iterator to the cell. + /// Only for non-zero keys. Find the right place, insert the key there, if it does not already exist. Set iterator to the cell in output parameter. void ALWAYS_INLINE emplaceNonZero(Key x, iterator & it, bool & inserted, size_t hash_value) { size_t place_value = findCell(x, hash_value, grower.place(hash_value)); @@ -664,8 +664,8 @@ protected: } catch (...) { - /** If you do not do it, then there will be problems. - * After all, there remains a key, but uninitialized mapped-value, + /** If we have not resized successfully, then there will be problems. + * There remains a key, but uninitialized mapped-value, * which, perhaps, can not even be called a destructor. */ --m_size; @@ -698,7 +698,7 @@ public: * return the iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. * - * You are required to make `placement new` of value ​​if you inserted a new key, + * You have to make `placement new` of value if you inserted a new key, * since when destroying a hash table, it will call the destructor! * * Example usage: diff --git a/dbms/src/Common/HashTable/SmallTable.h b/dbms/src/Common/HashTable/SmallTable.h index 190bb295b2e..64e90f6208a 100644 --- a/dbms/src/Common/HashTable/SmallTable.h +++ b/dbms/src/Common/HashTable/SmallTable.h @@ -215,7 +215,7 @@ public: * return the iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. * - * You have to make `placement new` of value ​​if you inserted a new key, + * You have to make `placement new` of value if you inserted a new key, * since when destroying a hash table, a destructor will be called for it! * * Example usage: diff --git a/dbms/src/Common/HashTable/TwoLevelHashTable.h b/dbms/src/Common/HashTable/TwoLevelHashTable.h index d33b8b50bfe..29bbaca988a 100644 --- a/dbms/src/Common/HashTable/TwoLevelHashTable.h +++ b/dbms/src/Common/HashTable/TwoLevelHashTable.h @@ -224,7 +224,7 @@ public: * return the iterator to a position that can be used for `placement new` value, * as well as the flag - whether a new key was inserted. * - * You have to make `placement new` values ​​if you inserted a new key, + * You have to make `placement new` values if you inserted a new key, * since when destroying a hash table, the destructor will be invoked for it! * * Example usage: diff --git a/dbms/src/Common/HyperLogLogBiasEstimator.h b/dbms/src/Common/HyperLogLogBiasEstimator.h index 7d0ba470865..82da2f66597 100644 --- a/dbms/src/Common/HyperLogLogBiasEstimator.h +++ b/dbms/src/Common/HyperLogLogBiasEstimator.h @@ -22,7 +22,7 @@ public: return false; } - /// Maximum number of unique values ​​to which the correction should apply + /// Maximum number of unique values to which the correction should apply /// from the LinearCounting algorithm. static double getThreshold() { @@ -83,7 +83,7 @@ private: }; /** Trivial case of HyperLogLogBiasEstimator: used if we do not want to fix - * error. This has meaning for small values ​​of the accuracy parameter, for example 5 or 12. + * error. This has meaning for small values of the accuracy parameter, for example 5 or 12. * Then the corrections from the original version of the HyperLogLog algorithm are applied. * See "HyperLogLog: The analysis of a near-optimal cardinality estimation algorithm" * (P. Flajolet et al., AOFA '07: Proceedings of the 2007 International Conference on Analysis diff --git a/dbms/src/Common/SimpleCache.h b/dbms/src/Common/SimpleCache.h index b0a9d043782..4620ea7e626 100644 --- a/dbms/src/Common/SimpleCache.h +++ b/dbms/src/Common/SimpleCache.h @@ -8,7 +8,7 @@ /** The simplest cache for a free function. * You can also pass a static class method or lambda without capturing. - * The size is unlimited. Values ​​are not obsolete. + * The size is unlimited. Values are not obsolete. * To synchronize, use mutex. * Suitable only for the simplest cases. * diff --git a/dbms/src/Common/UInt128.h b/dbms/src/Common/UInt128.h index 8f33c1b197b..2b46af6f4a3 100644 --- a/dbms/src/Common/UInt128.h +++ b/dbms/src/Common/UInt128.h @@ -4,6 +4,10 @@ #include #include +#if __SSE4_2__ +#include +#endif + namespace DB { @@ -42,15 +46,15 @@ struct UInt128Hash } }; -#if defined(__x86_64__) +#if __SSE4_2__ struct UInt128HashCRC32 { size_t operator()(UInt128 x) const { UInt64 crc = -1ULL; - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.first)); - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.second)); + crc = _mm_crc32_u64(crc, x.first); + crc = _mm_crc32_u64(crc, x.second); return crc; } }; @@ -122,17 +126,17 @@ struct UInt256Hash } }; -#if defined(__x86_64__) +#if __SSE4_2__ struct UInt256HashCRC32 { size_t operator()(UInt256 x) const { UInt64 crc = -1ULL; - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.a)); - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.b)); - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.c)); - asm("crc32q %[x], %[crc]\n" : [crc] "+r" (crc) : [x] "rm" (x.d)); + crc = _mm_crc32_u64(crc, x.a); + crc = _mm_crc32_u64(crc, x.b); + crc = _mm_crc32_u64(crc, x.c); + crc = _mm_crc32_u64(crc, x.d); return crc; } }; diff --git a/dbms/src/Common/Volnitsky.h b/dbms/src/Common/Volnitsky.h index 8194f413e3a..18c5b1538d1 100644 --- a/dbms/src/Common/Volnitsky.h +++ b/dbms/src/Common/Volnitsky.h @@ -19,7 +19,7 @@ * - when initializing, fill in an open-addressing linear probing hash table of the form * hash from the bigram of needle -> the position of this bigram in needle + 1. * (one is added only to distinguish zero offset from an empty cell) - * - the keys are not stored in the hash table, only the values ​​are stored; + * - the keys are not stored in the hash table, only the values are stored; * - bigrams can be inserted several times if they occur in the needle several times; * - when searching, take from haystack bigram, which should correspond to the last bigram of needle (comparing from the end); * - look for it in the hash table, if found - get the offset from the hash table and compare the string bytewise; diff --git a/dbms/src/Core/BlockInfo.h b/dbms/src/Core/BlockInfo.h index 508980c5783..ebfbd117de7 100644 --- a/dbms/src/Core/BlockInfo.h +++ b/dbms/src/Core/BlockInfo.h @@ -15,7 +15,7 @@ struct BlockInfo { /** is_overflows: * After running GROUP BY ... WITH TOTALS with the max_rows_to_group_by and group_by_overflow_mode = 'any' settings, - * a row is inserted in the separate block with aggregated values ​​that have not passed max_rows_to_group_by. + * a row is inserted in the separate block with aggregated values that have not passed max_rows_to_group_by. * If it is such a block, then is_overflows is set to true for it. */ @@ -36,10 +36,10 @@ struct BlockInfo #undef DECLARE_FIELD - /// Write the values ​​in binary form. NOTE: You could use protobuf, but it would be overkill for this case. + /// Write the values in binary form. NOTE: You could use protobuf, but it would be overkill for this case. void write(WriteBuffer & out) const; - /// Read the values ​​in binary form. + /// Read the values in binary form. void read(ReadBuffer & in); }; diff --git a/dbms/src/Core/Defines.h b/dbms/src/Core/Defines.h index 06e3513a5ad..7dde20e6ccb 100644 --- a/dbms/src/Core/Defines.h +++ b/dbms/src/Core/Defines.h @@ -27,7 +27,7 @@ #define DEFAULT_MAX_COMPRESS_BLOCK_SIZE 1048576 /** Which blocks by default read the data (by number of rows). - * Smaller values ​​give better cache locality, less consumption of RAM, but more overhead to process the query. + * Smaller values give better cache locality, less consumption of RAM, but more overhead to process the query. */ #define DEFAULT_BLOCK_SIZE 65536 diff --git a/dbms/src/Core/StringRef.h b/dbms/src/Core/StringRef.h index a49f5373d8c..ba1d32b80d5 100644 --- a/dbms/src/Core/StringRef.h +++ b/dbms/src/Core/StringRef.h @@ -171,17 +171,7 @@ struct StringRefHash64 #if __SSE4_2__ -#ifdef __SSE4_1__ #include -#else - -inline UInt64 _mm_crc32_u64(UInt64 crc, UInt64 value) -{ - asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); - return crc; -} - -#endif /// Parts are taken from CityHash. diff --git a/dbms/src/Core/Types.h b/dbms/src/Core/Types.h index ad43dffbd2f..99491fe0518 100644 --- a/dbms/src/Core/Types.h +++ b/dbms/src/Core/Types.h @@ -9,7 +9,7 @@ namespace DB { -/** Data types for representing values ​​from a database in RAM. +/** Data types for representing values from a database in RAM. */ STRONG_TYPEDEF(char, Null); diff --git a/dbms/src/DataTypes/DataTypeAggregateFunction.h b/dbms/src/DataTypes/DataTypeAggregateFunction.h index 1866b760d6b..0de4487ed70 100644 --- a/dbms/src/DataTypes/DataTypeAggregateFunction.h +++ b/dbms/src/DataTypes/DataTypeAggregateFunction.h @@ -41,7 +41,7 @@ public: DataTypePtr clone() const override { return std::make_shared(function, argument_types, parameters); } - /// NOTE These two functions for serializing single values ​​are incompatible with the functions below. + /// NOTE These two functions for serializing single values are incompatible with the functions below. void serializeBinary(const Field & field, WriteBuffer & ostr) const override; void deserializeBinary(Field & field, ReadBuffer & istr) const override; diff --git a/dbms/src/DataTypes/DataTypeSet.h b/dbms/src/DataTypes/DataTypeSet.h index 514547136b9..8e4f11b100d 100644 --- a/dbms/src/DataTypes/DataTypeSet.h +++ b/dbms/src/DataTypes/DataTypeSet.h @@ -6,7 +6,7 @@ namespace DB { -/** The data type corresponding to the set of values ​​in the IN section. +/** The data type corresponding to the set of values in the IN section. * Used only as an intermediate option when evaluating expressions. */ class DataTypeSet final : public IDataTypeDummy diff --git a/dbms/src/Databases/DatabaseCloud.h b/dbms/src/Databases/DatabaseCloud.h index 3c31ab56dd4..e8fa46e7097 100644 --- a/dbms/src/Databases/DatabaseCloud.h +++ b/dbms/src/Databases/DatabaseCloud.h @@ -26,7 +26,7 @@ namespace DB * * cloud_path - the path to the "cloud"; There may be several different independent clouds /table_definitions - set of unique table definitions so you do not write them many times for a large number of tables - /hash128 -> sql - mapping: hash from table definition (identifier) ​​-> table definition itself as CREATE query + /hash128 -> sql - mapping: hash from table definition (identifier) -> table definition itself as CREATE query /tables - list of tables /database_name - name of the database /name_hash_mod -> compressed_table_list diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h index a19cde60f2d..af834757dea 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h +++ b/dbms/src/Storages/MergeTree/MergeTreeDataSelectExecutor.h @@ -28,7 +28,7 @@ public: QueryProcessingStage::Enum & processed_stage, size_t max_block_size, unsigned threads, - size_t * inout_part_index, /// If not nullptr, from this counter values are taken ​​for the virtual column _part_index. + size_t * inout_part_index, /// If not nullptr, from this counter values are taken for the virtual column _part_index. Int64 max_block_number_to_read) const; private: diff --git a/dbms/src/Storages/MergeTree/MergedBlockOutputStream.h b/dbms/src/Storages/MergeTree/MergedBlockOutputStream.h index 01da66151f6..92a0dda7013 100644 --- a/dbms/src/Storages/MergeTree/MergedBlockOutputStream.h +++ b/dbms/src/Storages/MergeTree/MergedBlockOutputStream.h @@ -136,7 +136,7 @@ public: private: void init(); - /** If `permutation` is given, it rearranges the values ​​in the columns when writing. + /** If `permutation` is given, it rearranges the values in the columns when writing. * This is necessary to not keep the whole block in the RAM to sort it. */ void writeImpl(const Block & block, const IColumn::Permutation * permutation); diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h index ef255ff2ca7..06e331ad652 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h @@ -63,7 +63,7 @@ struct ReplicatedMergeTreeLogEntryData /// The name of resulting part. /// For DROP_RANGE, the name of a non-existent part. You need to remove all the parts covered by it. String new_part_name; - String block_id; /// For parts of level zero, the block identifier for deduplication (node ​​name in /blocks /). + String block_id; /// For parts of level zero, the block identifier for deduplication (node name in /blocks /). Strings parts_to_merge; bool deduplicate = false; /// Do deduplicate on merge diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.h b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.h index 42f192ae909..4feff1b0443 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.h +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.h @@ -14,7 +14,7 @@ class StorageReplicatedMergeTree; /** Initializes ZK session. - * Exposes ephemeral nodes. It sets the node values ​​that are required for replica detection. + * Exposes ephemeral nodes. It sets the node values that are required for replica detection. * Starts participation in the leader selection. Starts all background threads. * Then monitors whether the session has expired. And if it expired, it will reinitialize it. */ From 7fc3d900356069aeb8b4a8fbc6f063a3afdd6276 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 9 May 2017 22:41:26 -0400 Subject: [PATCH 30/76] Renamed .inl file to .inl.h to avoid confusion [#CLICKHOUSE-2]. --- ...izedRegularExpression.inl => OptimizedRegularExpression.inl.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dbms/src/Common/{OptimizedRegularExpression.inl => OptimizedRegularExpression.inl.h} (100%) diff --git a/dbms/src/Common/OptimizedRegularExpression.inl b/dbms/src/Common/OptimizedRegularExpression.inl.h similarity index 100% rename from dbms/src/Common/OptimizedRegularExpression.inl rename to dbms/src/Common/OptimizedRegularExpression.inl.h From ff02af9804bbfbaa5f0b3a13b127caf0eaee24b2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 9 May 2017 22:45:21 -0400 Subject: [PATCH 31/76] Addition to prev. revision [#CLICKHOUSE-2]. --- cmake/dbms_glob_sources.cmake | 2 +- dbms/src/Common/OptimizedRegularExpression.h | 4 +- .../Common/OptimizedRegularExpression.inl.h | 694 +++++++++--------- 3 files changed, 351 insertions(+), 349 deletions(-) diff --git a/cmake/dbms_glob_sources.cmake b/cmake/dbms_glob_sources.cmake index 7d9bd2444b1..2d2200c2c55 100644 --- a/cmake/dbms_glob_sources.cmake +++ b/cmake/dbms_glob_sources.cmake @@ -4,7 +4,7 @@ macro(add_glob cur_list) endmacro() macro(add_headers_and_sources prefix common_path) - add_glob(${prefix}_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${common_path}/*.h ${common_path}/*.inl) + add_glob(${prefix}_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${common_path}/*.h) add_glob(${prefix}_sources ${common_path}/*.cpp ${common_path}/*.h) endmacro() diff --git a/dbms/src/Common/OptimizedRegularExpression.h b/dbms/src/Common/OptimizedRegularExpression.h index 3cd22ea3c15..906359df503 100644 --- a/dbms/src/Common/OptimizedRegularExpression.h +++ b/dbms/src/Common/OptimizedRegularExpression.h @@ -26,6 +26,8 @@ * - if in most calls, the regular expression does not match; * - if the regular expression is compatible with the re2 engine; * - you can use at your own risk, since, probably, not all cases are taken into account. + * + * NOTE: Multi-character metasymbols such as \Pl are handled incorrectly. */ namespace OptimizedRegularExpressionDetails @@ -105,4 +107,4 @@ private: using OptimizedRegularExpression = OptimizedRegularExpressionImpl; -#include "OptimizedRegularExpression.inl" +#include "OptimizedRegularExpression.inl.h" diff --git a/dbms/src/Common/OptimizedRegularExpression.inl.h b/dbms/src/Common/OptimizedRegularExpression.inl.h index a60ff314e7d..278d9d3814d 100644 --- a/dbms/src/Common/OptimizedRegularExpression.inl.h +++ b/dbms/src/Common/OptimizedRegularExpression.inl.h @@ -10,420 +10,420 @@ template void OptimizedRegularExpressionImpl::analyze( - const std::string & regexp, - std::string & required_substring, - bool & is_trivial, - bool & required_substring_is_prefix) + const std::string & regexp, + std::string & required_substring, + bool & is_trivial, + bool & required_substring_is_prefix) { - /** The expression is trivial if all the metacharacters in it are escaped. - * The non-alternative string is - * a string outside parentheses, - * in which all metacharacters are escaped, - * and also if there are no '|' outside the brackets, - * and also avoid substrings of the form `http://` or `www`. - */ - const char * begin = regexp.data(); - const char * pos = begin; - const char * end = regexp.data() + regexp.size(); - int depth = 0; - is_trivial = true; - required_substring_is_prefix = false; - required_substring.clear(); - bool has_alternative_on_depth_0 = false; + /** The expression is trivial if all the metacharacters in it are escaped. + * The non-alternative string is + * a string outside parentheses, + * in which all metacharacters are escaped, + * and also if there are no '|' outside the brackets, + * and also avoid substrings of the form `http://` or `www`. + */ + const char * begin = regexp.data(); + const char * pos = begin; + const char * end = regexp.data() + regexp.size(); + int depth = 0; + is_trivial = true; + required_substring_is_prefix = false; + required_substring.clear(); + bool has_alternative_on_depth_0 = false; - /// Substring with a position. - typedef std::pair Substring; + /// Substring with a position. + typedef std::pair Substring; - typedef std::vector Substrings; - Substrings trivial_substrings(1); - Substring * last_substring = &trivial_substrings.back(); + typedef std::vector Substrings; + Substrings trivial_substrings(1); + Substring * last_substring = &trivial_substrings.back(); - bool in_curly_braces = false; - bool in_square_braces = false; + bool in_curly_braces = false; + bool in_square_braces = false; - while (pos != end) - { - switch (*pos) - { - case '\0': - pos = end; - break; + while (pos != end) + { + switch (*pos) + { + case '\0': + pos = end; + break; - case '\\': - { - ++pos; - if (pos == end) - break; + case '\\': + { + ++pos; + if (pos == end) + break; - switch (*pos) - { - case '|': case '(': case ')': case '^': case '$': case '.': case '[': case '?': case '*': case '+': case '{': - if (depth == 0 && !in_curly_braces && !in_square_braces) - { - if (last_substring->first.empty()) - last_substring->second = pos - begin; - last_substring->first.push_back(*pos); - } - break; - default: - /// all other escape sequences are not supported - is_trivial = false; - if (!last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - break; - } + switch (*pos) + { + case '|': case '(': case ')': case '^': case '$': case '.': case '[': case '?': case '*': case '+': case '{': + if (depth == 0 && !in_curly_braces && !in_square_braces) + { + if (last_substring->first.empty()) + last_substring->second = pos - begin; + last_substring->first.push_back(*pos); + } + break; + default: + /// all other escape sequences are not supported + is_trivial = false; + if (!last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + break; + } - ++pos; - break; - } + ++pos; + break; + } - case '|': - if (depth == 0) - has_alternative_on_depth_0 = true; - is_trivial = false; - if (!in_square_braces && !last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - ++pos; - break; + case '|': + if (depth == 0) + has_alternative_on_depth_0 = true; + is_trivial = false; + if (!in_square_braces && !last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + ++pos; + break; - case '(': - if (!in_square_braces) - { - ++depth; - is_trivial = false; - if (!last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - } - ++pos; - break; + case '(': + if (!in_square_braces) + { + ++depth; + is_trivial = false; + if (!last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + } + ++pos; + break; - case '[': - in_square_braces = true; - ++depth; - is_trivial = false; - if (!last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - ++pos; - break; + case '[': + in_square_braces = true; + ++depth; + is_trivial = false; + if (!last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + ++pos; + break; - case ']': - if (!in_square_braces) - goto ordinary; + case ']': + if (!in_square_braces) + goto ordinary; - in_square_braces = false; - --depth; - is_trivial = false; - if (!last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - ++pos; - break; + in_square_braces = false; + --depth; + is_trivial = false; + if (!last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + ++pos; + break; - case ')': - if (!in_square_braces) - { - --depth; - is_trivial = false; - if (!last_substring->first.empty()) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - } - ++pos; - break; + case ')': + if (!in_square_braces) + { + --depth; + is_trivial = false; + if (!last_substring->first.empty()) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + } + ++pos; + break; - case '^': case '$': case '.': case '+': - is_trivial = false; - if (!last_substring->first.empty() && !in_square_braces) - { - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - ++pos; - break; + case '^': case '$': case '.': case '+': + is_trivial = false; + if (!last_substring->first.empty() && !in_square_braces) + { + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + ++pos; + break; - /// Quantifiers that allow a zero number. - case '{': - in_curly_braces = true; - case '?': case '*': - is_trivial = false; - if (!last_substring->first.empty() && !in_square_braces) - { - last_substring->first.resize(last_substring->first.size() - 1); - trivial_substrings.resize(trivial_substrings.size() + 1); - last_substring = &trivial_substrings.back(); - } - ++pos; - break; + /// Quantifiers that allow a zero number. + case '{': + in_curly_braces = true; + case '?': case '*': + is_trivial = false; + if (!last_substring->first.empty() && !in_square_braces) + { + last_substring->first.resize(last_substring->first.size() - 1); + trivial_substrings.resize(trivial_substrings.size() + 1); + last_substring = &trivial_substrings.back(); + } + ++pos; + break; - case '}': - if (!in_curly_braces) - goto ordinary; + case '}': + if (!in_curly_braces) + goto ordinary; - in_curly_braces = false; - ++pos; - break; + in_curly_braces = false; + ++pos; + break; - ordinary: /// Normal, not escaped symbol. - default: - if (depth == 0 && !in_curly_braces && !in_square_braces) - { - if (last_substring->first.empty()) - last_substring->second = pos - begin; - last_substring->first.push_back(*pos); - } - ++pos; - break; - } - } + ordinary: /// Normal, not escaped symbol. + default: + if (depth == 0 && !in_curly_braces && !in_square_braces) + { + if (last_substring->first.empty()) + last_substring->second = pos - begin; + last_substring->first.push_back(*pos); + } + ++pos; + break; + } + } - if (last_substring && last_substring->first.empty()) - trivial_substrings.pop_back(); + if (last_substring && last_substring->first.empty()) + trivial_substrings.pop_back(); - if (!is_trivial) - { - if (!has_alternative_on_depth_0) - { - /** We choose the non-alternative substring of the maximum length, among the prefixes, - * or a non-alternative substring of maximum length. - */ - size_t max_length = 0; - Substrings::const_iterator candidate_it = trivial_substrings.begin(); - for (Substrings::const_iterator it = trivial_substrings.begin(); it != trivial_substrings.end(); ++it) - { - if (((it->second == 0 && candidate_it->second != 0) - || ((it->second == 0) == (candidate_it->second == 0) && it->first.size() > max_length)) - /// Tuning for the domain - && (it->first.size() > strlen("://") || strncmp(it->first.data(), "://", strlen("://"))) - && (it->first.size() > strlen("http://") || strncmp(it->first.data(), "http", strlen("http"))) - && (it->first.size() > strlen("www.") || strncmp(it->first.data(), "www", strlen("www"))) - && (it->first.size() > strlen("Windows ") || strncmp(it->first.data(), "Windows ", strlen("Windows ")))) - { - max_length = it->first.size(); - candidate_it = it; - } - } + if (!is_trivial) + { + if (!has_alternative_on_depth_0) + { + /** We choose the non-alternative substring of the maximum length, among the prefixes, + * or a non-alternative substring of maximum length. + */ + size_t max_length = 0; + Substrings::const_iterator candidate_it = trivial_substrings.begin(); + for (Substrings::const_iterator it = trivial_substrings.begin(); it != trivial_substrings.end(); ++it) + { + if (((it->second == 0 && candidate_it->second != 0) + || ((it->second == 0) == (candidate_it->second == 0) && it->first.size() > max_length)) + /// Tuning for the domain + && (it->first.size() > strlen("://") || strncmp(it->first.data(), "://", strlen("://"))) + && (it->first.size() > strlen("http://") || strncmp(it->first.data(), "http", strlen("http"))) + && (it->first.size() > strlen("www.") || strncmp(it->first.data(), "www", strlen("www"))) + && (it->first.size() > strlen("Windows ") || strncmp(it->first.data(), "Windows ", strlen("Windows ")))) + { + max_length = it->first.size(); + candidate_it = it; + } + } - if (max_length >= MIN_LENGTH_FOR_STRSTR) - { - required_substring = candidate_it->first; - required_substring_is_prefix = candidate_it->second == 0; - } - } - } - else - { - required_substring = trivial_substrings.front().first; - required_substring_is_prefix = trivial_substrings.front().second == 0; - } + if (max_length >= MIN_LENGTH_FOR_STRSTR) + { + required_substring = candidate_it->first; + required_substring_is_prefix = candidate_it->second == 0; + } + } + } + else + { + required_substring = trivial_substrings.front().first; + required_substring_is_prefix = trivial_substrings.front().second == 0; + } -/* std::cerr - << "regexp: " << regexp - << ", is_trivial: " << is_trivial - << ", required_substring: " << required_substring - << ", required_substring_is_prefix: " << required_substring_is_prefix - << std::endl;*/ +/* std::cerr + << "regexp: " << regexp + << ", is_trivial: " << is_trivial + << ", required_substring: " << required_substring + << ", required_substring_is_prefix: " << required_substring_is_prefix + << std::endl;*/ } template OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::string & regexp_, int options) { - analyze(regexp_, required_substring, is_trivial, required_substring_is_prefix); + analyze(regexp_, required_substring, is_trivial, required_substring_is_prefix); - /// 3 options are supported - if (options & (~(RE_CASELESS | RE_NO_CAPTURE | RE_DOT_NL))) - throw Poco::Exception("OptimizedRegularExpression: Unsupported option."); + /// 3 options are supported + if (options & (~(RE_CASELESS | RE_NO_CAPTURE | RE_DOT_NL))) + throw Poco::Exception("OptimizedRegularExpression: Unsupported option."); - is_case_insensitive = options & RE_CASELESS; - bool is_no_capture = options & RE_NO_CAPTURE; - bool is_dot_nl = options & RE_DOT_NL; + is_case_insensitive = options & RE_CASELESS; + bool is_no_capture = options & RE_NO_CAPTURE; + bool is_dot_nl = options & RE_DOT_NL; - number_of_subpatterns = 0; - if (!is_trivial) - { - /// Compile the re2 regular expression. - typename RegexType::Options options; + number_of_subpatterns = 0; + if (!is_trivial) + { + /// Compile the re2 regular expression. + typename RegexType::Options options; - if (is_case_insensitive) - options.set_case_sensitive(false); + if (is_case_insensitive) + options.set_case_sensitive(false); - if (is_dot_nl) - options.set_dot_nl(true); + if (is_dot_nl) + options.set_dot_nl(true); - re2 = std::make_unique(regexp_, options); - if (!re2->ok()) - throw Poco::Exception("OptimizedRegularExpression: cannot compile re2: " + regexp_ + ", error: " + re2->error()); + re2 = std::make_unique(regexp_, options); + if (!re2->ok()) + throw Poco::Exception("OptimizedRegularExpression: cannot compile re2: " + regexp_ + ", error: " + re2->error()); - if (!is_no_capture) - { - number_of_subpatterns = re2->NumberOfCapturingGroups(); - if (number_of_subpatterns > MAX_SUBPATTERNS) - throw Poco::Exception("OptimizedRegularExpression: too many subpatterns in regexp: " + regexp_); - } - } + if (!is_no_capture) + { + number_of_subpatterns = re2->NumberOfCapturingGroups(); + if (number_of_subpatterns > MAX_SUBPATTERNS) + throw Poco::Exception("OptimizedRegularExpression: too many subpatterns in regexp: " + regexp_); + } + } } template bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size) const { - if (is_trivial) - { - if (is_case_insensitive) - return nullptr != strcasestr(subject, required_substring.data()); - else - return nullptr != strstr(subject, required_substring.data()); - } - else - { - if (!required_substring.empty()) - { - const char * pos; - if (is_case_insensitive) - pos = strcasestr(subject, required_substring.data()); - else - pos = strstr(subject, required_substring.data()); + if (is_trivial) + { + if (is_case_insensitive) + return nullptr != strcasestr(subject, required_substring.data()); + else + return nullptr != strstr(subject, required_substring.data()); + } + else + { + if (!required_substring.empty()) + { + const char * pos; + if (is_case_insensitive) + pos = strcasestr(subject, required_substring.data()); + else + pos = strstr(subject, required_substring.data()); - if (nullptr == pos) - return 0; - } + if (nullptr == pos) + return 0; + } - return re2->Match(StringPieceType(subject, subject_size), 0, subject_size, RegexType::UNANCHORED, nullptr, 0); - } + return re2->Match(StringPieceType(subject, subject_size), 0, subject_size, RegexType::UNANCHORED, nullptr, 0); + } } template bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, Match & match) const { - if (is_trivial) - { - const char * pos; - if (is_case_insensitive) - pos = strcasestr(subject, required_substring.data()); - else - pos = strstr(subject, required_substring.data()); + if (is_trivial) + { + const char * pos; + if (is_case_insensitive) + pos = strcasestr(subject, required_substring.data()); + else + pos = strstr(subject, required_substring.data()); - if (pos == nullptr) - return 0; - else - { - match.offset = pos - subject; - match.length = required_substring.size(); - return 1; - } - } - else - { - if (!required_substring.empty()) - { - const char * pos; - if (is_case_insensitive) - pos = strcasestr(subject, required_substring.data()); - else - pos = strstr(subject, required_substring.data()); + if (pos == nullptr) + return 0; + else + { + match.offset = pos - subject; + match.length = required_substring.size(); + return 1; + } + } + else + { + if (!required_substring.empty()) + { + const char * pos; + if (is_case_insensitive) + pos = strcasestr(subject, required_substring.data()); + else + pos = strstr(subject, required_substring.data()); - if (nullptr == pos) - return 0; - } + if (nullptr == pos) + return 0; + } - StringPieceType piece; + StringPieceType piece; - if (!RegexType::PartialMatch(StringPieceType(subject, subject_size), *re2, &piece)) - return 0; - else - { - match.offset = piece.data() - subject; - match.length = piece.length(); - return 1; - } - } + if (!RegexType::PartialMatch(StringPieceType(subject, subject_size), *re2, &piece)) + return 0; + else + { + match.offset = piece.data() - subject; + match.length = piece.length(); + return 1; + } + } } template unsigned OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, MatchVec & matches, unsigned limit) const { - matches.clear(); + matches.clear(); - if (limit == 0) - return 0; + if (limit == 0) + return 0; - if (limit > number_of_subpatterns + 1) - limit = number_of_subpatterns + 1; + if (limit > number_of_subpatterns + 1) + limit = number_of_subpatterns + 1; - if (is_trivial) - { - const char * pos; - if (is_case_insensitive) - pos = strcasestr(subject, required_substring.data()); - else - pos = strstr(subject, required_substring.data()); + if (is_trivial) + { + const char * pos; + if (is_case_insensitive) + pos = strcasestr(subject, required_substring.data()); + else + pos = strstr(subject, required_substring.data()); - if (pos == nullptr) - return 0; - else - { - Match match; - match.offset = pos - subject; - match.length = required_substring.size(); - matches.push_back(match); - return 1; - } - } - else - { - if (!required_substring.empty()) - { - const char * pos; - if (is_case_insensitive) - pos = strcasestr(subject, required_substring.data()); - else - pos = strstr(subject, required_substring.data()); + if (pos == nullptr) + return 0; + else + { + Match match; + match.offset = pos - subject; + match.length = required_substring.size(); + matches.push_back(match); + return 1; + } + } + else + { + if (!required_substring.empty()) + { + const char * pos; + if (is_case_insensitive) + pos = strcasestr(subject, required_substring.data()); + else + pos = strstr(subject, required_substring.data()); - if (nullptr == pos) - return 0; - } + if (nullptr == pos) + return 0; + } - StringPieceType pieces[MAX_SUBPATTERNS]; + StringPieceType pieces[MAX_SUBPATTERNS]; - if (!re2->Match(StringPieceType(subject, subject_size), 0, subject_size, RegexType::UNANCHORED, pieces, limit)) - return 0; - else - { - matches.resize(limit); - for (size_t i = 0; i < limit; ++i) - { - if (pieces[i] != nullptr) - { - matches[i].offset = pieces[i].data() - subject; - matches[i].length = pieces[i].length(); - } - else - { - matches[i].offset = std::string::npos; - matches[i].length = 0; - } - } - return limit; - } - } + if (!re2->Match(StringPieceType(subject, subject_size), 0, subject_size, RegexType::UNANCHORED, pieces, limit)) + return 0; + else + { + matches.resize(limit); + for (size_t i = 0; i < limit; ++i) + { + if (pieces[i] != nullptr) + { + matches[i].offset = pieces[i].data() - subject; + matches[i].length = pieces[i].length(); + } + else + { + matches[i].offset = std::string::npos; + matches[i].length = 0; + } + } + return limit; + } + } } #undef MIN_LENGTH_FOR_STRSTR From 7bf7242ad3dea783a689d566e6913701917b4780 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 00:00:19 -0400 Subject: [PATCH 32/76] Fixed translation errors; miscellaneous changes [#CLICKHOUSE-3]. --- .../src/Common/CombinedCardinalityEstimator.h | 2 +- dbms/src/Common/HashTable/Hash.h | 2 +- dbms/src/Common/HashTable/HashTable.h | 2 +- dbms/src/Common/HashTable/SmallTable.h | 2 +- dbms/src/Common/HashTable/TwoLevelHashTable.h | 12 ++--- .../HyperLogLogWithSmallSetOptimization.h | 2 +- dbms/src/Common/Increment.h | 18 +++---- dbms/src/Common/Macros.h | 3 +- dbms/src/Common/MemoryTracker.h | 8 +-- .../Common/OptimizedRegularExpression.inl.h | 34 ++++++------ dbms/src/Common/PODArray.h | 38 +++++++------- dbms/src/Common/PoolBase.h | 37 ++++++++----- dbms/src/Common/RadixSort.h | 19 +++---- dbms/src/Common/ShellCommand.h | 8 +-- dbms/src/Common/SimpleCache.h | 6 +-- dbms/src/Common/SipHash.h | 48 ++++++++--------- dbms/src/Common/StringSearcher.h | 36 ++++++------- dbms/src/Common/Throttler.h | 10 ++-- dbms/src/Common/VirtualColumnUtils.h | 4 +- dbms/src/Common/Volnitsky.h | 52 ++++++++++--------- dbms/src/Common/formatReadable.h | 4 +- dbms/src/Common/getFQDNOrHostName.h | 4 +- dbms/src/Common/typeid_cast.h | 2 +- 23 files changed, 184 insertions(+), 169 deletions(-) diff --git a/dbms/src/Common/CombinedCardinalityEstimator.h b/dbms/src/Common/CombinedCardinalityEstimator.h index 82c2951e44a..94d21064a42 100644 --- a/dbms/src/Common/CombinedCardinalityEstimator.h +++ b/dbms/src/Common/CombinedCardinalityEstimator.h @@ -23,7 +23,7 @@ static inline ContainerType max(const ContainerType & lhs, const ContainerType & } -/** For a small number of keys - an array of fixed size "on the stack." +/** For a small number of keys - an array of fixed size "on the stack". * For the average, HashSet is allocated. * For large, HyperLogLog is allocated. */ diff --git a/dbms/src/Common/HashTable/Hash.h b/dbms/src/Common/HashTable/Hash.h index b2733058cb7..a9517e3e5e1 100644 --- a/dbms/src/Common/HashTable/Hash.h +++ b/dbms/src/Common/HashTable/Hash.h @@ -5,7 +5,7 @@ /** Hash functions that are better than the trivial function std::hash. * - * Example: when aggregated by the visitor ID, the performance increase is more than 5 times. + * Example: when we do aggregation by the visitor ID, the performance increase is more than 5 times. * This is because of following reasons: * - in Yandex, visitor identifier is an integer that has timestamp with seconds resolution in lower bits; * - in typical implementation of standard library, hash function for integers is trivial and just use lower bits; diff --git a/dbms/src/Common/HashTable/HashTable.h b/dbms/src/Common/HashTable/HashTable.h index be762733897..a965b8e6e9d 100644 --- a/dbms/src/Common/HashTable/HashTable.h +++ b/dbms/src/Common/HashTable/HashTable.h @@ -695,7 +695,7 @@ public: /** Insert the key, - * return the iterator to a position that can be used for `placement new` of value, + * return an iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. * * You have to make `placement new` of value if you inserted a new key, diff --git a/dbms/src/Common/HashTable/SmallTable.h b/dbms/src/Common/HashTable/SmallTable.h index 64e90f6208a..823bc93bf5d 100644 --- a/dbms/src/Common/HashTable/SmallTable.h +++ b/dbms/src/Common/HashTable/SmallTable.h @@ -212,7 +212,7 @@ public: /** Insert the key, - * return the iterator to a position that can be used for `placement new` of value, + * return an iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. * * You have to make `placement new` of value if you inserted a new key, diff --git a/dbms/src/Common/HashTable/TwoLevelHashTable.h b/dbms/src/Common/HashTable/TwoLevelHashTable.h index 29bbaca988a..6d4edf49fc7 100644 --- a/dbms/src/Common/HashTable/TwoLevelHashTable.h +++ b/dbms/src/Common/HashTable/TwoLevelHashTable.h @@ -9,9 +9,9 @@ * * Usually works a little slower than a simple hash table. * However, it has advantages in some cases: - * - if you need to measure two hash tables together, then you can easily parallelize them by buckets; - * - lag during resizes is spread, since the small hash tables will be resized separately; - * - in theory, the cache resize is local in a larger range of sizes. + * - if you need to merge two hash tables together, then you can easily parallelize it by buckets; + * - delay during resizes is amortized, since the small hash tables will be resized separately; + * - in theory, resizes are cache-local in a larger range of sizes. */ template @@ -52,7 +52,7 @@ public: size_t hash(const Key & x) const { return Hash::operator()(x); } - /// NOTE Bad for hash tables for more than 2^32 cells. + /// NOTE Bad for hash tables with more than 2^32 cells. static size_t getBucketFromHash(size_t hash_value) { return (hash_value >> (32 - BITS_FOR_BUCKET)) & MAX_BUCKET; } protected: @@ -95,7 +95,7 @@ public: { typename Source::const_iterator it = src.begin(); - /// It is assumed that the zero key (stored separately) when iterating is first. + /// It is assumed that the zero key (stored separately) is first in iteration order. if (it != src.end() && it.getPtr()->isZero(src)) { insert(*it); @@ -221,7 +221,7 @@ public: /** Insert the key, - * return the iterator to a position that can be used for `placement new` value, + * return an iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. * * You have to make `placement new` values if you inserted a new key, diff --git a/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h b/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h index b604d82d85b..5296a606121 100644 --- a/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h +++ b/dbms/src/Common/HyperLogLogWithSmallSetOptimization.h @@ -9,7 +9,7 @@ namespace DB { -/** For a small number of keys - an array of fixed size "on the stack." +/** For a small number of keys - an array of fixed size "on the stack". * For large, HyperLogLog is allocated. * See also the more practical implementation in CombinedCardinalityEstimator.h, * where a hash table is also used for medium-sized sets. diff --git a/dbms/src/Common/Increment.h b/dbms/src/Common/Increment.h index fc8820975fa..c03c6ef5575 100644 --- a/dbms/src/Common/Increment.h +++ b/dbms/src/Common/Increment.h @@ -3,8 +3,8 @@ #include -/** Lets you receive an auto-increment number, storing it in a file. - * Designed for rare calls (not designed for performance). +/** Allows to get an auto-increment number, storing it in a file. + * Intended for rare calls (not designed for performance). */ class Increment { @@ -39,13 +39,13 @@ public: return getBunch(0, create_if_need); } - /** Get the next number and increase the count by `count`. - * If the `create_if_need` parameter is not set to true, then - * the file should already have a number written (if not - create the file manually with zero). - * - * To protect against race conditions between different processes, file locks are used. - * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) - */ + /** Get the next number and increase the counter by `count`. + * If the `create_if_need` parameter is not set to true, then + * the file should already have a number written (if not - create the file manually with zero). + * + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) + */ UInt64 getBunch(UInt64 count, bool create_if_need = false) { return static_cast(counter.add(static_cast(count), create_if_need) - count + 1); diff --git a/dbms/src/Common/Macros.h b/dbms/src/Common/Macros.h index dec296fcbfe..0ebf52afd02 100644 --- a/dbms/src/Common/Macros.h +++ b/dbms/src/Common/Macros.h @@ -4,10 +4,11 @@ #include #include + namespace DB { -/** Apply the macros from the config in the line. +/** Apply substitutions from the macros in config to the string. */ class Macros { diff --git a/dbms/src/Common/MemoryTracker.h b/dbms/src/Common/MemoryTracker.h index 7066e20ee17..c06fc33444e 100644 --- a/dbms/src/Common/MemoryTracker.h +++ b/dbms/src/Common/MemoryTracker.h @@ -102,10 +102,10 @@ public: }; -/** The MemoryTracker object is quite difficult to drag to all places where significant amounts of memory are allocated. - * Therefore, a thread-local pointer to used MemoryTracker or nullptr is used, if it does not need to be used. - * This pointer is set when memory consumption is monitored in this thread. - * So, you just need to drag it to all the threads that handle one request. +/** The MemoryTracker object is quite difficult to pass to all places where significant amounts of memory are allocated. + * Therefore, a thread-local pointer to used MemoryTracker is set, or nullptr if MemoryTracker does not need to be used. + * This pointer is set when memory consumption is monitored in current thread. + * So, you just need to pass it to all the threads that handle one request. */ extern __thread MemoryTracker * current_memory_tracker; diff --git a/dbms/src/Common/OptimizedRegularExpression.inl.h b/dbms/src/Common/OptimizedRegularExpression.inl.h index 278d9d3814d..ef6cb781a39 100644 --- a/dbms/src/Common/OptimizedRegularExpression.inl.h +++ b/dbms/src/Common/OptimizedRegularExpression.inl.h @@ -8,8 +8,9 @@ #define MIN_LENGTH_FOR_STRSTR 3 #define MAX_SUBPATTERNS 5 -template -void OptimizedRegularExpressionImpl::analyze( + +template +void OptimizedRegularExpressionImpl::analyze( const std::string & regexp, std::string & required_substring, bool & is_trivial, @@ -20,7 +21,8 @@ void OptimizedRegularExpressionImpl::analyze( * a string outside parentheses, * in which all metacharacters are escaped, * and also if there are no '|' outside the brackets, - * and also avoid substrings of the form `http://` or `www`. + * and also avoid substrings of the form `http://` or `www` and some other + * (this is the hack for typical use case in Yandex.Metrica). */ const char * begin = regexp.data(); const char * pos = begin; @@ -32,9 +34,9 @@ void OptimizedRegularExpressionImpl::analyze( bool has_alternative_on_depth_0 = false; /// Substring with a position. - typedef std::pair Substring; + using Substring = std::pair; + using Substrings = std::vector; - typedef std::vector Substrings; Substrings trivial_substrings(1); Substring * last_substring = &trivial_substrings.back(); @@ -157,7 +159,7 @@ void OptimizedRegularExpressionImpl::analyze( ++pos; break; - /// Quantifiers that allow a zero number. + /// Quantifiers that allow a zero number of occurences. case '{': in_curly_braces = true; case '?': case '*': @@ -208,7 +210,7 @@ void OptimizedRegularExpressionImpl::analyze( { if (((it->second == 0 && candidate_it->second != 0) || ((it->second == 0) == (candidate_it->second == 0) && it->first.size() > max_length)) - /// Tuning for the domain + /// Tuning for typical usage domain && (it->first.size() > strlen("://") || strncmp(it->first.data(), "://", strlen("://"))) && (it->first.size() > strlen("http://") || strncmp(it->first.data(), "http", strlen("http"))) && (it->first.size() > strlen("www.") || strncmp(it->first.data(), "www", strlen("www"))) @@ -241,12 +243,12 @@ void OptimizedRegularExpressionImpl::analyze( } -template -OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::string & regexp_, int options) +template +OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::string & regexp_, int options) { analyze(regexp_, required_substring, is_trivial, required_substring_is_prefix); - /// 3 options are supported + /// Just three following options are supported if (options & (~(RE_CASELESS | RE_NO_CAPTURE | RE_DOT_NL))) throw Poco::Exception("OptimizedRegularExpression: Unsupported option."); @@ -280,8 +282,8 @@ OptimizedRegularExpressionImpl::OptimizedRegularExpressionImpl(const std::str } -template -bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size) const +template +bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size) const { if (is_trivial) { @@ -309,8 +311,8 @@ bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subje } -template -bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, Match & match) const +template +bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, Match & match) const { if (is_trivial) { @@ -357,8 +359,8 @@ bool OptimizedRegularExpressionImpl::match(const char * subject, size_t subje } -template -unsigned OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, MatchVec & matches, unsigned limit) const +template +unsigned OptimizedRegularExpressionImpl::match(const char * subject, size_t subject_size, MatchVec & matches, unsigned limit) const { matches.clear(); diff --git a/dbms/src/Common/PODArray.h b/dbms/src/Common/PODArray.h index 0b46fecf5f9..e098756c8ae 100644 --- a/dbms/src/Common/PODArray.h +++ b/dbms/src/Common/PODArray.h @@ -24,7 +24,7 @@ namespace DB * To be more precise - for use in ColumnVector. * It differs from std::vector in that it does not initialize the elements. * - * Made uncopable so that there are no random copies. You can copy the data using `assign` method. + * Made noncopyable so that there are no accidential copies. You can copy the data using `assign` method. * * Only part of the std::vector interface is supported. * @@ -40,20 +40,20 @@ template (c_start); } - T * t_end() { return reinterpret_cast(c_end); } - T * t_end_of_storage() { return reinterpret_cast(c_end_of_storage); } + T * t_start() { return reinterpret_cast(c_start); } + T * t_end() { return reinterpret_cast(c_end); } + T * t_end_of_storage() { return reinterpret_cast(c_end_of_storage); } - const T * t_start() const { return reinterpret_cast(c_start); } - const T * t_end() const { return reinterpret_cast(c_end); } - const T * t_end_of_storage() const { return reinterpret_cast(c_end_of_storage); } + const T * t_start() const { return reinterpret_cast(c_start); } + const T * t_end() const { return reinterpret_cast(c_end); } + const T * t_end_of_storage() const { return reinterpret_cast(c_end_of_storage); } /// The amount of memory occupied by the num_elements of the elements. static size_t byte_size(size_t num_elements) { return num_elements * sizeof(T); } @@ -173,16 +173,16 @@ public: const T & operator[] (size_t n) const { return t_start()[n]; } T & front() { return t_start()[0]; } - T & back() { return t_end()[-1]; } + T & back() { return t_end()[-1]; } const T & front() const { return t_start()[0]; } const T & back() const { return t_end()[-1]; } - iterator begin() { return t_start(); } - iterator end() { return t_end(); } - const_iterator begin() const { return t_start(); } - const_iterator end() const { return t_end(); } - const_iterator cbegin() const { return t_start(); } - const_iterator cend() const { return t_end(); } + iterator begin() { return t_start(); } + iterator end() { return t_end(); } + const_iterator begin() const { return t_start(); } + const_iterator end() const { return t_end(); } + const_iterator cbegin() const { return t_start(); } + const_iterator cend() const { return t_end(); } void reserve(size_t n) { @@ -209,7 +209,7 @@ public: c_end = c_start + byte_size(n); } - /// Same as resize, but zeros new elements. + /// Same as resize, but zeroes new elements. void resize_fill(size_t n) { size_t old_size = size(); @@ -261,7 +261,7 @@ public: c_end -= byte_size(1); } - /// Do not insert a piece of yourself into the array. Because with the resize, the iterators on themselves can be invalidated. + /// Do not insert into the array a piece of itself. Because with the resize, the iterators on themselves can be invalidated. template void insert(It1 from_begin, It2 from_end) { diff --git a/dbms/src/Common/PoolBase.h b/dbms/src/Common/PoolBase.h index 4b81197ee0a..194d7e421ad 100644 --- a/dbms/src/Common/PoolBase.h +++ b/dbms/src/Common/PoolBase.h @@ -8,8 +8,17 @@ #include #include + +namespace DB +{ + namespace ErrorCodes + { + extern const int LOGICAL_ERROR; + } +} + /** A class from which you can inherit and get a pool of something. Used for database connection pools. - * The heir must provide a method for creating a new object to place in the pool. + * Descendant class must provide a method for creating a new object to place in the pool. */ template @@ -63,27 +72,27 @@ public: Entry() {} /// For deferred initialization. /** The `Entry` object protects the resource from being used by another thread. - * The following methods are forbidden for `rvalue`, so you can not write a similar to - * - * auto q = pool.Get()->query("SELECT .."); // Oops, after this line Entry was destroyed - * q.execute (); // Someone else can use this Connection - */ + * The following methods are forbidden for `rvalue`, so you can not write a similar to + * + * auto q = pool.Get()->query("SELECT .."); // Oops, after this line Entry was destroyed + * q.execute (); // Someone else can use this Connection + */ Object * operator->() && = delete; const Object * operator->() const && = delete; Object & operator*() && = delete; const Object & operator*() const && = delete; - Object * operator->() & { return &*data->data.object; } - const Object * operator->() const & { return &*data->data.object; } - Object & operator*() & { return *data->data.object; } - const Object & operator*() const & { return *data->data.object; } + Object * operator->() & { return &*data->data.object; } + const Object * operator->() const & { return &*data->data.object; } + Object & operator*() & { return *data->data.object; } + const Object & operator*() const & { return *data->data.object; } bool isNull() const { return data == nullptr; } PoolBase * getPool() const { if (!data) - throw DB::Exception("attempt to get pool from uninitialized entry"); + throw DB::Exception("Attempt to get pool from uninitialized entry", DB::ErrorCodes::LOGICAL_ERROR); return &data->data.pool; } @@ -95,7 +104,7 @@ public: virtual ~PoolBase() {} - /** Allocates the object for the job. With timeout < 0, the timeout is infinite. */ + /** Allocates the object. Wait for free object in pool for 'timeout'. With 'timeout' < 0, the timeout is infinite. */ Entry get(Poco::Timespan::TimeDiff timeout) { std::unique_lock lock(mutex); @@ -137,7 +146,7 @@ private: /** Pool. */ Objects items; - /** Block to access the pool. */ + /** Lock to access the pool. */ std::mutex mutex; std::condition_variable available; @@ -151,7 +160,7 @@ protected: items.reserve(max_items); } - /** Creates a new object to put in the pool. */ + /** Creates a new object to put into the pool. */ virtual ObjectPtr allocObject() = 0; }; diff --git a/dbms/src/Common/RadixSort.h b/dbms/src/Common/RadixSort.h index 47232b1f19d..ee844fa83a8 100644 --- a/dbms/src/Common/RadixSort.h +++ b/dbms/src/Common/RadixSort.h @@ -13,10 +13,10 @@ #include -/** Bitwise sort, has the following functionality: +/** Radix sort, has the following functionality: * Can sort unsigned, signed numbers, and floats. * Can sort an array of fixed length elements that contain something else besides the key. - * Customizable digit size. + * Customizable radix size. * * LSB, stable. * NOTE For some applications it makes sense to add MSB-radix-sort, @@ -49,7 +49,7 @@ struct RadixSortMallocAllocator template struct RadixSortFloatTransform { - /// Is it worth writing the result in memory, or is it better to do it every time again? + /// Is it worth writing the result in memory, or is it better to do calculation every time again? static constexpr bool transform_is_simple = false; static KeyBits forward(KeyBits x) @@ -74,7 +74,7 @@ struct RadixSortFloatTraits /// The type to which the key is transformed to do bit operations. This UInt is the same size as the key. using KeyBits = typename std::conditional::type; - static constexpr size_t PART_SIZE_BITS = 8; /// With what pieces of the key, it bits, to do one pass - reshuffle of the array. + static constexpr size_t PART_SIZE_BITS = 8; /// With what pieces of the key, in bits, to do one pass - reshuffle of the array. /// Converting a key into KeyBits is such that the order relation over the key corresponds to the order relation over KeyBits. using Transform = RadixSortFloatTransform; @@ -95,7 +95,7 @@ struct RadixSortIdentityTransform static constexpr bool transform_is_simple = true; static KeyBits forward(KeyBits x) { return x; } - static KeyBits backward(KeyBits x) { return x; } + static KeyBits backward(KeyBits x) { return x; } }; @@ -105,7 +105,7 @@ struct RadixSortSignedTransform static constexpr bool transform_is_simple = true; static KeyBits forward(KeyBits x) { return x ^ (KeyBits(1) << (sizeof(KeyBits) * 8 - 1)); } - static KeyBits backward(KeyBits x) { return x ^ (KeyBits(1) << (sizeof(KeyBits) * 8 - 1)); } + static KeyBits backward(KeyBits x) { return x ^ (KeyBits(1) << (sizeof(KeyBits) * 8 - 1)); } }; @@ -150,7 +150,7 @@ struct RadixSort private: using Element = typename Traits::Element; using Key = typename Traits::Key; - using CountType = typename Traits::CountType; + using CountType = typename Traits::CountType; using KeyBits = typename Traits::KeyBits; static constexpr size_t HISTOGRAM_SIZE = 1 << Traits::PART_SIZE_BITS; @@ -174,9 +174,9 @@ public: { /// If the array is smaller than 256, then it is better to use another algorithm. - /// There are loops of NUM_PASSES. It is very important that they unfold in compile-time. + /// There are loops of NUM_PASSES. It is very important that they are unfolded at compile-time. - /// For each of the NUM_PASSES bits of the key, consider how many times each value of this piece met. + /// For each of the NUM_PASSES bit ranges of the key, consider how many times each value of this bit range met. CountType histograms[HISTOGRAM_SIZE * NUM_PASSES] = {0}; typename Traits::Allocator allocator; @@ -230,6 +230,7 @@ public: } /// If the number of passes is odd, the result array is in a temporary buffer. Copy it to the place of the original array. + /// NOTE Sometimes it will be more optimal to provide non-destructive interface, that will not modify original array. if (NUM_PASSES % 2) memcpy(arr, swap_buffer, size * sizeof(Element)); diff --git a/dbms/src/Common/ShellCommand.h b/dbms/src/Common/ShellCommand.h index ad2f4fdd0c6..a558216fcbf 100644 --- a/dbms/src/Common/ShellCommand.h +++ b/dbms/src/Common/ShellCommand.h @@ -10,8 +10,8 @@ namespace DB /** Lets you run the command, - * read it stdout, stderr, write to stdin, - * wait for completion. + * read it stdout and stderr; write to stdin; + * wait for completion. * * The implementation is similar to the popen function from POSIX (see libc source code). * @@ -20,8 +20,8 @@ namespace DB * with some overcommit settings, if the address space of the process is more than half the amount of available memory. * Also, changing memory maps - a fairly resource-intensive operation. * - * The second difference - allows to work simultaneously with stdin, and with stdout, and with stderr running process, - * and also find out the code and the completion status. + * The second difference - allows to work simultaneously with stdin, and with stdout, and with stderr of running process, + * and also to obtain the return code and completion status. */ class ShellCommand { diff --git a/dbms/src/Common/SimpleCache.h b/dbms/src/Common/SimpleCache.h index 4620ea7e626..4de92baa9f5 100644 --- a/dbms/src/Common/SimpleCache.h +++ b/dbms/src/Common/SimpleCache.h @@ -7,9 +7,9 @@ /** The simplest cache for a free function. - * You can also pass a static class method or lambda without capturing. - * The size is unlimited. Values are not obsolete. - * To synchronize, use mutex. + * You can also pass a static class method or lambda without captures. + * The size is unlimited. Values are stored permanently and never evicted. + * Mutex is used for synchronization. * Suitable only for the simplest cases. * * Usage diff --git a/dbms/src/Common/SipHash.h b/dbms/src/Common/SipHash.h index f6f241df9d7..10e5d642ebb 100644 --- a/dbms/src/Common/SipHash.h +++ b/dbms/src/Common/SipHash.h @@ -3,17 +3,17 @@ /** SipHash is a fast cryptographic hash function for short strings. * Taken from here: https://www.131002.net/siphash/ * + * This is SipHash 2-4 variant. + * * Two changes are made: - * - returns 128 bits, not 64; + * - returns also 128 bits, not only 64; * - done streaming (can be calculated in parts). * * On short strings (URL, search phrases) more than 3 times faster than MD5 from OpenSSL. * (~ 700 MB/sec, 15 million strings per second) */ -#include -#include -#include +#include #define ROTL(x,b) static_cast( ((x) << (b)) | ( (x) >> (64 - (b))) ) @@ -30,23 +30,20 @@ class SipHash { private: - using u64 = DB::UInt64; - using u8 = DB::UInt8; - - /// Status. - u64 v0; - u64 v1; - u64 v2; - u64 v3; + /// State. + UInt64 v0; + UInt64 v1; + UInt64 v2; + UInt64 v3; /// How many bytes have been processed. - u64 cnt; + UInt64 cnt; /// The current 8 bytes of input data. union { - u64 current_word; - u8 current_bytes[8]; + UInt64 current_word; + UInt8 current_bytes[8]; }; void finalize() @@ -68,7 +65,7 @@ private: public: /// Arguments - seed. - SipHash(u64 k0 = 0, u64 k1 = 0) + SipHash(UInt64 k0 = 0, UInt64 k1 = 0) { /// Initialize the state with some random bytes and seed. v0 = 0x736f6d6570736575ULL ^ k0; @@ -80,7 +77,7 @@ public: current_word = 0; } - void update(const char * data, u64 size) + void update(const char * data, UInt64 size) { const char * end = data + size; @@ -94,7 +91,7 @@ public: ++cnt; } - /// If you still do not have enough bytes to an 8-byte word. + /// If we still do not have enough bytes to an 8-byte word. if (cnt & 7) return; @@ -108,7 +105,7 @@ public: while (data + 8 <= end) { - current_word = *reinterpret_cast(data); + current_word = *reinterpret_cast(data); v3 ^= current_word; SIPROUND; @@ -138,18 +135,18 @@ public: void get128(char * out) { finalize(); - reinterpret_cast(out)[0] = v0 ^ v1; - reinterpret_cast(out)[1] = v2 ^ v3; + reinterpret_cast(out)[0] = v0 ^ v1; + reinterpret_cast(out)[1] = v2 ^ v3; } - void get128(u64 & lo, u64 & hi) + void get128(UInt64 & lo, UInt64 & hi) { finalize(); lo = v0 ^ v1; hi = v2 ^ v3; } - u64 get64() + UInt64 get64() { finalize(); return v0 ^ v1 ^ v2 ^ v3; @@ -160,6 +157,7 @@ public: #undef ROTL #undef SIPROUND +#include inline void sipHash128(const char * data, const size_t size, char * out) { @@ -168,7 +166,7 @@ inline void sipHash128(const char * data, const size_t size, char * out) hash.get128(out); } -inline DB::UInt64 sipHash64(const char * data, const size_t size) +inline UInt64 sipHash64(const char * data, const size_t size) { SipHash hash; hash.update(data, size); @@ -177,7 +175,7 @@ inline DB::UInt64 sipHash64(const char * data, const size_t size) #include -inline DB::UInt64 sipHash64(const std::string & s) +inline UInt64 sipHash64(const std::string & s) { return sipHash64(s.data(), s.size()); } diff --git a/dbms/src/Common/StringSearcher.h b/dbms/src/Common/StringSearcher.h index 9d83d4d19f9..ba1947f515c 100644 --- a/dbms/src/Common/StringSearcher.h +++ b/dbms/src/Common/StringSearcher.h @@ -19,15 +19,14 @@ namespace DB { - namespace ErrorCodes { extern const int UNSUPPORTED_PARAMETER; } -/** Variants for finding a substring in a string. - * In most cases, less productive than Volnitsky (see Volnitsky.h). +/** Variants for searching a substring in a string. + * In most cases, performance is less than Volnitsky (see Volnitsky.h). */ @@ -37,7 +36,7 @@ struct StringSearcherBase static constexpr auto n = sizeof(__m128i); const int page_size = getpagesize(); - bool page_safe(const void * const ptr) const + bool pageSafe(const void * const ptr) const { return ((page_size - 1) & reinterpret_cast(ptr)) <= page_size - n; } @@ -55,7 +54,7 @@ class StringSearcher : private StringSearcherBase private: using UTF8SequenceBuffer = UInt8[6]; - /// string to be searched for + /// substring to be searched for const UInt8 * const needle; const std::size_t needle_size; const UInt8 * const needle_end = needle + needle_size; @@ -135,8 +134,7 @@ public: if (!(dst_l_len == dst_u_len && dst_u_len == src_len)) throw DB::Exception{ "UTF8 sequences with different lowercase and uppercase lengths are not supported", - DB::ErrorCodes::UNSUPPORTED_PARAMETER - }; + DB::ErrorCodes::UNSUPPORTED_PARAMETER}; cache_actual_len += src_len; if (cache_actual_len < n) @@ -165,7 +163,7 @@ public: static const Poco::UTF8Encoding utf8; #if __SSE4_1__ - if (page_safe(pos)) + if (pageSafe(pos)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(pos)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, cachel); @@ -230,7 +228,7 @@ public: while (haystack < haystack_end) { #if __SSE4_1__ - if (haystack + n <= haystack_end && page_safe(haystack)) + if (haystack + n <= haystack_end && pageSafe(haystack)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, patl); @@ -249,7 +247,7 @@ public: const auto offset = __builtin_ctz(mask); haystack += offset; - if (haystack < haystack_end && haystack + n <= haystack_end && page_safe(haystack)) + if (haystack < haystack_end && haystack + n <= haystack_end && pageSafe(haystack)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, cachel); @@ -377,7 +375,7 @@ public: bool compare(const UInt8 * pos) const { #if __SSE4_1__ - if (page_safe(pos)) + if (pageSafe(pos)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(pos)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, cachel); @@ -429,7 +427,7 @@ public: while (haystack < haystack_end) { #if __SSE4_1__ - if (haystack + n <= haystack_end && page_safe(haystack)) + if (haystack + n <= haystack_end && pageSafe(haystack)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, patl); @@ -447,7 +445,7 @@ public: const auto offset = __builtin_ctz(mask); haystack += offset; - if (haystack < haystack_end && haystack + n <= haystack_end && page_safe(haystack)) + if (haystack < haystack_end && haystack + n <= haystack_end && pageSafe(haystack)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); const auto v_against_l = _mm_cmpeq_epi8(v_haystack, cachel); @@ -559,7 +557,7 @@ public: bool compare(const UInt8 * pos) const { #if __SSE4_1__ - if (page_safe(pos)) + if (pageSafe(pos)) { const auto v_haystack = _mm_loadu_si128(reinterpret_cast(pos)); const auto v_against_cache = _mm_cmpeq_epi8(v_haystack, cache); @@ -609,7 +607,7 @@ public: while (haystack < haystack_end) { #if __SSE4_1__ - if (haystack + n <= haystack_end && page_safe(haystack)) + if (haystack + n <= haystack_end && pageSafe(haystack)) { /// find first character const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); @@ -627,7 +625,7 @@ public: const auto offset = __builtin_ctz(mask); haystack += offset; - if (haystack < haystack_end && haystack + n <= haystack_end && page_safe(haystack)) + if (haystack < haystack_end && haystack + n <= haystack_end && pageSafe(haystack)) { /// check for first 16 octets const auto v_haystack = _mm_loadu_si128(reinterpret_cast(haystack)); @@ -694,9 +692,9 @@ using UTF8CaseInsensitiveStringSearcher = StringSearcher; /** Uses functions from libc. - * It makes sense to use short strings when cheap initialization is required. - * There is no option for register-independent search for UTF-8 strings. - * It is required that the end of the lines be zero byte. + * It makes sense to use only with short haystacks when cheap initialization is required. + * There is no option for case-insensitive search for UTF-8 strings. + * It is required that strings are zero-terminated. */ struct LibCASCIICaseSensitiveStringSearcher diff --git a/dbms/src/Common/Throttler.h b/dbms/src/Common/Throttler.h index 75bf6490849..0b242b25110 100644 --- a/dbms/src/Common/Throttler.h +++ b/dbms/src/Common/Throttler.h @@ -1,11 +1,13 @@ #pragma once +#include /// nanosleep #include #include #include #include #include + namespace DB { @@ -15,12 +17,12 @@ namespace ErrorCodes } -/** Allows you to limit the speed of something (in pieces per second) using sleep. +/** Allows you to limit the speed of something (in entities per second) using sleep. * Specifics of work: * - only the average speed is considered, from the moment of the first call of `add` function; * if there were periods with low speed, then during some time after them, the speed will be higher; * - * Also allows you to set a limit on the maximum number of pieces. If you exceed, an exception is thrown. + * Also allows you to set a limit on the maximum number of entities. If exceeded, an exception will be thrown. */ class Throttler { @@ -56,7 +58,7 @@ public: if (max_speed) { - /// How much time would have gone for the speed to become `max_speed`. + /// How much time to wait for the average speed to become `max_speed`. UInt64 desired_ns = new_count * 1000000000 / max_speed; if (desired_ns > elapsed_ns) @@ -65,7 +67,7 @@ public: timespec sleep_ts; sleep_ts.tv_sec = sleep_ns / 1000000000; sleep_ts.tv_nsec = sleep_ns % 1000000000; - nanosleep(&sleep_ts, nullptr); /// NOTE Ends early in case of a signal. This is considered normal. + nanosleep(&sleep_ts, nullptr); /// NOTE Returns early in case of a signal. This is considered normal. } } } diff --git a/dbms/src/Common/VirtualColumnUtils.h b/dbms/src/Common/VirtualColumnUtils.h index cbe0120ea7e..b70245f0333 100644 --- a/dbms/src/Common/VirtualColumnUtils.h +++ b/dbms/src/Common/VirtualColumnUtils.h @@ -16,10 +16,10 @@ class Context; namespace VirtualColumnUtils { -/// Calculate the minimum numeric suffix to add to the row so that it is not present in the set +/// Calculate the minimum numeric suffix to add to the string so that it is not present in the set String chooseSuffix(const NamesAndTypesList & columns, const String & name); -/// Calculate the minimum total numeric suffix to add to each row, +/// Calculate the minimum total numeric suffix to add to each string, /// so that none is present in the set. String chooseSuffixForSet(const NamesAndTypesList & columns, const std::vector & names); diff --git a/dbms/src/Common/Volnitsky.h b/dbms/src/Common/Volnitsky.h index 18c5b1538d1..e1fda9f0bb0 100644 --- a/dbms/src/Common/Volnitsky.h +++ b/dbms/src/Common/Volnitsky.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -12,7 +13,7 @@ /** Search for a substring in a string by Volnitsky's algorithm * http://volnitsky.com/project/str_search/ * - * `haystack` and `needle` can contain null bytes. + * `haystack` and `needle` can contain zero bytes. * * Algorithm: * - if the `needle` is too small or too large, or too small `haystack`, use std::search or memchr; @@ -23,7 +24,7 @@ * - bigrams can be inserted several times if they occur in the needle several times; * - when searching, take from haystack bigram, which should correspond to the last bigram of needle (comparing from the end); * - look for it in the hash table, if found - get the offset from the hash table and compare the string bytewise; - * - if it did not work, we check the next cell of the hash table from the collision resolution chain; + * - if it did not match, we check the next cell of the hash table from the collision resolution chain; * - if not found, skip to haystack almost the size of the needle bytes; * * Unaligned memory access is used. @@ -39,34 +40,35 @@ template class VolnitskyBase { protected: - using offset_t = uint8_t; /// Offset in the needle. For the basic algorithm, the length of the needle must not be greater than 255. - using ngram_t = uint16_t; /// n-gram (2 bytes). + using Offset = UInt8; /// Offset in the needle. For the basic algorithm, the length of the needle must not be greater than 255. + using Ngram = UInt16; /// n-gram (2 bytes). const UInt8 * const needle; const size_t needle_size; const UInt8 * const needle_end = needle + needle_size; /// For how long we move, if the n-gram from haystack is not found in the hash table. - const size_t step = needle_size - sizeof(ngram_t) + 1; + const size_t step = needle_size - sizeof(Ngram) + 1; /** max needle length is 255, max distinct ngrams for case-sensitive is (255 - 1), case-insensitive is 4 * (255 - 1) - * storage of 64K ngrams (n = 2, 128 KB) should be large enough for both cases */ - static const size_t hash_size = 64 * 1024; /// Fits into the L2 cache. - offset_t hash[hash_size]; /// Hash table. + * storage of 64K ngrams (n = 2, 128 KB) should be large enough for both cases */ + static const size_t hash_size = 64 * 1024; /// Fits into the L2 cache (of common Intel CPUs). + Offset hash[hash_size]; /// Hash table. /// min haystack size to use main algorithm instead of fallback static constexpr auto min_haystack_size_for_algorithm = 20000; - const bool fallback; /// Do I need to use the fallback algorithm. + const bool fallback; /// Do we need to use the fallback algorithm. public: - /** haystack_size_hint - the expected total size of the haystack for `search` calls. Can not specify. + /** haystack_size_hint - the expected total size of the haystack for `search` calls. Optional (zero means unspecified). * If you specify it small enough, the fallback algorithm will be used, * since it is considered that it's useless to waste time initializing the hash table. */ VolnitskyBase(const char * const needle, const size_t needle_size, size_t haystack_size_hint = 0) : needle{reinterpret_cast(needle)}, needle_size{needle_size}, fallback{ - needle_size < 2 * sizeof(ngram_t) || needle_size >= std::numeric_limits::max() || - (haystack_size_hint && haystack_size_hint < min_haystack_size_for_algorithm)} + needle_size < 2 * sizeof(Ngram) + || needle_size >= std::numeric_limits::max() + || (haystack_size_hint && haystack_size_hint < min_haystack_size_for_algorithm)} { if (fallback) return; @@ -74,7 +76,7 @@ public: memset(hash, 0, sizeof(hash)); /// int is used here because unsigned can't be used with condition like `i >= 0`, unsigned always >= 0 - for (auto i = static_cast(needle_size - sizeof(ngram_t)); i >= 0; --i) + for (auto i = static_cast(needle_size - sizeof(Ngram)); i >= 0; --i) self().putNGram(this->needle + i, i + 1, this->needle); } @@ -91,7 +93,7 @@ public: return self().search_fallback(haystack, haystack_end); /// Let's "apply" the needle to the haystack and compare the n-gram from the end of the needle. - const auto * pos = haystack + needle_size - sizeof(ngram_t); + const auto * pos = haystack + needle_size - sizeof(Ngram); for (; pos <= haystack_end - needle_size; pos += step) { /// We look at all the cells of the hash table that can correspond to the n-gram from haystack. @@ -119,12 +121,12 @@ protected: CRTP & self() { return static_cast(*this); } const CRTP & self() const { return const_cast(this)->self(); } - static const ngram_t & toNGram(const UInt8 * const pos) + static const Ngram & toNGram(const UInt8 * const pos) { - return *reinterpret_cast(pos); + return *reinterpret_cast(pos); } - void putNGramBase(const ngram_t ngram, const int offset) + void putNGramBase(const Ngram ngram, const int offset) { /// Put the offset for the n-gram in the corresponding cell or the nearest free cell. size_t cell_num = ngram % hash_size; @@ -145,7 +147,7 @@ protected: union { - ngram_t n; + Ngram n; Chars chars; }; @@ -260,7 +262,7 @@ template <> struct VolnitskyImpl : VolnitskyBase struct VolnitskyImpl : VolnitskyBase struct VolnitskyImpl : VolnitskyBase struct VolnitskyImpl : VolnitskyBase -/// Displays the transmitted size in bytes as 123.45 GiB. +/// Displays the passed size in bytes as 123.45 GiB. void formatReadableSizeWithBinarySuffix(double value, DB::WriteBuffer & out, int precision = 2); std::string formatReadableSizeWithBinarySuffix(double value, int precision = 2); -/// Displays the transmitted size in bytes as 132.55 GB. +/// Displays the passed size in bytes as 132.55 GB. void formatReadableSizeWithDecimalSuffix(double value, DB::WriteBuffer & out, int precision = 2); std::string formatReadableSizeWithDecimalSuffix(double value, int precision = 2); diff --git a/dbms/src/Common/getFQDNOrHostName.h b/dbms/src/Common/getFQDNOrHostName.h index ea796426c85..a4367a72622 100644 --- a/dbms/src/Common/getFQDNOrHostName.h +++ b/dbms/src/Common/getFQDNOrHostName.h @@ -2,7 +2,7 @@ #include -/** Get the FQDN for the local server by resolving DNS hostname - similar to calling the hostname utility with the -f flag. - * If it does not work, return hostname - similar to calling hostname without flags or uname -n. +/** Get the FQDN for the local server by resolving DNS hostname - similar to calling the 'hostname' tool with the -f flag. + * If it does not work, return hostname - similar to calling 'hostname' without flags or 'uname -n'. */ const std::string & getFQDNOrHostName(); diff --git a/dbms/src/Common/typeid_cast.h b/dbms/src/Common/typeid_cast.h index a83a414f70e..e335f8f9672 100644 --- a/dbms/src/Common/typeid_cast.h +++ b/dbms/src/Common/typeid_cast.h @@ -16,7 +16,7 @@ namespace DB } -/** Checks match of type by comparing typeid. +/** Checks type by comparing typeid. * The exact match of the type is checked. That is, cast in the ancestor will be unsuccessful. * In the rest, behaves like a dynamic_cast. */ From 27a324b469864723921f46c596c7401a0e6e25d5 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 00:29:36 -0400 Subject: [PATCH 33/76] Tiny modifications [#CLICKHOUSE-2]. --- .../Storages/Distributed/DistributedBlockOutputStream.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index 2e1f4e8b2bc..36359bb8475 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -13,9 +13,11 @@ #include #include -#include #include +#include + +#include #include @@ -124,8 +126,8 @@ void DistributedBlockOutputStream::writeToLocal(const Block & block, const size_ void DistributedBlockOutputStream::writeToShard(const Block & block, const std::vector & dir_names) { /** tmp directory is used to ensure atomicity of transactions - * and keep monitor thread out from reading incomplete data - */ + * and keep monitor thread out from reading incomplete data + */ std::string first_file_tmp_path{}; auto first = true; From 542eba7e177416b66e12b56246d5ea90053d1940 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 00:30:33 -0400 Subject: [PATCH 34/76] Fixed translation errors [#CLICKHOUSE-3]. --- dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h | 2 +- dbms/src/Common/FileChecker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h index eb9f035f5fe..114495d9e5a 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h @@ -100,7 +100,7 @@ public: -/// General case (ineffective). NOTE You can also implement a special case for strings. +/// General case (inefficient). NOTE You can also implement a special case for strings. struct AggregateFunctionGroupArrayDataGeneric { Array value; /// TODO Add MemoryTracker diff --git a/dbms/src/Common/FileChecker.cpp b/dbms/src/Common/FileChecker.cpp index fb5a12c5bf7..66e315fd754 100644 --- a/dbms/src/Common/FileChecker.cpp +++ b/dbms/src/Common/FileChecker.cpp @@ -136,7 +136,7 @@ void FileChecker::load(Map & map) const ReadBufferFromFile in(files_info_path); WriteBufferFromString out(content); - /// The JSON library does not support whitespace. We delete them. Ineffective. + /// The JSON library does not support whitespace. We delete them. Inefficient. while (!in.eof()) { char c; From b9a7917a8de64ec36304fda0459db036de4e247d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 01:43:27 -0400 Subject: [PATCH 35/76] Tiny modifications [#CLICKHOUSE-2]. --- dbms/src/AggregateFunctions/AggregateFunctionGroupArray.cpp | 2 +- dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h | 2 +- dbms/src/AggregateFunctions/IBinaryAggregateFunction.h | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.cpp b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.cpp index 5f52e80eb4a..6989e4ef93a 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.cpp @@ -11,7 +11,7 @@ namespace AggregateFunctionPtr createAggregateFunctionGroupArray(const std::string & name, const DataTypes & argument_types) { if (argument_types.size() != 1) - throw Exception("Incorrect number of arguments for aggregate function " + name, + throw Exception("Incorrect number of arguments for aggregate function " + name + ", should be 2", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); AggregateFunctionPtr res(createWithNumericType(*argument_types[0])); diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h index 114495d9e5a..3bc72c1f974 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArray.h @@ -109,7 +109,7 @@ struct AggregateFunctionGroupArrayDataGeneric /// Puts all values to an array, general case. Implemented inefficiently. class AggregateFunctionGroupArrayGeneric final -: public IUnaryAggregateFunction + : public IUnaryAggregateFunction { private: DataTypePtr type; diff --git a/dbms/src/AggregateFunctions/IBinaryAggregateFunction.h b/dbms/src/AggregateFunctions/IBinaryAggregateFunction.h index 94aea8d947b..1d07cd22f74 100644 --- a/dbms/src/AggregateFunctions/IBinaryAggregateFunction.h +++ b/dbms/src/AggregateFunctions/IBinaryAggregateFunction.h @@ -19,8 +19,7 @@ public: if (arguments.size() != 2) throw Exception{ "Passed " + toString(arguments.size()) + " arguments to binary aggregate function " + this->getName(), - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH - }; + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH}; getDerived().setArgumentsImpl(arguments); } From 21af88775811b56ddd0a7c8b63814c5675f9eb13 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 01:46:23 -0400 Subject: [PATCH 36/76] Added aggregate function 'groupArrayInsertAt' (for Graphite) [#CLICKHOUSE-2]. --- .../AggregateFunctionGroupArrayInsertAt.cpp | 27 +++ .../AggregateFunctionGroupArrayInsertAt.h | 171 ++++++++++++++++++ .../registerAggregateFunctions.cpp | 2 + 3 files changed, 200 insertions(+) create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.cpp create mode 100644 dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.cpp b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.cpp new file mode 100644 index 00000000000..09af12fa132 --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +namespace DB +{ + +namespace +{ + +AggregateFunctionPtr createAggregateFunctionGroupArrayInsertAt(const std::string & name, const DataTypes & argument_types) +{ + if (argument_types.size() != 2) + throw Exception("Incorrect number of arguments for aggregate function " + name + ", should be 2", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + return std::make_shared(); +} + +} + +void registerAggregateFunctionGroupArrayInsertAt(AggregateFunctionFactory & factory) +{ + factory.registerFunction("groupArrayInsertAt", createAggregateFunctionGroupArrayInsertAt); +} + +} diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h new file mode 100644 index 00000000000..3119a38af12 --- /dev/null +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -0,0 +1,171 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include + +#include + +#define AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE 0xFFFFFF + + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int TOO_LARGE_ARRAY_SIZE; +} + + +/** Aggregate function, that takes two arguments: value and position, + * and as a result, builds an array with values are located at corresponding positions. + * + * If more than one value was inserted to single position, the any value (first in case of single thread) is stored. + * If no values was inserted to some position, then default value will be substituted. + * + * Default value is optional parameter for aggregate function. + */ + + +/// Generic case (inefficient). +struct AggregateFunctionGroupArrayInsertAtDataGeneric +{ + Array value; /// TODO Add MemoryTracker +}; + + +class AggregateFunctionGroupArrayInsertAtGeneric final + : public IBinaryAggregateFunction +{ +private: + DataTypePtr type; + Field default_value; + +public: + String getName() const override { return "groupArrayInsertAt"; } + + DataTypePtr getReturnType() const override + { + return std::make_shared(type); + } + + void setArgumentsImpl(const DataTypes & arguments) + { + type = arguments.front(); + } + + void setParameters(const Array & params) override + { + if (params.empty()) + { + default_value = type->getDefault(); + return; + } + + if (params.size() != 1) + throw Exception("Aggregate function " + getName() + " requires at most one parameter.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + default_value = params.front(); + } + + void addImpl(AggregateDataPtr place, const IColumn & column_value, const IColumn & column_position, size_t row_num, Arena *) const + { + /// TODO Do positions need to be 1-based for this function? + size_t position = column_position.get64(row_num); + if (position >= AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE) + throw Exception("Too large array size: position argument (" + toString(position) + ")" + " is greater or equals to limit (" + toString(AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE) + ")", + ErrorCodes::TOO_LARGE_ARRAY_SIZE); + + Array & arr = data(place).value; + + if (arr.size() <= position) + arr.resize(position + 1); + else if (!arr[position].isNull()) + return; /// Element was already inserted to the specified position. + + column_value.get(row_num, arr[position]); + } + + void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override + { + Array & arr_lhs = data(place).value; + const Array & arr_rhs = data(rhs).value; + + if (arr_lhs.size() < arr_rhs.size()) + arr_lhs.resize(arr_rhs.size()); + + for (size_t i = 0, size = arr_lhs.size(); i < size; ++i) + if (arr_lhs[i].isNull() && !arr_rhs[i].isNull()) + arr_lhs[i] = arr_rhs[i]; + } + + void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override + { + const Array & arr = data(place).value; + size_t size = arr.size(); + writeVarUInt(size, buf); + for (const Field & elem : arr) + { + if (elem.isNull()) + { + writeBinary(UInt8(1), buf); + } + else + { + writeBinary(UInt8(0), buf); + type->serializeBinary(elem, buf); + } + } + } + + void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override + { + size_t size = 0; + readVarUInt(size, buf); + + if (size > AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE) + throw Exception("Too large array size", ErrorCodes::TOO_LARGE_ARRAY_SIZE); + + Array & arr = data(place).value; + + arr.resize(size); + for (size_t i = 0; i < size; ++i) + { + UInt8 is_null = 0; + readBinary(is_null, buf); + if (!is_null) + type->deserializeBinary(arr[i], buf); + } + } + + void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override + { + ColumnArray & to_array = static_cast(to); + IColumn & to_data = to_array.getData(); + ColumnArray::Offsets_t & to_offsets = to_array.getOffsets(); + + const Array & arr = data(place).value; + + for (const Field & elem : arr) + { + if (!elem.isNull()) + to_data.insert(elem); + else + to_data.insert(default_value); + } + + to_offsets.push_back(arr.size()); + } +}; + + +#undef AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE + +} diff --git a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp index e690af7eb83..5c8646fd583 100644 --- a/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp +++ b/dbms/src/AggregateFunctions/registerAggregateFunctions.cpp @@ -9,6 +9,7 @@ void registerAggregateFunctionAvg(AggregateFunctionFactory & factory); void registerAggregateFunctionCount(AggregateFunctionFactory & factory); void registerAggregateFunctionGroupArray(AggregateFunctionFactory & factory); void registerAggregateFunctionGroupUniqArray(AggregateFunctionFactory & factory); +void registerAggregateFunctionGroupArrayInsertAt(AggregateFunctionFactory & factory); void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory); void registerAggregateFunctionsQuantileExact(AggregateFunctionFactory & factory); void registerAggregateFunctionsQuantileExactWeighted(AggregateFunctionFactory & factory); @@ -33,6 +34,7 @@ void registerAggregateFunctions() registerAggregateFunctionCount(factory); registerAggregateFunctionGroupArray(factory); registerAggregateFunctionGroupUniqArray(factory); + registerAggregateFunctionGroupArrayInsertAt(factory); registerAggregateFunctionsQuantile(factory); registerAggregateFunctionsQuantileExact(factory); registerAggregateFunctionsQuantileExactWeighted(factory); From e2f8ec8f2dbf86bad5ec79a477001b5a71d69bd5 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 02:36:15 -0400 Subject: [PATCH 37/76] Addition to prev. revision [#CLICKHOUSE-2]. --- dbms/src/Common/SipHash.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dbms/src/Common/SipHash.h b/dbms/src/Common/SipHash.h index 10e5d642ebb..55b4574d851 100644 --- a/dbms/src/Common/SipHash.h +++ b/dbms/src/Common/SipHash.h @@ -15,15 +15,15 @@ #include -#define ROTL(x,b) static_cast( ((x) << (b)) | ( (x) >> (64 - (b))) ) +#define ROTL(x, b) static_cast(((x) << (b)) | ((x) >> (64 - (b)))) -#define SIPROUND \ - do \ - { \ - v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ - v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ - v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ - v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ +#define SIPROUND \ + do \ + { \ + v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; v0 = ROTL(v0, 32); \ + v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \ + v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \ + v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; v2 = ROTL(v2, 32); \ } while(0) From acfe3d5028350fc5415f1c8dd39ef58b8ca6e41b Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 02:39:37 -0400 Subject: [PATCH 38/76] Improved performance of inserting into StorageDistributed with very high number of shards (not tested) [#CLICKHOUSE-2]. --- .../DistributedBlockOutputStream.cpp | 3 +- dbms/src/Storages/StorageDistributed.cpp | 90 ++++++++++++++----- dbms/src/Storages/StorageDistributed.h | 4 + 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index 36359bb8475..99ded795581 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -142,7 +141,7 @@ void DistributedBlockOutputStream::writeToShard(const Block & block, const std:: if (Poco::File(path).createDirectory()) storage.requireDirectoryMonitor(dir_name); - const auto & file_name = toString(Increment{path + "increment.txt"}.get(true)) + ".bin"; + const auto & file_name = toString(storage.file_names_increment.get()) + ".bin"; const auto & block_file_path = path + file_name; /** on first iteration write block to a temporary directory for subsequent hardlinking to ensure diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 9f9f34da749..3b2093be68b 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -38,6 +38,8 @@ #include +#include + namespace DB { @@ -53,29 +55,70 @@ namespace ErrorCodes namespace { - /// select query has database and table names as AST pointers - /// Creates a copy of query, changes database and table names. - inline ASTPtr rewriteSelectQuery(const ASTPtr & query, const std::string & database, const std::string & table) + +/// select query has database and table names as AST pointers +/// Creates a copy of query, changes database and table names. +ASTPtr rewriteSelectQuery(const ASTPtr & query, const std::string & database, const std::string & table) +{ + auto modified_query_ast = query->clone(); + typeid_cast(*modified_query_ast).replaceDatabaseAndTable(database, table); + return modified_query_ast; +} + +/// insert query has database and table names as bare strings +/// Creates a copy of query, changes the database and table names. +ASTPtr rewriteInsertQuery(const ASTPtr & query, const std::string & database, const std::string & table) +{ + auto modified_query_ast = query->clone(); + + auto & actual_query = typeid_cast(*modified_query_ast); + actual_query.database = database; + actual_query.table = table; + /// make sure query is not INSERT SELECT + actual_query.select = nullptr; + + return modified_query_ast; +} + +/// Calculate maximum number in file names in directory and all subdirectories. +/// To ensure global order of data blocks yet to be sent across server restarts. +UInt64 getMaximumFileNumber(const std::string & path) +{ + UInt64 res = 0; + + boost::filesystem::recursive_directory_iterator begin(path); + boost::filesystem::recursive_directory_iterator end; + for (auto it = begin; it != end; ++it) { - auto modified_query_ast = query->clone(); - typeid_cast(*modified_query_ast).replaceDatabaseAndTable(database, table); - return modified_query_ast; + const auto & path = it->path(); + + if (it->status().type() != boost::filesystem::regular_file || !endsWith(path.filename().string(), ".bin")) + continue; + + UInt64 num = 0; + try + { + num = parse(path.filename().stem().string()); + } + catch (Exception & e) + { + e.addMessage("Unexpected file name " + path.filename().string() + " found at " + path.parent_path().string() + ", should have numeric base name."); + throw; + } + + if (num > res) + res = num; } - /// insert query has database and table names as bare strings - /// Creates a copy of query, changes the database and table names. - inline ASTPtr rewriteInsertQuery(const ASTPtr & query, const std::string & database, const std::string & table) - { - auto modified_query_ast = query->clone(); + return res; +} - auto & actual_query = typeid_cast(*modified_query_ast); - actual_query.database = database; - actual_query.table = table; - /// make sure query is not INSERT SELECT - actual_query.select = nullptr; +void initializeFileNamesIncrement(const std::string & path, SimpleIncrement & increment) +{ + if (!path.empty()) + increment.set(getMaximumFileNumber(path)); +} - return modified_query_ast; - } } @@ -96,6 +139,7 @@ StorageDistributed::StorageDistributed( path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/')) { createDirectoryMonitors(); + initializeFileNamesIncrement(path, file_names_increment); } @@ -120,6 +164,7 @@ StorageDistributed::StorageDistributed( path(data_path_.empty() ? "" : (data_path_ + escapeForFileName(name) + '/')) { createDirectoryMonitors(); + initializeFileNamesIncrement(path, file_names_increment); } @@ -443,10 +488,11 @@ void StorageDistributed::createDirectoryMonitors() Poco::File{path}.createDirectory(); - Poco::DirectoryIterator end; - for (Poco::DirectoryIterator it{path}; it != end; ++it) - if (it->isDirectory()) - createDirectoryMonitor(it.name()); + boost::filesystem::directory_iterator begin(path); + boost::filesystem::directory_iterator end; + for (auto it = begin; it != end; ++it) + if (it->status().type() == boost::filesystem::directory_file) + createDirectoryMonitor(it->path().filename().string()); } diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index db6c3417ef4..3a008b416b8 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -159,6 +160,9 @@ private: String path; /// Can be empty if data_path_ is empty. In this case, a directory for the data to be sent is not created. std::unordered_map> directory_monitors; + + /// Used for global monotonic ordering of files to send. + SimpleIncrement file_names_increment; }; } From 5ca7650c86d477d9f72b25df3294c51533f971fc Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 02:49:19 -0400 Subject: [PATCH 39/76] Removed Increment and CounterInFile [#CLICKHOUSE-2]. --- dbms/src/Common/CounterInFile.h | 184 ------------------ dbms/src/Common/Increment.h | 87 --------- dbms/src/Common/SimpleIncrement.h | 21 ++ dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- .../MergeTree/MergeTreeDataMerger.cpp | 2 +- dbms/src/Storages/StorageDistributed.h | 2 +- dbms/src/Storages/StorageMergeTree.h | 2 +- 7 files changed, 25 insertions(+), 275 deletions(-) delete mode 100644 dbms/src/Common/CounterInFile.h delete mode 100644 dbms/src/Common/Increment.h create mode 100644 dbms/src/Common/SimpleIncrement.h diff --git a/dbms/src/Common/CounterInFile.h b/dbms/src/Common/CounterInFile.h deleted file mode 100644 index 99320a1fbfd..00000000000 --- a/dbms/src/Common/CounterInFile.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define SMALL_READ_WRITE_BUFFER_SIZE 16 - - -/** Stores a number in the file. - * Designed for rare calls (not designed for performance). - */ -class CounterInFile -{ -public: - /// path - the name of the file, including the path - CounterInFile(const std::string & path_) : path(path_) {} - - /** Add `delta` to the number in the file and return the new value. - * If the `create_if_need` parameter is not set to true, then - * the file should already have a number written (if not - create the file manually with zero). - * - * To protect against race conditions between different processes, file locks are used. - * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) - * - * `locked_callback` is called when the counter file is locked. A new value is passed to it. - * `locked_callback` can be used to do something atomically with incrementing the counter (for example, renaming files). - */ - template - Int64 add(Int64 delta, Callback && locked_callback, bool create_if_need = false) - { - std::lock_guard lock(mutex); - - Int64 res = -1; - - bool file_doesnt_exists = !Poco::File(path).exists(); - if (file_doesnt_exists && !create_if_need) - { - throw Poco::Exception("File " + path + " does not exist. " - "You must create it manulally with appropriate value or 0 for first start."); - } - - int fd = open(path.c_str(), O_RDWR | O_CREAT, 0666); - if (-1 == fd) - DB::throwFromErrno("Cannot open file " + path); - - try - { - int flock_ret = flock(fd, LOCK_EX); - if (-1 == flock_ret) - DB::throwFromErrno("Cannot lock file " + path); - - if (!file_doesnt_exists) - { - DB::ReadBufferFromFileDescriptor rb(fd, SMALL_READ_WRITE_BUFFER_SIZE); - try - { - DB::readIntText(res, rb); - } - catch (const DB::Exception & e) - { - /// A more understandable error message. - if (e.code() == DB::ErrorCodes::CANNOT_READ_ALL_DATA || e.code() == DB::ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) - throw DB::Exception("File " + path + " is empty. You must fill it manually with appropriate value.", e.code()); - else - throw; - } - } - else - res = 0; - - if (delta || file_doesnt_exists) - { - res += delta; - - DB::WriteBufferFromFileDescriptor wb(fd, SMALL_READ_WRITE_BUFFER_SIZE); - wb.seek(0); - wb.truncate(); - DB::writeIntText(res, wb); - DB::writeChar('\n', wb); - wb.sync(); - } - - locked_callback(res); - } - catch (...) - { - close(fd); - throw; - } - - close(fd); - return res; - } - - Int64 add(Int64 delta, bool create_if_need = false) - { - return add(delta, [](UInt64){}, create_if_need); - } - - const std::string & getPath() const - { - return path; - } - - /// Change the path to the file. - void setPath(std::string path_) - { - path = path_; - } - - // Not thread-safe and not synchronized between processes. - void fixIfBroken(UInt64 value) - { - bool file_exists = Poco::File(path).exists(); - - int fd = open(path.c_str(), O_RDWR | O_CREAT, 0666); - if (-1 == fd) - DB::throwFromErrno("Cannot open file " + path); - - try - { - bool broken = true; - - if (file_exists) - { - DB::ReadBufferFromFileDescriptor rb(fd, SMALL_READ_WRITE_BUFFER_SIZE); - try - { - UInt64 current_value; - DB::readIntText(current_value, rb); - char c; - DB::readChar(c, rb); - if (rb.count() > 0 && c == '\n' && rb.eof()) - broken = false; - } - catch (const DB::Exception & e) - { - if (e.code() != DB::ErrorCodes::CANNOT_READ_ALL_DATA && e.code() != DB::ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) - throw; - } - } - - if (broken) - { - DB::WriteBufferFromFileDescriptor wb(fd, SMALL_READ_WRITE_BUFFER_SIZE); - wb.seek(0); - wb.truncate(); - DB::writeIntText(value, wb); - DB::writeChar('\n', wb); - wb.sync(); - } - } - catch (...) - { - close(fd); - throw; - } - - close(fd); - } - -private: - std::string path; - std::mutex mutex; -}; - - -#undef SMALL_READ_WRITE_BUFFER_SIZE diff --git a/dbms/src/Common/Increment.h b/dbms/src/Common/Increment.h deleted file mode 100644 index c03c6ef5575..00000000000 --- a/dbms/src/Common/Increment.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include - - -/** Allows to get an auto-increment number, storing it in a file. - * Intended for rare calls (not designed for performance). - */ -class Increment -{ -public: - /// path - the name of the file, including the path - Increment(const std::string & path_) : counter(path_) {} - - /** Get the next number. - * If the `create_if_need` parameter is not set to true, then - * the file must already have a number written (if not - create the file manually with zero). - * - * To protect against race conditions between different processes, file locks are used. - * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) - * - * `locked_callback` is called when the counter file is locked. A new value is passed to it. - * `locked_callback` can be used to do something atomically with the increment of the counter (for example, rename files). - */ - template - UInt64 get(Callback && locked_callback, bool create_if_need = false) - { - return static_cast(counter.add(1, std::forward(locked_callback), create_if_need)); - } - - UInt64 get(bool create_if_need = false) - { - return getBunch(1, create_if_need); - } - - /// Peek the next value. - UInt64 peek(bool create_if_need = false) - { - return getBunch(0, create_if_need); - } - - /** Get the next number and increase the counter by `count`. - * If the `create_if_need` parameter is not set to true, then - * the file should already have a number written (if not - create the file manually with zero). - * - * To protect against race conditions between different processes, file locks are used. - * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) - */ - UInt64 getBunch(UInt64 count, bool create_if_need = false) - { - return static_cast(counter.add(static_cast(count), create_if_need) - count + 1); - } - - /// Change the path to the file. - void setPath(std::string path_) - { - counter.setPath(path_); - } - - void fixIfBroken(UInt64 value) - { - counter.fixIfBroken(value); - } - -private: - CounterInFile counter; -}; - - -/** The same, but without storing it in a file. - */ -struct SimpleIncrement : private boost::noncopyable -{ - std::atomic value; - - SimpleIncrement(UInt64 start = 0) : value(start) {} - - void set(UInt64 new_value) - { - value = new_value; - } - - UInt64 get() - { - return ++value; - } -}; diff --git a/dbms/src/Common/SimpleIncrement.h b/dbms/src/Common/SimpleIncrement.h new file mode 100644 index 00000000000..32180ca6466 --- /dev/null +++ b/dbms/src/Common/SimpleIncrement.h @@ -0,0 +1,21 @@ +#pragma once + +#include + + +struct SimpleIncrement +{ + std::atomic value; + + SimpleIncrement(UInt64 start = 0) : value(start) {} + + void set(UInt64 new_value) + { + value = new_value; + } + + UInt64 get() + { + return ++value; + } +}; diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index efea7b58feb..bc16caa2ba5 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index 61b3a6a1626..dea080e9a18 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 3a008b416b8..4cac100568b 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/dbms/src/Storages/StorageMergeTree.h b/dbms/src/Storages/StorageMergeTree.h index ea8af476c46..6d4ab228f00 100644 --- a/dbms/src/Storages/StorageMergeTree.h +++ b/dbms/src/Storages/StorageMergeTree.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace DB From bb41d4709657cdc638f25ce3b362e350d45bd70a Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 02:50:37 -0400 Subject: [PATCH 40/76] Removed Increment and CounterInFile [#CLICKHOUSE-2]. --- dbms/src/Common/SimpleIncrement.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dbms/src/Common/SimpleIncrement.h b/dbms/src/Common/SimpleIncrement.h index 32180ca6466..29e0010b0fa 100644 --- a/dbms/src/Common/SimpleIncrement.h +++ b/dbms/src/Common/SimpleIncrement.h @@ -1,8 +1,11 @@ #pragma once #include +#include +/** Is used for numbering of files. + */ struct SimpleIncrement { std::atomic value; From a7b9a1275983cc6b9d4b57846803d2fb0ba24390 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:08:32 -0400 Subject: [PATCH 41/76] Returned back Increment and CounterInFile, because they are still needed [#CLICKHOUSE-2]. --- dbms/src/Common/CounterInFile.h | 184 ++++++++++++++++++ dbms/src/Common/Increment.h | 87 +++++++++ dbms/src/Storages/MergeTree/MergeTreeData.cpp | 1 + 3 files changed, 272 insertions(+) create mode 100644 dbms/src/Common/CounterInFile.h create mode 100644 dbms/src/Common/Increment.h diff --git a/dbms/src/Common/CounterInFile.h b/dbms/src/Common/CounterInFile.h new file mode 100644 index 00000000000..99320a1fbfd --- /dev/null +++ b/dbms/src/Common/CounterInFile.h @@ -0,0 +1,184 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define SMALL_READ_WRITE_BUFFER_SIZE 16 + + +/** Stores a number in the file. + * Designed for rare calls (not designed for performance). + */ +class CounterInFile +{ +public: + /// path - the name of the file, including the path + CounterInFile(const std::string & path_) : path(path_) {} + + /** Add `delta` to the number in the file and return the new value. + * If the `create_if_need` parameter is not set to true, then + * the file should already have a number written (if not - create the file manually with zero). + * + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) + * + * `locked_callback` is called when the counter file is locked. A new value is passed to it. + * `locked_callback` can be used to do something atomically with incrementing the counter (for example, renaming files). + */ + template + Int64 add(Int64 delta, Callback && locked_callback, bool create_if_need = false) + { + std::lock_guard lock(mutex); + + Int64 res = -1; + + bool file_doesnt_exists = !Poco::File(path).exists(); + if (file_doesnt_exists && !create_if_need) + { + throw Poco::Exception("File " + path + " does not exist. " + "You must create it manulally with appropriate value or 0 for first start."); + } + + int fd = open(path.c_str(), O_RDWR | O_CREAT, 0666); + if (-1 == fd) + DB::throwFromErrno("Cannot open file " + path); + + try + { + int flock_ret = flock(fd, LOCK_EX); + if (-1 == flock_ret) + DB::throwFromErrno("Cannot lock file " + path); + + if (!file_doesnt_exists) + { + DB::ReadBufferFromFileDescriptor rb(fd, SMALL_READ_WRITE_BUFFER_SIZE); + try + { + DB::readIntText(res, rb); + } + catch (const DB::Exception & e) + { + /// A more understandable error message. + if (e.code() == DB::ErrorCodes::CANNOT_READ_ALL_DATA || e.code() == DB::ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) + throw DB::Exception("File " + path + " is empty. You must fill it manually with appropriate value.", e.code()); + else + throw; + } + } + else + res = 0; + + if (delta || file_doesnt_exists) + { + res += delta; + + DB::WriteBufferFromFileDescriptor wb(fd, SMALL_READ_WRITE_BUFFER_SIZE); + wb.seek(0); + wb.truncate(); + DB::writeIntText(res, wb); + DB::writeChar('\n', wb); + wb.sync(); + } + + locked_callback(res); + } + catch (...) + { + close(fd); + throw; + } + + close(fd); + return res; + } + + Int64 add(Int64 delta, bool create_if_need = false) + { + return add(delta, [](UInt64){}, create_if_need); + } + + const std::string & getPath() const + { + return path; + } + + /// Change the path to the file. + void setPath(std::string path_) + { + path = path_; + } + + // Not thread-safe and not synchronized between processes. + void fixIfBroken(UInt64 value) + { + bool file_exists = Poco::File(path).exists(); + + int fd = open(path.c_str(), O_RDWR | O_CREAT, 0666); + if (-1 == fd) + DB::throwFromErrno("Cannot open file " + path); + + try + { + bool broken = true; + + if (file_exists) + { + DB::ReadBufferFromFileDescriptor rb(fd, SMALL_READ_WRITE_BUFFER_SIZE); + try + { + UInt64 current_value; + DB::readIntText(current_value, rb); + char c; + DB::readChar(c, rb); + if (rb.count() > 0 && c == '\n' && rb.eof()) + broken = false; + } + catch (const DB::Exception & e) + { + if (e.code() != DB::ErrorCodes::CANNOT_READ_ALL_DATA && e.code() != DB::ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) + throw; + } + } + + if (broken) + { + DB::WriteBufferFromFileDescriptor wb(fd, SMALL_READ_WRITE_BUFFER_SIZE); + wb.seek(0); + wb.truncate(); + DB::writeIntText(value, wb); + DB::writeChar('\n', wb); + wb.sync(); + } + } + catch (...) + { + close(fd); + throw; + } + + close(fd); + } + +private: + std::string path; + std::mutex mutex; +}; + + +#undef SMALL_READ_WRITE_BUFFER_SIZE diff --git a/dbms/src/Common/Increment.h b/dbms/src/Common/Increment.h new file mode 100644 index 00000000000..c03c6ef5575 --- /dev/null +++ b/dbms/src/Common/Increment.h @@ -0,0 +1,87 @@ +#pragma once + +#include + + +/** Allows to get an auto-increment number, storing it in a file. + * Intended for rare calls (not designed for performance). + */ +class Increment +{ +public: + /// path - the name of the file, including the path + Increment(const std::string & path_) : counter(path_) {} + + /** Get the next number. + * If the `create_if_need` parameter is not set to true, then + * the file must already have a number written (if not - create the file manually with zero). + * + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) + * + * `locked_callback` is called when the counter file is locked. A new value is passed to it. + * `locked_callback` can be used to do something atomically with the increment of the counter (for example, rename files). + */ + template + UInt64 get(Callback && locked_callback, bool create_if_need = false) + { + return static_cast(counter.add(1, std::forward(locked_callback), create_if_need)); + } + + UInt64 get(bool create_if_need = false) + { + return getBunch(1, create_if_need); + } + + /// Peek the next value. + UInt64 peek(bool create_if_need = false) + { + return getBunch(0, create_if_need); + } + + /** Get the next number and increase the counter by `count`. + * If the `create_if_need` parameter is not set to true, then + * the file should already have a number written (if not - create the file manually with zero). + * + * To protect against race conditions between different processes, file locks are used. + * (But when the first file is created, the race condition is possible, so it's better to create the file in advance.) + */ + UInt64 getBunch(UInt64 count, bool create_if_need = false) + { + return static_cast(counter.add(static_cast(count), create_if_need) - count + 1); + } + + /// Change the path to the file. + void setPath(std::string path_) + { + counter.setPath(path_); + } + + void fixIfBroken(UInt64 value) + { + counter.fixIfBroken(value); + } + +private: + CounterInFile counter; +}; + + +/** The same, but without storing it in a file. + */ +struct SimpleIncrement : private boost::noncopyable +{ + std::atomic value; + + SimpleIncrement(UInt64 start = 0) : value(start) {} + + void set(UInt64 new_value) + { + value = new_value; + } + + UInt64 get() + { + return ++value; + } +}; diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index bc16caa2ba5..1662a0f208f 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include From e5e8667bc966b8e4e2db0dd644b7bbe7fde5291d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:10:50 -0400 Subject: [PATCH 42/76] Addition to prev. revision [#CLICKHOUSE-2]. --- dbms/src/Common/Increment.h | 20 ------------------- .../MergeTree/MergeTreeDataMerger.cpp | 2 ++ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/dbms/src/Common/Increment.h b/dbms/src/Common/Increment.h index c03c6ef5575..45ef604ccd9 100644 --- a/dbms/src/Common/Increment.h +++ b/dbms/src/Common/Increment.h @@ -65,23 +65,3 @@ public: private: CounterInFile counter; }; - - -/** The same, but without storing it in a file. - */ -struct SimpleIncrement : private boost::noncopyable -{ - std::atomic value; - - SimpleIncrement(UInt64 start = 0) : value(start) {} - - void set(UInt64 new_value) - { - value = new_value; - } - - UInt64 get() - { - return ++value; - } -}; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index dea080e9a18..45a4bcb22e9 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include #include From 19d0d47c8a41656ecde1ae1f11703f0cc23d6ddd Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:40:14 -0400 Subject: [PATCH 43/76] Aggregate function groupArrayInsertAt: development [#CLICKHOUSE-2]. --- .../AggregateFunctionGroupArrayInsertAt.h | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h index 3119a38af12..86dae149026 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -9,6 +9,9 @@ #include #include +#include +#include + #include #define AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE 0xFFFFFF @@ -20,6 +23,8 @@ namespace DB namespace ErrorCodes { extern const int TOO_LARGE_ARRAY_SIZE; + extern const int CANNOT_CONVERT_TYPE; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; } @@ -57,16 +62,28 @@ public: void setArgumentsImpl(const DataTypes & arguments) { + if (!arguments.at(1)->behavesAsNumber()) /// TODO filter out floating point types. + throw Exception("Second argument of aggregate function " + getName() + " must be integer.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + type = arguments.front(); + + if (default_value.isNull()) + default_value = type->getDefault(); + else + { + Field converted = convertFieldToType(default_value, *type); + if (converted.isNull()) + throw Exception("Cannot convert parameter of aggregate function " + getName() + " (" + applyVisitor(FieldVisitorToString(), default_value) + ")" + " to type " + type->getName() + " to be used as default value in array", ErrorCodes::CANNOT_CONVERT_TYPE); + + default_value = converted; + } } void setParameters(const Array & params) override { if (params.empty()) - { - default_value = type->getDefault(); return; - } if (params.size() != 1) throw Exception("Aggregate function " + getName() + " requires at most one parameter.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); From 21c5ee0f1df2dd10a2ee463be5349e46244d1b84 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:41:25 -0400 Subject: [PATCH 44/76] Aggregate function groupArrayInsertAt: development [#CLICKHOUSE-2]. --- .../AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h index 86dae149026..d4505d66943 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -178,7 +178,7 @@ public: to_data.insert(default_value); } - to_offsets.push_back(arr.size()); + to_offsets.push_back(to_offsets.back() + arr.size()); } }; From 2a57cfdbc2c6abd2d9edd5dcc628c0d10f976fd3 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:42:15 -0400 Subject: [PATCH 45/76] Aggregate function groupArrayInsertAt: development [#CLICKHOUSE-2]. --- .../AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h index d4505d66943..d92b8cbefd1 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -178,7 +178,7 @@ public: to_data.insert(default_value); } - to_offsets.push_back(to_offsets.back() + arr.size()); + to_offsets.push_back((to_offsets.empty() ? 0 : to_offsets.back()) + arr.size()); } }; From 66436db836c0323e60725d7563eebab6ffa1f79b Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 10 May 2017 04:46:07 -0400 Subject: [PATCH 46/76] Added test [#CLICKHOUSE-2]. --- .../00459_group_array_insert_at.reference | 13 +++++++++++++ .../0_stateless/00459_group_array_insert_at.sql | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference create mode 100644 dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference new file mode 100644 index 00000000000..d10d5acfc83 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference @@ -0,0 +1,13 @@ +['0','','1','','2','','3','','4','','5','','6','','7','','8','','9'] +['0','-','1','-','2','-','3','-','4','-','5','-','6','-','7','-','8','-','9'] +[[],[123],[0],[123],[0,1],[123],[0,1,2],[123],[0,1,2,3],[123],[0,1,2,3,4],[123],[0,1,2,3,4,5],[123],[0,1,2,3,4,5,6],[123],[0,1,2,3,4,5,6,7],[123],[0,1,2,3,4,5,6,7,8]] +0 [0] +1 [0,1] +2 [0,0,2] +3 [0,0,0,3] +4 [0,0,0,0,4] +5 [0,0,0,0,0,5] +6 [0,0,0,0,0,0,6] +7 [0,0,0,0,0,0,0,7] +8 [0,0,0,0,0,0,0,0,8] +9 [0,0,0,0,0,0,0,0,0,9] diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql new file mode 100644 index 00000000000..fc91473ad21 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql @@ -0,0 +1,4 @@ +SELECT groupArrayInsertAt(toString(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); +SELECT groupArrayInsertAt('-')(toString(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); +SELECT groupArrayInsertAt([123])(range(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); +SELECT number, groupArrayInsertAt(number, number) FROM (SELECT * FROM system.numbers LIMIT 10) GROUP BY number ORDER BY number; From a21a6caf4ed93dfdc4b25a7287a3ae9221f52839 Mon Sep 17 00:00:00 2001 From: Dmitry Luhtionov Date: Mon, 8 May 2017 13:02:10 +0300 Subject: [PATCH 47/76] =?UTF-8?q?=D0=94=D0=BE=D1=8E=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=84=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20FunctionMACNumToString=20=D0=B8=20FunctionMACStringToNum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dbms/src/Functions/FunctionsCoding.cpp | 2 + dbms/src/Functions/FunctionsCoding.h | 205 +++++++++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/dbms/src/Functions/FunctionsCoding.cpp b/dbms/src/Functions/FunctionsCoding.cpp index 32e64ddb83d..12f3f7c315f 100644 --- a/dbms/src/Functions/FunctionsCoding.cpp +++ b/dbms/src/Functions/FunctionsCoding.cpp @@ -14,6 +14,8 @@ void registerFunctionsCoding(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); + factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); diff --git a/dbms/src/Functions/FunctionsCoding.h b/dbms/src/Functions/FunctionsCoding.h index 96a5ac965a8..3258608ad9c 100644 --- a/dbms/src/Functions/FunctionsCoding.h +++ b/dbms/src/Functions/FunctionsCoding.h @@ -985,6 +985,211 @@ private: }; +class FunctionMACNumToString : public IFunction +{ +public: + static constexpr auto name = "MACNumToString"; + static FunctionPtr create(const Context & context) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 1; } + bool isInjective(const Block &) override { return true; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!typeid_cast(&*arguments[0])) + throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName() + ", expected UInt64", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + static void formatMAC(UInt64 mac, char *& out) + { + char * begin = out; + + /// mapping of digits up to base 16 + static char digits[] = "0123456789ABCDEF"; + + /// Запишем все задом наперед. + for (size_t offset = 0; offset <= 40; offset += 8) + { + if (offset > 0) + *(out++) = ':'; + + /// Достаем очередной байт. + UInt64 value = (mac >> offset) & static_cast(255); + + /// Быстрее, чем sprintf. + if (value < 16) + { + *(out++) = '0'; + } + if (value == 0) + { + *(out++) = '0'; + } + else + { + while (value > 0) + { + *(out++) = digits[value % 16]; + value /= 16; + } + } + } + + /// И развернем. + std::reverse(begin, out); + + *(out++) = '\0'; + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override + { + const ColumnPtr & column = block.safeGetByPosition(arguments[0]).column; + + if (const ColumnUInt64 * col = typeid_cast(column.get())) + { + const ColumnUInt64::Container_t & vec_in = col->getData(); + + std::shared_ptr col_res = std::make_shared(); + block.safeGetByPosition(result).column = col_res; + + ColumnString::Chars_t & vec_res = col_res->getChars(); + ColumnString::Offsets_t & offsets_res = col_res->getOffsets(); + + vec_res.resize(vec_in.size() * 18); /// самое длинное значение: xx:xx:xx:xx:xx:xx\0 + offsets_res.resize(vec_in.size()); + char * begin = reinterpret_cast(&vec_res[0]); + char * pos = begin; + + for (size_t i = 0; i < vec_in.size(); ++i) + { + formatMAC(vec_in[i], pos); + offsets_res[i] = pos - begin; + } + + vec_res.resize(pos - begin); + } + else if (const ColumnConst * col = typeid_cast *>(column.get())) + { + char buf[18]; + char * pos = buf; + formatMAC(col->getData(), pos); + + auto col_res = std::make_shared(col->size(), buf); + block.safeGetByPosition(result).column = col_res; + } + else + throw Exception("Illegal column " + block.safeGetByPosition(arguments[0]).column->getName() + + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } +}; + + +class FunctionMACStringToNum : public IFunction +{ +public: + static constexpr auto name = "MACStringToNum"; + static FunctionPtr create(const Context & context) { return std::make_shared(); } + + String getName() const override + { + return name; + } + + size_t getNumberOfArguments() const override { return 1; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!typeid_cast(&*arguments[0])) + throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + static UInt64 parseMAC(const char * pos) + { + + /// get integer value for a hexademical char digit, or -1 + const auto number_by_char = [] (const char ch) + { + if ('A' <= ch && ch <= 'F') + return 10 + ch - 'A'; + + if ('a' <= ch && ch <= 'f') + return 10 + ch - 'a'; + + if ('0' <= ch && ch <= '9') + return ch - '0'; + + return -1; + }; + + UInt64 res = 0; + for (int offset = 40; offset >= 0; offset -= 8) + { + UInt64 value = 0; + size_t len = 0; + int val = 0; + while ((val = number_by_char(*pos)) >= 0 && len <= 2) + { + value = value * 16 + val; + ++len; + ++pos; + } + if (len == 0 || value > 255 || (offset > 0 && *pos != ':')) + return 0; + res |= value << offset; + ++pos; + } + if (*(pos - 1) != '\0') + return 0; + return res; + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override + { + const ColumnPtr & column = block.safeGetByPosition(arguments[0]).column; + + if (const ColumnString * col = typeid_cast(column.get())) + { + auto col_res = std::make_shared(); + block.safeGetByPosition(result).column = col_res; + + ColumnUInt64::Container_t & vec_res = col_res->getData(); + vec_res.resize(col->size()); + + const ColumnString::Chars_t & vec_src = col->getChars(); + const ColumnString::Offsets_t & offsets_src = col->getOffsets(); + size_t prev_offset = 0; + + for (size_t i = 0; i < vec_res.size(); ++i) + { + vec_res[i] = parseMAC(reinterpret_cast(&vec_src[prev_offset])); + prev_offset = offsets_src[i]; + } + } + else if (const ColumnConstString * col = typeid_cast(column.get())) + { + auto col_res = std::make_shared>(col->size(), parseMAC(col->getData().c_str())); + block.safeGetByPosition(result).column = col_res; + } + else + throw Exception("Illegal column " + block.safeGetByPosition(arguments[0]).column->getName() + + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } +}; + + class FunctionUUIDNumToString : public IFunction { private: From 0f1627691e557d797a7b88ddcefa4ed34ab92c37 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 11 May 2017 17:05:08 +0300 Subject: [PATCH 48/76] Don't forget to ATTACH MATERIALIZED columns. [#CLICKHOUSE-1993] --- .../Storages/MergeTree/MergeTreeDataPart.cpp | 12 ++++-- .../0_stateless/00428_partition.reference | 6 +++ .../queries/0_stateless/00428_partition.sh | 41 +++++++++++++++++++ .../queries/0_stateless/00428_partition.sql | 9 ---- 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100755 dbms/tests/queries/0_stateless/00428_partition.sh delete mode 100644 dbms/tests/queries/0_stateless/00428_partition.sql diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index a995be61138..56f9ea069d8 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -565,11 +565,17 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - for (const NameAndTypePair & column : *storage.columns) - { + + auto add_column_if_exists = [this] (const NameAndTypePair & column) { if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); - } + }; + + for (const NameAndTypePair & column : *storage.columns) + add_column_if_exists(column); + + for (const NameAndTypePair & column : storage.materialized_columns) + add_column_if_exists(column); if (columns.empty()) throw Exception("No columns in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); diff --git a/dbms/tests/queries/0_stateless/00428_partition.reference b/dbms/tests/queries/0_stateless/00428_partition.reference index e69de29bb2d..788600df41e 100644 --- a/dbms/tests/queries/0_stateless/00428_partition.reference +++ b/dbms/tests/queries/0_stateless/00428_partition.reference @@ -0,0 +1,6 @@ +5 +5 +5 +5 +31,1,2 +1,2,3 diff --git a/dbms/tests/queries/0_stateless/00428_partition.sh b/dbms/tests/queries/0_stateless/00428_partition.sh new file mode 100755 index 00000000000..293a7a60836 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00428_partition.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e +# Not found column date in block. There are only columns: x. + +# Test 1. Complex test checking columns.txt + +chl="clickhouse-client -q" +ch_dir=`clickhouse --extract-from-config -c /etc/clickhouse-server/config.xml -k path` + +$chl "DROP TABLE IF EXISTS partition_428" +$chl "CREATE TABLE test.partition_428 (p Date, k Int8, v1 Int8 MATERIALIZED k + 1) ENGINE = MergeTree(p, k, 1)" +$chl "INSERT INTO test.partition_428 (p, k) VALUES(toDate(31), 1)" +$chl "INSERT INTO test.partition_428 (p, k) VALUES(toDate(1), 2)" + +for part in `$chl "SELECT name FROM system.parts WHERE database='test' AND table='partition_428'"`; do + cat $ch_dir/data/test/partition_428/$part/columns.txt | wc -l # 2 header lines + 3 columns +done + +$chl "ALTER TABLE test.partition_428 DETACH PARTITION 197001" +$chl "ALTER TABLE test.partition_428 ATTACH PARTITION 197001" + +for part in `$chl "SELECT name FROM system.parts WHERE database='test' AND table='partition_428'"`; do + cat $ch_dir/data/test/partition_428/$part/columns.txt | wc -l # 2 header lines + 3 columns +done + +$chl "ALTER TABLE test.partition_428 MODIFY COLUMN v1 Int8" +$chl "OPTIMIZE TABLE test.partition_428" + +$chl "SELECT toUInt16(p), k, v1 FROM test.partition_428 ORDER BY k FORMAT CSV" +$chl "DROP TABLE test.partition_428" + +# Test 2. Simple test + +$chl "drop table if exists test.partition_428" +$chl "create table test.partition_428 (date MATERIALIZED toDate(0), x UInt64, sample_key MATERIALIZED intHash64(x)) ENGINE=MergeTree(date,sample_key,(date,x,sample_key),8192)" +$chl "insert into test.partition_428 ( x ) VALUES ( now() )" +$chl "insert into test.partition_428 ( x ) VALUES ( now()+1 )" +$chl "alter table test.partition_428 detach partition 197001" +$chl "alter table test.partition_428 attach partition 197001" +$chl "optimize table test.partition_428" +$chl "drop table test.partition_428" diff --git a/dbms/tests/queries/0_stateless/00428_partition.sql b/dbms/tests/queries/0_stateless/00428_partition.sql deleted file mode 100644 index 365f0ba5c4b..00000000000 --- a/dbms/tests/queries/0_stateless/00428_partition.sql +++ /dev/null @@ -1,9 +0,0 @@ --- Not found column date in block. There are only columns: x. -drop table if exists test.partition_428; -create table test.partition_428 (date MATERIALIZED toDate(0), x UInt64, sample_key MATERIALIZED intHash64(x)) ENGINE=MergeTree(date,sample_key,(date,x,sample_key),8192); -insert into test.partition_428 ( x ) VALUES ( now() ); -insert into test.partition_428 ( x ) VALUES ( now()+1 ); -alter table test.partition_428 detach partition 197001; -alter table test.partition_428 attach partition 197001; -optimize table test.partition_428; -drop table test.partition_428; From caf69fd4b30e75d6784c7a530e1ce1ca499f4167 Mon Sep 17 00:00:00 2001 From: Dmitry Luhtionov Date: Wed, 10 May 2017 18:33:41 +0300 Subject: [PATCH 49/76] Update documentations --- docs/en/functions/other_functions.rst | 8 ++++++++ docs/ru/functions/other_functions.rst | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/en/functions/other_functions.rst b/docs/en/functions/other_functions.rst index d518b5daf93..be5947c9048 100644 --- a/docs/en/functions/other_functions.rst +++ b/docs/en/functions/other_functions.rst @@ -258,3 +258,11 @@ Example: │ 1110 │ 2016-11-24 00:00:10 │ 1 │ └─────────┴─────────────────────┴───────┘ +MACNumToString(num) +~~~~~~~~~~~~~ +Takes a UInt64 number. Interprets it as an MAC address in big endian. Returns a string containing the corresponding MAC address in the format AA:BB:CC:DD:EE:FF (colon-separated numbers in hexadecimal form). + +MACStringToNum(s) +~~~~~~~~ +The reverse function of MACNumToString. If the MAC address has an invalid format, it returns 0. + \ No newline at end of file diff --git a/docs/ru/functions/other_functions.rst b/docs/ru/functions/other_functions.rst index ff73662d971..ecaff8f327a 100644 --- a/docs/ru/functions/other_functions.rst +++ b/docs/ru/functions/other_functions.rst @@ -260,3 +260,11 @@ runningDifference(x) │ 1110 │ 2016-11-24 00:00:10 │ 1 │ └─────────┴─────────────────────┴───────┘ +MACNumToString(num) +~~~~~~~~~~~~~~~~~~~~ +Принимает число типа UInt64. Интерпретирует его, как MAC-адрес в big endian. Возвращает строку, содержащую соответствующий MAC-адрес в формате AA:BB:CC:DD:EE:FF (числа в шестнадцатеричной форме через двоеточие). + +MACStringToNum(s) +~~~~~~~~~~~~~~~~~~ +Функция, обратная к MACNumToString. Если MAC адрес в неправильном формате, то возвращает 0. + \ No newline at end of file From bc878f978572280a5cd09486fb46ce90d692b56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Tue, 9 May 2017 17:13:12 -0700 Subject: [PATCH 50/76] Common/HashTable: allow cell reinsertion * fixes missing setHash on reinsert * reuses hash when emplacing value --- dbms/src/Common/HashTable/HashTable.h | 31 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dbms/src/Common/HashTable/HashTable.h b/dbms/src/Common/HashTable/HashTable.h index a965b8e6e9d..d505bf2c94c 100644 --- a/dbms/src/Common/HashTable/HashTable.h +++ b/dbms/src/Common/HashTable/HashTable.h @@ -365,7 +365,7 @@ protected: size_t i = 0; for (; i < old_size; ++i) if (!buf[i].isZero(*this) && !buf[i].isDeleted()) - reinsert(buf[i]); + reinsert(buf[i], buf[i].getHash(*this)); /** There is also a special case: * if the element was to be at the end of the old buffer, [ x] @@ -376,7 +376,7 @@ protected: * process tail from the collision resolution chain immediately after it [ o x ] */ for (; !buf[i].isZero(*this) && !buf[i].isDeleted(); ++i) - reinsert(buf[i]); + reinsert(buf[i], buf[i].getHash(*this)); #ifdef DBMS_HASH_MAP_DEBUG_RESIZES watch.stop(); @@ -390,9 +390,8 @@ protected: /** Paste into the new buffer the value that was in the old buffer. * Used when increasing the buffer size. */ - void reinsert(Cell & x) + void reinsert(Cell & x, size_t hash_value) { - size_t hash_value = x.getHash(*this); size_t place_value = grower.place(hash_value); /// If the element is in its place. @@ -407,6 +406,7 @@ protected: return; /// Copy to a new location and zero the old one. + x.setHash(hash_value); memcpy(&buf[place_value], &x, sizeof(x)); x.setZero(); @@ -612,7 +612,7 @@ protected: /// If the key is zero, insert it into a special place and return true. - bool ALWAYS_INLINE emplaceIfZero(Key x, iterator & it, bool & inserted) + bool ALWAYS_INLINE emplaceIfZero(Key x, iterator & it, bool & inserted, size_t hash_value) { /// If it is claimed that the zero key can not be inserted into the table. if (!Cell::need_zero_value_storage) @@ -625,7 +625,7 @@ protected: { ++m_size; this->setHasZero(); - it.ptr->setHash(hash(x)); + it.ptr->setHash(hash_value); inserted = true; } else @@ -684,8 +684,9 @@ public: { std::pair res; - if (!emplaceIfZero(Cell::getKey(x), res.first, res.second)) - emplaceNonZero(Cell::getKey(x), res.first, res.second, hash(Cell::getKey(x))); + size_t hash_value = hash(Cell::getKey(x)); + if (!emplaceIfZero(Cell::getKey(x), res.first, res.second, hash_value)) + emplaceNonZero(Cell::getKey(x), res.first, res.second, hash_value); if (res.second) res.first.ptr->setMapped(x); @@ -694,6 +695,13 @@ public: } + /// Reinsert node pointed to by iterator + void ALWAYS_INLINE reinsert(iterator & it, size_t hash_value) + { + reinsert(*it.getPtr(), hash_value); + } + + /** Insert the key, * return an iterator to a position that can be used for `placement new` of value, * as well as the flag - whether a new key was inserted. @@ -711,15 +719,16 @@ public: */ void ALWAYS_INLINE emplace(Key x, iterator & it, bool & inserted) { - if (!emplaceIfZero(x, it, inserted)) - emplaceNonZero(x, it, inserted, hash(x)); + size_t hash_value = hash(x); + if (!emplaceIfZero(x, it, inserted, hash_value)) + emplaceNonZero(x, it, inserted, hash_value); } /// Same, but with a precalculated value of hash function. void ALWAYS_INLINE emplace(Key x, iterator & it, bool & inserted, size_t hash_value) { - if (!emplaceIfZero(x, it, inserted)) + if (!emplaceIfZero(x, it, inserted, hash_value)) emplaceNonZero(x, it, inserted, hash_value); } From 45bd332460bf5560c42dec11ee8399a553a25efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Tue, 9 May 2017 17:17:45 -0700 Subject: [PATCH 51/76] AggregateFunctionTopK: fix memory usage, performance * allow separate table key / hash key, and use std::string / StringRef for generic variant as it has built-in storage and StringRef is supported by the hash table, this avoids infinitely growing arena with serialised keys * use power-of-2 size for alpha vector for faster binning without using modulo * use custom grower and allocator for SpaceSaving to start with smaller tables * store computed hash in counter for faster reinsertion of smallest element --- .../AggregateFunctionTopK.h | 51 +++++++------- dbms/src/Common/SpaceSaving.h | 67 +++++++++++-------- dbms/src/Common/tests/space_saving.cpp | 12 ++-- 3 files changed, 66 insertions(+), 64 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h index 0e2400c8d04..e616f0436b9 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h @@ -22,13 +22,21 @@ namespace DB // Allow NxK more space before calculating top K to increase accuracy #define TOP_K_LOAD_FACTOR 3 +#define TOP_K_DEFAULT_DEGREE 10 #define TOP_K_MAX_SIZE 0xFFFFFF template struct AggregateFunctionTopKData { - using Set = SpaceSaving>; + using Set = SpaceSaving + < + T, + T, + HashCRC32, + HashTableGrower, + HashTableAllocatorWithStackMemory + >; Set value; }; @@ -39,7 +47,7 @@ class AggregateFunctionTopK { private: using State = AggregateFunctionTopKData; - size_t threshold = 10; // Default value if the parameter is not specified. + size_t threshold = TOP_K_DEFAULT_DEGREE; size_t reserved = TOP_K_LOAD_FACTOR * threshold; public: @@ -119,7 +127,14 @@ public: /// Generic implementation, it uses serialized representation as object descriptor. struct AggregateFunctionTopKGenericData { - using Set = SpaceSaving; + using Set = SpaceSaving + < + std::string, + StringRef, + StringRefHash, + HashTableGrower, + HashTableAllocatorWithStackMemory + >; Set value; }; @@ -133,10 +148,9 @@ class AggregateFunctionTopKGeneric : public IUnaryAggregateFunctioninsert(str_serialized.data, str_serialized.size); - str_serialized = StringRef(ptr, str_serialized.size); - } - - set.insert(str_serialized); + StringRef str_serialized = column.getDataAt(row_num); + set.insert(str_serialized.toString()); } void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override @@ -231,19 +241,6 @@ public: }; -template <> -inline StringRef AggregateFunctionTopKGeneric::getSerialization(const IColumn & column, size_t row_num, Arena & arena) -{ - const char * begin = nullptr; - return column.serializeValueIntoArena(row_num, arena, begin); -} - -template <> -inline StringRef AggregateFunctionTopKGeneric::getSerialization(const IColumn & column, size_t row_num, Arena &) -{ - return column.getDataAt(row_num); -} - template <> inline void AggregateFunctionTopKGeneric::deserializeAndInsert(StringRef str, IColumn & data_to) { diff --git a/dbms/src/Common/SpaceSaving.h b/dbms/src/Common/SpaceSaving.h index f1973d9b823..7483d098990 100644 --- a/dbms/src/Common/SpaceSaving.h +++ b/dbms/src/Common/SpaceSaving.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -26,18 +25,34 @@ namespace DB { -template > +template +< + typename TKey, + typename HashKey = TKey, + typename Hash = DefaultHash, + typename Grower = HashTableGrower<>, + typename Allocator = HashTableAllocator +> class SpaceSaving { +private: + // Suggested constants in the paper "Finding top-k elements in data streams", chap 6. equation (24) + // Round to nearest power of 2 for cheaper binning without modulo + constexpr uint64_t nextAlphaSize (uint64_t x) + { + constexpr uint64_t ALPHA_MAP_ELEMENTS_PER_COUNTER = 6; + return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x * ALPHA_MAP_ELEMENTS_PER_COUNTER)); + } + public: - using Self = SpaceSaving; + using Self = SpaceSaving; struct Counter { Counter() {} - Counter(const TKey & k, UInt64 c = 0, UInt64 e = 0) - : key(k), slot(0), count(c), error(e) {} + Counter(const TKey & k, UInt64 c = 0, UInt64 e = 0, size_t h = 0) + : key(k), slot(0), hash(h), count(c), error(e) {} void write(WriteBuffer & wb) const { @@ -60,12 +75,12 @@ public: } TKey key; - size_t slot; + size_t slot, hash; UInt64 count; UInt64 error; }; - SpaceSaving(size_t c = 10) : alpha_map(ALPHA_MAP_ELEMENTS_PER_COUNTER * c), m_capacity(c) {} + SpaceSaving(size_t c = 10) : alpha_map(nextAlphaSize(c)), m_capacity(c) {} ~SpaceSaving() { destroyElements(); } inline size_t size() const @@ -81,7 +96,7 @@ public: void resize(size_t new_capacity) { counter_list.reserve(new_capacity); - alpha_map.resize(new_capacity * ALPHA_MAP_ELEMENTS_PER_COUNTER); + alpha_map.resize(nextAlphaSize(new_capacity)); m_capacity = new_capacity; } @@ -99,17 +114,17 @@ public: percolate(c); return; } - // Key doesn't exist, but can fit in the top K - if (size() < capacity()) + else if (unlikely(size() < capacity())) { - auto c = new Counter(key, increment, error); + auto c = new Counter(key, increment, error, hash); push(c); return; } auto min = counter_list.back(); - auto & alpha = alpha_map[hash % alpha_map.size()]; + const size_t alpha_mask = alpha_map.size() - 1; + auto & alpha = alpha_map[hash & alpha_mask]; if (alpha + increment < min->count) { alpha += increment; @@ -117,25 +132,21 @@ public: } // Erase the current minimum element - auto min_hash = counter_map.hash(min->key); - it = counter_map.find(min->key, min_hash); - if (it != counter_map.end()) - { - auto cell = it.getPtr(); - cell->setZero(); - } + alpha_map[min->hash & alpha_mask] = min->count; + it = counter_map.find(min->key, min->hash); // Replace minimum with newly inserted element - bool inserted = false; - counter_map.emplace(key, it, inserted, hash); - if (inserted) + if (it != counter_map.end()) { - alpha_map[min_hash % alpha_map.size()] = min->count; + min->hash = hash; min->key = key; min->count = alpha + increment; min->error = alpha + error; - it->second = min; percolate(min); + + it->second = min; + it->first = key; + counter_map.reinsert(it, hash); } } @@ -220,10 +231,11 @@ public: { auto counter = new Counter(); counter->read(rb); + counter->hash = counter_map.hash(counter->key); push(counter); } - for (size_t i = 0; i < m_capacity * ALPHA_MAP_ELEMENTS_PER_COUNTER; ++i) + for (size_t i = 0; i < nextAlphaSize(m_capacity); ++i) { UInt64 alpha = 0; readVarUInt(alpha, rb); @@ -267,13 +279,10 @@ private: alpha_map.clear(); } - HashMap counter_map; + HashMap counter_map; std::vector counter_list; std::vector alpha_map; size_t m_capacity; - - // Suggested constants in the paper "Finding top-k elements in data streams", chap 6. equation (24) - enum { ALPHA_MAP_ELEMENTS_PER_COUNTER = 6 }; }; }; diff --git a/dbms/src/Common/tests/space_saving.cpp b/dbms/src/Common/tests/space_saving.cpp index 5b37b94f43b..50c15424ef5 100644 --- a/dbms/src/Common/tests/space_saving.cpp +++ b/dbms/src/Common/tests/space_saving.cpp @@ -66,16 +66,12 @@ int main(int argc, char ** argv) { /* Same test for string keys */ - using Cont = DB::SpaceSaving; + using Cont = DB::SpaceSaving; Cont cont(10); - std::vector refs; - for (int i = 0; i < 400; ++i) { - refs.push_back(std::to_string(i)); - cont.insert(StringRef(refs.back())); - refs.push_back(std::to_string(i % 5)); // Bias towards 0-4 - cont.insert(StringRef(refs.back())); + cont.insert(std::to_string(i)); + cont.insert(std::to_string(i % 5)); // Bias towards 0-4 } // The hashing is going to be more lossy @@ -86,7 +82,7 @@ int main(int argc, char ** argv) } for (auto x : cont.topK(5)) { - auto key = x.key.toString(); + auto key = x.key; if (x.count < expect[key]) { std::cerr << "key: " << key << " value: " << x.count << " expected: " << expect[key] << std::endl; } else { From 8f0e833b52efb58aecc2fe1b16e2aa6c29c573dd Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 11 May 2017 22:48:46 +0300 Subject: [PATCH 52/76] Whitespaces [#CLICKHOUSE-2]. --- dbms/src/Core/Field.h | 146 +++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/dbms/src/Core/Field.h b/dbms/src/Core/Field.h index 4fbb7646b1b..87b2c819d89 100644 --- a/dbms/src/Core/Field.h +++ b/dbms/src/Core/Field.h @@ -47,16 +47,16 @@ public: /// Type tag. enum Which { - Null = 0, - UInt64 = 1, - Int64 = 2, - Float64 = 3, + Null = 0, + UInt64 = 1, + Int64 = 2, + Float64 = 3, /// Non-POD types. - String = 16, - Array = 17, - Tuple = 18, + String = 16, + Array = 17, + Tuple = 18, }; static const int MIN_NON_POD = 16; @@ -65,13 +65,13 @@ public: { switch (which) { - case Null: return "Null"; - case UInt64: return "UInt64"; - case Int64: return "Int64"; - case Float64: return "Float64"; - case String: return "String"; - case Array: return "Array"; - case Tuple: return "Tuple"; + case Null: return "Null"; + case UInt64: return "UInt64"; + case Int64: return "Int64"; + case Float64: return "Float64"; + case String: return "String"; + case Array: return "Array"; + case Tuple: return "Tuple"; default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -231,13 +231,13 @@ public: switch (which) { - case Types::Null: return false; - case Types::UInt64: return get() < rhs.get(); - case Types::Int64: return get() < rhs.get(); - case Types::Float64: return get() < rhs.get(); - case Types::String: return get() < rhs.get(); - case Types::Array: return get() < rhs.get(); - case Types::Tuple: return get() < rhs.get(); + case Types::Null: return false; + case Types::UInt64: return get() < rhs.get(); + case Types::Int64: return get() < rhs.get(); + case Types::Float64: return get() < rhs.get(); + case Types::String: return get() < rhs.get(); + case Types::Array: return get() < rhs.get(); + case Types::Tuple: return get() < rhs.get(); default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -258,13 +258,13 @@ public: switch (which) { - case Types::Null: return true; - case Types::UInt64: return get() <= rhs.get(); - case Types::Int64: return get() <= rhs.get(); - case Types::Float64: return get() <= rhs.get(); - case Types::String: return get() <= rhs.get(); - case Types::Array: return get() <= rhs.get(); - case Types::Tuple: return get() <= rhs.get(); + case Types::Null: return true; + case Types::UInt64: return get() <= rhs.get(); + case Types::Int64: return get() <= rhs.get(); + case Types::Float64: return get() <= rhs.get(); + case Types::String: return get() <= rhs.get(); + case Types::Array: return get() <= rhs.get(); + case Types::Tuple: return get() <= rhs.get(); default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -283,13 +283,13 @@ public: switch (which) { - case Types::Null: return true; + case Types::Null: return true; case Types::UInt64: case Types::Int64: - case Types::Float64: return get() == rhs.get(); - case Types::String: return get() == rhs.get(); - case Types::Array: return get() == rhs.get(); - case Types::Tuple: return get() == rhs.get(); + case Types::Float64: return get() == rhs.get(); + case Types::String: return get() == rhs.get(); + case Types::Array: return get() == rhs.get(); + case Types::Tuple: return get() == rhs.get(); default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -335,13 +335,13 @@ private: { switch (field.which) { - case Types::Null: f(field.template get()); return; - case Types::UInt64: f(field.template get()); return; - case Types::Int64: f(field.template get()); return; - case Types::Float64: f(field.template get()); return; - case Types::String: f(field.template get()); return; - case Types::Array: f(field.template get()); return; - case Types::Tuple: f(field.template get()); return; + case Types::Null: f(field.template get()); return; + case Types::UInt64: f(field.template get()); return; + case Types::Int64: f(field.template get()); return; + case Types::Float64: f(field.template get()); return; + case Types::String: f(field.template get()); return; + case Types::Array: f(field.template get()); return; + case Types::Tuple: f(field.template get()); return; default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -416,21 +416,21 @@ private: #undef DBMS_MIN_FIELD_SIZE -template <> struct Field::TypeToEnum { static const Types::Which value = Types::Null; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::UInt64; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::Int64; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::Float64; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::String; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::Array; }; -template <> struct Field::TypeToEnum { static const Types::Which value = Types::Tuple; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::Null; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::UInt64; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::Int64; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::Float64; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::String; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::Array; }; +template <> struct Field::TypeToEnum { static const Types::Which value = Types::Tuple; }; -template <> struct Field::EnumToType { using Type = Null ; }; -template <> struct Field::EnumToType { using Type = UInt64 ; }; -template <> struct Field::EnumToType { using Type = Int64 ; }; -template <> struct Field::EnumToType { using Type = Float64 ; }; -template <> struct Field::EnumToType { using Type = String ; }; -template <> struct Field::EnumToType { using Type = Array ; }; -template <> struct Field::EnumToType { using Type = Tuple ; }; +template <> struct Field::EnumToType { using Type = Null; }; +template <> struct Field::EnumToType { using Type = UInt64; }; +template <> struct Field::EnumToType { using Type = Int64; }; +template <> struct Field::EnumToType { using Type = Float64; }; +template <> struct Field::EnumToType { using Type = String; }; +template <> struct Field::EnumToType { using Type = Array; }; +template <> struct Field::EnumToType { using Type = Tuple; }; template @@ -464,21 +464,21 @@ template <> struct TypeName { static std::string get() { return "Tuple"; template struct NearestFieldType; -template <> struct NearestFieldType { using Type = UInt64 ; }; -template <> struct NearestFieldType { using Type = UInt64 ; }; -template <> struct NearestFieldType { using Type = UInt64 ; }; -template <> struct NearestFieldType { using Type = UInt64 ; }; -template <> struct NearestFieldType { using Type = Int64 ; }; -template <> struct NearestFieldType { using Type = Int64 ; }; -template <> struct NearestFieldType { using Type = Int64 ; }; -template <> struct NearestFieldType { using Type = Int64 ; }; -template <> struct NearestFieldType { using Type = Float64 ; }; -template <> struct NearestFieldType { using Type = Float64 ; }; -template <> struct NearestFieldType { using Type = String ; }; -template <> struct NearestFieldType { using Type = Array ; }; -template <> struct NearestFieldType { using Type = Tuple ; }; -template <> struct NearestFieldType { using Type = UInt64 ; }; -template <> struct NearestFieldType { using Type = Null; }; +template <> struct NearestFieldType { using Type = UInt64; }; +template <> struct NearestFieldType { using Type = UInt64; }; +template <> struct NearestFieldType { using Type = UInt64; }; +template <> struct NearestFieldType { using Type = UInt64; }; +template <> struct NearestFieldType { using Type = Int64; }; +template <> struct NearestFieldType { using Type = Int64; }; +template <> struct NearestFieldType { using Type = Int64; }; +template <> struct NearestFieldType { using Type = Int64; }; +template <> struct NearestFieldType { using Type = Float64; }; +template <> struct NearestFieldType { using Type = Float64; }; +template <> struct NearestFieldType { using Type = String; }; +template <> struct NearestFieldType { using Type = Array; }; +template <> struct NearestFieldType { using Type = Tuple; }; +template <> struct NearestFieldType { using Type = UInt64; }; +template <> struct NearestFieldType { using Type = Null; }; template @@ -494,8 +494,8 @@ class WriteBuffer; /// It is assumed that all elements of the array have the same type. void readBinary(Array & x, ReadBuffer & buf); -inline void readText(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); } -inline void readQuoted(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); } +inline void readText(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); } +inline void readQuoted(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); } /// It is assumed that all elements of the array have the same type. void writeBinary(const Array & x, WriteBuffer & buf); @@ -506,8 +506,8 @@ inline void writeQuoted(const Array & x, WriteBuffer & buf) { throw Exception("C void readBinary(Tuple & x, ReadBuffer & buf); -inline void readText(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); } -inline void readQuoted(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); } +inline void readText(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); } +inline void readQuoted(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); } void writeBinary(const Tuple & x, WriteBuffer & buf); From 9ad1d5676a5df91e5f40a6b9f62d58e8d6656ea2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 01:21:06 +0300 Subject: [PATCH 53/76] Miscellaneous [#CLICKHOUSE-2]. --- dbms/src/AggregateFunctions/AggregateFunctionUniq.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionUniq.h b/dbms/src/AggregateFunctions/AggregateFunctionUniq.h index 690fa330693..51ee93024d1 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionUniq.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionUniq.h @@ -86,12 +86,11 @@ struct AggregateFunctionUniqExactData using Key = T; /// When creating, the hash table must be small. - typedef HashSet< + using Set = HashSet< Key, HashCRC32, HashTableGrower<4>, - HashTableAllocatorWithStackMemory - > Set; + HashTableAllocatorWithStackMemory>; Set set; @@ -105,12 +104,11 @@ struct AggregateFunctionUniqExactData using Key = UInt128; /// When creating, the hash table must be small. - typedef HashSet< + using Set = HashSet< Key, UInt128TrivialHash, HashTableGrower<3>, - HashTableAllocatorWithStackMemory - > Set; + HashTableAllocatorWithStackMemory>; Set set; From 021e37943eb657aba46a46d83adcb1ef9ddcba16 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Fri, 12 May 2017 16:44:11 +0300 Subject: [PATCH 54/76] More clearer code and correct test. [#CLICKHOUSE-1993] --- dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp | 10 +--------- dbms/tests/queries/0_stateless/00428_partition.sh | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 56f9ea069d8..9584b8ace19 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -565,17 +565,9 @@ void MergeTreeDataPart::loadColumns(bool require) throw Exception("No columns.txt in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); /// If there is no file with a list of columns, write it down. - - auto add_column_if_exists = [this] (const NameAndTypePair & column) { + for (const NameAndTypePair & column : storage.getColumnsList()) if (Poco::File(getFullPath() + escapeForFileName(column.name) + ".bin").exists()) columns.push_back(column); - }; - - for (const NameAndTypePair & column : *storage.columns) - add_column_if_exists(column); - - for (const NameAndTypePair & column : storage.materialized_columns) - add_column_if_exists(column); if (columns.empty()) throw Exception("No columns in part " + name, ErrorCodes::NO_FILE_IN_DATA_PART); diff --git a/dbms/tests/queries/0_stateless/00428_partition.sh b/dbms/tests/queries/0_stateless/00428_partition.sh index 293a7a60836..08705d3d24c 100755 --- a/dbms/tests/queries/0_stateless/00428_partition.sh +++ b/dbms/tests/queries/0_stateless/00428_partition.sh @@ -7,7 +7,7 @@ set -e chl="clickhouse-client -q" ch_dir=`clickhouse --extract-from-config -c /etc/clickhouse-server/config.xml -k path` -$chl "DROP TABLE IF EXISTS partition_428" +$chl "DROP TABLE IF EXISTS test.partition_428" $chl "CREATE TABLE test.partition_428 (p Date, k Int8, v1 Int8 MATERIALIZED k + 1) ENGINE = MergeTree(p, k, 1)" $chl "INSERT INTO test.partition_428 (p, k) VALUES(toDate(31), 1)" $chl "INSERT INTO test.partition_428 (p, k) VALUES(toDate(1), 2)" From 4b852584cec139efd419e2558b83dd3298db0062 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 17:01:02 +0300 Subject: [PATCH 55/76] Whitespaces [#CLICKHOUSE-2]. --- dbms/src/Functions/FunctionsString.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dbms/src/Functions/FunctionsString.h b/dbms/src/Functions/FunctionsString.h index 420829ffb4b..617832cba3f 100644 --- a/dbms/src/Functions/FunctionsString.h +++ b/dbms/src/Functions/FunctionsString.h @@ -20,10 +20,10 @@ namespace DB * lengthUTF8, substringUTF8, lowerUTF8, upperUTF8, reverseUTF8 * * s -> UInt8: empty, notEmpty - * s -> UInt64: length, lengthUTF8 - * s -> s: lower, upper, lowerUTF8, upperUTF8, reverse, reverseUTF8 - * s, s -> s: concat - * s, c1, c2 -> s: substring, substringUTF8 + * s -> UInt64: length, lengthUTF8 + * s -> s: lower, upper, lowerUTF8, upperUTF8, reverse, reverseUTF8 + * s, s -> s: concat + * s, c1, c2 -> s: substring, substringUTF8 * s, c1, c2, s2 -> s: replace, replaceUTF8 * * Функции поиска строк и регулярных выражений расположены отдельно. @@ -76,7 +76,7 @@ inline void UTF8CyrillicToCase(const UInt8 *& src, const UInt8 * const src_end, } else if (src[0] == 0xD0u && (src[1] >= 0xA0u && src[1] <= 0xAFu)) { - /// Р-Я + /// Р-Я *dst++ = xor_or_identity(*src++, 0x1); *dst++ = xor_or_identity(*src++, 0x20); } From 38192160856e2419d7b4b381fb36deb0d3eff32e Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 17:02:24 +0300 Subject: [PATCH 56/76] StorageBuffer: explicitly disable support for PREWHERE, because possibility of wrong query results [#CLICKHOUSE-2999]. --- dbms/src/Storages/StorageBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/StorageBuffer.h b/dbms/src/Storages/StorageBuffer.h index 21c5f0a957f..90608253dec 100644 --- a/dbms/src/Storages/StorageBuffer.h +++ b/dbms/src/Storages/StorageBuffer.h @@ -85,7 +85,7 @@ public: void rename(const String & new_path_to_db, const String & new_database_name, const String & new_table_name) override { name = new_table_name; } bool supportsSampling() const override { return true; } - bool supportsPrewhere() const override { return true; } + bool supportsPrewhere() const override { return false; } bool supportsFinal() const override { return true; } bool supportsIndexForIn() const override { return true; } bool supportsParallelReplicas() const override { return true; } From 1d090bd4e2880d5cceb25ccd1eae42cc2544215d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 23:05:19 +0300 Subject: [PATCH 57/76] AggregateFunctionGroupArrayInsertAt: fixed error [#CLICKHOUSE-3003]. --- .../AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h | 3 ++- .../queries/0_stateless/00459_group_array_insert_at.reference | 1 + dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h index d92b8cbefd1..e6881a9354a 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -118,7 +118,7 @@ public: if (arr_lhs.size() < arr_rhs.size()) arr_lhs.resize(arr_rhs.size()); - for (size_t i = 0, size = arr_lhs.size(); i < size; ++i) + for (size_t i = 0, size = arr_rhs.size(); i < size; ++i) if (arr_lhs[i].isNull() && !arr_rhs[i].isNull()) arr_lhs[i] = arr_rhs[i]; } @@ -128,6 +128,7 @@ public: const Array & arr = data(place).value; size_t size = arr.size(); writeVarUInt(size, buf); + for (const Field & elem : arr) { if (elem.isNull()) diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference index d10d5acfc83..ebd7abe32e0 100644 --- a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference @@ -11,3 +11,4 @@ 7 [0,0,0,0,0,0,0,7] 8 [0,0,0,0,0,0,0,0,8] 9 [0,0,0,0,0,0,0,0,0,9] +0 0 diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql index fc91473ad21..0dff44d6336 100644 --- a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql @@ -2,3 +2,4 @@ SELECT groupArrayInsertAt(toString(number), number * 2) FROM (SELECT * FROM syst SELECT groupArrayInsertAt('-')(toString(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); SELECT groupArrayInsertAt([123])(range(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); SELECT number, groupArrayInsertAt(number, number) FROM (SELECT * FROM system.numbers LIMIT 10) GROUP BY number ORDER BY number; +SELECT k, ignore(groupArrayInsertAt(x, x)) FROM (SELECT dummy AS k, randConstant() % 10 AS x FROM remote('127.0.0.{1,1}', system.one)) GROUP BY k ORDER BY k; From 40595ce68898f1b8d9d6ed1c7f7eae1067c12aec Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 23:41:50 +0300 Subject: [PATCH 58/76] Whitespaces [#CLICKHOUSE-3003]. --- dbms/src/Core/FieldVisitors.h | 68 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/dbms/src/Core/FieldVisitors.h b/dbms/src/Core/FieldVisitors.h index 92a7ace374d..99a18ee3d8d 100644 --- a/dbms/src/Core/FieldVisitors.h +++ b/dbms/src/Core/FieldVisitors.h @@ -33,13 +33,13 @@ typename std::decay::type::ResultType applyVisitor(Visitor && visitor, { switch (field.getType()) { - case Field::Types::Null: return visitor(field.template get()); - case Field::Types::UInt64: return visitor(field.template get()); - case Field::Types::Int64: return visitor(field.template get()); + case Field::Types::Null: return visitor(field.template get()); + case Field::Types::UInt64: return visitor(field.template get()); + case Field::Types::Int64: return visitor(field.template get()); case Field::Types::Float64: return visitor(field.template get()); - case Field::Types::String: return visitor(field.template get()); - case Field::Types::Array: return visitor(field.template get()); - case Field::Types::Tuple: return visitor(field.template get()); + case Field::Types::String: return visitor(field.template get()); + case Field::Types::Array: return visitor(field.template get()); + case Field::Types::Tuple: return visitor(field.template get()); default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -52,13 +52,13 @@ static typename std::decay::type::ResultType applyBinaryVisitorImpl(Vis { switch (field2.getType()) { - case Field::Types::Null: return visitor(field1, field2.template get()); - case Field::Types::UInt64: return visitor(field1, field2.template get()); - case Field::Types::Int64: return visitor(field1, field2.template get()); + case Field::Types::Null: return visitor(field1, field2.template get()); + case Field::Types::UInt64: return visitor(field1, field2.template get()); + case Field::Types::Int64: return visitor(field1, field2.template get()); case Field::Types::Float64: return visitor(field1, field2.template get()); - case Field::Types::String: return visitor(field1, field2.template get()); - case Field::Types::Array: return visitor(field1, field2.template get()); - case Field::Types::Tuple: return visitor(field1, field2.template get()); + case Field::Types::String: return visitor(field1, field2.template get()); + case Field::Types::Array: return visitor(field1, field2.template get()); + case Field::Types::Tuple: return visitor(field1, field2.template get()); default: throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD); @@ -102,13 +102,13 @@ typename std::decay::type::ResultType applyVisitor(Visitor && visitor, class FieldVisitorToString : public StaticVisitor { public: - String operator() (const Null & x) const; - String operator() (const UInt64 & x) const; - String operator() (const Int64 & x) const; - String operator() (const Float64 & x) const; - String operator() (const String & x) const; - String operator() (const Array & x) const; - String operator() (const Tuple & x) const; + String operator() (const Null & x) const; + String operator() (const UInt64 & x) const; + String operator() (const Int64 & x) const; + String operator() (const Float64 & x) const; + String operator() (const String & x) const; + String operator() (const Array & x) const; + String operator() (const Tuple & x) const; }; @@ -116,13 +116,13 @@ public: class FieldVisitorDump : public StaticVisitor { public: - String operator() (const Null & x) const; - String operator() (const UInt64 & x) const; - String operator() (const Int64 & x) const; - String operator() (const Float64 & x) const; - String operator() (const String & x) const; - String operator() (const Array & x) const; - String operator() (const Tuple & x) const; + String operator() (const Null & x) const; + String operator() (const UInt64 & x) const; + String operator() (const Int64 & x) const; + String operator() (const Float64 & x) const; + String operator() (const String & x) const; + String operator() (const Array & x) const; + String operator() (const Tuple & x) const; }; @@ -151,8 +151,8 @@ public: throw Exception("Cannot convert Tuple to " + TypeName::get(), ErrorCodes::CANNOT_CONVERT_TYPE); } - T operator() (const UInt64 & x) const { return x; } - T operator() (const Int64 & x) const { return x; } + T operator() (const UInt64 & x) const { return x; } + T operator() (const Int64 & x) const { return x; } T operator() (const Float64 & x) const { return x; } }; @@ -165,12 +165,12 @@ private: public: FieldVisitorHash(SipHash & hash); - void operator() (const Null & x) const; - void operator() (const UInt64 & x) const; - void operator() (const Int64 & x) const; - void operator() (const Float64 & x) const; - void operator() (const String & x) const; - void operator() (const Array & x) const; + void operator() (const Null & x) const; + void operator() (const UInt64 & x) const; + void operator() (const Int64 & x) const; + void operator() (const Float64 & x) const; + void operator() (const String & x) const; + void operator() (const Array & x) const; }; From cfc4c987c5e1b4290ceb15247846ca39225496eb Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 23:57:24 +0300 Subject: [PATCH 59/76] Added optional length parameter to aggregate function groupArrayInsertAt [#CLICKHOUSE-3003]. --- .../AggregateFunctionGroupArrayInsertAt.h | 31 ++++++++++++++++--- .../00459_group_array_insert_at.reference | 11 +++++++ .../00459_group_array_insert_at.sql | 1 + 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h index e6881a9354a..6a48e621444 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionGroupArrayInsertAt.h @@ -34,7 +34,11 @@ namespace ErrorCodes * If more than one value was inserted to single position, the any value (first in case of single thread) is stored. * If no values was inserted to some position, then default value will be substituted. * - * Default value is optional parameter for aggregate function. + * Aggregate function also accept optional parameters: + * - default value to substitute; + * - length to resize result arrays (if you want to have results of same length for all aggregation keys); + * + * If you want to pass length, default value should be also given. */ @@ -51,6 +55,7 @@ class AggregateFunctionGroupArrayInsertAtGeneric final private: DataTypePtr type; Field default_value; + size_t length_to_resize = 0; /// zero means - do not do resizing. public: String getName() const override { return "groupArrayInsertAt"; } @@ -85,16 +90,26 @@ public: if (params.empty()) return; - if (params.size() != 1) - throw Exception("Aggregate function " + getName() + " requires at most one parameter.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + if (params.size() > 2) + throw Exception("Aggregate function " + getName() + " requires at most two parameters.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - default_value = params.front(); + default_value = params[0]; + + if (params.size() == 2) + { + length_to_resize = applyVisitor(FieldVisitorConvertToNumber(), params[1]); + } } void addImpl(AggregateDataPtr place, const IColumn & column_value, const IColumn & column_position, size_t row_num, Arena *) const { /// TODO Do positions need to be 1-based for this function? size_t position = column_position.get64(row_num); + + /// If position is larger than size to which array will be cutted - simply ignore value. + if (length_to_resize && position >= length_to_resize) + return; + if (position >= AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE) throw Exception("Too large array size: position argument (" + toString(position) + ")" " is greater or equals to limit (" + toString(AGGREGATE_FUNCTION_GROUP_ARRAY_INSERT_AT_MAX_SIZE) + ")", @@ -179,7 +194,13 @@ public: to_data.insert(default_value); } - to_offsets.push_back((to_offsets.empty() ? 0 : to_offsets.back()) + arr.size()); + size_t result_array_size = length_to_resize ? length_to_resize : arr.size(); + + /// Pad array if need. + for (size_t i = arr.size(); i < result_array_size; ++i) + to_data.insert(default_value); + + to_offsets.push_back((to_offsets.empty() ? 0 : to_offsets.back()) + result_array_size); } }; diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference index ebd7abe32e0..f55b099b52e 100644 --- a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.reference @@ -12,3 +12,14 @@ 8 [0,0,0,0,0,0,0,0,8] 9 [0,0,0,0,0,0,0,0,0,9] 0 0 +0 ['0','-','-','-','-','-','-','-','-','-'] +1 ['-','1','-','-','-','-','-','-','-','-'] +2 ['-','-','2','-','-','-','-','-','-','-'] +3 ['-','-','-','3','-','-','-','-','-','-'] +4 ['-','-','-','-','4','-','-','-','-','-'] +5 ['-','-','-','-','-','5','-','-','-','-'] +6 ['-','-','-','-','-','-','6','-','-','-'] +7 ['-','-','-','-','-','-','-','7','-','-'] +8 ['-','-','-','-','-','-','-','-','8','-'] +9 ['-','-','-','-','-','-','-','-','-','9'] +10 ['-','-','-','-','-','-','-','-','-','-'] diff --git a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql index 0dff44d6336..b692038e9c5 100644 --- a/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql +++ b/dbms/tests/queries/0_stateless/00459_group_array_insert_at.sql @@ -3,3 +3,4 @@ SELECT groupArrayInsertAt('-')(toString(number), number * 2) FROM (SELECT * FROM SELECT groupArrayInsertAt([123])(range(number), number * 2) FROM (SELECT * FROM system.numbers LIMIT 10); SELECT number, groupArrayInsertAt(number, number) FROM (SELECT * FROM system.numbers LIMIT 10) GROUP BY number ORDER BY number; SELECT k, ignore(groupArrayInsertAt(x, x)) FROM (SELECT dummy AS k, randConstant() % 10 AS x FROM remote('127.0.0.{1,1}', system.one)) GROUP BY k ORDER BY k; +SELECT k, groupArrayInsertAt('-', 10)(toString(x), x) FROM (SELECT number AS k, number AS x FROM system.numbers LIMIT 11) GROUP BY k ORDER BY k; \ No newline at end of file From d3a8faee1695e4380db84dbb3ce8226a3b86c717 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 12 May 2017 23:59:14 +0300 Subject: [PATCH 60/76] Fixed test reference file for aggregate function topK [#CLICKHOUSE-3]. --- dbms/tests/queries/0_stateless/00453_top_k.reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/tests/queries/0_stateless/00453_top_k.reference b/dbms/tests/queries/0_stateless/00453_top_k.reference index 0b5c06820e8..1a768b03965 100644 --- a/dbms/tests/queries/0_stateless/00453_top_k.reference +++ b/dbms/tests/queries/0_stateless/00453_top_k.reference @@ -1 +1 @@ -[0,1,2,3,4,5,6,7,8,9] \ No newline at end of file +[0,1,2,3,4,5,6,7,8,9] From 282a3954649edaeac27dfb8d1678906dc8a912db Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 13 May 2017 00:03:01 +0300 Subject: [PATCH 61/76] Fixed test [#CLICKHOUSE-2]. --- dbms/src/Storages/StorageFactory.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/StorageFactory.cpp b/dbms/src/Storages/StorageFactory.cpp index 2ecb5c46ddd..a9223385c78 100644 --- a/dbms/src/Storages/StorageFactory.cpp +++ b/dbms/src/Storages/StorageFactory.cpp @@ -249,9 +249,14 @@ StoragePtr StorageFactory::get( bool attach, bool has_force_restore_data_flag) const { - checkAllTypesAreAllowedInTable(*columns); - checkAllTypesAreAllowedInTable(materialized_columns); - checkAllTypesAreAllowedInTable(alias_columns); + /// Check for some special types, that are not allowed to be stored in tables. Example: NULL data type. + /// Exception: any type is allowed in View, because plain (non-materialized) View does not store anything itself. + if (name != "View") + { + checkAllTypesAreAllowedInTable(*columns); + checkAllTypesAreAllowedInTable(materialized_columns); + checkAllTypesAreAllowedInTable(alias_columns); + } if (name == "Log") { From 9d475d34f6368148a5781385803de25360feadde Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Sat, 13 May 2017 00:05:22 +0300 Subject: [PATCH 62/76] Auto version update to [54234] --- dbms/cmake/version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index ba006fdf6c7..248c11bf89e 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ #This strings autochanged from release_lib.sh : -set(VERSION_DESCRIBE v1.1.54233-testing) -set(VERSION_REVISION 54233) +set(VERSION_DESCRIBE v1.1.54234-testing) +set(VERSION_REVISION 54234) #===end of autochange set (VERSION_MAJOR 1) From f53acf40a08d9abc1b52c46b58397f3e3c61c387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Fri, 12 May 2017 13:38:43 -0700 Subject: [PATCH 63/76] build: pass PATH to debuild this fixes build on Debian --- release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release b/release index dc6e63278eb..11153458ce7 100755 --- a/release +++ b/release @@ -63,4 +63,4 @@ echo -e "\nCurrent revision is $REVISION" gen_changelog "$REVISION" "$CHDATE" "$AUTHOR" "$CHLOG" # Build (only binary packages). -debuild -e SSH_AUTH_SOCK -e DEB_BUILD_OPTIONS=parallel=$THREAD_COUNT -e DEB_CC -e DEB_CXX -e CMAKE_FLAGS_ADD="$CMAKE_FLAGS_ADD" -b ${DEBUILD_NOSIGN_OPTIONS} ${DEBUILD_NODEPS_OPTIONS} +debuild -e PATH -e SSH_AUTH_SOCK -e DEB_BUILD_OPTIONS=parallel=$THREAD_COUNT -e DEB_CC -e DEB_CXX -e CMAKE_FLAGS_ADD="$CMAKE_FLAGS_ADD" -b ${DEBUILD_NOSIGN_OPTIONS} ${DEBUILD_NODEPS_OPTIONS} From 74cc0849dc497efb9f89e6b2d83b2d6d754db7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Fri, 12 May 2017 14:28:22 -0700 Subject: [PATCH 64/76] iostream_debug_helpers: fixed build --- dbms/src/Common/iostream_debug_helpers.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/dbms/src/Common/iostream_debug_helpers.cpp b/dbms/src/Common/iostream_debug_helpers.cpp index 4ae42fafeae..d4cded2fab7 100644 --- a/dbms/src/Common/iostream_debug_helpers.cpp +++ b/dbms/src/Common/iostream_debug_helpers.cpp @@ -39,10 +39,7 @@ std::ostream & operator<<(std::ostream & stream, const DB::IDataType & what) std::ostream & operator<<(std::ostream & stream, const DB::IStorage & what) { stream << "IStorage(name = " << what.getName() << ", tableName = " << what.getTableName() << ") {" -// TODO: uncomment #if and fix me: -#if !defined(__APPLE__) - << what.getColumnsList() -#endif + << what.getColumnsList().toString() << "}"; // isRemote supportsSampling supportsFinal supportsPrewhere supportsParallelReplicas return stream; @@ -64,10 +61,7 @@ std::ostream & operator<<(std::ostream & stream, const DB::IFunction & what) std::ostream & operator<<(std::ostream & stream, const DB::Block & what) { stream << "Block(" -// TODO: uncomment #if and fix me: -#if !defined(__APPLE__) - << "data = " << what.getColumns() -#endif + << "size = " << what.getColumns().size() << ")"; return stream; } From 95d926ec147d0ef323540e573f20122ff77829df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= Date: Fri, 12 May 2017 13:38:03 -0700 Subject: [PATCH 65/76] AggregateFunctionTopK: smaller initial table size By default start with 2^4 elements --- .../AggregateFunctions/AggregateFunctionTopK.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h index e616f0436b9..f8143cbe7b4 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionTopK.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionTopK.h @@ -21,8 +21,8 @@ namespace DB // Allow NxK more space before calculating top K to increase accuracy +#define TOP_K_DEFAULT 10 #define TOP_K_LOAD_FACTOR 3 -#define TOP_K_DEFAULT_DEGREE 10 #define TOP_K_MAX_SIZE 0xFFFFFF @@ -34,8 +34,8 @@ struct AggregateFunctionTopKData T, T, HashCRC32, - HashTableGrower, - HashTableAllocatorWithStackMemory + HashTableGrower<4>, + HashTableAllocatorWithStackMemory >; Set value; }; @@ -47,7 +47,7 @@ class AggregateFunctionTopK { private: using State = AggregateFunctionTopKData; - size_t threshold = TOP_K_DEFAULT_DEGREE; + size_t threshold = TOP_K_DEFAULT; size_t reserved = TOP_K_LOAD_FACTOR * threshold; public: @@ -132,8 +132,8 @@ struct AggregateFunctionTopKGenericData std::string, StringRef, StringRefHash, - HashTableGrower, - HashTableAllocatorWithStackMemory + HashTableGrower<4>, + HashTableAllocatorWithStackMemory >; Set value; @@ -148,7 +148,7 @@ class AggregateFunctionTopKGeneric : public IUnaryAggregateFunction::deserializeAndInsert(StringRef s } +#undef TOP_K_DEFAULT #undef TOP_K_MAX_SIZE #undef TOP_K_LOAD_FACTOR From 043717ed7bd313bb3f58ce3d4a4ca0a9499c8f5d Mon Sep 17 00:00:00 2001 From: Igor Hatarist Date: Sat, 13 May 2017 21:15:23 +0300 Subject: [PATCH 66/76] Update the ontime example dataset instructions --- doc/example_datasets/1_ontime.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/example_datasets/1_ontime.txt b/doc/example_datasets/1_ontime.txt index 752e242faae..3b9f96de503 100644 --- a/doc/example_datasets/1_ontime.txt +++ b/doc/example_datasets/1_ontime.txt @@ -9,11 +9,11 @@ http://nickmakos.blogspot.ru/2012/08/analyzing-air-traffic-performance-with.html 1. https://github.com/Percona-Lab/ontime-airline-performance/blob/master/download.sh -for s in `seq 1987 2015` +for s in `seq 1987 2017` do for m in `seq 1 12` do -wget http://tsdata.bts.gov/PREZIP/On_Time_On_Time_Performance_${s}_${m}.zip +wget http://transtats.bts.gov/PREZIP/On_Time_On_Time_Performance_${s}_${m}.zip done done From c252863b2e6d8347a6033776f99699d3fbd20bce Mon Sep 17 00:00:00 2001 From: f1yegor Date: Sun, 14 May 2017 00:19:04 +0200 Subject: [PATCH 67/76] translate comments --- .../AddingConstColumnBlockInputStream.h | 2 +- .../AddingDefaultBlockInputStream.h | 4 +- .../AddingDefaultBlockOutputStream.h | 4 +- .../DataStreams/AggregatingBlockInputStream.h | 18 +-- .../AggregatingSortedBlockInputStream.h | 26 ++-- .../AsynchronousBlockInputStream.h | 27 ++-- dbms/src/DataStreams/BinaryRowInputStream.h | 2 +- dbms/src/DataStreams/BinaryRowOutputStream.h | 2 +- .../DataStreams/BlockExtraInfoInputStream.h | 4 +- dbms/src/DataStreams/BlockIO.h | 8 +- .../BlockOutputStreamFromRowOutputStream.h | 4 +- dbms/src/DataStreams/BlockStreamProfileInfo.h | 24 ++-- .../DataStreams/BlocksListBlockInputStream.h | 8 +- dbms/src/DataStreams/CSVRowInputStream.h | 12 +- dbms/src/DataStreams/CSVRowOutputStream.h | 8 +- .../CollapsingFinalBlockInputStream.h | 40 +++--- .../CollapsingSortedBlockInputStream.h | 48 +++---- dbms/src/DataStreams/ConcatBlockInputStream.h | 8 +- .../CreatingSetsBlockInputStream.h | 10 +- dbms/src/DataStreams/EmptyBlockOutputStream.h | 4 +- .../DataStreams/ExpressionBlockInputStream.h | 8 +- dbms/src/DataStreams/FilterBlockInputStream.h | 8 +- dbms/src/DataStreams/ForkBlockInputStreams.h | 24 ++-- dbms/src/DataStreams/FormatFactory.h | 4 +- .../GraphiteRollupSortedBlockInputStream.h | 24 ++-- dbms/src/DataStreams/IBlockInputStream.h | 52 ++++---- .../DataStreams/IProfilingBlockInputStream.h | 122 +++++++++--------- .../DataStreams/JSONCompactRowOutputStream.h | 2 +- .../DataStreams/JSONEachRowRowInputStream.h | 12 +- .../DataStreams/JSONEachRowRowOutputStream.h | 4 +- dbms/src/DataStreams/LazyBlockInputStream.h | 8 +- dbms/src/DataStreams/LimitBlockInputStream.h | 10 +- dbms/src/DataStreams/MarkInCompressedFile.h | 4 +- .../MaterializingBlockInputStream.h | 2 +- .../MaterializingBlockOutputStream.h | 2 +- .../MergingAggregatedBlockInputStream.h | 4 +- ...ggregatedMemoryEfficientBlockInputStream.h | 87 +++++++------ .../MergingSortedBlockInputStream.h | 32 ++--- dbms/src/DataStreams/NativeBlockInputStream.h | 30 ++--- .../src/DataStreams/NativeBlockOutputStream.h | 16 +-- .../NullAndDoCopyBlockInputStream.h | 10 +- dbms/src/DataStreams/NullBlockInputStream.h | 2 +- dbms/src/DataStreams/NullBlockOutputStream.h | 2 +- .../DataStreams/ODBCDriverBlockOutputStream.h | 10 +- dbms/src/DataStreams/OneBlockInputStream.h | 4 +- .../ParallelAggregatingBlockInputStream.h | 24 ++-- .../src/DataStreams/ParallelInputsProcessor.h | 104 +++++++-------- .../PartialSortingBlockInputStream.h | 6 +- .../src/DataStreams/PrettyBlockOutputStream.h | 6 +- .../PrettyCompactBlockOutputStream.h | 2 +- .../PrettyCompactMonoBlockOutputStream.h | 4 +- .../PrettySpaceBlockOutputStream.h | 2 +- .../PushingToViewsBlockOutputStream.h | 10 +- dbms/src/DataStreams/QueueBlockIOStream.h | 20 +-- .../RemoveColumnsBlockInputStream.h | 2 +- .../ReplacingSortedBlockInputStream.h | 10 +- .../SummingSortedBlockInputStream.h | 68 +++++----- dbms/src/DataStreams/TSKVRowInputStream.h | 20 +-- dbms/src/DataStreams/TSKVRowOutputStream.h | 6 +- .../TabSeparatedBlockOutputStream.h | 6 +- .../TabSeparatedRawRowOutputStream.h | 4 +- .../DataStreams/TabSeparatedRowInputStream.h | 10 +- .../DataStreams/TabSeparatedRowOutputStream.h | 6 +- .../TotalsHavingBlockInputStream.h | 14 +- dbms/src/DataStreams/UnionBlockInputStream.h | 72 +++++------ dbms/src/DataStreams/ValuesRowOutputStream.h | 2 +- dbms/src/DataStreams/XMLRowOutputStream.h | 2 +- dbms/src/DataStreams/copyData.h | 4 +- dbms/src/DataStreams/glueBlockInputStreams.h | 8 +- .../src/DataStreams/narrowBlockInputStreams.h | 10 +- dbms/src/Functions/FunctionsArithmetic.h | 20 +-- dbms/src/Functions/FunctionsConversion.h | 12 +- .../Functions/FunctionsEmbeddedDictionaries.h | 36 +++--- .../Functions/FunctionsExternalDictionaries.h | 14 +- dbms/src/Functions/FunctionsFormatting.h | 8 +- dbms/src/Functions/FunctionsMath.h | 2 +- dbms/src/Functions/FunctionsMiscellaneous.h | 4 +- dbms/src/Functions/FunctionsReinterpret.h | 2 +- dbms/src/Functions/Regexps.h | 2 +- dbms/src/Functions/likePatternToRegexp.h | 2 +- .../MergeTree/ReplicatedMergeTreeLogEntry.h | 2 +- 81 files changed, 637 insertions(+), 635 deletions(-) diff --git a/dbms/src/DataStreams/AddingConstColumnBlockInputStream.h b/dbms/src/DataStreams/AddingConstColumnBlockInputStream.h index 7a430537f57..bf278ed9547 100644 --- a/dbms/src/DataStreams/AddingConstColumnBlockInputStream.h +++ b/dbms/src/DataStreams/AddingConstColumnBlockInputStream.h @@ -7,7 +7,7 @@ namespace DB { -/** Добавляет в блок материализованный const column с заданным значением. +/** Adds a materialized const column to the block with a specified value. */ template class AddingConstColumnBlockInputStream : public IProfilingBlockInputStream diff --git a/dbms/src/DataStreams/AddingDefaultBlockInputStream.h b/dbms/src/DataStreams/AddingDefaultBlockInputStream.h index 10d3e5affab..d34d8b1adf4 100644 --- a/dbms/src/DataStreams/AddingDefaultBlockInputStream.h +++ b/dbms/src/DataStreams/AddingDefaultBlockInputStream.h @@ -11,8 +11,8 @@ namespace DB { -/** Добавляет в блок недостающие столбцы со значениями по-умолчанию. - * Эти столбцы - материалированные (не константы). +/** Adds missing columns to the block with default values. + * These columns are materialized (not constants). */ class AddingDefaultBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/AddingDefaultBlockOutputStream.h b/dbms/src/DataStreams/AddingDefaultBlockOutputStream.h index fda6cd35c32..e8f1cb30b80 100644 --- a/dbms/src/DataStreams/AddingDefaultBlockOutputStream.h +++ b/dbms/src/DataStreams/AddingDefaultBlockOutputStream.h @@ -11,8 +11,8 @@ namespace DB { -/** Добавляет в блок недостающие столбцы со значениями по-умолчанию. - * Эти столбцы - материалированные (не константы). +/** Adds missing columns to the block with default values. + * These columns are materialized (not constants). */ class AddingDefaultBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/AggregatingBlockInputStream.h b/dbms/src/DataStreams/AggregatingBlockInputStream.h index 195aa7d2282..8bc92c3c3ec 100644 --- a/dbms/src/DataStreams/AggregatingBlockInputStream.h +++ b/dbms/src/DataStreams/AggregatingBlockInputStream.h @@ -10,17 +10,17 @@ namespace DB { -/** Агрегирует поток блоков, используя заданные столбцы-ключи и агрегатные функции. - * Столбцы с агрегатными функциями добавляет в конец блока. - * Если final=false, агрегатные функции не финализируются, то есть, не заменяются на своё значение, а содержат промежуточное состояние вычислений. - * Это необходимо, чтобы можно было продолжить агрегацию (например, объединяя потоки частично агрегированных данных). +/** Aggregates the stream of blocks using the specified key columns and aggregate functions. + * Columns with aggregate functions adds to the end of the block. + * If final = false, the aggregate functions are not finalized, that is, they are not replaced by their value, but contain an intermediate state of calculations. + * This is necessary so that aggregation can continue (for example, by combining streams of partially aggregated data). */ class AggregatingBlockInputStream : public IProfilingBlockInputStream { public: - /** keys берутся из GROUP BY части запроса - * Агрегатные функции ищутся везде в выражении. - * Столбцы, соответствующие keys и аргументам агрегатных функций, уже должны быть вычислены. + /** keys are taken from the GROUP BY part of the query + * Aggregate functions are searched everywhere in the expression. + * Columns corresponding to keys and arguments of aggregate functions must already be computed. */ AggregatingBlockInputStream(BlockInputStreamPtr input_, const Aggregator::Params & params_, bool final_) : params(params_), aggregator(params), final(final_) @@ -46,7 +46,7 @@ protected: bool executed = false; - /// Для чтения сброшенных во временный файл данных. + /// To read the data that was flushed into the temporary data file. struct TemporaryFileStream { ReadBufferFromFile file_in; @@ -57,7 +57,7 @@ protected: }; std::vector> temporary_inputs; - /** Отсюда будем доставать готовые блоки после агрегации. */ + /** From here we will get the completed blocks after the aggregation. */ std::unique_ptr impl; Logger * log = &Logger::get("AggregatingBlockInputStream"); diff --git a/dbms/src/DataStreams/AggregatingSortedBlockInputStream.h b/dbms/src/DataStreams/AggregatingSortedBlockInputStream.h index 8a5907e976e..455af621df1 100644 --- a/dbms/src/DataStreams/AggregatingSortedBlockInputStream.h +++ b/dbms/src/DataStreams/AggregatingSortedBlockInputStream.h @@ -12,11 +12,11 @@ namespace DB { -/** Соединяет несколько сортированных потоков в один. - * При этом, для каждой группы идущих подряд одинаковых значений первичного ключа (столбцов, по которым сортируются данные), - * сливает их в одну строку. При слиянии, производится доагрегация данных - слияние состояний агрегатных функций, - * соответствующих одному значению первичного ключа. Для столбцов, не входящих в первичный ключ, и не имеющих тип AggregateFunction, - * при слиянии, выбирается первое попавшееся значение. +/** Merges several sorted streams to one. + * During this for each group of consecutive identical values of the primary key (the columns by which the data is sorted), + * merges them into one row. When merging, the data is pre-aggregated - merge of states of aggregate functions, + * corresponding to a one value of the primary key. For columns that are not part of the primary key and which do not have the AggregateFunction type, + * when merged, the first random value is selected. */ class AggregatingSortedBlockInputStream : public MergingSortedBlockInputStream { @@ -50,30 +50,30 @@ public: const SortDescription & getSortDescription() const override { return description; } protected: - /// Может возвращаться на 1 больше записей, чем max_block_size. + /// Can return 1 more records than max_block_size. Block readImpl() override; private: Logger * log = &Logger::get("AggregatingSortedBlockInputStream"); - /// Прочитали до конца. + /// Read finished. bool finished = false; - /// Столбцы с какими номерами надо аггрегировать. + /// Columns with which numbers should be aggregated. ColumnNumbers column_numbers_to_aggregate; ColumnNumbers column_numbers_not_to_aggregate; std::vector columns_to_aggregate; - RowRef current_key; /// Текущий первичный ключ. - RowRef next_key; /// Первичный ключ следующей строки. + RowRef current_key; /// The current primary key. + RowRef next_key; /// The primary key of the next row. - /** Делаем поддержку двух разных курсоров - с Collation и без. - * Шаблоны используем вместо полиморфных SortCursor'ов и вызовов виртуальных функций. + /** We support two different cursors - with Collation and without. + * Templates are used instead of polymorphic SortCursor and calls to virtual functions. */ template void merge(ColumnPlainPtrs & merged_columns, std::priority_queue & queue); - /** Извлечь все состояния аггрегатных функций и объединить с текущей группой. + /** Extract all states of aggregate functions and merge them with the current group. */ template void addRow(TSortCursor & cursor); diff --git a/dbms/src/DataStreams/AsynchronousBlockInputStream.h b/dbms/src/DataStreams/AsynchronousBlockInputStream.h index 37784e7b33a..7776b661e25 100644 --- a/dbms/src/DataStreams/AsynchronousBlockInputStream.h +++ b/dbms/src/DataStreams/AsynchronousBlockInputStream.h @@ -17,12 +17,13 @@ namespace CurrentMetrics namespace DB { -/** Выполняет другой BlockInputStream в отдельном потоке. - * Это служит для двух целей: - * 1. Позволяет сделать так, чтобы разные стадии конвейера выполнения запроса работали параллельно. - * 2. Позволяет не ждать до того, как данные будут готовы, а периодически проверять их готовность без блокировки. - * Это нужно, например, чтобы можно было во время ожидания проверить, не пришёл ли по сети пакет с просьбой прервать выполнение запроса. - * Также это позволяет выполнить несколько запросов одновременно. +/** Executes another BlockInputStream in a separate thread. + * This serves two purposes: + * 1. Allows you to make the different stages of the query execution pipeline work in parallel. + * 2. Allows you not to wait until the data is ready, and periodically check their readiness without blocking. + * This is necessary, for example, so that during the waiting period you can check if a packet + * has come over the network with a request to interrupt the execution of the query. + * It also allows you to execute multiple queries at the same time. */ class AsynchronousBlockInputStream : public IProfilingBlockInputStream { @@ -43,7 +44,7 @@ public: void readPrefix() override { - /// Не будем вызывать readPrefix у ребёнка, чтобы соответствующие действия совершались в отдельном потоке. + /// Do not call `readPrefix` on the child, so that the corresponding actions are performed in a separate thread. if (!started) { next(); @@ -64,8 +65,8 @@ public: } - /** Ждать готовность данных не более заданного таймаута. Запустить получение данных, если нужно. - * Если функция вернула true - данные готовы и можно делать read(); нельзя вызвать функцию сразу ещё раз. + /** Wait for the data to be ready no more than the specified timeout. Start receiving data if necessary. + * If the function returned true - the data is ready and you can do `read()`; You can not call the function just at the same moment again. */ bool poll(UInt64 milliseconds) { @@ -97,13 +98,13 @@ protected: Block readImpl() override { - /// Если вычислений ещё не было - вычислим первый блок синхронно + /// If there were no calculations yet, calculate the first block synchronously if (!started) { calculate(current_memory_tracker); started = true; } - else /// Если вычисления уже идут - подождём результата + else /// If the calculations are already in progress - wait for the result pool.wait(); if (exception) @@ -113,7 +114,7 @@ protected: if (!res) return res; - /// Запустим вычисления следующего блока + /// Start the next block calculation block = Block(); next(); @@ -128,7 +129,7 @@ protected: } - /// Вычисления, которые могут выполняться в отдельном потоке + /// Calculations that can be performed in a separate thread void calculate(MemoryTracker * memory_tracker) { CurrentMetrics::Increment metric_increment{CurrentMetrics::QueryThread}; diff --git a/dbms/src/DataStreams/BinaryRowInputStream.h b/dbms/src/DataStreams/BinaryRowInputStream.h index 86b7d9fa1c9..af3cccf535a 100644 --- a/dbms/src/DataStreams/BinaryRowInputStream.h +++ b/dbms/src/DataStreams/BinaryRowInputStream.h @@ -10,7 +10,7 @@ class Block; class ReadBuffer; -/** Поток для ввода данных в бинарном построчном формате. +/** A stream for inputting data in a binary line-by-line format. */ class BinaryRowInputStream : public IRowInputStream { diff --git a/dbms/src/DataStreams/BinaryRowOutputStream.h b/dbms/src/DataStreams/BinaryRowOutputStream.h index f91b16cc79d..190e7e15afd 100644 --- a/dbms/src/DataStreams/BinaryRowOutputStream.h +++ b/dbms/src/DataStreams/BinaryRowOutputStream.h @@ -11,7 +11,7 @@ class IDataType; class WriteBuffer; -/** Поток для вывода данных в бинарном построчном формате. +/** A stream for outputting data in a binary line-by-line format. */ class BinaryRowOutputStream : public IRowOutputStream { diff --git a/dbms/src/DataStreams/BlockExtraInfoInputStream.h b/dbms/src/DataStreams/BlockExtraInfoInputStream.h index be816fe78ac..fb3c7e03817 100644 --- a/dbms/src/DataStreams/BlockExtraInfoInputStream.h +++ b/dbms/src/DataStreams/BlockExtraInfoInputStream.h @@ -5,8 +5,8 @@ namespace DB { -/** Прибавляет к одному потоку дополнительную информацию о блоках, которая задана - * в качестве параметра конструктора. +/** Adds to one thread additional block information that is specified + * as the constructor parameter. */ class BlockExtraInfoInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/BlockIO.h b/dbms/src/DataStreams/BlockIO.h index c8c9333cb9d..0d704993ea3 100644 --- a/dbms/src/DataStreams/BlockIO.h +++ b/dbms/src/DataStreams/BlockIO.h @@ -21,14 +21,14 @@ struct BlockIO BlockInputStreamPtr in; BlockOutputStreamPtr out; - Block in_sample; /// Пример блока, который будет прочитан из in. - Block out_sample; /// Пример блока, которого нужно писать в out. + Block in_sample; /// Example of a block to be read from `in`. + Block out_sample; /// Example of a block to be written to `out`. /// Callbacks for query logging could be set here. std::function finish_callback; std::function exception_callback; - /// Вызывайте эти функции, если нужно логгировать запрос. + /// Call these functions if you want to log the request. void onFinish() { if (finish_callback) @@ -43,7 +43,7 @@ struct BlockIO BlockIO & operator= (const BlockIO & rhs) { - /// Обеспечиваем правильный порядок уничтожения. + /// We provide the correct order of destruction. out = nullptr; in = nullptr; process_list_entry = nullptr; diff --git a/dbms/src/DataStreams/BlockOutputStreamFromRowOutputStream.h b/dbms/src/DataStreams/BlockOutputStreamFromRowOutputStream.h index b52b0ffca60..63743f7827a 100644 --- a/dbms/src/DataStreams/BlockOutputStreamFromRowOutputStream.h +++ b/dbms/src/DataStreams/BlockOutputStreamFromRowOutputStream.h @@ -7,8 +7,8 @@ namespace DB { -/** Преобразует поток для записи данных по строкам в поток для записи данных по блокам. - * Наример, для записи текстового дампа. +/** Transforms a stream to write data by rows to a stream to write data by blocks. + * For example, to write a text dump. */ class BlockOutputStreamFromRowOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/BlockStreamProfileInfo.h b/dbms/src/DataStreams/BlockStreamProfileInfo.h index bb0c80f88a7..e95fd3b4f9b 100644 --- a/dbms/src/DataStreams/BlockStreamProfileInfo.h +++ b/dbms/src/DataStreams/BlockStreamProfileInfo.h @@ -16,29 +16,29 @@ class Block; class ReadBuffer; class WriteBuffer; -/// Информация для профайлинга. См. IProfilingBlockInputStream.h +/// Information for profiling. See IProfilingBlockInputStream.h struct BlockStreamProfileInfo { bool started = false; - Stopwatch total_stopwatch {CLOCK_MONOTONIC_COARSE}; /// Время с учётом ожидания + Stopwatch total_stopwatch {CLOCK_MONOTONIC_COARSE}; /// Time with waiting time - String stream_name; /// Короткое имя потока, для которого собирается информация + String stream_name; /// The short name of the stream for which information is collected size_t rows = 0; size_t blocks = 0; size_t bytes = 0; - /// Информация о вложенных потоках - для выделения чистого времени работы. + /// Information about nested threads - to calculate pure processing time. using BlockStreamProfileInfos = std::vector; BlockStreamProfileInfos nested_infos; - /// Собрать BlockStreamProfileInfo для ближайших в дереве источников с именем name. Пример; собрать все info для PartialSorting stream-ов. + /// Collect BlockStreamProfileInfo for the nearest sources in the tree named `name`. Example; collect all info for PartialSorting streams. void collectInfosForStreamsWithName(const char * name, BlockStreamProfileInfos & res) const; - /** Получить число строк, если бы не было LIMIT-а. - * Если нет LIMIT-а - возвращается 0. - * Если запрос не содержит ORDER BY, то число может быть занижено - возвращается количество строк в блоках, которые были прочитаны до LIMIT-а. - * Если запрос содержит ORDER BY, то возвращается точное число строк, которое было бы, если убрать LIMIT. + /** Get the number of rows if there were no LIMIT. + * If there is no LIMIT, 0 is returned. + * If the query does not contain ORDER BY, the number can be underestimated - return the number of rows in blocks that were read before LIMIT reached. + * If the query contains an ORDER BY, then returns the exact number of rows as if LIMIT is removed from query. */ size_t getRowsBeforeLimit() const; bool hasAppliedLimit() const; @@ -57,10 +57,10 @@ struct BlockStreamProfileInfo private: void calculateRowsBeforeLimit() const; - /// Для этих полей сделаем accessor'ы, т.к. их необходимо предварительно вычислять. - mutable bool applied_limit = false; /// Применялся ли LIMIT + /// For these fields we make accessors, because they must be calculated beforehand. + mutable bool applied_limit = false; /// Whether LIMIT was applied mutable size_t rows_before_limit = 0; - mutable bool calculated_rows_before_limit = false; /// Вычислялось ли поле rows_before_limit + mutable bool calculated_rows_before_limit = false; /// Whether the field rows_before_limit was calculated }; } diff --git a/dbms/src/DataStreams/BlocksListBlockInputStream.h b/dbms/src/DataStreams/BlocksListBlockInputStream.h index a83748f399f..b477e34d3ca 100644 --- a/dbms/src/DataStreams/BlocksListBlockInputStream.h +++ b/dbms/src/DataStreams/BlocksListBlockInputStream.h @@ -6,17 +6,17 @@ namespace DB { -/** Поток блоков, из которого можно прочитать следующий блок из явно предоставленного списка. - * Также смотрите OneBlockInputStream. +/** A stream of blocks from which you can read the next block from an explicitly provided list. + * Also see OneBlockInputStream. */ class BlocksListBlockInputStream : public IProfilingBlockInputStream { public: - /// Захватывает владение списком блоков. + /// Acquires the ownership of the block list. BlocksListBlockInputStream(BlocksList && list_) : list(std::move(list_)), it(list.begin()), end(list.end()) {} - /// Использует лежащий где-то ещё список блоков. + /// Uses a list of blocks lying somewhere else. BlocksListBlockInputStream(BlocksList::iterator & begin_, BlocksList::iterator & end_) : it(begin_), end(end_) {} diff --git a/dbms/src/DataStreams/CSVRowInputStream.h b/dbms/src/DataStreams/CSVRowInputStream.h index 61bf3e11fb5..16d1f1056b8 100644 --- a/dbms/src/DataStreams/CSVRowInputStream.h +++ b/dbms/src/DataStreams/CSVRowInputStream.h @@ -9,14 +9,14 @@ namespace DB class ReadBuffer; -/** Поток для ввода данных в формате csv. - * Не соответствует https://tools.ietf.org/html/rfc4180 потому что пропускает пробелы и табы между значениями. +/** A stream for inputting data in csv format. + * Does not conform with https://tools.ietf.org/html/rfc4180 because it skips spaces and tabs between values. */ class CSVRowInputStream : public IRowInputStream { public: - /** with_names - в первой строке заголовок с именами столбцов - * with_types - на следующей строке заголовок с именами типов + /** with_names - in the first line the header with column names + * with_types - on the next line header with type names */ CSVRowInputStream(ReadBuffer & istr_, const Block & sample_, const char delimiter_, bool with_names_ = false, bool with_types_ = false); @@ -35,11 +35,11 @@ private: bool with_types; DataTypes data_types; - /// Для удобной диагностики в случае ошибки. + /// For convenient diagnostics in case of an error. size_t row_num = 0; - /// Сколько байт было считано, не считая тех, что ещё в буфере. + /// How many bytes were read, not counting those that are still in the buffer. size_t bytes_read_at_start_of_buffer_on_current_row = 0; size_t bytes_read_at_start_of_buffer_on_prev_row = 0; diff --git a/dbms/src/DataStreams/CSVRowOutputStream.h b/dbms/src/DataStreams/CSVRowOutputStream.h index 81f536613af..161eab16985 100644 --- a/dbms/src/DataStreams/CSVRowOutputStream.h +++ b/dbms/src/DataStreams/CSVRowOutputStream.h @@ -10,14 +10,14 @@ namespace DB class WriteBuffer; -/** Поток для вывода данных в формате csv. - * Не соответствует https://tools.ietf.org/html/rfc4180 потому что использует LF, а не CR LF. +/** The stream for outputting data in csv format. + * Does not conform with https://tools.ietf.org/html/rfc4180 because it uses LF, not CR LF. */ class CSVRowOutputStream : public IRowOutputStream { public: - /** with_names - выводить в первой строке заголовок с именами столбцов - * with_types - выводить на следующей строке заголовок с именами типов + /** with_names - output in the first line a header with column names + * with_types - output in the next line header with the names of the types */ CSVRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_ = false, bool with_types_ = false); diff --git a/dbms/src/DataStreams/CollapsingFinalBlockInputStream.h b/dbms/src/DataStreams/CollapsingFinalBlockInputStream.h index 42ab1b96f22..4a867f96f2d 100644 --- a/dbms/src/DataStreams/CollapsingFinalBlockInputStream.h +++ b/dbms/src/DataStreams/CollapsingFinalBlockInputStream.h @@ -8,9 +8,9 @@ namespace DB { -/// Схлопывает одинаковые строки с противоположным знаком примерно как CollapsingSortedBlockInputStream. -/// Выдает строки в произвольном порядке (входные потоки по-прежнему должны быть упорядочены). -/// Выдает только строки с положительным знаком. +/// Collapses the same rows with the opposite sign roughly like CollapsingSortedBlockInputStream. +/// Outputs the rows in random order (the input streams must still be ordered). +/// Outputs only rows with a positive sign. class CollapsingFinalBlockInputStream : public IProfilingBlockInputStream { public: @@ -79,31 +79,31 @@ private: throw Exception("Sign column must have type Int8", ErrorCodes::BAD_TYPE_OF_FIELD); rows = sign_column->size(); - /// Заполняется целиком нулями. Потом выставляются единички в позициях строчек, которых нужно оставить. + /// Filled entirely with zeros. Then `1` are set in the positions of the rows to be left. filter.resize_fill(rows); } Block block; - /// Строки с одинаковым ключом будут упорядочены по возрастанию stream_index. + /// Rows with the same key will be sorted in ascending order of stream_index. size_t stream_index; size_t rows; - /// Какие строки нужно оставить. Заполняется при слиянии потоков. + /// Which rows should be left. Filled when the threads merge. IColumn::Filter filter; - /// Указывают в block. + /// Point to `block`. ConstColumnPlainPtrs sort_columns; const ColumnInt8 * sign_column; - /// Когда достигает нуля, блок можно выдавать в ответ. + /// When it reaches zero, the block can be outputted in response. int refcount = 0; - /// Куда положить блок, когда он готов попасть в ответ. + /// Where to put the block when it is ready to be outputted in response. BlockPlainPtrs * output_blocks; }; - /// При удалении последней ссылки на блок, добавляет блок в output_blocks. + /// When deleting the last block reference, adds a block to `output_blocks`. class MergingBlockPtr { public: @@ -135,7 +135,7 @@ private: destroy(); } - /// Обнулить указатель и не добавлять блок в output_blocks. + /// Zero the pointer and do not add a block to output_blocks. void cancel() { if (ptr) @@ -194,7 +194,7 @@ private: return block->stream_index > rhs.block->stream_index; } - /// Не согласован с operator< : не учитывает order. + /// Not consistent with operator< : does not consider order. bool equal(const Cursor & rhs) const { if (!block || !rhs.block) @@ -215,7 +215,7 @@ private: return block->sign_column->getData()[pos]; } - /// Помечает, что эту строку нужно взять в ответ. + /// Indicates that this row should be outputted in response. void addToFilter() { block->filter[pos] = 1; @@ -245,16 +245,16 @@ private: Queue queue; - Cursor previous; /// Текущий первичный ключ. - Cursor last_positive; /// Последняя положительная строка для текущего первичного ключа. + Cursor previous; /// The current primary key. + Cursor last_positive; /// The last positive row for the current primary key. - size_t count_positive = 0; /// Количество положительных строк для текущего первичного ключа. - size_t count_negative = 0; /// Количество отрицательных строк для текущего первичного ключа. - bool last_is_positive = false; /// true, если последняя строка для текущего первичного ключа положительная. + size_t count_positive = 0; /// The number of positive rows for the current primary key. + size_t count_negative = 0; /// The number of negative rows for the current primary key. + bool last_is_positive = false; /// true if the last row for the current primary key is positive. - size_t count_incorrect_data = 0; /// Чтобы не писать в лог слишком много сообщений об ошибке. + size_t count_incorrect_data = 0; /// To prevent too many error messages from writing to the log. - /// Посчитаем, сколько блоков получили на вход и отдали на выход. + /// Count the number of blocks fetched and outputted. size_t blocks_fetched = 0; size_t blocks_output = 0; diff --git a/dbms/src/DataStreams/CollapsingSortedBlockInputStream.h b/dbms/src/DataStreams/CollapsingSortedBlockInputStream.h index c229246813f..0f082fbcb80 100644 --- a/dbms/src/DataStreams/CollapsingSortedBlockInputStream.h +++ b/dbms/src/DataStreams/CollapsingSortedBlockInputStream.h @@ -8,17 +8,17 @@ namespace DB { -/** Соединяет несколько сортированных потоков в один. - * При этом, для каждой группы идущих подряд одинаковых значений первичного ключа (столбцов, по которым сортируются данные), - * оставляет не более одной строки со значением столбца sign_column = -1 ("отрицательной строки") - * и не более одиной строки со значением столбца sign_column = 1 ("положительной строки"). - * То есть - производит схлопывание записей из лога изменений. +/** Merges several sorted streams to one. + * For each group of consecutive identical values of the primary key (the columns by which the data is sorted), + * keeps no more than one row with the value of the column `sign_column = -1` ("negative row") + * and no more than a row with the value of the column `sign_column = 1` ("positive row"). + * That is, it collapses the records from the change log. * - * Если количество положительных и отрицательных строк совпадает, и последняя строка положительная - то пишет первую отрицательную и последнюю положительную строку. - * Если количество положительных и отрицательных строк совпадает, и последняя строка отрицательная - то ничего не пишет. - * Если положительных на 1 больше, чем отрицательных - то пишет только последнюю положительную строку. - * Если отрицательных на 1 больше, чем положительных - то пишет только первую отрицательную строку. - * Иначе - логическая ошибка. + * If the number of positive and negative rows is the same, and the last row is positive, then the first negative and last positive rows are written. + * If the number of positive and negative rows is the same, and the last line is negative, it writes nothing. + * If the positive by 1 is greater than the negative rows, then only the last positive row is written. + * If negative by 1 is greater than positive rows, then only the first negative row is written. + * Otherwise, a logical error. */ class CollapsingSortedBlockInputStream : public MergingSortedBlockInputStream { @@ -50,7 +50,7 @@ public: } protected: - /// Может возвращаться на 1 больше записей, чем max_block_size. + /// Can return 1 more records than max_block_size. Block readImpl() override; private: @@ -59,21 +59,21 @@ private: Logger * log = &Logger::get("CollapsingSortedBlockInputStream"); - /// Прочитали до конца. + /// Read is finished. bool finished = false; - RowRef current_key; /// Текущий первичный ключ. - RowRef next_key; /// Первичный ключ следующей строки. + RowRef current_key; /// The current primary key. + RowRef next_key; /// The primary key of the next row. - RowRef first_negative; /// Первая отрицательная строка для текущего первичного ключа. - RowRef last_positive; /// Последняя положительная строка для текущего первичного ключа. - RowRef last_negative; /// Последняя отрицательная. Сорраняется только если ни одной строки в ответ еще не выписано. + RowRef first_negative; /// The first negative row for the current primary key. + RowRef last_positive; /// The last positive row for the current primary key. + RowRef last_negative; /// Last negative row. It is only stored if there is not one row is written to output. - size_t count_positive = 0; /// Количество положительных строк для текущего первичного ключа. - size_t count_negative = 0; /// Количество отрицательных строк для текущего первичного ключа. - bool last_is_positive = false; /// true, если последняя строка для текущего первичного ключа положительная. + size_t count_positive = 0; /// The number of positive rows for the current primary key. + size_t count_negative = 0; /// The number of negative rows for the current primary key. + bool last_is_positive = false; /// true if the last row for the current primary key is positive. - size_t count_incorrect_data = 0; /// Чтобы не писать в лог слишком много сообщений об ошибке. + size_t count_incorrect_data = 0; /// To prevent too many error messages from writing to the log. size_t blocks_written = 0; @@ -83,13 +83,13 @@ private: size_t last_positive_pos = 0; /// Global row number of last_positive size_t last_negative_pos = 0; /// Global row number of last_negative - /** Делаем поддержку двух разных курсоров - с Collation и без. - * Шаблоны используем вместо полиморфных SortCursor'ов и вызовов виртуальных функций. + /** We support two different cursors - with Collation and without. + * Templates are used instead of polymorphic SortCursors and calls to virtual functions. */ template void merge(ColumnPlainPtrs & merged_columns, std::priority_queue & queue); - /// Вставить в результат строки для текущего первичного ключа. + /// Output to result rows for the current primary key. void insertRows(ColumnPlainPtrs & merged_columns, size_t & merged_rows, bool last_in_stream = false); void reportIncorrectData(); diff --git a/dbms/src/DataStreams/ConcatBlockInputStream.h b/dbms/src/DataStreams/ConcatBlockInputStream.h index 5133265208b..e8da47a7c02 100644 --- a/dbms/src/DataStreams/ConcatBlockInputStream.h +++ b/dbms/src/DataStreams/ConcatBlockInputStream.h @@ -7,9 +7,9 @@ namespace DB { -/** Объединяет несколько источников в один. - * В отличие от UnionBlockInputStream, делает это последовательно. - * Блоки разных источников не перемежаются друг с другом. +/** Combines several sources into one. + * Unlike UnionBlockInputStream, it does this sequentially. + * Blocks of different sources are not interleaved with each other. */ class ConcatBlockInputStream : public IProfilingBlockInputStream { @@ -31,7 +31,7 @@ public: for (size_t i = 0; i < children.size(); ++i) children_ids[i] = children[i]->getID(); - /// Будем считать, что порядок конкатенации блоков не имеет значения. + /// Let's assume that the order of concatenation of blocks does not matter. std::sort(children_ids.begin(), children_ids.end()); for (size_t i = 0; i < children_ids.size(); ++i) diff --git a/dbms/src/DataStreams/CreatingSetsBlockInputStream.h b/dbms/src/DataStreams/CreatingSetsBlockInputStream.h index d9d096f6a92..c3b5bfcf3b7 100644 --- a/dbms/src/DataStreams/CreatingSetsBlockInputStream.h +++ b/dbms/src/DataStreams/CreatingSetsBlockInputStream.h @@ -10,9 +10,9 @@ namespace Poco { class Logger; } namespace DB { -/** Отдаёт без изменений данные из потока блоков, но - * в функции readPrefix или перед чтением первого блока - * инициализирует все переданные множества. +/** Returns the data from the stream of blocks without changes, but + * in the `readPrefix` function or before reading the first block + * initializes all the passed sets. */ class CreatingSetsBlockInputStream : public IProfilingBlockInputStream { @@ -44,7 +44,7 @@ public: for (size_t i = 0; i < children.size(); ++i) children_ids[i] = children[i]->getID(); - /// Будем считать, что порядок создания множеств не имеет значения. + /// Let's assume that the order of creating sets does not matter. std::sort(children_ids.begin(), children_ids.end() - 1); for (size_t i = 0; i < children_ids.size(); ++i) @@ -54,7 +54,7 @@ public: return res.str(); } - /// Берёт totals только из основного источника, а не из источников подзапросов. + /// Takes `totals` only from the main source, not from subquery sources. const Block & getTotals() override; protected: diff --git a/dbms/src/DataStreams/EmptyBlockOutputStream.h b/dbms/src/DataStreams/EmptyBlockOutputStream.h index 340be887939..b84e8d483e6 100644 --- a/dbms/src/DataStreams/EmptyBlockOutputStream.h +++ b/dbms/src/DataStreams/EmptyBlockOutputStream.h @@ -12,8 +12,8 @@ namespace ErrorCodes extern const int CANNOT_WRITE_TO_EMPTY_BLOCK_OUTPUT_STREAM; } -/** При попытке записать в этот поток блоков, кидает исключение. - * Используется там, где, в общем случае, нужно передать поток блоков, но в некоторых случаях, он не должен быть использован. +/** When trying to write blocks to this stream of blocks, throws an exception. + * Used where, in general, you need to pass a stream of blocks, but in some cases, it should not be used. */ class EmptyBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/ExpressionBlockInputStream.h b/dbms/src/DataStreams/ExpressionBlockInputStream.h index c19921e1b67..6e5b166bad8 100644 --- a/dbms/src/DataStreams/ExpressionBlockInputStream.h +++ b/dbms/src/DataStreams/ExpressionBlockInputStream.h @@ -8,10 +8,10 @@ namespace DB class ExpressionActions; -/** Выполняет над блоком вычисление некоторого выражения. - * Выражение состоит из идентификаторов столбцов из блока, констант, обычных функций. - * Например: hits * 2 + 3, url LIKE '%yandex%' - * Выражение обрабатывает каждую строку независимо от других. +/** Executes a certain expression over the block. + * The expression consists of column identifiers from the block, constants, common functions. + * For example: hits * 2 + 3, url LIKE '%yandex%' + * The expression processes each row independently of the others. */ class ExpressionBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/FilterBlockInputStream.h b/dbms/src/DataStreams/FilterBlockInputStream.h index 25767b22dc2..3f0cda420c6 100644 --- a/dbms/src/DataStreams/FilterBlockInputStream.h +++ b/dbms/src/DataStreams/FilterBlockInputStream.h @@ -9,9 +9,9 @@ namespace DB class ExpressionActions; -/** Реализует операции WHERE, HAVING. - * На вход подаётся поток блоков и выражение, добавляющее в блок один столбец типа ColumnUInt8, содержащий условия фильтрации. - * Выражение вычисляется и возвращается поток блоков, в котором содержатся только отфильтрованные строки. +/** Implements WHERE, HAVING operations. + * A stream of blocks and an expression, which adds to the block one ColumnUInt8 column containing the filtering conditions, are passed as input. + * The expression is evaluated and a stream of blocks is returned, which contains only the filtered rows. */ class FilterBlockInputStream : public IProfilingBlockInputStream { @@ -19,7 +19,7 @@ private: using ExpressionActionsPtr = std::shared_ptr; public: - /// filter_column_ - номер столбца с условиями фильтрации. + /// filter_column_ - the number of the column with filter conditions. FilterBlockInputStream(BlockInputStreamPtr input_, ExpressionActionsPtr expression_, ssize_t filter_column_); FilterBlockInputStream(BlockInputStreamPtr input_, ExpressionActionsPtr expression_, const String & filter_column_name_); diff --git a/dbms/src/DataStreams/ForkBlockInputStreams.h b/dbms/src/DataStreams/ForkBlockInputStreams.h index 0fc7cd6a88d..e10e0d3f8fd 100644 --- a/dbms/src/DataStreams/ForkBlockInputStreams.h +++ b/dbms/src/DataStreams/ForkBlockInputStreams.h @@ -7,27 +7,27 @@ namespace DB { -/** Позволяет из одного источника сделать несколько. - * Используется для однопроходного выполнения сразу нескольких запросов. +/** Allows you to make several sources from one. + * Used for single-pass execution of several queries at once. * - * Несколько полученных источников должны читаться из разных потоков! - * Расходует O(1) оперативки (не буферизует все данные). - * Для этого, чтения из разных полученных источников синхронизируются: - * чтение следующего блока блокируется, пока все источники не прочитают текущий блок. + * Multiple received sources should be read from different threads! + * Uses O(1) RAM (does not buffer all data). + * For this, readings from different sources are synchronized: + * reading of next block is blocked until all sources have read the current block. */ class ForkBlockInputStreams : private boost::noncopyable { public: ForkBlockInputStreams(BlockInputStreamPtr source_) : source(source_) {} - /// Создать источник. Вызывайте функцию столько раз, сколько размноженных источников вам нужно. + /// Create a source. Call the function as many times as many forked sources you need. BlockInputStreamPtr createInput() { destinations.emplace_back(std::make_shared(1)); return destinations.back(); } - /// Перед тем, как из полученных источников можно будет читать, необходимо "запустить" эту конструкцию. + /// Before you can read from the sources you have to "run" this construct. void run() { while (1) @@ -56,12 +56,12 @@ public: } private: - /// Откуда читать. + /// From where to read. BlockInputStreamPtr source; - /** Размноженные источники. - * Сделаны на основе очереди небольшой длины. - * Блок из source кладётся в каждую очередь. + /** Forked sources. + * Made on the basis of a queue of small length. + * A block from `source` is put in each queue. */ using Destination = std::shared_ptr; using Destinations = std::list; diff --git a/dbms/src/DataStreams/FormatFactory.h b/dbms/src/DataStreams/FormatFactory.h index a58f778df4f..c2aaa9a9fb7 100644 --- a/dbms/src/DataStreams/FormatFactory.h +++ b/dbms/src/DataStreams/FormatFactory.h @@ -9,8 +9,8 @@ namespace DB class Context; -/** Позволяет создать IBlockInputStream или IBlockOutputStream по названию формата. - * Замечание: формат и сжатие - независимые вещи. +/** Allows to create an IBlockInputStream or IBlockOutputStream by the name of the format. + * Note: format and compression are independent things. */ class FormatFactory { diff --git a/dbms/src/DataStreams/GraphiteRollupSortedBlockInputStream.h b/dbms/src/DataStreams/GraphiteRollupSortedBlockInputStream.h index 5a7a6a74e70..0c289cb025d 100644 --- a/dbms/src/DataStreams/GraphiteRollupSortedBlockInputStream.h +++ b/dbms/src/DataStreams/GraphiteRollupSortedBlockInputStream.h @@ -111,16 +111,16 @@ namespace Graphite }; } -/** Соединяет несколько сортированных потоков в один. +/** Merges several sorted streams into one. * - * При этом, для каждой группы идущих подряд одинаковых значений столбца path, - * и одинаковых значений time с округлением до некоторой точности - * (где точность округления зависит от набора шаблонов на path - * и количества времени, прошедшего от time до заданного времени), - * оставляет одну строку, - * выполняя округление времени, - * слияние значений value, используя заданные агрегатные функции, - * а также оставляя максимальное значение столбца version. + * For each group of consecutive identical values of the `path` column, + * and the same `time` values, rounded to some precision + * (where rounding accuracy depends on the template set for `path` + * and the amount of time elapsed from `time` to the specified time), + * keeps one line, + * performing the rounding of time, + * merge `value` values using the specified aggregate functions, + * as well as keeping the maximum value of the `version` column. */ class GraphiteRollupSortedBlockInputStream : public MergingSortedBlockInputStream { @@ -200,14 +200,14 @@ private: template void merge(ColumnPlainPtrs & merged_columns, std::priority_queue & queue); - /// Вставить значения в результирующие столбцы, которые не будут меняться в дальнейшем. + /// Insert the values into the resulting columns, which will not be changed in the future. template void startNextRow(ColumnPlainPtrs & merged_columns, TSortCursor & cursor); - /// Вставить в результирующие столбцы вычисленные значения time, value, version по последней группе строк. + /// Insert the calculated `time`, `value`, `version` values into the resulting columns by the last group of rows. void finishCurrentRow(ColumnPlainPtrs & merged_columns); - /// Обновить состояние агрегатной функции новым значением value. + /// Update the state of the aggregate function with the new `value`. void accumulateRow(RowRef & row); }; diff --git a/dbms/src/DataStreams/IBlockInputStream.h b/dbms/src/DataStreams/IBlockInputStream.h index e0d3c44f0ef..24c4692e3f7 100644 --- a/dbms/src/DataStreams/IBlockInputStream.h +++ b/dbms/src/DataStreams/IBlockInputStream.h @@ -31,53 +31,53 @@ namespace ErrorCodes } -/** Коллбэк для отслеживания прогресса выполнения запроса. - * Используется в IProfilingBlockInputStream и Context-е. - * Функция принимает количество строк в последнем блоке, количество байт в последнем блоке. - * Следует иметь ввиду, что колбэк может вызываться из разных потоков. +/** Callback to track the progress of the query. + * Used in IProfilingBlockInputStream and Context. + * The function takes the number of rows in the last block, the number of bytes in the last block. + * Note that the callback can be called from different threads. */ using ProgressCallback = std::function; -/** Интерфейс потока для чтения данных по блокам из БД. - * Реляционные операции предполагается делать также реализациями этого интерфейса. +/** The stream interface for reading data by blocks from the database. + * Relational operations are supposed to be done also as implementations of this interface. */ class IBlockInputStream : private boost::noncopyable { public: IBlockInputStream() {} - /** Прочитать следующий блок. - * Если блоков больше нет - вернуть пустой блок (для которого operator bool возвращает false). + /** Read next block. + * If there are no more blocks, return an empty block (for which operator `bool` returns false). */ virtual Block read() = 0; - /** Получить информацию про последний полученный блок. + /** Get information about the last block received. */ virtual BlockExtraInfo getBlockExtraInfo() const { throw Exception("Method getBlockExtraInfo is not supported by the data stream " + getName(), ErrorCodes::NOT_IMPLEMENTED); } - /** Прочитать что-нибудь перед началом всех данных или после конца всех данных. - * В функции readSuffix можно реализовать финализацию, которая может привести к исключению. - * readPrefix() должна вызываться до первого вызова read(). - * readSuffix() должна вызываться после того, как read() вернула пустой блок, или после вызова cancel(), но не во время выполнения read(). + /** Read something before starting all data or after the end of all data. + * In the `readSuffix` function, you can implement a finalization that can lead to an exception. + * readPrefix() must be called before the first call to read(). + * readSuffix() should be called after read() returns an empty block, or after a call to cancel(), but not during read() execution. */ virtual void readPrefix() {} virtual void readSuffix() {} virtual ~IBlockInputStream() {} - /** Для вывода дерева преобразований потока данных (плана выполнения запроса). + /** To output the data stream transformation tree (query execution plan). */ virtual String getName() const = 0; - /** Уникальный идентификатор части конвейера выполнения запроса. - * Источники с одинаковым идентификатором считаются идентичными - * (выдающими одинаковые данные), и могут быть заменены на один источник - * при одновременном выполнении сразу нескольких запросов. - * Если источник нельзя склеивать ни с каким другим - верните в качестве идентификатора адрес объекта. + /** The unique identifier of the pipeline part of the query execution. + * Sources with the same identifier are considered identical + * (producing the same data), and can be replaced by one source + * if several queries are executed simultaneously. + * If the source can not be glued together with any other - return the object's address as an identifier. */ virtual String getID() const = 0; @@ -92,18 +92,18 @@ public: void dumpTree(std::ostream & ostr, size_t indent = 0, size_t multiplier = 1); - /// Получить листовые источники (не считая этот). + /// Get leaf sources (not including this one). BlockInputStreams getLeaves(); - /// Получить количество строк и байт, прочитанных в листовых источниках. + /// Get the number of rows and bytes read in the leaf sources. void getLeafRowsBytes(size_t & rows, size_t & bytes); - /** Проверить глубину конвейера. - * Если задано max_depth и глубина больше - кинуть исключение. + /** Check the depth of the pipeline. + * If max_depth is specified and the `depth` is greater - throw an exception. */ size_t checkDepth(size_t max_depth) const; - /** Не давать изменить таблицу, пока жив поток блоков. + /** Do not allow to change the table while the blocks stream is alive. */ void addTableLock(const TableStructureReadLockPtr & lock) { table_locks.push_back(lock); } @@ -117,8 +117,8 @@ private: size_t checkDepthImpl(size_t max_depth, size_t level) const; - /** Получить текст, который идентифицирует этот источник и всё поддерево. - * В отличие от getID - без учёта параметров. + /** Get text that identifies this source and the entire subtree. + * Unlike getID - without taking into account the parameters. */ String getTreeID() const; }; diff --git a/dbms/src/DataStreams/IProfilingBlockInputStream.h b/dbms/src/DataStreams/IProfilingBlockInputStream.h index 17806f79785..88834789464 100644 --- a/dbms/src/DataStreams/IProfilingBlockInputStream.h +++ b/dbms/src/DataStreams/IProfilingBlockInputStream.h @@ -19,66 +19,66 @@ class IProfilingBlockInputStream; using ProfilingBlockInputStreamPtr = std::shared_ptr; -/** Смотрит за тем, как работает источник блоков. - * Позволяет получить информацию для профайлинга: - * строк в секунду, блоков в секунду, мегабайт в секунду и т. п. - * Позволяет остановить чтение данных (во вложенных источниках). +/** Watches out at how the source of the blocks works. + * Lets you get information for profiling: + * rows per second, blocks per second, megabytes per second, etc. + * Allows you to stop reading data (in nested sources). */ class IProfilingBlockInputStream : public IBlockInputStream { public: Block read() override final; - /** Реализация по-умолчанию вызывает readPrefixImpl() у себя, а затем readPrefix() у всех детей рекурсивно. - * Есть случаи, когда вы не хотите, чтобы readPrefix у детей вызывался синхронно, в этой функции, - * а хотите, чтобы они вызывались, например, в отдельных потоках (для распараллеливания инициализации детей). - * Тогда перегрузите функцию readPrefix. + /** The default implementation calls readPrefixImpl() on itself, and then readPrefix() recursively for all children. + * There are cases when you do not want `readPrefix` of children to be called synchronously, in this function, + * but you want them to be called, for example, in separate threads (for parallel initialization of children). + * Then overload `readPrefix` function. */ void readPrefix() override; - /** Реализация по-умолчанию вызывает рекурсивно readSuffix() у всех детей, а затем readSuffixImpl() у себя. - * Если этот поток вызывает у детей read() в отдельном потоке, этот поведение обычно неверно: - * readSuffix() у ребенка нельзя вызывать в момент, когда read() того же ребенка выполняется в другом потоке. - * В таком случае нужно переопределить этот метод, чтобы readSuffix() у детей вызывался, например, после соединения потоков. + /** The default implementation calls recursively readSuffix() on all children, and then readSuffixImpl() on itself. + * If this stream calls read() in children in a separate thread, this behavior is usually incorrect: + * readSuffix() of the child can not be called at the moment when the same child's read() is executed in another thread. + * In this case, you need to override this method so that readSuffix() in children is called, for example, after connecting streams. */ void readSuffix() override; /// Get information about execution speed. const BlockStreamProfileInfo & getProfileInfo() const { return info; } - /** Получить "тотальные" значения. - * Реализация по-умолчанию берёт их из себя или из первого дочернего источника, в котором они есть. - * Переопределённый метод может провести некоторые вычисления. Например, применить выражение к totals дочернего источника. - * Тотальных значений может не быть - тогда возвращается пустой блок. + /** Get "total" values. + * The default implementation takes them from itself or from the first child source in which they are. + * The overridden method can perform some calculations. For example, apply an expression to the `totals` of the child source. + * There can be no total values - then an empty block is returned. * - * Вызывайте этот метод только после получения всех данных с помощью read, - * иначе будут проблемы, если какие-то данные в это же время вычисляются в другом потоке. + * Call this method only after all the data has been retrieved with `read`, + * otherwise there will be problems if any data at the same time is computed in another thread. */ virtual const Block & getTotals(); - /// То же самое для минимумов и максимумов. + /// The same for minimums and maximums. const Block & getExtremes() const; - /** Установить колбэк прогресса выполнения. - * Колбэк пробрасывается во все дочерние источники. - * По-умолчанию, он вызывается для листовых источников, после каждого блока. - * (Но это может быть переопределено в методе progress()) - * Функция принимает количество строк в последнем блоке, количество байт в последнем блоке. - * Следует иметь ввиду, что колбэк может вызываться из разных потоков. + /** Set the execution progress bar callback. + * The callback is passed to all child sources. + * By default, it is called for leaf sources, after each block. + * (But this can be overridden in the progress() method) + * The function takes the number of rows in the last block, the number of bytes in the last block. + * Note that the callback can be called from different threads. */ void setProgressCallback(ProgressCallback callback); - /** В этом методе: - * - вызывается колбэк прогресса; - * - обновляется статус выполнения запроса в ProcessList-е; - * - проверяются ограничения и квоты, которые должны быть проверены не в рамках одного источника, - * а над общим количеством потраченных ресурсов во всех источниках сразу (информация в ProcessList-е). + /** In this method: + * - the progress callback is called; + * - the status of the query execution in ProcessList is updated; + * - checks restrictions and quotas that should be checked not within the same source, + * but over the total amount of resources spent in all sources at once (information in the ProcessList). */ virtual void progress(const Progress & value) { - /// Данные для прогресса берутся из листовых источников. + /// The data for progress is taken from leaf sources. if (children.empty()) progressImpl(value); } @@ -86,26 +86,26 @@ public: void progressImpl(const Progress & value); - /** Установить указатель на элемент списка процессов. - * Пробрасывается во все дочерние источники. - * В него будет записываться общая информация о потраченных на запрос ресурсах. - * На основе этой информации будет проверяться квота, и некоторые ограничения. - * Также эта информация будет доступна в запросе SHOW PROCESSLIST. + /** Set the pointer to the process list item. + * It is passed to all child sources. + * General information about the resources spent on the request will be written into it. + * Based on this information, the quota and some restrictions will be checked. + * This information will also be available in the SHOW PROCESSLIST request. */ void setProcessListElement(ProcessListElement * elem); - /** Установить информацию о приблизительном общем количестве строк, которых нужно прочитать. + /** Set the approximate total number of rows to read. */ void setTotalRowsApprox(size_t value) { total_rows_approx = value; } - /** Попросить прервать получение данных как можно скорее. - * По-умолчанию - просто выставляет флаг is_cancelled и просит прерваться всех детей. - * Эта функция может вызываться несколько раз, в том числе, одновременно из разных потоков. + /** Ask to abort the receipt of data as soon as possible. + * By default - just sets the flag is_cancelled and asks that all children be interrupted. + * This function can be called several times, including simultaneously from different threads. */ virtual void cancel(); - /** Требуется ли прервать получение данных. + /** Do you want to abort the receipt of data. */ bool isCancelled() const { @@ -140,7 +140,7 @@ public: /// in rows per second size_t min_execution_speed = 0; - /// Проверять, что скорость не слишком низкая, после прошествия указанного времени. + /// Verify that the speed is not too low after the specified time has elapsed. Poco::Timespan timeout_before_checking_execution_speed = 0; }; @@ -155,15 +155,15 @@ public: return limits; } - /** Установить квоту. Если устанавливается квота на объём исходных данных, - * то следует ещё установить mode = LIMITS_TOTAL в LocalLimits с помощью setLimits. + /** Set the quota. If you set a quota on the amount of raw data, + * then you should also set mode = LIMITS_TOTAL to LocalLimits with setLimits. */ void setQuota(QuotaForIntervals & quota_) { quota = "a_; } - /// Включить рассчёт минимумов и максимумов по столбцам результата. + /// Enable calculation of minimums and maximums by the result columns. void enableExtremes() { enabled_extremes = true; } protected: @@ -174,49 +174,49 @@ protected: bool enabled_extremes = false; - /// Дополнительная информация, которая может образоваться в процессе работы. + /// Additional information that can be generated during the work process. - /// Тотальные значения при агрегации. + /// Total values during aggregation. Block totals; - /// Минимумы и максимумы. Первая строчка блока - минимумы, вторая - максимумы. + /// Minimums and maximums. The first row of the block - minimums, the second - the maximums. Block extremes; - /// Приблизительное общее количество строк, которых нужно прочитать. Для прогресс-бара. + /// The approximate total number of rows to read. For progress bar. size_t total_rows_approx = 0; - /// Информация о приблизительном общем количестве строк собрана в родительском источнике. + /// Information about the approximate total number of rows is collected in the parent source. bool collected_total_rows_approx = false; - /// Превышено ограничение на количество строк/байт, и нужно прекратить выполнение на следующем вызове read, как будто поток иссяк. + /// The limit on the number of rows/bytes has been exceeded, and you need to stop execution on the next `read` call, as if the thread has run out. bool limit_exceeded_need_break = false; - /// Ограничения и квоты. + /// Limitations and quotas. LocalLimits limits; - QuotaForIntervals * quota = nullptr; /// Если nullptr - квота не используется. + QuotaForIntervals * quota = nullptr; /// If nullptr - the quota is not used. double prev_elapsed = 0; - /// Наследники должны реализовать эту функцию. + /// The heirs must implement this function. virtual Block readImpl() = 0; - /// Здесь можно делать предварительную инициализацию. + /// Here you can do a preliminary initialization. virtual void readPrefixImpl() {} - /// Здесь необходимо делать финализацию, которая может привести к исключению. + /// Here you need to do a finalization, which can lead to an exception. virtual void readSuffixImpl() {} void updateExtremes(Block & block); - /** Проверить ограничения и квоты. - * Но только те, что могут быть проверены в рамках каждого отдельного источника. + /** Check constraints and quotas. + * But only those that can be tested within each separate source. */ bool checkLimits(); void checkQuota(Block & block); - /// Собрать информацию о приблизительном общем числе строк по всем детям. + /// Gather information about the approximate total number of rows from all children. void collectTotalRowsApprox(); - /** Передать информацию о приблизительном общем числе строк в колбэк прогресса. - * Сделано так, что отправка происходит лишь в верхнем источнике. + /** Send information about the approximate total number of rows to the progress bar. + * It is done so that sending occurs only in the upper source. */ void collectAndSendTotalRowsApprox(); }; diff --git a/dbms/src/DataStreams/JSONCompactRowOutputStream.h b/dbms/src/DataStreams/JSONCompactRowOutputStream.h index 9423cde034c..21ebc58b7c3 100644 --- a/dbms/src/DataStreams/JSONCompactRowOutputStream.h +++ b/dbms/src/DataStreams/JSONCompactRowOutputStream.h @@ -9,7 +9,7 @@ namespace DB { -/** Поток для вывода данных в формате JSONCompact. +/** The stream for outputting data in the JSONCompact format. */ class JSONCompactRowOutputStream : public JSONRowOutputStream { diff --git a/dbms/src/DataStreams/JSONEachRowRowInputStream.h b/dbms/src/DataStreams/JSONEachRowRowInputStream.h index 7c7471203e7..a57ebe3c11f 100644 --- a/dbms/src/DataStreams/JSONEachRowRowInputStream.h +++ b/dbms/src/DataStreams/JSONEachRowRowInputStream.h @@ -11,10 +11,10 @@ namespace DB class ReadBuffer; -/** Поток для чтения данных в формате JSON, где каждая строчка представлена отдельным JSON объектом. - * Объекты могут быть разделены переводом строки, другими пробельными символами в любом количестве и, возможно, запятой. - * Поля могут быть перечислены в произвольном порядке (в том числе, в разных строках может быть разный порядок), - * и часть полей может отсутствовать. +/** A stream for reading data in JSON format, where each row is represented by a separate JSON object. + * Objects can be separated by feed return, other whitespace characters in any number and possibly a comma. + * Fields can be listed in any order (including, in different lines there may be different order), + * and some fields may be missing. */ class JSONEachRowRowInputStream : public IRowInputStream { @@ -30,10 +30,10 @@ private: const Block sample; bool skip_unknown; - /// Буфер для прочитанного из потока имени поля. Используется, если его потребовалось скопировать. + /// Buffer for the read from the stream field name. Used when you have to copy it. String name_buf; - /// Хэш-таблица соответствия имя поля -> позиция в блоке. NOTE Можно использовать perfect hash map. + /// Hash table match `field name -> position in the block`. NOTE You can use perfect hash map. using NameMap = HashMap; NameMap name_map; }; diff --git a/dbms/src/DataStreams/JSONEachRowRowOutputStream.h b/dbms/src/DataStreams/JSONEachRowRowOutputStream.h index cbf92aa6576..48dce75a324 100644 --- a/dbms/src/DataStreams/JSONEachRowRowOutputStream.h +++ b/dbms/src/DataStreams/JSONEachRowRowOutputStream.h @@ -8,8 +8,8 @@ namespace DB { -/** Поток для вывода данных в формате JSON, по объекту на каждую строчку. - * Не валидирует UTF-8. +/** The stream for outputting data in JSON format, by object per line. + * Does not validate UTF-8. */ class JSONEachRowRowOutputStream : public IRowOutputStream { diff --git a/dbms/src/DataStreams/LazyBlockInputStream.h b/dbms/src/DataStreams/LazyBlockInputStream.h index b9a9904ba4a..6239bfcafb4 100644 --- a/dbms/src/DataStreams/LazyBlockInputStream.h +++ b/dbms/src/DataStreams/LazyBlockInputStream.h @@ -6,9 +6,9 @@ namespace DB { -/** Инициализировать другой источник при первом вызове read, и затем использовать его. - * Это нужно, например, для чтения из таблицы, которая будет заполнена - * после создания объекта LazyBlockInputStream, но до первого вызова read. +/** Initialize another source on the first `read` call, and then use it. + * This is needed, for example, to read from a table that will be populated + * after creation of LazyBlockInputStream object, but before the first `read` call. */ class LazyBlockInputStream : public IProfilingBlockInputStream { @@ -41,7 +41,7 @@ protected: if (IProfilingBlockInputStream * p_input = dynamic_cast(input.get())) { - /// Они могли быть установлены раньше, но не были протащены в input. + /// They could have been set before, but were not passed into the `input`. if (progress_callback) p_input->setProgressCallback(progress_callback); if (process_list_elem) diff --git a/dbms/src/DataStreams/LimitBlockInputStream.h b/dbms/src/DataStreams/LimitBlockInputStream.h index 0ca994916e0..1588441ee91 100644 --- a/dbms/src/DataStreams/LimitBlockInputStream.h +++ b/dbms/src/DataStreams/LimitBlockInputStream.h @@ -7,15 +7,15 @@ namespace DB { -/** Реализует реляционную операцию LIMIT. +/** Implements the LIMIT relational operation. */ class LimitBlockInputStream : public IProfilingBlockInputStream { public: - /** Если always_read_till_end = false (по-умолчанию), то после чтения достаточного количества данных, - * возвращает пустой блок, и это приводит к отмене выполнения запроса. - * Если always_read_till_end = true - читает все данные до конца, но игнорирует их. Это нужно в редких случаях: - * когда иначе, из-за отмены запроса, мы бы не получили данные для GROUP BY WITH TOTALS с удалённого сервера. + /** If always_read_till_end = false (by default), then after reading enough data, + * returns an empty block, and this causes the query to be canceled. + * If always_read_till_end = true - reads all the data to the end, but ignores them. This is necessary in rare cases: + * when otherwise, due to the cancellation of the request, we would not have received the data for GROUP BY WITH TOTALS from the remote server. */ LimitBlockInputStream(BlockInputStreamPtr input_, size_t limit_, size_t offset_, bool always_read_till_end_ = false); diff --git a/dbms/src/DataStreams/MarkInCompressedFile.h b/dbms/src/DataStreams/MarkInCompressedFile.h index ba0578bffa3..3a1d9aa0f19 100644 --- a/dbms/src/DataStreams/MarkInCompressedFile.h +++ b/dbms/src/DataStreams/MarkInCompressedFile.h @@ -10,8 +10,8 @@ namespace DB { -/** Засечка - позиция в сжатом файле. Сжатый файл состоит из уложенных подряд сжатых блоков. - * Засечка представляют собой пару - смещение в файле до начала сжатого блока, смещение в разжатом блоке до начала данных. +/** Mark is the position in the compressed file. The compressed file consists of adjacent compressed blocks. + * Mark is a tuple - the offset in the file to the start of the compressed block, the offset in the decompressed block to the start of the data. */ struct MarkInCompressedFile { diff --git a/dbms/src/DataStreams/MaterializingBlockInputStream.h b/dbms/src/DataStreams/MaterializingBlockInputStream.h index afcc670010e..654249e309a 100644 --- a/dbms/src/DataStreams/MaterializingBlockInputStream.h +++ b/dbms/src/DataStreams/MaterializingBlockInputStream.h @@ -5,7 +5,7 @@ namespace DB { -/** Преобразует столбцы-константы в полноценные столбцы ("материализует" их). +/** Converts columns-constants to full columns ("materializes" them). */ class MaterializingBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/MaterializingBlockOutputStream.h b/dbms/src/DataStreams/MaterializingBlockOutputStream.h index 3d57c53cc9e..c71531d5338 100644 --- a/dbms/src/DataStreams/MaterializingBlockOutputStream.h +++ b/dbms/src/DataStreams/MaterializingBlockOutputStream.h @@ -7,7 +7,7 @@ namespace DB { -/** Преобразует столбцы-константы в полноценные столбцы ("материализует" их). +/** Converts columns-constants to full columns ("materializes" them). */ class MaterializingBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/MergingAggregatedBlockInputStream.h b/dbms/src/DataStreams/MergingAggregatedBlockInputStream.h index 1b50896f568..2346f7bd221 100644 --- a/dbms/src/DataStreams/MergingAggregatedBlockInputStream.h +++ b/dbms/src/DataStreams/MergingAggregatedBlockInputStream.h @@ -8,8 +8,8 @@ namespace DB { -/** Доагрегирует поток блоков, в котором каждый блок уже агрегирован. - * Агрегатные функции в блоках не должны быть финализированы, чтобы их состояния можно было объединить. +/** A pre-aggregate stream of blocks in which each block is already aggregated. + * Aggregate functions in blocks should not be finalized so that their states can be merged. */ class MergingAggregatedBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/MergingAggregatedMemoryEfficientBlockInputStream.h b/dbms/src/DataStreams/MergingAggregatedMemoryEfficientBlockInputStream.h index 42e9ddfa657..f6d2b311858 100644 --- a/dbms/src/DataStreams/MergingAggregatedMemoryEfficientBlockInputStream.h +++ b/dbms/src/DataStreams/MergingAggregatedMemoryEfficientBlockInputStream.h @@ -13,48 +13,48 @@ namespace DB { -/** Доагрегирует потоки блоков, держа в оперативной памяти только по одному или несколько (до merging_threads) блоков из каждого источника. - * Это экономит оперативку в случае использования двухуровневой агрегации, где в каждом источнике будет до 256 блоков с частями результата. +/** Pre-aggregates block streams, holding in RAM only one or more (up to merging_threads) blocks from each source. + * This saves RAM in case of using two-level aggregation, where in each source there will be up to 256 blocks with parts of the result. * - * Агрегатные функции в блоках не должны быть финализированы, чтобы их состояния можно было объединить. + * Aggregate functions in blocks should not be finalized so that their states can be combined. * - * Используется для решения двух задач: + * Used to solve two tasks: * - * 1. Внешняя агрегация со сбросом данных на диск. - * Частично агрегированные данные (предварительно разбитые на 256 корзин) сброшены в какое-то количество файлов на диске. - * Нужно читать их и мерджить по корзинам - держа в оперативке одновременно только несколько корзин из каждого файла. + * 1. External aggregation with data flush to disk. + * Partially aggregated data (previously divided into 256 buckets) is flushed to some number of files on the disk. + * We need to read them and merge them by buckets - keeping only a few buckets from each file in RAM simultaneously. * - * 2. Слияние результатов агрегации при распределённой обработке запроса. - * С разных серверов приезжают частично агрегированные данные, которые могут быть разбиты, а могут быть не разбиты на 256 корзин, - * и эти корзины отдаются нам по сети с каждого сервера последовательно, друг за другом. - * Надо так же читать и мерджить по корзинам. + * 2. Merge aggregation results for distributed query processing. + * Partially aggregated data arrives from different servers, which can be splitted down or not, into 256 buckets, + * and these buckets are passed to us by the network from each server in sequence, one by one. + * You should also read and merge by the buckets. * - * Суть работы: + * The essence of the work: * - * Есть какое-то количество источников. Они отдают блоки с частично агрегированными данными. - * Каждый источник может отдать одну из следующих последовательностей блоков: - * 1. "неразрезанный" блок с bucket_num = -1; - * 2. "разрезанные" (two_level) блоки с bucket_num от 0 до 255; - * В обоих случаях, может ещё присутствовать блок "переполнений" (overflows) с bucket_num = -1 и is_overflows = true; + * There are a number of sources. They give out blocks with partially aggregated data. + * Each source can return one of the following block sequences: + * 1. "unsplitted" block with bucket_num = -1; + * 2. "splitted" (two_level) blocks with bucket_num from 0 to 255; + * In both cases, there may also be a block of "overflows" with bucket_num = -1 and is_overflows = true; * - * Исходим из соглашения, что разрезанные блоки всегда передаются в порядке bucket_num. - * То есть, если a < b, то блок с bucket_num = a идёт раньше bucket_num = b. - * Это нужно для экономного по памяти слияния - * - чтобы не надо было читать блоки наперёд, а идти по всем последовательностям по возрастанию bucket_num. + * We start from the convention that splitted blocks are always passed in the order of bucket_num. + * That is, if a < b, then the bucket_num = a block goes before bucket_num = b. + * This is needed for a memory-efficient merge + * - so that you do not need to read the blocks up front, but go all the way up by bucket_num. * - * При этом, не все bucket_num из диапазона 0..255 могут присутствовать. - * Блок переполнений может присутствовать в любом порядке относительно других блоков (но он может быть только один). + * In this case, not all bucket_num from the range of 0..255 can be present. + * The overflow block can be presented in any order relative to other blocks (but it can be only one). * - * Необходимо объединить эти последовательности блоков и отдать результат в виде последовательности с такими же свойствами. - * То есть, на выходе, если в последовательности есть "разрезанные" блоки, то они должны идти в порядке bucket_num. + * It is necessary to combine these sequences of blocks and return the result as a sequence with the same properties. + * That is, at the output, if there are "splitted" blocks in the sequence, then they should go in the order of bucket_num. * - * Мердж можно осуществлять с использованием нескольких (merging_threads) потоков. - * Для этого, получение набора блоков для следующего bucket_num надо делать последовательно, - * а затем, когда мы имеем несколько полученных наборов, их объединение можно делать параллельно. + * The merge can be performed using several (merging_threads) threads. + * For this, receiving of a set of blocks for the next bucket_num should be done sequentially, + * and then, when we have several received sets, they can be merged in parallel. * - * При получении следующих блоков из разных источников, - * данные из источников можно также читать в несколько потоков (reading_threads) - * для оптимальной работы при наличии быстрой сети или дисков (откуда эти блоки читаются). + * When you receive next blocks from different sources, + * data from sources can also be read in several threads (reading_threads) + * for optimal performance in the presence of a fast network or disks (from where these blocks are read). */ class MergingAggregatedMemoryEfficientBlockInputStream : public IProfilingBlockInputStream { @@ -69,14 +69,14 @@ public: String getID() const override; - /// Отправляет запрос (инициирует вычисления) раньше, чем read. + /// Sends the request (initiates calculations) earlier than `read`. void readPrefix() override; - /// Вызывается либо после того, как всё прочитано, либо после cancel-а. + /// Called either after everything is read, or after cancel. void readSuffix() override; - /** Отличается от реализации по-умолчанию тем, что пытается остановить все источники, - * пропуская отвалившиеся по эксепшену. + /** Different from the default implementation by trying to stop all sources, + * skipping failed by execution. */ void cancel() override; @@ -117,32 +117,33 @@ private: void start(); - /// Получить блоки, которые можно мерджить. Это позволяет мерджить их параллельно в отдельных потоках. + /// Get blocks that you can merge. This allows you to merge them in parallel in separate threads. BlocksToMerge getNextBlocksToMerge(); std::unique_ptr reading_pool; - /// Для параллельного мерджа. + /// For a parallel merge. struct ParallelMergeData { ThreadPool pool; - /// Сейчас один из мерджащих потоков получает следующие блоки для мерджа. Эта операция должна делаться последовательно. + /// Now one of the merging threads receives next blocks for the merge. This operation must be done sequentially. std::mutex get_next_blocks_mutex; std::atomic exhausted {false}; /// No more source data. std::atomic finish {false}; /// Need to terminate early. std::exception_ptr exception; - /// Следует отдавать блоки стого в порядке ключа (bucket_num). - /// Если значение - пустой блок - то нужно дождаться его мерджа. - /// (Такое значение означает обещание, что здесь будут данные. Это важно, потому что данные нужно отдавать в порядке ключа - bucket_num) + /// It is necessary to give out blocks in the order of the key (bucket_num). + /// If the value is an empty block, you need to wait for its merge. + /// (This means the promise that there will be data here, which is important because the data should be given out + /// in the order of the key - bucket_num) std::map merged_blocks; std::mutex merged_blocks_mutex; - /// Событие, с помощью которого мерджащие потоки говорят главному потоку, что новый блок готов. + /// An event that is used by merging threads to tell the main thread that the new block is ready. std::condition_variable merged_blocks_changed; - /// Событие, с помощью которого главный поток говорят мерджащим потокам, что можно обработать следующую группу блоков. + /// An event by which the main thread is telling merging threads that it is possible to process the next group of blocks. std::condition_variable have_space; ParallelMergeData(size_t max_threads) : pool(max_threads) {} diff --git a/dbms/src/DataStreams/MergingSortedBlockInputStream.h b/dbms/src/DataStreams/MergingSortedBlockInputStream.h index 437c9c96997..bc1a9772614 100644 --- a/dbms/src/DataStreams/MergingSortedBlockInputStream.h +++ b/dbms/src/DataStreams/MergingSortedBlockInputStream.h @@ -22,12 +22,12 @@ namespace ErrorCodes } -/// Позволяет ссылаться на строку в блоке и удерживать владение блоком, -/// и таким образом избежать создания временного объекта-строки. -/// Не используется std::shared_ptr, так как не нужно место для weak_count и deleter; -/// не используется Poco::SharedPtr, так как нужно выделять блок и refcount одним куском; -/// не используется Poco::AutoPtr, так как у него нет move конструктора и есть лишние проверки на nullptr; -/// Счётчик ссылок неатомарный, так как используется из одного потока. +/// Allows you refer to the row in the block and hold the block ownership, +/// and thus avoid creating a temporary row object. +/// Do not use std::shared_ptr, since there is no need for a place for `weak_count` and `deleter`; +/// does not use Poco::SharedPtr, since you need to allocate a block and `refcount` in one piece; +/// does not use Poco::AutoPtr, since it does not have a `move` constructor and there are extra checks for nullptr; +/// The reference counter is not atomic, since it is used from one thread. namespace detail { struct SharedBlock : Block @@ -87,7 +87,7 @@ protected: std::swap(shared_block, other.shared_block); } - /// Количество и типы столбцов обязаны соответствовать. + /// The number and types of columns must match. bool operator==(const RowRef & other) const { size_t size = columns.size(); @@ -111,10 +111,10 @@ protected: void readSuffixImpl() override; - /// Инициализирует очередь и следующий блок результата. + /// Initializes the queue and the next result block. void init(Block & merged_block, ColumnPlainPtrs & merged_columns); - /// Достаёт из источника, соответствующего current следующий блок. + /// Gets the next block from the source corresponding to the `current`. template void fetchNextBlock(const TSortCursor & current, std::priority_queue & queue); @@ -131,7 +131,7 @@ protected: /// May be smaller or equal to max_block_size. To do 'reserve' for columns. size_t expected_block_size = 0; - /// Текущие сливаемые блоки. + /// Blocks currently being merged. size_t num_columns = 0; std::vector source_blocks; @@ -149,9 +149,9 @@ protected: MergedRowSources * out_row_sources = nullptr; - /// Эти методы используются в Collapsing/Summing/Aggregating... SortedBlockInputStream-ах. + /// These methods are used in Collapsing/Summing/Aggregating... SortedBlockInputStream-s. - /// Сохранить строчку, на которую указывает cursor, в row. + /// Save the row pointed to by cursor in `row`. template void setRow(Row & row, TSortCursor & cursor) { @@ -165,7 +165,7 @@ protected: { tryLogCurrentException(__PRETTY_FUNCTION__); - /// Узнаем имя столбца и бросим исключение поинформативней. + /// Find out the name of the column and throw more informative exception. String column_name; for (const auto & block : source_blocks) @@ -206,8 +206,8 @@ protected: private: - /** Делаем поддержку двух разных курсоров - с Collation и без. - * Шаблоны используем вместо полиморфных SortCursor'ов и вызовов виртуальных функций. + /** We support two different cursors - with Collation and without. + * Templates are used instead of polymorphic SortCursor and calls to virtual functions. */ template void initQueue(std::priority_queue & queue); @@ -217,7 +217,7 @@ private: Logger * log = &Logger::get("MergingSortedBlockInputStream"); - /// Прочитали до конца. + /// Read is finished. bool finished = false; }; diff --git a/dbms/src/DataStreams/NativeBlockInputStream.h b/dbms/src/DataStreams/NativeBlockInputStream.h index 879bff9bc62..74128408ff1 100644 --- a/dbms/src/DataStreams/NativeBlockInputStream.h +++ b/dbms/src/DataStreams/NativeBlockInputStream.h @@ -10,12 +10,12 @@ namespace DB class CompressedReadBufferFromFile; -/** Формат Native может содержать отдельно расположенный индекс, - * который позволяет понять, где какой столбец расположен, - * и пропускать ненужные столбцы. +/** The Native format can contain a separately located index, + * which allows you to understand where what column is located, + * and skip unnecessary columns. */ -/** Позиция одного кусочка одного столбца. */ +/** The position of one piece of a single column. */ struct IndexOfOneColumnForNativeFormat { String name; @@ -23,7 +23,7 @@ struct IndexOfOneColumnForNativeFormat MarkInCompressedFile location; }; -/** Индекс для блока данных. */ +/** The index for the data block. */ struct IndexOfBlockForNativeFormat { using Columns = std::vector; @@ -33,7 +33,7 @@ struct IndexOfBlockForNativeFormat Columns columns; }; -/** Весь индекс. */ +/** The whole index. */ struct IndexForNativeFormat { using Blocks = std::vector; @@ -46,24 +46,24 @@ struct IndexForNativeFormat read(istr, required_columns); } - /// Прочитать индекс, только для нужных столбцов. + /// Read the index, only for the required columns. void read(ReadBuffer & istr, const NameSet & required_columns); }; -/** Десериализует поток блоков из родного бинарного формата (с именами и типами столбцов). - * Предназначено для взаимодействия между серверами. +/** Deserializes the stream of blocks from the native binary format (with names and column types). + * Designed for communication between servers. * - * Также может использоваться для хранения данных на диске. - * В этом случае, может использовать индекс. + * Can also be used to store data on disk. + * In this case, can use the index. */ class NativeBlockInputStream : public IProfilingBlockInputStream { public: - /** В случае указания ненулевой server_revision, может ожидаться и считываться дополнительная информация о блоке, - * в зависимости от поддерживаемой для указанной ревизии. + /** If a non-zero server_revision is specified, additional block information may be expected and read, + * depending on what is supported for the specified revision. * - * index - не обязательный параметр. Если задан, то будут читаться только указанные в индексе кусочки столбцов. + * `index` is not required parameter. If set, only parts of columns specified in the index will be read. */ NativeBlockInputStream( ReadBuffer & istr_, UInt64 server_revision_ = 0, @@ -94,7 +94,7 @@ private: IndexForNativeFormat::Blocks::const_iterator index_block_end; IndexOfBlockForNativeFormat::Columns::const_iterator index_column_it; - /// Если задан индекс, то istr должен быть CompressedReadBufferFromFile. + /// If an index is specified, then `istr` must be CompressedReadBufferFromFile. CompressedReadBufferFromFile * istr_concrete; }; diff --git a/dbms/src/DataStreams/NativeBlockOutputStream.h b/dbms/src/DataStreams/NativeBlockOutputStream.h index e0af3523284..16ba2415cc7 100644 --- a/dbms/src/DataStreams/NativeBlockOutputStream.h +++ b/dbms/src/DataStreams/NativeBlockOutputStream.h @@ -11,17 +11,17 @@ class WriteBuffer; class CompressedWriteBuffer; -/** Сериализует поток блоков в родном бинарном формате (с именами и типами столбцов). - * Предназначено для взаимодействия между серверами. +/** Serializes the stream of blocks in their native binary format (with names and column types). + * Designed for communication between servers. * - * Может быть указан поток для записи индекса. Индекс содержит смещения до каждого кусочка каждого столбца. - * Если делается append в уже существующий файл, и нужно записать индекс, то укажите initial_size_of_file. + * A stream can be specified to write the index. The index contains offsets to each part of each column. + * If an `append` is made to an existing file, and you need to write the index, then specify `initial_size_of_file`. */ class NativeBlockOutputStream : public IBlockOutputStream { public: - /** В случае указания ненулевой client_revision, может записываться дополнительная информация о блоке, - * в зависимости от поддерживаемой для указанной ревизии. + /** If non-zero client_revision is specified, additional block information can be written, + * depending on what is supported for the specified revision. */ NativeBlockOutputStream( WriteBuffer & ostr_, UInt64 client_revision_ = 0, @@ -39,8 +39,8 @@ private: UInt64 client_revision; WriteBuffer * index_ostr; - size_t initial_size_of_file; /// Начальный размер файла с данными, если делается append. Используется для индекса. - /// Если требуется записывать индекс, то ostr обязан быть CompressedWriteBuffer. + size_t initial_size_of_file; /// The initial size of the data file, if `append` done. Used for the index. + /// If you need to write index, then `ostr` must be a CompressedWriteBuffer. CompressedWriteBuffer * ostr_concrete = nullptr; }; diff --git a/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h b/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h index a1f49de2470..3aa39e2da23 100644 --- a/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h +++ b/dbms/src/DataStreams/NullAndDoCopyBlockInputStream.h @@ -11,11 +11,11 @@ class IBlockOutputStream; using BlockOutputStreamPtr = std::shared_ptr; -/** Пустой поток блоков. - * Но при первой попытке чтения, копирует данные из переданного input-а в переданный output. - * Это нужно для выполнения запроса INSERT SELECT - запрос копирует данные, но сам ничего не возвращает. - * Запрос можно было бы выполнять и без оборачивания в пустой BlockInputStream, - * но не работал бы прогресс выполнения запроса и возможность отменить запрос. +/** An empty stream of blocks. + * But at the first read attempt, copies the data from the passed `input` to the `output`. + * This is necessary to execute the query INSERT SELECT - the query copies data, but returns nothing. + * The query could be executed without wrapping it in an empty BlockInputStream, + * but the progress of query execution and the ability to cancel the query would not work. */ class NullAndDoCopyBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/NullBlockInputStream.h b/dbms/src/DataStreams/NullBlockInputStream.h index 7c42c97bcd3..a68612afb19 100644 --- a/dbms/src/DataStreams/NullBlockInputStream.h +++ b/dbms/src/DataStreams/NullBlockInputStream.h @@ -6,7 +6,7 @@ namespace DB { -/** Пустой поток блоков. +/** Empty stream of blocks. */ class NullBlockInputStream : public IBlockInputStream { diff --git a/dbms/src/DataStreams/NullBlockOutputStream.h b/dbms/src/DataStreams/NullBlockOutputStream.h index 2c51a138cff..1742bd6e33c 100644 --- a/dbms/src/DataStreams/NullBlockOutputStream.h +++ b/dbms/src/DataStreams/NullBlockOutputStream.h @@ -6,7 +6,7 @@ namespace DB { -/** Ничего не делает. Используется для отладки и бенчмарков. +/** Does nothing. Used for debugging and benchmarks. */ class NullBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/ODBCDriverBlockOutputStream.h b/dbms/src/DataStreams/ODBCDriverBlockOutputStream.h index 1353e7d31b1..09795b72a3a 100644 --- a/dbms/src/DataStreams/ODBCDriverBlockOutputStream.h +++ b/dbms/src/DataStreams/ODBCDriverBlockOutputStream.h @@ -10,11 +10,11 @@ namespace DB class WriteBuffer; -/** Формат данных, предназначенный для упрощения реализации ODBC драйвера. - * ODBC драйвер предназначен для сборки под разные платформы без зависимостей от основного кода, - * поэтому формат сделан так, чтобы в нём можно было как можно проще его распарсить. - * Выводится заголовок с нужной информацией. - * Затем данные выводятся в порядке строк. Каждое значение выводится так: длина в формате VarUInt, затем данные в текстовом виде. +/** A data format designed to simplify the implementation of the ODBC driver. + * ODBC driver is designed to be build for different platforms without dependencies from the main code, + * so the format is made that way so that it can be as easy as possible to parse it. + * A header is displayed with the required information. + * The data is then output in the order of the rows. Each value is displayed as follows: length in VarUInt format, then data in text form. */ class ODBCDriverBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/OneBlockInputStream.h b/dbms/src/DataStreams/OneBlockInputStream.h index 74f81c3c46a..a9f0f928696 100644 --- a/dbms/src/DataStreams/OneBlockInputStream.h +++ b/dbms/src/DataStreams/OneBlockInputStream.h @@ -6,8 +6,8 @@ namespace DB { -/** Поток блоков, из которого можно прочитать один блок. - * Также смотрите BlocksListBlockInputStream. +/** A stream of blocks from which you can read one block. + * Also see BlocksListBlockInputStream. */ class OneBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/ParallelAggregatingBlockInputStream.h b/dbms/src/DataStreams/ParallelAggregatingBlockInputStream.h index b10f2c51f35..3bc08e75ea3 100644 --- a/dbms/src/DataStreams/ParallelAggregatingBlockInputStream.h +++ b/dbms/src/DataStreams/ParallelAggregatingBlockInputStream.h @@ -11,15 +11,15 @@ namespace DB { -/** Агрегирует несколько источников параллельно. - * Производит агрегацию блоков из разных источников независимо в разных потоках, затем объединяет результаты. - * Если final == false, агрегатные функции не финализируются, то есть, не заменяются на своё значение, а содержат промежуточное состояние вычислений. - * Это необходимо, чтобы можно было продолжить агрегацию (например, объединяя потоки частично агрегированных данных). +/** Aggregates several sources in parallel. + * Makes aggregation of blocks from different sources independently in different threads, then combines the results. + * If final == false, aggregate functions are not finalized, that is, they are not replaced by their value, but contain an intermediate state of calculations. + * This is necessary so that aggregation can continue (for example, by combining streams of partially aggregated data). */ class ParallelAggregatingBlockInputStream : public IProfilingBlockInputStream { public: - /** Столбцы из key_names и аргументы агрегатных функций, уже должны быть вычислены. + /** Columns from key_names and arguments of aggregate functions must already be computed. */ ParallelAggregatingBlockInputStream( BlockInputStreams inputs, BlockInputStreamPtr additional_input_at_end, @@ -32,7 +32,7 @@ public: void cancel() override; protected: - /// Ничего не делаем, чтобы подготовка к выполнению запроса делалась параллельно, в ParallelInputsProcessor. + /// Do nothing that preparation to execution of the query be done in parallel, in ParallelInputsProcessor. void readPrefix() override { } @@ -49,16 +49,16 @@ private: size_t keys_size; size_t aggregates_size; - /** Используется, если есть ограничение на максимальное количество строк при агрегации, - * и если group_by_overflow_mode == ANY. - * В этом случае, новые ключи не добавляются в набор, а производится агрегация только по - * ключам, которые уже успели попасть в набор. + /** Used if there is a limit on the maximum number of rows in the aggregation, + * and if group_by_overflow_mode == ANY. + * In this case, new keys are not added to the set, but aggregation is performed only by + * keys that have already been added into the set. */ bool no_more_keys = false; std::atomic executed {false}; - /// Для чтения сброшенных во временный файл данных. + /// To read the data stored into the temporary data file. struct TemporaryFileStream { ReadBufferFromFile file_in; @@ -117,7 +117,7 @@ private: void execute(); - /** Отсюда будем доставать готовые блоки после агрегации. + /** From here we get the finished blocks after the aggregation. */ std::unique_ptr impl; }; diff --git a/dbms/src/DataStreams/ParallelInputsProcessor.h b/dbms/src/DataStreams/ParallelInputsProcessor.h index cf098c1b09b..cdf17e1ab4f 100644 --- a/dbms/src/DataStreams/ParallelInputsProcessor.h +++ b/dbms/src/DataStreams/ParallelInputsProcessor.h @@ -33,33 +33,33 @@ namespace CurrentMetrics namespace DB { -/** Режим объединения. +/** Union mode. */ enum class StreamUnionMode { - Basic = 0, /// вынимать блоки - ExtraInfo /// вынимать блоки + дополнительную информацию + Basic = 0, /// take out blocks + ExtraInfo /// take out blocks + additional information }; -/// Пример обработчика. +/// Example of the handler. struct ParallelInputsHandler { - /// Обработка блока данных. + /// Processing the data block. void onBlock(Block & block, size_t thread_num) {} - /// Обработка блока данных + дополнительных информаций. + /// Processing the data block + additional information. void onBlock(Block & block, BlockExtraInfo & extra_info, size_t thread_num) {} - /// Вызывается для каждого потока, когда потоку стало больше нечего делать. - /// Из-за того, что иссякла часть источников, и сейчас источников осталось меньше, чем потоков. - /// Вызывается, если метод onException не кидает исключение; вызывается до метода onFinish. + /// Called for each thread, when the thread has nothing else to do. + /// Due to the fact that part of the sources has run out, and now there are fewer sources left than streams. + /// Called if the `onException` method does not throw an exception; is called before the `onFinish` method. void onFinishThread(size_t thread_num) {} - /// Блоки закончились. Из-за того, что все источники иссякли или из-за отмены работы. - /// Этот метод всегда вызывается ровно один раз, в конце работы, если метод onException не кидает исключение. + /// Blocks are over. Due to the fact that all sources ran out or because of the cancellation of work. + /// This method is always called exactly once, at the end of the work, if the `onException` method does not throw an exception. void onFinish() {} - /// Обработка исключения. Разумно вызывать в этом методе метод ParallelInputsProcessor::cancel, а также передавать эксепшен в основной поток. + /// Exception handling. It is reasonable to call the ParallelInputsProcessor::cancel method in this method, and also pass the exception to the main thread. void onException(std::exception_ptr & exception, size_t thread_num) {} }; @@ -68,13 +68,13 @@ template class ParallelInputsProcessor { public: - /** additional_input_at_end - если не nullptr, - * то из этого источника начинают доставаться блоки лишь после того, как все остальные источники обработаны. - * Это делается в основном потоке. + /** additional_input_at_end - if not nullptr, + * then the blocks from this source will start to be processed only after all other sources are processed. + * This is done in the main thread. * - * Предназначено для реализации FULL и RIGHT JOIN - * - где нужно сначала параллельно сделать JOIN, при этом отмечая, какие ключи не найдены, - * и только после завершения этой работы, создать блоки из ненайденных ключей. + * Intended for implementation of FULL and RIGHT JOIN + * - where you must first make JOIN in parallel, while noting which keys are not found, + * and only after the completion of this work, create blocks of keys that are not found. */ ParallelInputsProcessor(BlockInputStreams inputs_, BlockInputStreamPtr additional_input_at_end_, size_t max_threads_, Handler & handler_) : inputs(inputs_), additional_input_at_end(additional_input_at_end_), max_threads(std::min(inputs_.size(), max_threads_)), handler(handler_) @@ -95,7 +95,7 @@ public: } } - /// Запустить фоновые потоки, начать работу. + /// Start background threads, start work. void process() { active_threads = max_threads; @@ -104,7 +104,7 @@ public: threads.emplace_back(std::bind(&ParallelInputsProcessor::thread, this, current_memory_tracker, i)); } - /// Попросить все источники остановиться раньше, чем они иссякнут. + /// Ask all sources to stop earlier than they run out. void cancel() { finish = true; @@ -119,9 +119,9 @@ public: } catch (...) { - /** Если не удалось попросить остановиться одного или несколько источников. - * (например, разорвано соединение при распределённой обработке запроса) - * - то пофиг. + /** If you can not ask one or more sources to stop. + * (for example, the connection is broken for distributed query processing) + * - then do not care. */ LOG_ERROR(log, "Exception while cancelling " << child->getName()); } @@ -129,7 +129,7 @@ public: } } - /// Подождать завершения работы всех потоков раньше деструктора. + /// Wait until all threads are finished, before the destructor. void wait() { if (joined_threads) @@ -148,11 +148,11 @@ public: } private: - /// Данные отдельного источника + /// Single source data struct InputData { BlockInputStreamPtr in; - size_t i; /// Порядковый номер источника (для отладки). + size_t i; /// The source number (for debugging). InputData() {} InputData(BlockInputStreamPtr & in_, size_t i_) : in(in_), i(i_) {} @@ -197,10 +197,10 @@ private: handler.onFinishThread(thread_num); - /// Последний поток при выходе сообщает, что данных больше нет. + /// The last thread on the output indicates that there is no more data. if (0 == --active_threads) { - /// И ещё обрабатывает дополнительный источник, если такой есть. + /// And then it processes an additional source, if there is one. if (additional_input_at_end) { try @@ -219,38 +219,38 @@ private: } } - handler.onFinish(); /// TODO Если в onFinish или onFinishThread эксепшен, то вызывается std::terminate. + handler.onFinish (); /// TODO If in `onFinish` or `onFinishThread` there is an exception, then std::terminate is called. } } void loop(size_t thread_num) { - while (!finish) /// Может потребоваться прекратить работу раньше, чем все источники иссякнут. + while (!finish) /// You may need to stop work earlier than all sources run out. { InputData input; - /// Выбираем следующий источник. + /// Select the next source. { std::lock_guard lock(available_inputs_mutex); - /// Если свободных источников нет, то этот поток больше не нужен. (Но другие потоки могут работать со своими источниками.) + /// If there are no free sources, then this thread is no longer needed. (But other threads can work with their sources.) if (available_inputs.empty()) break; input = available_inputs.front(); - /// Убираем источник из очереди доступных источников. + /// We remove the source from the queue of available sources. available_inputs.pop(); } - /// Основная работа. + /// The main work. Block block = input.in->read(); { if (finish) break; - /// Если этот источник ещё не иссяк, то положим полученный блок в очередь готовых. + /// If this source is not run out yet, then put the resulting block in the ready queue. { std::lock_guard lock(available_inputs_mutex); @@ -280,38 +280,38 @@ private: Handler & handler; - /// Потоки. + /// Streams. using ThreadsData = std::vector; ThreadsData threads; - /** Набор доступных источников, которые не заняты каким-либо потоком в данный момент. - * Каждый поток берёт из этого набора один источник, вынимает из источника блок (в этот момент источник делает вычисления), - * и (если источник не исчерпан), кладёт назад в набор доступных источников. + /** A set of available sources that are not currently processed by any thread. + * Each thread takes one source from this set, takes a block out of the source (at this moment the source does the calculations) + * and (if the source is not run out), puts it back into the set of available sources. * - * Возникает вопрос, что лучше использовать: - * - очередь (только что обработанный источник будет в следующий раз обработан позже остальных) - * - стек (только что обработанный источник будет обработан как можно раньше). + * The question arises what is better to use: + * - the queue (just processed source will be processed the next time later than the rest) + * - stack (just processed source will be processed as soon as possible). * - * Стек лучше очереди, когда надо выполнять работу по чтению одного источника более последовательно, - * и теоретически, это позволяет достичь более последовательных чтений с диска. + * The stack is better than the queue when you need to do work on reading one source more consequentially, + * and theoretically, this allows you to achieve more consequent/consistent reads from the disk. * - * Но при использовании стека, возникает проблема при распределённой обработке запроса: - * данные всё-время читаются только с части серверов, а на остальных серверах - * возникает таймаут при send-е, и обработка запроса завершается с исключением. + * But when using the stack, there is a problem with distributed query processing: + * data is read only from a part of the servers, and on the other servers + * a timeout occurs during send, and the request processing ends with an exception. * - * Поэтому, используется очередь. Это можно улучшить в дальнейшем. + * Therefore, a queue is used. This can be improved in the future. */ using AvailableInputs = std::queue; AvailableInputs available_inputs; - /// Для операций с available_inputs. + /// For operations with available_inputs. std::mutex available_inputs_mutex; - /// Сколько источников иссякло. + /// How many sources ran out. std::atomic active_threads { 0 }; - /// Завершить работу потоков (раньше, чем иссякнут источники). + /// Finish the threads work (before the sources run out). std::atomic finish { false }; - /// Подождали завершения всех потоков. + /// Wait for the completion of all threads. std::atomic joined_threads { false }; Logger * log = &Logger::get("ParallelInputsProcessor"); diff --git a/dbms/src/DataStreams/PartialSortingBlockInputStream.h b/dbms/src/DataStreams/PartialSortingBlockInputStream.h index 438f6b44739..924fdb0e2bf 100644 --- a/dbms/src/DataStreams/PartialSortingBlockInputStream.h +++ b/dbms/src/DataStreams/PartialSortingBlockInputStream.h @@ -8,13 +8,13 @@ namespace DB { -/** Сортирует каждый блок по отдельности по значениям указанных столбцов. - * На данный момент, используется не очень оптимальный алгоритм. +/** Sorts each block individually by the values of the specified columns. + * At the moment, not very optimal algorithm is used. */ class PartialSortingBlockInputStream : public IProfilingBlockInputStream { public: - /// limit - если не 0, то можно каждый блок сортировать не полностью, а только limit первых по порядку строк. + /// limit - if not 0, then you can sort each block not completely, but only `limit` first rows by order. PartialSortingBlockInputStream(BlockInputStreamPtr input_, SortDescription & description_, size_t limit_ = 0) : description(description_), limit(limit_) { diff --git a/dbms/src/DataStreams/PrettyBlockOutputStream.h b/dbms/src/DataStreams/PrettyBlockOutputStream.h index 22222c539b3..9d60abf07e4 100644 --- a/dbms/src/DataStreams/PrettyBlockOutputStream.h +++ b/dbms/src/DataStreams/PrettyBlockOutputStream.h @@ -11,12 +11,12 @@ class WriteBuffer; class Context; -/** Выводит результат в виде красивых таблиц. +/** Prints the result in the form of beautiful tables. */ class PrettyBlockOutputStream : public IBlockOutputStream { public: - /// no_escapes - не использовать ANSI escape sequences - для отображения в браузере, а не в консоли. + /// no_escapes - do not use ANSI escape sequences - to display in the browser, not in the console. PrettyBlockOutputStream(WriteBuffer & ostr_, bool no_escapes_, size_t max_rows_, const Context & context_); void write(const Block & block) override; @@ -33,7 +33,7 @@ protected: using Widths_t = std::vector; - /// Вычислить видимую (при выводе на консоль с кодировкой UTF-8) ширину значений и имён столбцов. + /// Evaluate the visible width (when outputting to the console with UTF-8 encoding) the width of the values and column names. void calculateWidths(Block & block, Widths_t & max_widths, Widths_t & name_widths); WriteBuffer & ostr; diff --git a/dbms/src/DataStreams/PrettyCompactBlockOutputStream.h b/dbms/src/DataStreams/PrettyCompactBlockOutputStream.h index ddde71b1316..80d23690755 100644 --- a/dbms/src/DataStreams/PrettyCompactBlockOutputStream.h +++ b/dbms/src/DataStreams/PrettyCompactBlockOutputStream.h @@ -6,7 +6,7 @@ namespace DB { -/** Выводит результат в виде красивых таблиц, но с меньшим количеством строк-разделителей. +/** Prints the result in the form of beautiful tables, but with fewer delimiter lines. */ class PrettyCompactBlockOutputStream : public PrettyBlockOutputStream { diff --git a/dbms/src/DataStreams/PrettyCompactMonoBlockOutputStream.h b/dbms/src/DataStreams/PrettyCompactMonoBlockOutputStream.h index 26e727d5d8c..aa3ac169d2f 100644 --- a/dbms/src/DataStreams/PrettyCompactMonoBlockOutputStream.h +++ b/dbms/src/DataStreams/PrettyCompactMonoBlockOutputStream.h @@ -6,8 +6,8 @@ namespace DB { -/** Тоже самое, что и PrettyCompactBlockOutputStream, но выводит все max_rows (или меньше, - * если результат содержит меньшее число строк) одним блоком с одной шапкой. +/** Same as PrettyCompactBlockOutputStream, but prints all max_rows (or less, + * if the result contains fewer rows) by one block with one header. */ class PrettyCompactMonoBlockOutputStream : public PrettyCompactBlockOutputStream { diff --git a/dbms/src/DataStreams/PrettySpaceBlockOutputStream.h b/dbms/src/DataStreams/PrettySpaceBlockOutputStream.h index e8d968e27e5..2fd78fa883f 100644 --- a/dbms/src/DataStreams/PrettySpaceBlockOutputStream.h +++ b/dbms/src/DataStreams/PrettySpaceBlockOutputStream.h @@ -6,7 +6,7 @@ namespace DB { -/** Выводит результат, выравнивая пробелами. +/** Prints the result, aligned with spaces. */ class PrettySpaceBlockOutputStream : public PrettyBlockOutputStream { diff --git a/dbms/src/DataStreams/PushingToViewsBlockOutputStream.h b/dbms/src/DataStreams/PushingToViewsBlockOutputStream.h index 8e53a316776..6a8ea5fbb44 100644 --- a/dbms/src/DataStreams/PushingToViewsBlockOutputStream.h +++ b/dbms/src/DataStreams/PushingToViewsBlockOutputStream.h @@ -12,8 +12,8 @@ namespace DB { -/** Записывает данные в указанную таблицу, при этом рекурсивно вызываясь от всех зависимых вьюшек. - * Если вьюшка не материализованная, то в нее данные не записываются, лишь перенаправляются дальше. +/** Writes data to the specified table, recursively being called from all dependent views. + * If the view is not materialized, then the data is not written to it, only redirected further. */ class PushingToViewsBlockOutputStream : public IBlockOutputStream { @@ -23,9 +23,9 @@ public: { storage = context.getTable(database, table); - /** TODO Это очень важная строчка. При любой вставке в таблицу один из stream-ов должен владеть lock-ом. - * Хотя сейчас любая вставка в таблицу делается через PushingToViewsBlockOutputStream, - * но ясно, что здесь - не лучшее место для этой функциональности. + /** TODO This is a very important line. At any insertion into the table one of streams should own lock. + * Although now any insertion into the table is done via PushingToViewsBlockOutputStream, + * but it's clear that here is not the best place for this functionality. */ addTableLock(storage->lockStructure(true)); diff --git a/dbms/src/DataStreams/QueueBlockIOStream.h b/dbms/src/DataStreams/QueueBlockIOStream.h index aa9274426fb..cb5fed7eb1c 100644 --- a/dbms/src/DataStreams/QueueBlockIOStream.h +++ b/dbms/src/DataStreams/QueueBlockIOStream.h @@ -12,17 +12,17 @@ namespace DB { -/** Является одновременно InputStream и OutputStream. - * При записи, кладёт блоки в очередь. - * При чтении, вынимает их из очереди. - * Используется thread-safe очередь. - * Если очередь пуста - чтение блокируется. - * Если очередь переполнена - запись блокируется. +/** Is both an InputStream and an OutputStream. + * When writing, puts the blocks in the queue. + * When reading, it takes them out of the queue. + * A thread-safe queue is used. + * If the queue is empty, the read is blocked. + * If the queue is full, the write is blocked. * - * Используется для того, чтобы временно сохранить куда-то результат, и позже передать его дальше. - * Также используется для синхронизации, когда нужно из одного источника сделать несколько - * - для однопроходного выполнения сразу нескольких запросов. - * Также может использоваться для распараллеливания: несколько потоков кладут блоки в очередь, а один - вынимает. + * Used to temporarily store the result somewhere, and later pass it further. + * Also used for synchronization, when you need to make several sources from one + * - for single-pass execution of several queries at once. + * It can also be used for parallelization: several threads put blocks in the queue, and one - takes out. */ class QueueBlockIOStream : public IProfilingBlockInputStream, public IBlockOutputStream diff --git a/dbms/src/DataStreams/RemoveColumnsBlockInputStream.h b/dbms/src/DataStreams/RemoveColumnsBlockInputStream.h index 922e442b67c..3198ba2a803 100644 --- a/dbms/src/DataStreams/RemoveColumnsBlockInputStream.h +++ b/dbms/src/DataStreams/RemoveColumnsBlockInputStream.h @@ -8,7 +8,7 @@ namespace DB { -/** Удаляет из блока указанные столбцы. +/** Removes the specified columns from the block. */ class RemoveColumnsBlockInputStream : public IProfilingBlockInputStream { diff --git a/dbms/src/DataStreams/ReplacingSortedBlockInputStream.h b/dbms/src/DataStreams/ReplacingSortedBlockInputStream.h index c7c1625f5e5..e01c0fb6cf0 100644 --- a/dbms/src/DataStreams/ReplacingSortedBlockInputStream.h +++ b/dbms/src/DataStreams/ReplacingSortedBlockInputStream.h @@ -8,9 +8,9 @@ namespace DB { -/** Соединяет несколько сортированных потоков в один. - * При этом, для каждой группы идущих подряд одинаковых значений первичного ключа (столбцов, по которым сортируются данные), - * оставляет +/** Merges several sorted streams into one. + * For each group of consecutive identical values of the primary key (the columns by which the data is sorted), + * keeps row with max `version` value. */ class ReplacingSortedBlockInputStream : public MergingSortedBlockInputStream { @@ -42,7 +42,7 @@ public: } protected: - /// Может возвращаться на 1 больше записей, чем max_block_size. + /// Can return 1 more records than max_block_size. Block readImpl() override; private: @@ -64,7 +64,7 @@ private: template void merge(ColumnPlainPtrs & merged_columns, std::priority_queue & queue); - /// Вставить в результат строки для текущего первичного ключа. + /// Output into result the rows for current primary key. void insertRow(ColumnPlainPtrs & merged_columns, size_t & merged_rows); }; diff --git a/dbms/src/DataStreams/SummingSortedBlockInputStream.h b/dbms/src/DataStreams/SummingSortedBlockInputStream.h index 387506d9869..b401d469d21 100644 --- a/dbms/src/DataStreams/SummingSortedBlockInputStream.h +++ b/dbms/src/DataStreams/SummingSortedBlockInputStream.h @@ -14,17 +14,17 @@ namespace ErrorCodes } -/** Соединяет несколько сортированных потоков в один. - * При этом, для каждой группы идущих подряд одинаковых значений первичного ключа (столбцов, по которым сортируются данные), - * схлопывает их в одну строку, суммируя все числовые столбцы кроме первичного ключа. - * Если во всех числовых столбцах кроме первичного ключа получился ноль, то удаляет строчку. +/** Merges several sorted streams into one. + * For each group of consecutive identical values of the primary key (the columns by which the data is sorted), + * collapses them into one row, summing all the numeric columns except the primary key. + * If in all numeric columns, except for the primary key, the result is zero, it deletes the row. */ class SummingSortedBlockInputStream : public MergingSortedBlockInputStream { public: SummingSortedBlockInputStream(BlockInputStreams inputs_, const SortDescription & description_, - /// Список столбцов, которых нужно суммировать. Если пустое - берутся все числовые столбцы, не входящие в description. + /// List of columns to be summed. If empty, all numeric columns that are not in the description are taken. const Names & column_names_to_sum_, size_t max_block_size_) : MergingSortedBlockInputStream(inputs_, description_, max_block_size_), column_names_to_sum(column_names_to_sum_) @@ -36,68 +36,68 @@ public: String getID() const override; protected: - /// Может возвращаться на 1 больше записей, чем max_block_size. + /// Can return 1 more records than max_block_size. Block readImpl() override; private: Logger * log = &Logger::get("SummingSortedBlockInputStream"); - /// Прочитали до конца. + /// Read up to the end. bool finished = false; - /// Столбцы с какими номерами надо суммировать. - Names column_names_to_sum; /// Если задано - преобразуется в column_numbers_to_sum при инициализации. + /// Columns with which numbers should be summed. + Names column_names_to_sum; /// If set, it is converted to column_numbers_to_sum when initialized. ColumnNumbers column_numbers_to_sum; - /** Таблица может иметь вложенные таблицы, обрабатываемые особым образом. - * Если название вложенной таблицы заканчинвается на `Map` и она содержит не менее двух столбцов, - * удовлетворяющих следующим критериям: - * - первый столбец, а также все столбцы, имена которых заканчиваются на ID, Key или Type - числовые ((U)IntN, Date, DateTime); - * (кортеж из таких столбцов назовём keys) - * - остальные столбцы - арифметические ((U)IntN, Float32/64), условно (values...). - * Такая вложенная таблица воспринимается как отображение (keys...) => (values...) и при слиянии - * ее строк выполняется слияние элементов двух множеств по (keys...) со сложением соответствующих (values...). + /** A table can have nested tables that are treated in a special way. + * If the name of the nested table ends in `Map` and it contains at least two columns, + * satisfying the following criteria: + * - the first column, as well as all columns whose names end with `ID`, `Key` or `Type` - numeric ((U)IntN, Date, DateTime); + * (a tuple of such columns will be called `keys`) + * - the remaining columns are arithmetic ((U)IntN, Float32/64), called (`values`...). + * This nested table is treated as a mapping (keys...) => (values...) and when merge + * its rows, the merge of the elements of two sets by (keys...) with summing of corresponding (values...). * - * Пример: + * Example: * [(1, 100)] + [(2, 150)] -> [(1, 100), (2, 150)] * [(1, 100)] + [(1, 150)] -> [(1, 250)] * [(1, 100)] + [(1, 150), (2, 150)] -> [(1, 250), (2, 150)] * [(1, 100), (2, 150)] + [(1, -100)] -> [(2, 150)] * - * Эта весьма необычная функциональность сделана исключительно для БК, - * не предназначена для использования кем-либо ещё, - * и может быть удалена в любой момент. + * This very unusual functionality is made exclusively for the banner system, + * is not supposed for use by anyone else, + * and can be deleted at any time. */ - /// Хранит номера столбцов-ключей и столбцов-значений. + /// Stores numbers of key-columns and value-columns. struct MapDescription { std::vector key_col_nums; std::vector val_col_nums; }; - /// Найденные вложенные Map-таблицы. + /// Found nested Map-tables. std::vector maps_to_sum; - RowRef current_key; /// Текущий первичный ключ. - RowRef next_key; /// Первичный ключ следующей строки. + RowRef current_key; /// The current primary key. + RowRef next_key; /// The primary key of the next row. Row current_row; - bool current_row_is_zero = true; /// Текущая строчка просуммировалась в ноль, и её следует удалить. + bool current_row_is_zero = true; /// The current row is summed to zero, and it should be deleted. - bool output_is_non_empty = false; /// Отдали ли мы наружу хоть одну строку. + bool output_is_non_empty = false; /// Have we given out at least one row as a result. - /** Делаем поддержку двух разных курсоров - с Collation и без. - * Шаблоны используем вместо полиморфных SortCursor'ов и вызовов виртуальных функций. + /** We support two different cursors - with Collation and without. + * Templates are used instead of polymorphic SortCursor and calls to virtual functions. */ template void merge(ColumnPlainPtrs & merged_columns, std::priority_queue & queue); - /// Вставить в результат просуммированную строку для текущей группы. + /// Insert the summed row for the current group into the result. void insertCurrentRow(ColumnPlainPtrs & merged_columns); - /** Для вложенных Map выполняется слияние по ключу с выбрасыванием строк вложенных массивов, в которых - * все элементы - нулевые. + /** For nested Map, a merge by key is performed with the ejection of rows of nested arrays, in which + * all items are zero. */ template bool mergeMaps(Row & row, TSortCursor & cursor); @@ -105,8 +105,8 @@ private: template bool mergeMap(const MapDescription & map, Row & row, TSortCursor & cursor); - /** Прибавить строчку под курсором к row. - * Возвращает false, если результат получился нулевым. + /** Add the row under the cursor to the `row`. + * Returns false if the result is zero. */ template bool addRow(Row & row, TSortCursor & cursor); diff --git a/dbms/src/DataStreams/TSKVRowInputStream.h b/dbms/src/DataStreams/TSKVRowInputStream.h index 438705833e5..b057c22af8a 100644 --- a/dbms/src/DataStreams/TSKVRowInputStream.h +++ b/dbms/src/DataStreams/TSKVRowInputStream.h @@ -11,13 +11,13 @@ namespace DB class ReadBuffer; -/** Поток для чтения данных в формате TSKV. - * TSKV - очень неэффективный формат данных. - * Похож на TSV, но каждое поле записано в виде key=value. - * Поля могут быть перечислены в произвольном порядке (в том числе, в разных строках может быть разный порядок), - * и часть полей может отсутствовать. - * В имени поля может быть заэскейплен знак равенства. - * Также, в качестве дополнительного элемента может присутствовать бесполезный фрагмент tskv - его нужно игнорировать. +/** Stream for reading data in TSKV format. + * TSKV is a very inefficient data format. + * Similar to TSV, but each field is written as key=value. + * Fields can be listed in any order (including, in different lines there may be different order), + * and some fields may be missing. + * An equal sign can be escaped in the field name. + * Also, as an additional element there may be a useless tskv fragment - it needs to be ignored. */ class TSKVRowInputStream : public IRowInputStream { @@ -31,13 +31,13 @@ public: private: ReadBuffer & istr; const Block sample; - /// Пропускать неизвестные поля. + /// Skip unknown fields. bool skip_unknown; - /// Буфер для прочитанного из потока имени поля. Используется, если его потребовалось скопировать. + /// Buffer for the read from the stream the field name. Used when you have to copy it. String name_buf; - /// Хэш-таблица соответствия имя поля -> позиция в блоке. NOTE Можно использовать perfect hash map. + /// Hash table matching `field name -> position in the block`. NOTE You can use perfect hash map. using NameMap = HashMap; NameMap name_map; }; diff --git a/dbms/src/DataStreams/TSKVRowOutputStream.h b/dbms/src/DataStreams/TSKVRowOutputStream.h index 8d1c7d05a62..255c7bc5b77 100644 --- a/dbms/src/DataStreams/TSKVRowOutputStream.h +++ b/dbms/src/DataStreams/TSKVRowOutputStream.h @@ -6,9 +6,9 @@ namespace DB { -/** Поток для вывода данных в формате TSKV. - * TSKV похож на TabSeparated, но перед каждым значением указывается его имя и знак равенства: name=value. - * Этот формат весьма неэффективен. +/** The stream for outputting data in the TSKV format. + * TSKV is similar to TabSeparated, but before every value, its name and equal sign are specified: name=value. + * This format is very inefficient. */ class TSKVRowOutputStream : public TabSeparatedRowOutputStream { diff --git a/dbms/src/DataStreams/TabSeparatedBlockOutputStream.h b/dbms/src/DataStreams/TabSeparatedBlockOutputStream.h index af991fb507b..00b02c7de9b 100644 --- a/dbms/src/DataStreams/TabSeparatedBlockOutputStream.h +++ b/dbms/src/DataStreams/TabSeparatedBlockOutputStream.h @@ -10,9 +10,9 @@ class Block; class WriteBuffer; -/** Пишет данные в tab-separated файл, но по столбцам, блоками. - * Блоки разделены двойным переводом строки. - * На каждой строке блока - данные одного столбца. +/** Writes the data into a tab-separated file, but by columns, in blocks. + * Blocks are separated by a double line feed. + * On each row of the block - the data of one column. */ class TabSeparatedBlockOutputStream : public IBlockOutputStream { diff --git a/dbms/src/DataStreams/TabSeparatedRawRowOutputStream.h b/dbms/src/DataStreams/TabSeparatedRawRowOutputStream.h index 3f6b152e275..7cf8ab5ce19 100644 --- a/dbms/src/DataStreams/TabSeparatedRawRowOutputStream.h +++ b/dbms/src/DataStreams/TabSeparatedRawRowOutputStream.h @@ -6,8 +6,8 @@ namespace DB { -/** Поток для вывода данных в формате tsv, но без эскейпинга отдельных значений. - * (То есть - вывод необратимый.) +/** A stream for outputting data in tsv format, but without escaping individual values. + * (That is, the output is irreversible.) */ class TabSeparatedRawRowOutputStream : public TabSeparatedRowOutputStream { diff --git a/dbms/src/DataStreams/TabSeparatedRowInputStream.h b/dbms/src/DataStreams/TabSeparatedRowInputStream.h index bd186be734e..9674a522703 100644 --- a/dbms/src/DataStreams/TabSeparatedRowInputStream.h +++ b/dbms/src/DataStreams/TabSeparatedRowInputStream.h @@ -10,13 +10,13 @@ namespace DB class ReadBuffer; -/** Поток для ввода данных в формате tsv. +/** A stream to input data in tsv format. */ class TabSeparatedRowInputStream : public IRowInputStream { public: - /** with_names - в первой строке заголовок с именами столбцов - * with_types - на следующей строке заголовок с именами типов + /** with_names - the first line is the header with the names of the columns + * with_types - on the next line header with type names */ TabSeparatedRowInputStream(ReadBuffer & istr_, const Block & sample_, bool with_names_ = false, bool with_types_ = false); @@ -34,11 +34,11 @@ private: bool with_types; DataTypes data_types; - /// Для удобной диагностики в случае ошибки. + /// For convenient diagnostics in case of an error. size_t row_num = 0; - /// Сколько байт было считано, не считая тех, что ещё в буфере. + /// How many bytes were read, not counting those still in the buffer. size_t bytes_read_at_start_of_buffer_on_current_row = 0; size_t bytes_read_at_start_of_buffer_on_prev_row = 0; diff --git a/dbms/src/DataStreams/TabSeparatedRowOutputStream.h b/dbms/src/DataStreams/TabSeparatedRowOutputStream.h index b8750a1e382..9847b18872c 100644 --- a/dbms/src/DataStreams/TabSeparatedRowOutputStream.h +++ b/dbms/src/DataStreams/TabSeparatedRowOutputStream.h @@ -9,13 +9,13 @@ namespace DB class WriteBuffer; -/** Поток для вывода данных в формате tsv. +/** A stream for outputting data in tsv format. */ class TabSeparatedRowOutputStream : public IRowOutputStream { public: - /** with_names - выводить в первой строке заголовок с именами столбцов - * with_types - выводить на следующей строке заголовок с именами типов + /** with_names - output in the first line a header with column names + * with_types - output the next line header with the names of the types */ TabSeparatedRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool with_names_ = false, bool with_types_ = false); diff --git a/dbms/src/DataStreams/TotalsHavingBlockInputStream.h b/dbms/src/DataStreams/TotalsHavingBlockInputStream.h index 124dcedd006..42137947427 100644 --- a/dbms/src/DataStreams/TotalsHavingBlockInputStream.h +++ b/dbms/src/DataStreams/TotalsHavingBlockInputStream.h @@ -9,9 +9,9 @@ namespace DB class ExpressionActions; -/** Принимает блоки после группировки, с нефиализированными агрегатными функциями. - * Вычисляет тотальные значения в соответствии с totals_mode. - * Если нужно, вычисляет выражение из HAVING и фильтрует им строки. Отдает финализированные и отфильтрованные блоки. +/** Takes blocks after grouping, with non-finalized aggregate functions. + * Calculates total values according to totals_mode. + * If necessary, evaluates the expression from HAVING and filters rows. Returns the finalized and filtered blocks. */ class TotalsHavingBlockInputStream : public IProfilingBlockInputStream { @@ -42,15 +42,15 @@ private: size_t passed_keys = 0; size_t total_keys = 0; - /** Здесь находятся значения, не прошедшие max_rows_to_group_by. - * Они прибавляются или не прибавляются к current_totals в зависимости от totals_mode. + /** Here are the values that did not pass max_rows_to_group_by. + * They are added or not added to the current_totals, depending on the totals_mode. */ Block overflow_aggregates; - /// Здесь накапливаются тотальные значения. После окончания работы, они будут помещены в IProfilingBlockInputStream::totals. + /// Here, total values are accumulated. After the work is finished, they will be placed in IProfilingBlockInputStream::totals. Block current_totals; - /// Если filter == nullptr - прибавлять все строки. Иначе - только строки, проходящие фильтр (HAVING). + /// If filter == nullptr - add all rows. Otherwise, only the rows that pass the filter (HAVING). void addToTotals(Block & totals, Block & block, const IColumn::Filter * filter); }; diff --git a/dbms/src/DataStreams/UnionBlockInputStream.h b/dbms/src/DataStreams/UnionBlockInputStream.h index f988ef59bc4..2267a8ae218 100644 --- a/dbms/src/DataStreams/UnionBlockInputStream.h +++ b/dbms/src/DataStreams/UnionBlockInputStream.h @@ -22,7 +22,7 @@ namespace template struct OutputData; -/// Блок или эксепшен. +/// A block or an exception. template <> struct OutputData { @@ -34,7 +34,7 @@ struct OutputData OutputData(std::exception_ptr & exception_) : exception(exception_) {} }; -/// Блок + дополнительнцю информацию или эксепшен. +/// Block + additional information or an exception. template <> struct OutputData { @@ -49,17 +49,17 @@ struct OutputData } -/** Объединяет несколько источников в один. - * Блоки из разных источников перемежаются друг с другом произвольным образом. - * Можно указать количество потоков (max_threads), - * в которых будет выполняться получение данных из разных источников. +/** Merges several sources into one. + * Blocks from different sources are interleaved with each other in an arbitrary way. + * You can specify the number of threads (max_threads), + * in which data will be retrieved from different sources. * - * Устроено так: - * - с помощью ParallelInputsProcessor в нескольких потоках вынимает из источников блоки; - * - полученные блоки складываются в ограниченную очередь готовых блоков; - * - основной поток вынимает готовые блоки из очереди готовых блоков; - * - если указан режим StreamUnionMode::ExtraInfo, в дополнение к блокам UnionBlockInputStream - * вынимает информацию о блоках; в таком случае все источники должны поддержать такой режим. + * It's managed like this: + * - with the help of ParallelInputsProcessor in several threads it takes out blocks from the sources; + * - the completed blocks are added to a limited queue of finished blocks; + * - the main thread takes out completed blocks from the queue of finished blocks; + * - if the StreamUnionMode::ExtraInfo mode is specified, in addition to the UnionBlockInputStream + * extracts blocks information; In this case all sources should support such mode. */ template @@ -95,7 +95,7 @@ public: for (size_t i = 0; i < children.size(); ++i) children_ids[i] = children[i]->getID(); - /// Порядок не имеет значения. + /// Order does not matter. std::sort(children_ids.begin(), children_ids.end()); for (size_t i = 0; i < children_ids.size(); ++i) @@ -121,8 +121,8 @@ public: } } - /** Отличается от реализации по-умолчанию тем, что пытается остановить все источники, - * пропуская отвалившиеся по эксепшену. + /** Different from the default implementation by trying to stop all sources, + * skipping failed by execution. */ void cancel() override { @@ -150,8 +150,8 @@ protected: std::exception_ptr exception; if (!all_read) { - /** Прочитаем всё до конца, чтобы ParallelInputsProcessor не заблокировался при попытке вставить в очередь. - * Может быть, в очереди есть ещё эксепшен. + /** Let's read everything up to the end, so that ParallelInputsProcessor is not blocked when trying to insert into the queue. + * Maybe there is an exception in the queue. */ OutputData res; while (true) @@ -181,17 +181,17 @@ protected: std::rethrow_exception(exception); } - /// Ничего не делаем, чтобы подготовка к выполнению запроса делалась параллельно, в ParallelInputsProcessor. + /// Do nothing, to make the preparation for the query execution in parallel, in ParallelInputsProcessor. void readPrefix() override { } - /** Возможны следующие варианты: - * 1. Функция readImpl вызывается до тех пор, пока она не вернёт пустой блок. - * Затем вызывается функция readSuffix и затем деструктор. - * 2. Вызывается функция readImpl. В какой-то момент, возможно из другого потока вызывается функция cancel. - * Затем вызывается функция readSuffix и затем деструктор. - * 3. В любой момент, объект может быть и так уничтожен (вызываться деструктор). + /** The following options are possible: + * 1. `readImpl` function is called until it returns an empty block. + * Then `readSuffix` function is called and then destructor. + * 2. `readImpl` function is called. At some point, `cancel` function is called perhaps from another thread. + * Then `readSuffix` function is called and then destructor. + * 3. At any time, the object can be destroyed (destructor called). */ Block readImpl() override @@ -199,14 +199,14 @@ protected: if (all_read) return received_payload.block; - /// Запускаем потоки, если это ещё не было сделано. + /// Run threads if this has not already been done. if (!started) { started = true; processor.process(); } - /// Будем ждать, пока будет готов следующий блок или будет выкинуто исключение. + /// We will wait until the next block is ready or an exception is thrown. //std::cerr << "popping\n"; output_queue.pop(received_payload); @@ -223,7 +223,7 @@ protected: return received_payload.block; } - /// Вызывается либо после того, как всё прочитано, либо после cancel-а. + /// Called either after everything is read, or after cancel. void readSuffix() override { //std::cerr << "readSuffix\n"; @@ -255,11 +255,11 @@ private: using OutputQueue = ConcurrentBoundedQueue; private: - /** Очередь готовых блоков. Также туда можно положить эксепшен вместо блока. - * Когда данные закончатся - в очередь вставляется пустой блок. - * В очередь всегда (даже после исключения или отмены запроса) рано или поздно вставляется пустой блок. - * Очередь всегда (даже после исключения или отмены запроса, даже в деструкторе) нужно дочитывать до пустого блока, - * иначе ParallelInputsProcessor может заблокироваться при вставке в очередь. + /** The queue of the finished blocks. Also, you can put an exception instead of a block. + * When data is run out, an empty block is inserted into the queue. + * Sooner or later, an empty block is always inserted into the queue (even after exception or query cancellation). + * The queue is always (even after exception or canceling the query, even in destructor) you must read up to an empty block, + * otherwise ParallelInputsProcessor can be blocked during insertion into the queue. */ OutputQueue output_queue; @@ -297,12 +297,12 @@ private: { //std::cerr << "pushing exception\n"; - /// Порядок строк имеет значение. Если его поменять, то возможна ситуация, - /// когда перед эксепшеном, в очередь окажется вставлен пустой блок (конец данных), - /// и эксепшен потеряется. + /// The order of the rows matters. If it is changed, then the situation is possible, + /// when before exception, an empty block (end of data) will be put into the queue, + /// and the exception is lost. parent.output_queue.push(exception); - parent.cancel(); /// Не кидает исключений. + parent.cancel(); /// Does not throw exceptions. } Self & parent; diff --git a/dbms/src/DataStreams/ValuesRowOutputStream.h b/dbms/src/DataStreams/ValuesRowOutputStream.h index 2e0a9f63957..9b9dfdf6a0b 100644 --- a/dbms/src/DataStreams/ValuesRowOutputStream.h +++ b/dbms/src/DataStreams/ValuesRowOutputStream.h @@ -9,7 +9,7 @@ namespace DB class WriteBuffer; -/** Поток для вывода данных в формате VALUES (как в INSERT запросе). +/** A stream for outputting data in the VALUES format (as in the INSERT request). */ class ValuesRowOutputStream : public IRowOutputStream { diff --git a/dbms/src/DataStreams/XMLRowOutputStream.h b/dbms/src/DataStreams/XMLRowOutputStream.h index a412461b616..b11db4e3cf4 100644 --- a/dbms/src/DataStreams/XMLRowOutputStream.h +++ b/dbms/src/DataStreams/XMLRowOutputStream.h @@ -10,7 +10,7 @@ namespace DB { -/** Поток для вывода данных в формате XML. +/** A stream for outputting data in XML format. */ class XMLRowOutputStream : public IRowOutputStream { diff --git a/dbms/src/DataStreams/copyData.h b/dbms/src/DataStreams/copyData.h index c73e16a2803..2a42ef191cb 100644 --- a/dbms/src/DataStreams/copyData.h +++ b/dbms/src/DataStreams/copyData.h @@ -9,8 +9,8 @@ namespace DB class IBlockInputStream; class IBlockOutputStream; -/** Копирует данные из InputStream в OutputStream - * (например, из БД в консоль и т. п.) +/** Copies data from the InputStream into the OutputStream + * (for example, from the database to the console, etc.) */ void copyData(IBlockInputStream & from, IBlockOutputStream & to, std::atomic * is_cancelled = nullptr); diff --git a/dbms/src/DataStreams/glueBlockInputStreams.h b/dbms/src/DataStreams/glueBlockInputStreams.h index f3a084f724c..bf0272b675c 100644 --- a/dbms/src/DataStreams/glueBlockInputStreams.h +++ b/dbms/src/DataStreams/glueBlockInputStreams.h @@ -6,11 +6,11 @@ namespace DB { -/** Если переданные источники (конвейеры выполнения запроса) имеют одинаковые части, - * то склеивает эти части, заменяя на один источник и вставляя "вилки" (размножители). - * Это используется для однопроходного выполнения нескольких запросов. +/** If passed sources (query execution pipelines) have the same parts, + * then glues these parts, replacing them with one source and inserting "forks" (multipliers). + * This is used for single-pass execution of multiple queries. * - * Для выполнения склеенного конвейера, все inputs и forks должны использоваться в разных потоках. + * To execute a glued pipeline, all `inputs` and `forks` must be used in different threads. */ void glueBlockInputStreams(BlockInputStreams & inputs, Forks & forks); diff --git a/dbms/src/DataStreams/narrowBlockInputStreams.h b/dbms/src/DataStreams/narrowBlockInputStreams.h index b8fbd77cc75..305342185b7 100644 --- a/dbms/src/DataStreams/narrowBlockInputStreams.h +++ b/dbms/src/DataStreams/narrowBlockInputStreams.h @@ -6,12 +6,12 @@ namespace DB { -/** Если количество источников inputs больше width, - * то клеит источники друг с другом (с помощью ConcatBlockInputStream), - * чтобы количество источников стало не больше width. +/** If the number of sources of `inputs` is greater than `width`, + * then glues the sources to each other (using ConcatBlockInputStream), + * so that the number of sources becomes no more than `width`. * - * Старается клеить источники друг с другом равномерно-случайно. - * (чтобы избежать перевеса в случае, если распределение количества данных в разных источниках подчиняется некоторому шаблону) + * Trying to glue the sources with each other uniformly randomly. + * (to avoid overweighting if the distribution of the amount of data in different sources is subject to some pattern) */ BlockInputStreams narrowBlockInputStreams(BlockInputStreams & inputs, size_t width); diff --git a/dbms/src/Functions/FunctionsArithmetic.h b/dbms/src/Functions/FunctionsArithmetic.h index 9fb659af477..234a2f981c6 100644 --- a/dbms/src/Functions/FunctionsArithmetic.h +++ b/dbms/src/Functions/FunctionsArithmetic.h @@ -91,7 +91,7 @@ struct PlusImpl template static inline Result apply(A a, B b) { - /// Далее везде, static_cast - чтобы не было неправильного результата в выражениях вида Int64 c = UInt32(a) * Int32(-1). + /// Next everywhere, static_cast - so that there is no wrong result in expressions of the form Int64 c = UInt32(a) * Int32(-1). return static_cast(a) + b; } }; @@ -140,7 +140,7 @@ struct DivideFloatingImpl template inline void throwIfDivisionLeadsToFPE(A a, B b) { - /// Возможно, лучше вместо проверок использовать siglongjmp? + /// Is it better to use siglongjmp instead of checks? if (unlikely(b == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); @@ -153,7 +153,7 @@ inline void throwIfDivisionLeadsToFPE(A a, B b) template inline bool divisionLeadsToFPE(A a, B b) { - /// Возможно, лучше вместо проверок использовать siglongjmp? + /// Is it better to use siglongjmp instead of checks? if (unlikely(b == 0)) return true; @@ -308,7 +308,7 @@ struct LeastBaseImpl template static inline Result apply(A a, B b) { - /** gcc 4.9.2 успешно векторизует цикл из этой функции. */ + /** gcc 4.9.2 successfully vectorizes a loop from this function. */ return static_cast(a) < static_cast(b) ? static_cast(a) : static_cast(b); } }; @@ -937,7 +937,7 @@ using FunctionBitRotateRight = FunctionBinaryArithmetic; using FunctionGreatest = FunctionBinaryArithmetic; -/// Свойства монотонности для некоторых функций. +/// Monotonicity properties for some functions. template <> struct FunctionUnaryArithmeticMonotonicity { @@ -974,7 +974,7 @@ template <> struct FunctionUnaryArithmeticMonotonicity } -/// Оптимизации для целочисленного деления на константу. +/// Optimizations for integer division by a constant. #if __SSE2__ #define LIBDIVIDE_USE_SSE2 1 @@ -1065,16 +1065,16 @@ struct ModuloByConstantImpl libdivide::divider divider(b); - /// Тут не удалось сделать так, чтобы SSE вариант из libdivide давал преимущество. + /// Here we failed to make the SSE variant from libdivide give an advantage. size_t size = a.size(); for (size_t i = 0; i < size; ++i) - c[i] = a[i] - (a[i] / divider) * b; /// NOTE: возможно, не сохраняется семантика деления с остатком отрицательных чисел. + c[i] = a[i] - (a[i] / divider) * b; /// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved. } }; -/** Прописаны специализации для деления чисел типа UInt64 и UInt32 на числа той же знаковости. - * Можно дополнить до всех возможных комбинаций, но потребуется больше кода. +/** Specializations are specified for dividing numbers of the type UInt64 and UInt32 by the numbers of the same sign. + * Can be expanded to all possible combinations, but more code is needed. */ template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 816a6d2e5ae..b7a8cae759f 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -900,9 +900,9 @@ public: size_t getNumberOfArguments() const override { return 2; } bool isInjective(const Block &) override { return true; } - /** Получить тип результата по типам аргументов и значениям константных аргументов. - * Если функция неприменима для данных аргументов - кинуть исключение. - * Для неконстантных столбцов arguments[i].column = nullptr. + /** Get the result type by argument types and constant argument values. + * If the function does not apply to these arguments, throw an exception. + * For non-constant columns arguments[i].column = nullptr. */ void getReturnTypeAndPrerequisitesImpl(const ColumnsWithTypeAndName & arguments, DataTypePtr & out_return_type, @@ -1089,8 +1089,8 @@ struct ToIntMonotonicity } }; -/** Монотонность для функции toString определяем, в основном, для тестовых целей. - * Всерьёз вряд ли кто-нибудь рассчитывает на оптимизацию запросов с условиями toString(CounterID) = 34. +/** The monotonicity for the `toString` function is mainly determined for test purposes. + * It is doubtful that anyone is looking to optimize queries with conditions `toString(CounterID) = 34`. */ struct ToStringMonotonicity { @@ -1101,7 +1101,7 @@ struct ToStringMonotonicity IFunction::Monotonicity positive(true, true); IFunction::Monotonicity not_monotonic; - /// Функция toString монотонна, если аргумент - Date или DateTime, или неотрицательные числа с одинаковым количеством знаков. + /// `toString` function is monotonous if the argument is Date or DateTime, or non-negative numbers with the same number of symbols. if (typeid_cast(&type) || typeid_cast(&type)) diff --git a/dbms/src/Functions/FunctionsEmbeddedDictionaries.h b/dbms/src/Functions/FunctionsEmbeddedDictionaries.h index 828de8603f5..554f94be304 100644 --- a/dbms/src/Functions/FunctionsEmbeddedDictionaries.h +++ b/dbms/src/Functions/FunctionsEmbeddedDictionaries.h @@ -33,19 +33,19 @@ namespace ErrorCodes extern const int BAD_ARGUMENTS; } -/** Функции, использующие словари Яндекс.Метрики - * - словари регионов, операционных систем, поисковых систем. +/** Functions using Yandex.Metrica dictionaries + * - dictionaries of regions, operating systems, search engines. * - * Подняться по дереву до определенного уровня. + * Climb up the tree to a certain level. * regionToCity, regionToArea, regionToCountry, ... * - * Преобразовать значения в столбце + * Convert values of a column * regionToName * - * Является ли первый идентификатор потомком второго. + * Whether the first identifier is a descendant of the second. * regionIn * - * Получить массив идентификаторов регионов, состоящий из исходного и цепочки родителей. Порядок implementation defined. + * Get an array of region identifiers, consisting of the source and the parents chain. Order implementation defined. * regionHierarchy */ @@ -131,9 +131,9 @@ struct SEHierarchyImpl #endif -/** Вспомогательная вещь, позволяющая достать из словаря конкретный словарь, соответствующий точке зрения - * (ключу словаря, передаваемому в аргументе функции). - * Пример: при вызове regionToCountry(x, 'ua'), может быть использован словарь, в котором Крым относится к Украине. +/** Auxiliary thing, allowing to get from the dictionary a specific dictionary, corresponding to the point of view + * (the dictionary key passed as function argument). + * Example: when calling regionToCountry(x, 'ua'), a dictionary can be used, in which Crimea refers to Ukraine. */ struct RegionsHierarchyGetter { @@ -146,7 +146,7 @@ struct RegionsHierarchyGetter } }; -/** Для словарей без поддержки ключей. Ничего не делает. +/** For dictionaries without key support. Doing nothing. */ template struct IdentityDictionaryGetter @@ -164,7 +164,7 @@ struct IdentityDictionaryGetter }; -/// Преобразует идентификатор, используя словарь. +/// Converts an identifier using a dictionary. template class FunctionTransformWithDictionary : public IFunction { @@ -213,7 +213,7 @@ public: void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override { - /// Ключ словаря, определяющий "точку зрения". + /// The dictionary key that defines the "point of view". std::string dict_key; if (arguments.size() == 2) @@ -257,7 +257,7 @@ public: }; -/// Проверяет принадлежность, используя словарь. +/// Checks belonging using a dictionary. template class FunctionIsInWithDictionary : public IFunction { @@ -311,7 +311,7 @@ public: void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override { - /// Ключ словаря, определяющий "точку зрения". + /// The dictionary key that defines the "point of view". std::string dict_key; if (arguments.size() == 3) @@ -390,7 +390,7 @@ public: }; -/// Получает массив идентификаторов, состоящий из исходного и цепочки родителей. +/// Gets an array of identifiers consisting of the source and the parents chain. template class FunctionHierarchyWithDictionary : public IFunction { @@ -439,7 +439,7 @@ public: void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override { - /// Ключ словаря, определяющий "точку зрения". + /// The dictionary key that defines the "point of view". std::string dict_key; if (arguments.size() == 2) @@ -670,7 +670,7 @@ struct FunctionSEHierarchy : #endif -/// Преобразует числовой идентификатор региона в имя на заданном языке, используя словарь. +/// Converts a region's numeric identifier to a name in the specified language using a dictionary. class FunctionRegionToName : public IFunction { public: @@ -727,7 +727,7 @@ public: { RegionsNames::Language language = RegionsNames::Language::RU; - /// Если указан язык результата + /// If the result language is specified if (arguments.size() == 2) { if (const ColumnConstString * col_language = typeid_cast(block.safeGetByPosition(arguments[1]).column.get())) diff --git a/dbms/src/Functions/FunctionsExternalDictionaries.h b/dbms/src/Functions/FunctionsExternalDictionaries.h index 375f5212911..06e829d51cb 100644 --- a/dbms/src/Functions/FunctionsExternalDictionaries.h +++ b/dbms/src/Functions/FunctionsExternalDictionaries.h @@ -37,17 +37,17 @@ namespace ErrorCodes extern const int UNKNOWN_TYPE; } -/** Функции, использующие подключаемые (внешние) словари. +/** Functions that use plug-ins (external) dictionaries. * - * Получить значение аттрибута заданного типа. + * Get the value of the attribute of the specified type. * dictGetType(dictionary, attribute, id), - * Type - placeholder для имени типа, в данный момент поддерживаются любые числовые и строковой типы. - * Тип должен соответствовать реальному типу аттрибута, с которым он был объявлен в структуре словаря. + * Type - placeholder for the type name, any numeric and string types are currently supported. + * The type must match the actual attribute type with which it was declared in the dictionary structure. * - * Получить массив идентификаторов, состоящий из исходного и цепочки родителей. + * Get an array of identifiers, consisting of the source and parents chain. * dictGetHierarchy(dictionary, id). * - * Является ли первы йидентификатор потомком второго. + * Is the first identifier the child of the second. * dictIsIn(dictionary, child_id, parent_id). */ @@ -155,7 +155,7 @@ private: if (typeid_cast(key_col_with_type.column.get()) || typeid_cast(key_col_with_type.column.get())) { - /// Функции у внешних словарей поддерживают только полноценные (не константные) столбцы с ключами. + /// Functions in external dictionaries only support full-value (not constant) columns with keys. const ColumnPtr key_col_materialized = key_col_with_type.column->convertToFullColumnIfConst(); const auto key_columns = ext::map( diff --git a/dbms/src/Functions/FunctionsFormatting.h b/dbms/src/Functions/FunctionsFormatting.h index 288c453f464..25cb80f6ab1 100644 --- a/dbms/src/Functions/FunctionsFormatting.h +++ b/dbms/src/Functions/FunctionsFormatting.h @@ -13,12 +13,12 @@ namespace DB { -/** Функция для необычного преобразования в строку: +/** Function for an unusual conversion to a string: * - * bitmaskToList - принимает целое число - битовую маску, возвращает строку из степеней двойки через запятую. - * например, bitmaskToList(50) = '2,16,32' + * bitmaskToList - takes an integer - a bitmask, returns a string of degrees of 2 separated by a comma. + * for example, bitmaskToList(50) = '2,16,32' * - * formatReadableSize - выводит переданный размер в байтах в виде 123.45 GiB. + * formatReadableSize - prints the transferred size in bytes in form `123.45 GiB`. */ class FunctionBitmaskToList : public IFunction diff --git a/dbms/src/Functions/FunctionsMath.h b/dbms/src/Functions/FunctionsMath.h index ed808067b53..115790efe04 100644 --- a/dbms/src/Functions/FunctionsMath.h +++ b/dbms/src/Functions/FunctionsMath.h @@ -478,7 +478,7 @@ struct BinaryFunctionVectorized struct EImpl { static constexpr auto name = "e"; - static const double value; /// См. .cpp + static const double value; /// See .cpp }; struct PiImpl diff --git a/dbms/src/Functions/FunctionsMiscellaneous.h b/dbms/src/Functions/FunctionsMiscellaneous.h index 8bf61862206..951b3d3663b 100644 --- a/dbms/src/Functions/FunctionsMiscellaneous.h +++ b/dbms/src/Functions/FunctionsMiscellaneous.h @@ -49,8 +49,8 @@ public: }; -/** Создаёт массив, размножая столбец (первый аргумент) по количеству элементов в массиве (втором аргументе). - * Используется только в качестве prerequisites для функций высшего порядка. +/** Creates an array, multiplying the column (the first argument) by the number of elements in the array (the second argument). + * Used only as prerequisites for higher-order functions. */ class FunctionReplicate : public IFunction { diff --git a/dbms/src/Functions/FunctionsReinterpret.h b/dbms/src/Functions/FunctionsReinterpret.h index 5e7f72075b9..1ecc5beacbd 100644 --- a/dbms/src/Functions/FunctionsReinterpret.h +++ b/dbms/src/Functions/FunctionsReinterpret.h @@ -15,7 +15,7 @@ namespace DB { -/** Функции преобразования чисел и дат в строки, содержащие тот же набор байт в машинном представлении, и обратно. +/** Functions for transforming numbers and dates to strings that contain the same set of bytes in the machine representation, and vice versa. */ diff --git a/dbms/src/Functions/Regexps.h b/dbms/src/Functions/Regexps.h index 117930aebbd..c1f774e798d 100644 --- a/dbms/src/Functions/Regexps.h +++ b/dbms/src/Functions/Regexps.h @@ -29,7 +29,7 @@ namespace Regexps inline Pool::Pointer get(const std::string & pattern) { /// C++11 has thread-safe function-local statics on most modern compilers. - static Pool known_regexps; /// Разные переменные для разных параметров шаблона. + static Pool known_regexps; /// Different variables for different pattern parameters. return known_regexps.get(pattern, [&pattern] { diff --git a/dbms/src/Functions/likePatternToRegexp.h b/dbms/src/Functions/likePatternToRegexp.h index 9d769eb6fe4..3a078b468c2 100644 --- a/dbms/src/Functions/likePatternToRegexp.h +++ b/dbms/src/Functions/likePatternToRegexp.h @@ -4,7 +4,7 @@ namespace DB { -/// Переводит выражение LIKE в regexp re2. Например, abc%def -> ^abc.*def$ +/// Transforms the LIKE expression into regexp re2. For example, abc%def -> ^abc.*def$ inline String likePatternToRegexp(const String & pattern) { String res; diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h index 06e331ad652..077be41a693 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.h @@ -63,7 +63,7 @@ struct ReplicatedMergeTreeLogEntryData /// The name of resulting part. /// For DROP_RANGE, the name of a non-existent part. You need to remove all the parts covered by it. String new_part_name; - String block_id; /// For parts of level zero, the block identifier for deduplication (node name in /blocks /). + String block_id; /// For parts of level zero, the block identifier for deduplication (node name in /blocks/). Strings parts_to_merge; bool deduplicate = false; /// Do deduplicate on merge From 92b56c2c7d5a46ae313bb6187a055c797295f78f Mon Sep 17 00:00:00 2001 From: f1yegor Date: Sun, 14 May 2017 13:47:14 +0200 Subject: [PATCH 68/76] translate comments --- dbms/src/Interpreters/Limits.h | 66 +++++++------- dbms/src/Interpreters/Settings.h | 142 +++++++++++++++---------------- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/dbms/src/Interpreters/Limits.h b/dbms/src/Interpreters/Limits.h index c8192f587da..994bf213cdb 100644 --- a/dbms/src/Interpreters/Limits.h +++ b/dbms/src/Interpreters/Limits.h @@ -9,22 +9,22 @@ namespace DB { -/** Ограничения при выполнении запроса - часть настроек. - * Используются, чтобы обеспечить более безопасное исполнение запросов из пользовательского интерфейса. - * В основном, ограничения проверяются на каждый блок (а не на каждую строку). То есть, ограничения могут быть немного нарушены. - * Почти все ограничения действуют только на SELECT-ы. - * Почти все ограничения действуют на каждый поток по отдельности. +/** Limits during query execution are part of the settings. + * Used to provide a more safe execution of queries from the user interface. + * Basically, constraints are checked for each block (not every row). That is, the limits can be slightly violated. + * Almost all limits apply only to SELECTs. + * Almost all limits apply to each thread individually. */ struct Limits { - /** Перечисление ограничений: тип, имя, значение по-умолчанию. - * По-умолчанию: всё не ограничено, кроме довольно слабых ограничений на глубину рекурсии и размер выражений. + /** Enumeration of limits: type, name, default value. + * By default: everything is unlimited, except for rather weak restrictions on the depth of recursion and the size of the expressions. */ #define APPLY_FOR_LIMITS(M) \ - /** Ограничения на чтение из самых "глубоких" источников. \ - * То есть, только в самом глубоком подзапросе. \ - * При чтении с удалённого сервера, проверяется только на удалённом сервере. \ + /** Limits on reading from the most "deep" sources. \ + * That is, only in the deepest subquery. \ + * When reading from a remote server, it is only checked on a remote server. \ */ \ M(SettingUInt64, max_rows_to_read, 0) \ M(SettingUInt64, max_bytes_to_read, 0) \ @@ -39,20 +39,20 @@ struct Limits M(SettingOverflowMode, sort_overflow_mode, OverflowMode::THROW) \ M(SettingUInt64, max_bytes_before_external_sort, 0) \ \ - /** Ограничение на размер результата. \ - * Проверяются также для подзапросов и на удалённых серверах. \ + /** Limits on result size. \ + * Are also checked for subqueries and on remote servers. \ */ \ M(SettingUInt64, max_result_rows, 0) \ M(SettingUInt64, max_result_bytes, 0) \ M(SettingOverflowMode, result_overflow_mode, OverflowMode::THROW) \ \ - /* TODO: Проверять также при слиянии и финализации агрегатных функций. */ \ + /* TODO: Check also when merging and finalizing aggregate functions. */ \ M(SettingSeconds, max_execution_time, 0) \ M(SettingOverflowMode, timeout_overflow_mode, OverflowMode::THROW) \ \ - /** В строчках в секунду. */ \ + /** In rows per second. */ \ M(SettingUInt64, min_execution_speed, 0) \ - /** Проверять, что скорость не слишком низкая, после прошествия указанного времени. */ \ + /** Check that the speed is not too low after the specified time has elapsed. */ \ M(SettingSeconds, timeout_before_checking_execution_speed, 0) \ \ M(SettingUInt64, max_columns_to_read, 0) \ @@ -61,42 +61,42 @@ struct Limits \ M(SettingUInt64, max_subquery_depth, 100) \ M(SettingUInt64, max_pipeline_depth, 1000) \ - M(SettingUInt64, max_ast_depth, 1000) /** Проверяются не во время парсинга, */ \ - M(SettingUInt64, max_ast_elements, 50000) /** а уже после парсинга запроса. */ \ + M(SettingUInt64, max_ast_depth, 1000) /** Checked not during parsing, */ \ + M(SettingUInt64, max_ast_elements, 50000) /** but after parsing the request. */ \ \ - /** 0 - можно всё. 1 - только запросы на чтение. 2 - только запросы на чтение, а также изменение настроек, кроме настройки readonly. */ \ + /** 0 - everything is allowed. 1 - only read requests. 2 - only read requests, as well as changing settings, except for the readonly setting. */ \ M(SettingUInt64, readonly, 0) \ \ - /** Ограничения для максимального размера множества, получающегося при выполнении секции IN. */ \ + /** Limits for the maximum size of the set resulting from the execution of the IN section. */ \ M(SettingUInt64, max_rows_in_set, 0) \ M(SettingUInt64, max_bytes_in_set, 0) \ M(SettingOverflowMode, set_overflow_mode, OverflowMode::THROW) \ \ - /** Ограничения для максимального размера множества, получающегося при выполнении секции IN. */ \ + /** Limits for the maximum size of the set obtained by executing the IN section. */ \ M(SettingUInt64, max_rows_in_join, 0) \ M(SettingUInt64, max_bytes_in_join, 0) \ M(SettingOverflowMode, join_overflow_mode, OverflowMode::THROW) \ \ - /** Ограничения для максимального размера передаваемой внешней таблицы, получающейся при выполнении секции GLOBAL IN/JOIN. */ \ + /** Limits for the maximum size of the transmitted external table obtained when the GLOBAL IN/JOIN section is executed. */ \ M(SettingUInt64, max_rows_to_transfer, 0) \ M(SettingUInt64, max_bytes_to_transfer, 0) \ M(SettingOverflowMode, transfer_overflow_mode, OverflowMode::THROW) \ \ - /** Ограничения для максимального размера запоминаемого состояния при выполнении DISTINCT. */ \ + /** Limits for the maximum size of the stored state when executing DISTINCT. */ \ M(SettingUInt64, max_rows_in_distinct, 0) \ M(SettingUInt64, max_bytes_in_distinct, 0) \ M(SettingOverflowMode, distinct_overflow_mode, OverflowMode::THROW) \ \ - /** Максимальное использование памяти при обработке запроса. 0 - не ограничено. */ \ - M(SettingUInt64, max_memory_usage, 0) /* На один запрос */ \ - /* Суммарно на одновременно выполняющиеся запросы одного пользователя */ \ + /** Maximum memory usage when processing a request. 0 - not bounded. */ \ + M(SettingUInt64, max_memory_usage, 0) /* For one query */ \ + /* Totally for concurrently running queries of one user */ \ M(SettingUInt64, max_memory_usage_for_user, 0) \ - /* Суммарно на все одновременно выполняющиеся запросы */ \ + /* Totally for all concurrent queries */ \ M(SettingUInt64, max_memory_usage_for_all_queries, 0) \ \ - /** Максимальная скорость обмена данными по сети в байтах в секунду. 0 - не ограничена. */ \ + /** The maximum speed of data exchange over the network in bytes per second. 0 - not bounded. */ \ M(SettingUInt64, max_network_bandwidth, 0) \ - /** Максимальное количество байт на приём или передачу по сети, в рамках запроса. */ \ + /** The maximum number of bytes to receive or transmit over the network, as part of the query. */ \ M(SettingUInt64, max_network_bytes, 0) \ #define DECLARE(TYPE, NAME, DEFAULT) \ @@ -106,7 +106,7 @@ struct Limits #undef DECLARE - /// Установить настройку по имени. + /// Set setting by name. bool trySet(const String & name, const Field & value) { #define TRY_SET(TYPE, NAME, DEFAULT) \ @@ -122,7 +122,7 @@ struct Limits #undef TRY_SET } - /// Установить настройку по имени. Прочитать сериализованное в бинарном виде значение из буфера (для межсерверного взаимодействия). + /// Set the setting by name. Read the binary serialized value from the buffer (for server-to-server interaction). bool trySet(const String & name, ReadBuffer & buf) { #define TRY_SET(TYPE, NAME, DEFAULT) \ @@ -138,7 +138,7 @@ struct Limits #undef TRY_SET } - /// Пропустить сериализованное в бинарном виде значение из буфера. + /// Skip the binary-serialized value from the buffer. bool tryIgnore(const String & name, ReadBuffer & buf) { #define TRY_IGNORE(TYPE, NAME, DEFAULT) \ @@ -154,7 +154,7 @@ struct Limits #undef TRY_IGNORE } - /** Установить настройку по имени. Прочитать значение в текстовом виде из строки (например, из конфига, или из параметра URL). + /** Set the setting by name. Read the value in text form from a string (for example, from a config, or from a URL parameter). */ bool trySet(const String & name, const String & value) { @@ -174,7 +174,7 @@ struct Limits private: friend struct Settings; - /// Записать все настройки в буфер. (В отличие от соответствующего метода в Settings, пустая строка на конце не пишется). + /// Write all the settings to the buffer. (Unlike the corresponding method in Settings, the empty line on the end is not written). void serialize(WriteBuffer & buf) const { #define WRITE(TYPE, NAME, DEFAULT) \ diff --git a/dbms/src/Interpreters/Settings.h b/dbms/src/Interpreters/Settings.h index 4d696ddfec7..5653fe484a4 100644 --- a/dbms/src/Interpreters/Settings.h +++ b/dbms/src/Interpreters/Settings.h @@ -28,52 +28,52 @@ struct Settings */ #define APPLY_FOR_SETTINGS(M) \ - /** При записи данных, для сжатия выделяется буфер размером max_compress_block_size. При переполнении буфера или если в буфер */ \ - /** записано данных больше или равно, чем min_compress_block_size, то при очередной засечке, данные так же будут сжиматься */ \ - /** В результате, для маленьких столбцов (числа 1-8 байт), при index_granularity = 8192, размер блока будет 64 KБ. */ \ - /** А для больших столбцов (Title - строка ~100 байт), размер блока будет ~819 КБ. */ \ - /** За счёт этого, коэффициент сжатия почти не ухудшится. */ \ + /** When writing data, a buffer of max_compress_block_size size is allocated for compression. When the buffer overflows or if into the buffer */ \ + /** written data is greater than or equal to min_compress_block_size, then with the next mark, the data will also be compressed */ \ + /** As a result, for small columns (around 1-8 bytes), with index_granularity = 8192, the block size will be 64 KB. */ \ + /** And for large columns (Title - string ~100 bytes), the block size will be ~819 KB. */ \ + /** Due to this, the compression ratio almost does not get worse. */ \ M(SettingUInt64, min_compress_block_size, DEFAULT_MIN_COMPRESS_BLOCK_SIZE) \ M(SettingUInt64, max_compress_block_size, DEFAULT_MAX_COMPRESS_BLOCK_SIZE) \ - /** Максимальный размер блока для чтения */ \ + /** Maximum block size for reading */ \ M(SettingUInt64, max_block_size, DEFAULT_BLOCK_SIZE) \ - /** Максимальный размер блока для вставки, если мы управляем формированием блоков для вставки. */ \ + /** The maximum block size for insertion, if we control the creation of blocks for insertion. */ \ M(SettingUInt64, max_insert_block_size, DEFAULT_INSERT_BLOCK_SIZE) \ /** Squash blocks passed to INSERT query to specified size in rows, if blocks are not big enough. */ \ M(SettingUInt64, min_insert_block_size_rows, DEFAULT_INSERT_BLOCK_SIZE) \ /** Squash blocks passed to INSERT query to specified size in bytes, if blocks are not big enough. */ \ M(SettingUInt64, min_insert_block_size_bytes, (DEFAULT_INSERT_BLOCK_SIZE * 256)) \ - /** Максимальное количество потоков выполнения запроса. По-умолчанию - определять автоматически. */ \ + /** The maximum number of threads to execute the request. By default, it is determined automatically. */ \ M(SettingMaxThreads, max_threads, 0) \ - /** Максимальный размер буфера для чтения из файловой системы. */ \ + /** The maximum size of the buffer to read from the file system. */ \ M(SettingUInt64, max_read_buffer_size, DBMS_DEFAULT_BUFFER_SIZE) \ - /** Максимальное количество соединений при распределённой обработке одного запроса (должно быть больше, чем max_threads). */ \ + /** The maximum number of connections for distributed processing of one query (should be greater than max_threads). */ \ M(SettingUInt64, max_distributed_connections, DEFAULT_MAX_DISTRIBUTED_CONNECTIONS) \ - /** Какую часть запроса можно прочитать в оперативку для парсинга (оставшиеся данные для INSERT, если есть, считываются позже) */ \ + /** Which part of the query can be read into RAM for parsing (the remaining data for INSERT, if any, is read later) */ \ M(SettingUInt64, max_query_size, DEFAULT_MAX_QUERY_SIZE) \ - /** Интервал в микросекундах для проверки, не запрошена ли остановка выполнения запроса, и отправки прогресса. */ \ + /** The interval in microseconds to check if the request is cancelled, and to send progress info. */ \ M(SettingUInt64, interactive_delay, DEFAULT_INTERACTIVE_DELAY) \ M(SettingSeconds, connect_timeout, DBMS_DEFAULT_CONNECT_TIMEOUT_SEC) \ - /** Если следует выбрать одну из рабочих реплик. */ \ + /** If you should select one of the working replicas. */ \ M(SettingMilliseconds, connect_timeout_with_failover_ms, DBMS_DEFAULT_CONNECT_TIMEOUT_WITH_FAILOVER_MS) \ M(SettingSeconds, receive_timeout, DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC) \ M(SettingSeconds, send_timeout, DBMS_DEFAULT_SEND_TIMEOUT_SEC) \ - /** Время ожидания в очереди запросов, если количество одновременно выполняющихся запросов превышает максимальное. */ \ + /** The wait time in the request queue, if the number of concurrent requests exceeds the maximum. */ \ M(SettingMilliseconds, queue_max_wait_ms, DEFAULT_QUERIES_QUEUE_WAIT_TIME_MS) \ - /** Блокироваться в цикле ожидания запроса в сервере на указанное количество секунд. */ \ + /** Block at the query wait cycle on the server for the specified number of seconds. */ \ M(SettingUInt64, poll_interval, DBMS_DEFAULT_POLL_INTERVAL) \ - /** Максимальное количество соединений с одним удалённым сервером в пуле. */ \ + /** Maximum number of connections with one remote server in the pool. */ \ M(SettingUInt64, distributed_connections_pool_size, DBMS_DEFAULT_DISTRIBUTED_CONNECTIONS_POOL_SIZE) \ - /** Максимальное количество попыток соединения с репликами. */ \ + /** The maximum number of attempts to connect to replicas. */ \ M(SettingUInt64, connections_with_failover_max_tries, DBMS_CONNECTION_POOL_WITH_FAILOVER_DEFAULT_MAX_TRIES) \ - /** Считать минимумы и максимумы столбцов результата. Они могут выводиться в JSON-форматах. */ \ + /** Calculate minimums and maximums of the result columns. They can be output in JSON-formats. */ \ M(SettingBool, extremes, false) \ - /** Использовать ли кэш разжатых блоков. */ \ + /** Whether to use the cache of uncompressed blocks. */ \ M(SettingBool, use_uncompressed_cache, true) \ - /** Следует ли отменять выполняющийся запрос с таким же id, как новый. */ \ + /** Whether the running request should be canceled with the same id as the new one. */ \ M(SettingBool, replace_running_query, false) \ - /** Количество потоков, выполняющих фоновую работу для таблиц (например, слияние в merge tree). \ - * TODO: Сейчас применяется только при запуске сервера. Можно сделать изменяемым динамически. */ \ + /** Number of threads performing background work for tables (for example, merging in merge tree). \ + * TODO: Now only applies when the server is started. You can make it dynamically variable. */ \ M(SettingUInt64, background_pool_size, DBMS_DEFAULT_BACKGROUND_POOL_SIZE) \ \ /** Sleep time for StorageDistributed DirectoryMonitors in case there is no work or exception has been thrown */ \ @@ -82,9 +82,9 @@ struct Settings /** Allows disabling WHERE to PREWHERE optimization in SELECT queries from MergeTree */ \ M(SettingBool, optimize_move_to_prewhere, true) \ \ - /** Ожидать выполнения действий по манипуляции с партициями. 0 - не ждать, 1 - ждать выполнения только у себя, 2 - ждать всех. */ \ + /** Wait for actions to manipulate the partitions. 0 - do not wait, 1 - wait for execution only of itself, 2 - wait for everyone. */ \ M(SettingUInt64, replication_alter_partitions_sync, 1) \ - /** Ожидать выполнения действий по изменению структуры таблицы в течение указанного количества секунд. 0 - ждать неограниченное время. */ \ + /** Wait for actions to change the table structure within the specified number of seconds. 0 - wait unlimited time. */ \ M(SettingUInt64, replication_alter_columns_timeout, 60) \ \ M(SettingLoadBalancing, load_balancing, LoadBalancing::RANDOM) \ @@ -92,78 +92,78 @@ struct Settings M(SettingTotalsMode, totals_mode, TotalsMode::AFTER_HAVING_EXCLUSIVE) \ M(SettingFloat, totals_auto_threshold, 0.5) \ \ - /** Включена ли компиляция запросов. */ \ + /** Whether query compilation is enabled. */ \ M(SettingBool, compile, false) \ - /** Количество одинаковых по структуре запросов перед тем, как инициируется их компиляция. */ \ + /** The number of structurally identical queries before they are compiled. */ \ M(SettingUInt64, min_count_to_compile, 3) \ - /** При каком количестве ключей, начинает использоваться двухуровневая агрегация. 0 - порог не выставлен. */ \ + /** From what number of keys, a two-level aggregation starts. 0 - the threshold is not set. */ \ M(SettingUInt64, group_by_two_level_threshold, 100000) \ - /** При каком размере состояния агрегации в байтах, начинает использоваться двухуровневая агрегация. 0 - порог не выставлен. \ - * Двухуровневая агрегация начинает использоваться при срабатывании хотя бы одного из порогов. */ \ + /** From what size of the aggregation state in bytes, a two-level aggregation begins to be used. 0 - the threshold is not set. \ + * Two-level aggregation is used when at least one of the thresholds is triggered. */ \ M(SettingUInt64, group_by_two_level_threshold_bytes, 100000000) \ - /** Включён ли экономный по памяти режим распределённой агрегации. */ \ + /** Is the memory-saving mode of distributed aggregation enabled. */ \ M(SettingBool, distributed_aggregation_memory_efficient, false) \ /** Number of threads to use for merge intermediate aggregation results in memory efficient mode. When bigger, then more memory is consumed. \ * 0 means - same as 'max_threads'. */ \ M(SettingUInt64, aggregation_memory_efficient_merge_threads, 0) \ \ - /** Максимальное количество используемых реплик каждого шарда при выполнении запроса */ \ + /** The maximum number of replicas of each shard used when executing the query */ \ M(SettingUInt64, max_parallel_replicas, 1) \ M(SettingUInt64, parallel_replicas_count, 0) \ M(SettingUInt64, parallel_replica_offset, 0) \ \ - /** Тихо пропускать недоступные шарды. */ \ + /** Silently skip unavailable shards. */ \ M(SettingBool, skip_unavailable_shards, false) \ \ - /** Не мерджить состояния агрегации с разных серверов при распределённой обработке запроса \ - * - на случай, когда доподлинно известно, что на разных шардах разные ключи. \ + /** Do not merge aggregation states from different servers for distributed query processing \ + * - in case it is for certain that there are different keys on different shards. \ */ \ M(SettingBool, distributed_group_by_no_merge, false) \ \ - /** Тонкие настройки для чтения из MergeTree */ \ + /** Advanced settings for reading from MergeTree */ \ \ - /** Если из одного файла читается хотя бы столько строк, чтение можно распараллелить. */ \ + /** If at least as many lines are read from one file, the reading can be parallelized. */ \ M(SettingUInt64, merge_tree_min_rows_for_concurrent_read, (20 * 8192)) \ - /** Можно пропускать чтение более чем стольки строк ценой одного seek по файлу. */ \ + /** You can skip reading more than that number of rows at the price of one seek per file. */ \ M(SettingUInt64, merge_tree_min_rows_for_seek, 0) \ - /** Если отрезок индекса может содержать нужные ключи, делим его на столько частей и рекурсивно проверяем их. */ \ + /** If the index segment can contain the required keys, divide it into as many parts and recursively check them. */ \ M(SettingUInt64, merge_tree_coarse_index_granularity, 8) \ - /** Максимальное количество строк на запрос, для использования кэша разжатых данных. Если запрос большой - кэш не используется. \ - * (Чтобы большие запросы не вымывали кэш.) */ \ + /** The maximum number of rows per request, to use the cache of uncompressed data. If the request is large, the cache is not used. \ + * (For large queries not to flush out the cache.) */ \ M(SettingUInt64, merge_tree_max_rows_to_use_cache, (1024 * 1024)) \ \ - /** Распределять чтение из MergeTree по потокам равномерно, обеспечивая стабильное среднее время исполнения каждого потока в пределах одного чтения. */ \ + /** Distribute read from MergeTree over threads evenly, ensuring stable average execution time of each thread within one read operation. */ \ M(SettingBool, merge_tree_uniform_read_distribution, true) \ \ - /** Минимальная длина выражения expr = x1 OR ... expr = xN для оптимизации */ \ + /** The minimum length of the expression `expr = x1 OR ... expr = xN` for optimization */ \ M(SettingUInt64, optimize_min_equality_disjunction_chain_length, 3) \ \ - /** Минимальное количество байт для операций ввода/ввывода минуя кэш страниц. 0 - отключено. */ \ + /** The minimum number of bytes for input/output operations is bypassing the page cache. 0 - disabled. */ \ M(SettingUInt64, min_bytes_to_use_direct_io, 0) \ \ - /** Кидать исключение, если есть индекс, и он не используется. */ \ + /** Throw an exception if there is an index, and it is not used. */ \ M(SettingBool, force_index_by_date, 0) \ M(SettingBool, force_primary_key, 0) \ \ - /** В запросе INSERT с указанием столбцов, заполнять значения по-умолчанию только для столбцов с явными DEFAULT-ами. */ \ + /** In the INSERT query with specified columns, fill in the default values ​​only for columns with explicit DEFAULTs. */ \ M(SettingBool, strict_insert_defaults, 0) \ \ - /** В случае превышения максимального размера mark_cache, удалять только записи, старше чем mark_cache_min_lifetime секунд. */ \ + /** If the maximum size of mark_cache is exceeded, delete only records older than mark_cache_min_lifetime seconds. */ \ M(SettingUInt64, mark_cache_min_lifetime, 10000) \ \ - /** Позволяет использовать больше источников, чем количество потоков - для более равномерного распределения работы по потокам. \ - * Предполагается, что это временное решение, так как можно будет в будущем сделать количество источников равное количеству потоков, \ - * но чтобы каждый источник динамически выбирал себе доступную работу. \ + /** Allows you to use more sources than the number of threads - to more evenly distribute work across threads. \ + * It is assumed that this is a temporary solution, since it will be possible in the future to make the number of sources equal to the number of threads, \ + * but for each source to dynamically select available work for itself. \ */ \ M(SettingFloat, max_streams_to_max_threads_ratio, 1) \ \ - /** Позволяет выбирать метод сжатия данных при записи */\ + /** Allows you to select the method of data compression when writing */ \ M(SettingCompressionMethod, network_compression_method, CompressionMethod::LZ4) \ \ - /** Приоритет запроса. 1 - самый высокий, больше - ниже; 0 - не использовать приоритеты. */ \ + /** Priority of the query. 1 - the highest, higher value - lower priority; 0 - do not use priorities. */ \ M(SettingUInt64, priority, 0) \ \ - /** Логгировать запросы и писать лог в системную таблицу. */ \ + /** Log requests and write the log to the system table. */ \ M(SettingBool, log_queries, 0) \ \ /** If query length is greater than specified threshold (in bytes), then cut query when writing to query log. \ @@ -171,48 +171,48 @@ struct Settings */ \ M(SettingUInt64, log_queries_cut_to_length, 100000) \ \ - /** Как выполняются распределённые подзапросы внутри секций IN или JOIN? */ \ + /** How are distributed subqueries performed inside IN or JOIN sections? */ \ M(SettingDistributedProductMode, distributed_product_mode, DistributedProductMode::DENY) \ \ - /** Схема выполнения GLOBAL-подзапросов. */ \ + /** The scheme for executing GLOBAL subqueries. */ \ M(SettingGlobalSubqueriesMethod, global_subqueries_method, GlobalSubqueriesMethod::PUSH) \ \ - /** Максимальное количество одновременно выполняющихся запросов на одного user-а. */ \ + /** The maximum number of concurrent requests per user. */ \ M(SettingUInt64, max_concurrent_queries_for_user, 0) \ \ - /** Для запросов INSERT в реплицируемую таблицу, ждать записи на указанное число реплик и лианеризовать добавление данных. 0 - отключено. */ \ + /** For INSERT queries in the replicated table, wait writing for the specified number of replicas and linearize the addition of the data. 0 - disabled. */ \ M(SettingUInt64, insert_quorum, 0) \ M(SettingMilliseconds, insert_quorum_timeout, 600000) \ - /** Для запросов SELECT из реплицируемой таблицы, кидать исключение, если на реплике нет куска, записанного с кворумом; \ - * не читать куски, которые ещё не были записаны с кворумом. */ \ + /** For SELECT queries from the replicated table, throw an exception if the replica does not have a chunk written with the quorum; \ + * do not read the parts that have not yet been written with the quorum. */ \ M(SettingUInt64, select_sequential_consistency, 0) \ - /** Максимальное количество различных шардов и максимальное количество реплик одного шарда в функции remote. */ \ + /** The maximum number of different shards and the maximum number of replicas of one shard in the `remote` function. */ \ M(SettingUInt64, table_function_remote_max_addresses, 1000) \ - /** Маскимальное количество потоков при распределённой обработке одного запроса */ \ + /** Maximum number of threads for distributed processing of one query */ \ M(SettingUInt64, max_distributed_processing_threads, 8) \ \ - /** Настройки понижения числа потоков в случае медленных чтений. */ \ - /** Обращать внимания только на чтения, занявшие не меньше такого количества времени. */ \ + /** Settings to reduce the number of threads in case of slow reads. */ \ + /** Pay attention only to readings that took at least that much time. */ \ M(SettingMilliseconds, read_backoff_min_latency_ms, 1000) \ - /** Считать события, когда пропускная способность меньше стольки байт в секунду. */ \ + /** Count events when the bandwidth is less than that many bytes per second. */ \ M(SettingUInt64, read_backoff_max_throughput, 1048576) \ - /** Не обращать внимания на событие, если от предыдущего прошло меньше стольки-то времени. */ \ + /** Do not pay attention to the event, if the previous one has passed less than a certain amount of time. */ \ M(SettingMilliseconds, read_backoff_min_interval_between_events_ms, 1000) \ - /** Количество событий, после которого количество потоков будет уменьшено. */ \ + /** The number of events after which the number of threads will be reduced. */ \ M(SettingUInt64, read_backoff_min_events, 2) \ \ - /** В целях тестирования exception safety - кидать исключение при каждом выделении памяти с указанной вероятностью. */ \ + /** For testing of `exception safety` - throw an exception every time you allocate memory with the specified probability. */ \ M(SettingFloat, memory_tracker_fault_probability, 0.) \ \ - /** Сжимать результат, если клиент по HTTP сказал, что он понимает данные, сжатые методом gzip или deflate */ \ + /** Compress the result if the client over HTTP said that it understands data compressed by gzip or deflate */ \ M(SettingBool, enable_http_compression, 0) \ - /** Уровень сжатия - используется, если клиент по HTTP сказал, что он понимает данные, сжатые методом gzip или deflate */ \ + /** Compression level - used if the client on HTTP said that it understands data compressed by gzip or deflate */ \ M(SettingInt64, http_zlib_compression_level, 3) \ \ - /** При разжатии данных POST от клиента, сжатых родным форматом, не проверять чексуммы */ \ + /** If you uncompress the POST data from the client compressed by the native format, do not check the checksum */ \ M(SettingBool, http_native_compression_disable_checksumming_on_decompress, 0) \ \ - /** Таймаут в секундах */ \ + /** Timeout in seconds */ \ M(SettingUInt64, resharding_barrier_timeout, 300) \ \ /** What aggregate function to use for implementation of count(DISTINCT ...) */ \ @@ -301,7 +301,7 @@ struct Settings void set(const String & name, const String & value); /** Set multiple settings from "profile" (in server configuration file (users.xml), profiles contain groups of multiple settings). - * Профиль также может быть установлен с помощью функций set, как настройка profile. + * The profile can also be set using the `set` functions, like the profile setting. */ void setProfile(const String & profile_name, Poco::Util::AbstractConfiguration & config); From 6262fc86502b9ed48e4c5eb97ea2af9fb4e327a8 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Mon, 15 May 2017 02:14:21 +0300 Subject: [PATCH 69/76] Fix inccorect columns size in MergeTreeData after ALTER. [#CLICKHOUSE-2] --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 20 +++++++++++++------ dbms/src/Storages/MergeTree/MergeTreeData.h | 9 ++++++++- .../ReplicatedMergeTreeAlterThread.cpp | 5 +++++ dbms/src/Storages/StorageMergeTree.cpp | 4 ++++ .../Storages/StorageReplicatedMergeTree.cpp | 1 + 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 1662a0f208f..e438c23d8c5 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -446,7 +446,7 @@ void MergeTreeData::loadDataParts(bool skip_sanity_checks) } } - calculateColumnSizes(); + calculateColumnSizesImpl(); LOG_DEBUG(log, "Loaded data parts (" << data_parts.size() << " items)"); } @@ -1579,7 +1579,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeData::loadPartAndFixMetadata(const St } -void MergeTreeData::calculateColumnSizes() +void MergeTreeData::calculateColumnSizesImpl() { column_sizes.clear(); @@ -1592,7 +1592,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) const auto & files = part->checksums.files; /// TODO This method doesn't take into account columns with multiple files. - for (const auto & column : *columns) + for (const auto & column : getColumnsList()) { const auto escaped_name = escapeForFileName(column.name); const auto bin_file_name = escaped_name + ".bin"; @@ -1612,6 +1612,14 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) } } +inline void logSubtract(size_t & from, size_t value, Logger * log, const String & variable) +{ + if (value > from) + LOG_ERROR(log, "Possibly incorrect subtraction: " << from << " - " << value << " = " << from - value << ", variable " << variable); + + from -= value; +} + void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part) { const auto & files = part->checksums.files; @@ -1628,12 +1636,12 @@ void MergeTreeData::removePartContributionToColumnSizes(const DataPartPtr & part if (files.count(bin_file_name)) { const auto & bin_file_checksums = files.at(bin_file_name); - column_size.data_compressed -= bin_file_checksums.file_size; - column_size.data_uncompressed -= bin_file_checksums.uncompressed_size; + logSubtract(column_size.data_compressed, bin_file_checksums.file_size, log, bin_file_name + ".file_size"); + logSubtract(column_size.data_uncompressed, bin_file_checksums.uncompressed_size, log, bin_file_name + ".uncompressed_size"); } if (files.count(mrk_file_name)) - column_size.marks -= files.at(mrk_file_name).file_size; + logSubtract(column_size.marks, files.at(mrk_file_name).file_size, log, mrk_file_name + ".file_size"); } } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.h b/dbms/src/Storages/MergeTree/MergeTreeData.h index 78d48bdf7bd..a7f56476468 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.h +++ b/dbms/src/Storages/MergeTree/MergeTreeData.h @@ -446,9 +446,16 @@ public: for (const auto & col : column_sizes) total_size += col.second.getTotalCompressedSize(); + return total_size; } + void recalculateColumnSizes() + { + std::lock_guard lock{data_parts_mutex}; + calculateColumnSizesImpl(); + } + /// For ATTACH/DETACH/DROP/RESHARD PARTITION. static String getMonthName(const Field & partition); static String getMonthName(DayNum_t month); @@ -535,7 +542,7 @@ private: ExpressionActionsPtr & out_expression, NameToNameMap & out_rename_map, bool & out_force_update_metadata) const; /// Calculates column sizes in compressed form for the current state of data_parts. Call with data_parts mutex locked. - void calculateColumnSizes(); + void calculateColumnSizesImpl(); /// Adds or subtracts the contribution of the part to compressed column sizes. void addPartContributionToColumnSizes(const DataPartPtr & part); void removePartContributionToColumnSizes(const DataPartPtr & part); diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp index ec623d644eb..f69ccd3642f 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAlterThread.cpp @@ -199,6 +199,9 @@ void ReplicatedMergeTreeAlterThread::run() transaction->commit(); } + /// Columns sizes could be quietly changed in case of MODIFY/ADD COLUMN + storage.data.recalculateColumnSizes(); + /// The same for non-replicated data. if (storage.unreplicated_data) { @@ -216,6 +219,8 @@ void ReplicatedMergeTreeAlterThread::run() transaction->commit(); } + + storage.unreplicated_data->recalculateColumnSizes(); } /// List of columns for a specific replica. diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index 4bb34060a10..c2e8e3037df 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -131,6 +131,7 @@ BlockOutputStreamPtr StorageMergeTree::write(ASTPtr query, const Settings & sett bool StorageMergeTree::checkTableCanBeDropped() const { + const_cast(getData()).recalculateColumnSizes(); context.checkTableCanBeDropped(database_name, table_name, getData().getTotalCompressedSize()); return true; } @@ -243,6 +244,9 @@ void StorageMergeTree::alter( for (auto & transaction : transactions) transaction->commit(); + /// Columns sizes could be changed + data.recalculateColumnSizes(); + if (primary_key_is_modified) data.loadDataParts(false); } diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index d40e4bf529b..4a2bbc0801e 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -2954,6 +2954,7 @@ void StorageReplicatedMergeTree::attachPartition(ASTPtr query, const Field & fie bool StorageReplicatedMergeTree::checkTableCanBeDropped() const { /// Consider only synchronized data + const_cast(getData()).recalculateColumnSizes(); context.checkTableCanBeDropped(database_name, table_name, getData().getTotalCompressedSize()); return true; } From e7b7f6f73dac5eab3ca2a620ce6b3e909f5c9ee9 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 15 May 2017 09:34:26 +0300 Subject: [PATCH 70/76] Update MergeTreeData.cpp --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index e438c23d8c5..55a7d56e7b5 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1612,7 +1612,7 @@ void MergeTreeData::addPartContributionToColumnSizes(const DataPartPtr & part) } } -inline void logSubtract(size_t & from, size_t value, Logger * log, const String & variable) +static inline void logSubtract(size_t & from, size_t value, Logger * log, const String & variable) { if (value > from) LOG_ERROR(log, "Possibly incorrect subtraction: " << from << " - " << value << " = " << from - value << ", variable " << variable); From 95202343650278e7709da18c4c57dc8c007ab14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavrus=CC=8Ca?= Date: Fri, 12 May 2017 14:23:12 -0700 Subject: [PATCH 71/76] Dictionaries/TrieDictionary: IP prefix dictionary This commit implements a basic IP prefix dictionary that allows storing IPv4/IPv6 prefixes and matching them against a single IP address on query time. This allows for doing IP -> ASN matching and other similar things on query time. The implementation is basic for start, using a simple bitwise trie and reusing interface for complex key dictionaries (so using tuple instead of UInt32/FixedString(16) as the key). A faster bitwise trie implementation (like poptrie) is desired to improve lookup performance and memory consumption with large prefix tables. --- contrib/CMakeLists.txt | 1 + contrib/libbtrie/CMakeLists.txt | 6 + contrib/libbtrie/LICENSE | 23 + contrib/libbtrie/include/btrie.h | 155 +++++ contrib/libbtrie/src/btrie.c | 460 +++++++++++++++ contrib/libbtrie/test/test_btrie.c | 94 +++ dbms/CMakeLists.txt | 3 + dbms/src/Dictionaries/TrieDictionary.cpp | 545 ++++++++++++++++++ dbms/src/Dictionaries/TrieDictionary.h | 216 +++++++ .../Functions/FunctionsExternalDictionaries.h | 12 +- dbms/src/Interpreters/DictionaryFactory.cpp | 10 + docs/en/dicts/external_dicts.rst | 57 +- 12 files changed, 1578 insertions(+), 4 deletions(-) create mode 100644 contrib/libbtrie/CMakeLists.txt create mode 100644 contrib/libbtrie/LICENSE create mode 100644 contrib/libbtrie/include/btrie.h create mode 100644 contrib/libbtrie/src/btrie.c create mode 100644 contrib/libbtrie/test/test_btrie.c create mode 100644 dbms/src/Dictionaries/TrieDictionary.cpp create mode 100644 dbms/src/Dictionaries/TrieDictionary.h diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 0aba2218671..d5ed783e2cc 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -31,6 +31,7 @@ endif () add_subdirectory (libcityhash) add_subdirectory (libfarmhash) add_subdirectory (libmetrohash) +add_subdirectory (libbtrie) if (USE_INTERNAL_ZLIB_LIBRARY) add_subdirectory (libzlib-ng) diff --git a/contrib/libbtrie/CMakeLists.txt b/contrib/libbtrie/CMakeLists.txt new file mode 100644 index 00000000000..8d91eb1c316 --- /dev/null +++ b/contrib/libbtrie/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories (BEFORE include) + +add_library (btrie + src/btrie.c + include/btrie.h +) diff --git a/contrib/libbtrie/LICENSE b/contrib/libbtrie/LICENSE new file mode 100644 index 00000000000..d386c6f7b79 --- /dev/null +++ b/contrib/libbtrie/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2013, CobbLiu +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/libbtrie/include/btrie.h b/contrib/libbtrie/include/btrie.h new file mode 100644 index 00000000000..e395ddb09fe --- /dev/null +++ b/contrib/libbtrie/include/btrie.h @@ -0,0 +1,155 @@ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +#include +#include + +/** + * In btrie, each leaf means one bit in ip tree. + * Left means 0, and right means 1. + */ + +#define BTRIE_NULL (uintptr_t) -1 +#define MAX_PAGES 1024 * 16 + +typedef struct btrie_node_s btrie_node_t; + +struct btrie_node_s { + btrie_node_t *right; + btrie_node_t *left; + btrie_node_t *parent; + uintptr_t value; +}; + + +typedef struct btrie_s { + btrie_node_t *root; + + btrie_node_t *free; /* free list of btrie */ + char *start; + size_t size; + + /* + * memory pool. + * memory management(esp free) will be so easy by using this facility. + */ + char *pools[MAX_PAGES]; + size_t len; +} btrie_t; + + +/** + * Create an empty btrie + * + * @Return: + * An ip radix_tree created. + * NULL if creation failed. + */ + +btrie_t *btrie_create(); + +/** + * Destroy the ip radix_tree + * + * @Return: + * OK if deletion succeed. + * ERROR if error occurs while deleting. + */ +int btrie_destroy(btrie_t *tree); + +/** + * Count the nodes in the radix tree. + */ +size_t btrie_count(btrie_t *tree); + +/** + * Return the allocated number of bytes. + */ +size_t btrie_allocated(btrie_t *tree); + + +/** + * Add an ipv4 into btrie + * + * @Args: + * key: ip address + * mask: key's mask + * value: value of this IP, may be NULL. + * + * @Return: + * OK for success. + * ERROR for failure. + */ +int btrie_insert(btrie_t *tree, uint32_t key, uint32_t mask, + uintptr_t value); + + +/** + * Delete an ipv4 from btrie + * + * @Args: + * + * @Return: + * OK for success. + * ERROR for failure. + */ +int btrie_delete(btrie_t *tree, uint32_t key, uint32_t mask); + + +/** + * Find an ipv4 from btrie + * + + * @Args: + * + * @Return: + * Value if succeed. + * NULL if failed. + */ +uintptr_t btrie_find(btrie_t *tree, uint32_t key); + + +/** + * Add an ipv6 into btrie + * + * @Args: + * key: ip address + * mask: key's mask + * value: value of this IP, may be NULL. + * + * @Return: + * OK for success. + * ERROR for failure. + */ +int btrie_insert_a6(btrie_t *tree, const uint8_t *key, const uint8_t *mask, + uintptr_t value); + +/** + * Delete an ipv6 from btrie + * + * @Args: + * + * @Return: + * OK for success. + * ERROR for failure. + */ +int btrie_delete_a6(btrie_t *tree, const uint8_t *key, const uint8_t *mask); + +/** + * Find an ipv6 from btrie + * + + * @Args: + * + * @Return: + * Value if succeed. + * NULL if failed. + */ +uintptr_t btrie_find_a6(btrie_t *tree, const uint8_t *key); + +#if defined (__cplusplus) +} +#endif \ No newline at end of file diff --git a/contrib/libbtrie/src/btrie.c b/contrib/libbtrie/src/btrie.c new file mode 100644 index 00000000000..e959d3f1786 --- /dev/null +++ b/contrib/libbtrie/src/btrie.c @@ -0,0 +1,460 @@ +#include +#include +#include + +#define PAGE_SIZE 4096 + + +static btrie_node_t * +btrie_alloc(btrie_t *tree) +{ + btrie_node_t *p; + + if (tree->free) { + p = tree->free; + tree->free = tree->free->right; + return p; + } + + if (tree->size < sizeof(btrie_node_t)) { + tree->start = (char *) calloc(sizeof(char), PAGE_SIZE); + if (tree->start == NULL) { + return NULL; + } + + tree->pools[tree->len++] = tree->start; + tree->size = PAGE_SIZE; + } + + p = (btrie_node_t *) tree->start; + + tree->start += sizeof(btrie_node_t); + tree->size -= sizeof(btrie_node_t); + + return p; +} + + +btrie_t * +btrie_create() +{ + btrie_t *tree = (btrie_t *) malloc(sizeof(btrie_t)); + if (tree == NULL) { + return NULL; + } + + tree->free = NULL; + tree->start = NULL; + tree->size = 0; + memset(tree->pools, 0, sizeof(btrie_t *) * MAX_PAGES); + tree->len = 0; + + tree->root = btrie_alloc(tree); + if (tree->root == NULL) { + return NULL; + } + + tree->root->right = NULL; + tree->root->left = NULL; + tree->root->parent = NULL; + tree->root->value = BTRIE_NULL; + + return tree; +} + +static size_t +subtree_weight(btrie_node_t *node) +{ + size_t weight = 1; + if (node->left) { + weight += subtree_weight(node->left); + } + if (node->right) { + weight += subtree_weight(node->right); + } + return weight; +} + +size_t +btrie_count(btrie_t *tree) +{ + if (tree->root == NULL) { + return 0; + } + + return subtree_weight(tree->root); +} + +size_t +btrie_allocated(btrie_t *tree) +{ + return tree->len * PAGE_SIZE; +} + + +int +btrie_insert(btrie_t *tree, uint32_t key, uint32_t mask, + uintptr_t value) +{ + uint32_t bit; + btrie_node_t *node, *next; + + bit = 0x80000000; + + node = tree->root; + next = tree->root; + + while (bit & mask) { + if (key & bit) { + next = node->right; + + } else { + next = node->left; + } + + if (next == NULL) { + break; + } + + bit >>= 1; + node = next; + } + + if (next) { + if (node->value != BTRIE_NULL) { + return -1; + } + + node->value = value; + return 0; + } + + while (bit & mask) { + next = btrie_alloc(tree); + if (next == NULL) { + return -1; + } + + next->right = NULL; + next->left = NULL; + next->parent = node; + next->value = BTRIE_NULL; + + if (key & bit) { + node->right = next; + + } else { + node->left = next; + } + + bit >>= 1; + node = next; + } + + node->value = value; + + return 0; +} + + +int +btrie_delete(btrie_t *tree, uint32_t key, uint32_t mask) +{ + uint32_t bit; + btrie_node_t *node; + + bit = 0x80000000; + node = tree->root; + + while (node && (bit & mask)) { + if (key & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + } + + if (node == NULL) { + return -1; + } + + if (node->right || node->left) { + if (node->value != BTRIE_NULL) { + node->value = BTRIE_NULL; + return 0; + } + + return -1; + } + + for ( ;; ) { + if (node->parent->right == node) { + node->parent->right = NULL; + + } else { + node->parent->left = NULL; + } + + node->right = tree->free; + tree->free = node; + + node = node->parent; + + if (node->right || node->left) { + break; + } + + if (node->value != BTRIE_NULL) { + break; + } + + if (node->parent == NULL) { + break; + } + } + + return 0; +} + + +uintptr_t +btrie_find(btrie_t *tree, uint32_t key) +{ + uint32_t bit; + uintptr_t value; + btrie_node_t *node; + + bit = 0x80000000; + value = BTRIE_NULL; + node = tree->root; + + while (node) { + if (node->value != BTRIE_NULL) { + value = node->value; + } + + if (key & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + } + + return value; +} + + +int +btrie_insert_a6(btrie_t *tree, const uint8_t *key, const uint8_t *mask, + uintptr_t value) +{ + uint8_t bit; + uint i; + btrie_node_t *node, *next; + + i = 0; + bit = 0x80; + + node = tree->root; + next = tree->root; + + while (bit & mask[i]) { + if (key[i] & bit) { + next = node->right; + + } else { + next = node->left; + } + + if (next == NULL) { + break; + } + + bit >>= 1; + node = next; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + if (next) { + if (node->value != BTRIE_NULL) { + return -1; + } + + node->value = value; + return 0; + } + + while (bit & mask[i]) { + next = btrie_alloc(tree); + if (next == NULL) { + return -1; + } + + next->right = NULL; + next->left = NULL; + next->parent = node; + next->value = BTRIE_NULL; + + if (key[i] & bit) { + node->right = next; + + } else { + node->left = next; + } + + bit >>= 1; + node = next; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + node->value = value; + + return 0; +} + + +int +btrie_delete_a6(btrie_t *tree, const uint8_t *key, const uint8_t *mask) +{ + uint8_t bit; + uint i; + btrie_node_t *node; + + i = 0; + bit = 0x80; + node = tree->root; + + while (node && (bit & mask[i])) { + if (key[i] & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + if (node == NULL) { + return -1; + } + + if (node->right || node->left) { + if (node->value != BTRIE_NULL) { + node->value = BTRIE_NULL; + return 0; + } + + return -1; + } + + for ( ;; ) { + if (node->parent->right == node) { + node->parent->right = NULL; + + } else { + node->parent->left = NULL; + } + + node->right = tree->free; + tree->free = node; + + node = node->parent; + + if (node->right || node->left) { + break; + } + + if (node->value != BTRIE_NULL) { + break; + } + + if (node->parent == NULL) { + break; + } + } + + return 0; +} + + +uintptr_t +btrie_find_a6(btrie_t *tree, const uint8_t *key) +{ + uint8_t bit; + uintptr_t value; + uint i; + btrie_node_t *node; + + i = 0; + bit = 0x80; + value = BTRIE_NULL; + node = tree->root; + + while (node) { + if (node->value != BTRIE_NULL) { + value = node->value; + } + + if (key[i] & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + + if (bit == 0) { + i++; + bit = 0x80; + } + } + + return value; +} + + +int +btrie_destroy(btrie_t *tree) +{ + size_t i; + + + /* free memory pools */ + for (i = 0; i < tree->len; i++) { + free(tree->pools[i]); + } + + free(tree); + + return 0; +} diff --git a/contrib/libbtrie/test/test_btrie.c b/contrib/libbtrie/test/test_btrie.c new file mode 100644 index 00000000000..a2daca2d6d5 --- /dev/null +++ b/contrib/libbtrie/test/test_btrie.c @@ -0,0 +1,94 @@ +#include +#include + +int main() +{ + btrie_t *it; + int ret; + + uint8_t prefix_v6[16] = {0xde, 0xad, 0xbe, 0xef}; + uint8_t mask_v6[16] = {0xff, 0xff, 0xff}; + uint8_t ip_v6[16] = {0xde, 0xad, 0xbe, 0xef, 0xde}; + + it = btrie_create(); + if (it == NULL) { + printf("create error!\n"); + return 0; + } + + //add 101.45.69.50/16 + ret = btrie_insert(it, 1697465650, 0xffff0000, 1); + if (ret != 0) { + printf("insert 1 error.\n"); + goto error; + } + + //add 10.45.69.50/16 + ret = btrie_insert(it, 170738994, 0xffff0000, 1); + if (ret != 0) { + printf("insert 2 error.\n"); + goto error; + } + + //add 10.45.79.50/16 + ret = btrie_insert(it, 170741554, 0xffff0000, 1); + if (ret == 0) { + printf("insert 3 error.\n"); + goto error; + } + + //add 102.45.79.50/24 + ret = btrie_insert(it, 1714245426, 0xffffff00, 1); + if (ret != 0) { + printf("insert 4 error.\n"); + goto error; + } + + ret = btrie_find(it, 170741554); + if (ret == 1) { + printf("test case 1 passed\n"); + } else { + printf("test case 1 error\n"); + } + + ret = btrie_find(it, 170786817); + if (ret != 1) { + printf("test case 2 passed\n"); + } else { + printf("test case 2 error\n"); + } + + ret = btrie_delete(it, 1714245426, 0xffffff00); + if (ret != 0) { + printf("delete 1 error\n"); + goto error; + } + + ret = btrie_find(it, 1714245426); + if (ret != 1) { + printf("test case 3 passed\n"); + } else { + printf("test case 3 error\n"); + } + + //add dead:beef::/32 + ret = btrie_insert_a6(it, prefix_v6, mask_v6, 1); + if (ret != 0) { + printf("insert 5 error\n"); + goto error; + } + + ret = btrie_find_a6(it, ip_v6); + if (ret == 1) { + printf("test case 4 passed\n"); + } else { + printf("test case 4 error\n"); + } + + return 0; + + error: + btrie_destroy(it); + printf("test failed\n"); + return 1; +} diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index 28c0753a157..5f93dc281b0 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -21,6 +21,7 @@ include_directories (BEFORE ${ClickHouse_SOURCE_DIR}/contrib/libdivide) include_directories (BEFORE ${ClickHouse_SOURCE_DIR}/contrib/libcpuid/include) include_directories (BEFORE ${ClickHouse_SOURCE_DIR}/contrib/libfarmhash) include_directories (BEFORE ${ClickHouse_SOURCE_DIR}/contrib/libmetrohash/src) +include_directories (BEFORE ${ClickHouse_SOURCE_DIR}/contrib/libbtrie/include) include_directories (${ClickHouse_SOURCE_DIR}/libs/libdaemon/include) include_directories (${ClickHouse_BINARY_DIR}/dbms/src) @@ -153,6 +154,7 @@ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") src/Dictionaries/FlatDictionary.cpp src/Dictionaries/HashedDictionary.cpp src/Dictionaries/CacheDictionary.cpp + src/Dictionaries/TrieDictionary.cpp src/Dictionaries/RangeHashedDictionary.cpp src/Dictionaries/ComplexKeyHashedDictionary.cpp src/Dictionaries/ComplexKeyCacheDictionary.cpp @@ -185,6 +187,7 @@ target_link_libraries (dbms ${OPENSSL_CRYPTO_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Poco_Data_LIBRARY} + btrie ) if (Poco_DataODBC_FOUND) diff --git a/dbms/src/Dictionaries/TrieDictionary.cpp b/dbms/src/Dictionaries/TrieDictionary.cpp new file mode 100644 index 00000000000..3e2ed7b4e8f --- /dev/null +++ b/dbms/src/Dictionaries/TrieDictionary.cpp @@ -0,0 +1,545 @@ +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int TYPE_MISMATCH; + extern const int ARGUMENT_OUT_OF_BOUND; + extern const int BAD_ARGUMENTS; + extern const int DICTIONARY_IS_EMPTY; +} + +TrieDictionary::TrieDictionary( + const std::string & name, const DictionaryStructure & dict_struct, DictionarySourcePtr source_ptr, + const DictionaryLifetime dict_lifetime, bool require_nonempty) + : name{name}, dict_struct(dict_struct), source_ptr{std::move(source_ptr)}, dict_lifetime(dict_lifetime), + require_nonempty(require_nonempty) +{ + createAttributes(); + trie = btrie_create(); + + try + { + loadData(); + calculateBytesAllocated(); + } + catch (...) + { + creation_exception = std::current_exception(); + } + + creation_time = std::chrono::system_clock::now(); +} + +TrieDictionary::TrieDictionary(const TrieDictionary & other) + : TrieDictionary{other.name, other.dict_struct, other.source_ptr->clone(), other.dict_lifetime, other.require_nonempty} +{ + trie = btrie_create(); +} + +TrieDictionary::~TrieDictionary() +{ + btrie_destroy(trie); +} + +#define DECLARE(TYPE)\ +void TrieDictionary::get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + PaddedPODArray & out) const\ +{\ + validateKeyTypes(key_types);\ + \ + const auto & attribute = getAttribute(attribute_name);\ + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::TYPE))\ + throw Exception{\ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type),\ + ErrorCodes::TYPE_MISMATCH};\ + \ + const auto null_value = std::get(attribute.null_values);\ + \ + getItemsNumber(attribute, key_columns,\ + [&] (const std::size_t row, const auto value) { out[row] = value; },\ + [&] (const std::size_t) { return null_value; });\ +} +DECLARE(UInt8) +DECLARE(UInt16) +DECLARE(UInt32) +DECLARE(UInt64) +DECLARE(Int8) +DECLARE(Int16) +DECLARE(Int32) +DECLARE(Int64) +DECLARE(Float32) +DECLARE(Float64) +#undef DECLARE + +void TrieDictionary::getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + ColumnString * out) const +{ + validateKeyTypes(key_types); + + const auto & attribute = getAttribute(attribute_name); + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::String)) + throw Exception{ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type), + ErrorCodes::TYPE_MISMATCH}; + + const auto & null_value = StringRef{std::get(attribute.null_values)}; + + getItemsImpl(attribute, key_columns, + [&] (const std::size_t row, const StringRef value) { out->insertData(value.data, value.size); }, + [&] (const std::size_t) { return null_value; }); +} + +#define DECLARE(TYPE)\ +void TrieDictionary::get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + const PaddedPODArray & def, PaddedPODArray & out) const\ +{\ + validateKeyTypes(key_types);\ + \ + const auto & attribute = getAttribute(attribute_name);\ + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::TYPE))\ + throw Exception{\ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type),\ + ErrorCodes::TYPE_MISMATCH};\ + \ + getItemsNumber(attribute, key_columns,\ + [&] (const std::size_t row, const auto value) { out[row] = value; },\ + [&] (const std::size_t row) { return def[row]; });\ +} +DECLARE(UInt8) +DECLARE(UInt16) +DECLARE(UInt32) +DECLARE(UInt64) +DECLARE(Int8) +DECLARE(Int16) +DECLARE(Int32) +DECLARE(Int64) +DECLARE(Float32) +DECLARE(Float64) +#undef DECLARE + +void TrieDictionary::getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + const ColumnString * const def, ColumnString * const out) const +{ + validateKeyTypes(key_types); + + const auto & attribute = getAttribute(attribute_name); + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::String)) + throw Exception{ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type), + ErrorCodes::TYPE_MISMATCH}; + + getItemsImpl(attribute, key_columns, + [&] (const std::size_t row, const StringRef value) { out->insertData(value.data, value.size); }, + [&] (const std::size_t row) { return def->getDataAt(row); }); +} + +#define DECLARE(TYPE)\ +void TrieDictionary::get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + const TYPE def, PaddedPODArray & out) const\ +{\ + validateKeyTypes(key_types);\ + \ + const auto & attribute = getAttribute(attribute_name);\ + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::TYPE))\ + throw Exception{\ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type),\ + ErrorCodes::TYPE_MISMATCH};\ + \ + getItemsNumber(attribute, key_columns,\ + [&] (const std::size_t row, const auto value) { out[row] = value; },\ + [&] (const std::size_t) { return def; });\ +} +DECLARE(UInt8) +DECLARE(UInt16) +DECLARE(UInt32) +DECLARE(UInt64) +DECLARE(Int8) +DECLARE(Int16) +DECLARE(Int32) +DECLARE(Int64) +DECLARE(Float32) +DECLARE(Float64) +#undef DECLARE + +void TrieDictionary::getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + const String & def, ColumnString * const out) const +{ + validateKeyTypes(key_types); + + const auto & attribute = getAttribute(attribute_name); + if (!isAttributeTypeConvertibleTo(attribute.type, AttributeUnderlyingType::String)) + throw Exception{ + name + ": type mismatch: attribute " + attribute_name + " has type " + toString(attribute.type), + ErrorCodes::TYPE_MISMATCH}; + + getItemsImpl(attribute, key_columns, + [&] (const std::size_t row, const StringRef value) { out->insertData(value.data, value.size); }, + [&] (const std::size_t) { return StringRef{def}; }); +} + +void TrieDictionary::has(const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, PaddedPODArray & out) const +{ + validateKeyTypes(key_types); + + const auto & attribute = attributes.front(); + + switch (attribute.type) + { + case AttributeUnderlyingType::UInt8: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::UInt16: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::UInt32: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::UInt64: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Int8: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Int16: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Int32: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Int64: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Float32: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::Float64: has(attribute, key_columns, out); break; + case AttributeUnderlyingType::String: has(attribute, key_columns, out); break; + } +} + +void TrieDictionary::createAttributes() +{ + const auto size = dict_struct.attributes.size(); + attributes.reserve(size); + + for (const auto & attribute : dict_struct.attributes) + { + attribute_index_by_name.emplace(attribute.name, attributes.size()); + attributes.push_back(createAttributeWithType(attribute.underlying_type, attribute.null_value)); + + if (attribute.hierarchical) + throw Exception{ + name + ": hierarchical attributes not supported for dictionary of type " + getTypeName(), + ErrorCodes::TYPE_MISMATCH}; + } +} + +void TrieDictionary::loadData() +{ + auto stream = source_ptr->loadAll(); + stream->readPrefix(); + + /// created upfront to avoid excess allocations + const auto keys_size = dict_struct.key.value().size(); + StringRefs keys(keys_size); + + const auto attributes_size = attributes.size(); + + while (const auto block = stream->read()) + { + const auto rows = block.rows(); + element_count += rows; + + const auto key_column_ptrs = ext::map(ext::range(0, keys_size), + [&] (const std::size_t attribute_idx) { + return block.safeGetByPosition(attribute_idx).column.get(); + }); + + const auto attribute_column_ptrs = ext::map(ext::range(0, attributes_size), + [&] (const std::size_t attribute_idx) { + return block.safeGetByPosition(keys_size + attribute_idx).column.get(); + }); + + for (const auto row_idx : ext::range(0, rows)) + { + /// calculate key once per row + const auto key_column = key_column_ptrs.front(); + + for (const auto attribute_idx : ext::range(0, attributes_size)) + { + const auto & attribute_column = *attribute_column_ptrs[attribute_idx]; + auto & attribute = attributes[attribute_idx]; + setAttributeValue(attribute, key_column->getDataAt(row_idx), attribute_column[row_idx]); + } + } + + } + + stream->readSuffix(); + + if (require_nonempty && 0 == element_count) + throw Exception{ + name + ": dictionary source is empty and 'require_nonempty' property is set.", + ErrorCodes::DICTIONARY_IS_EMPTY}; +} + +template +void TrieDictionary::addAttributeSize(const Attribute & attribute) +{ + const auto & vec = *std::get>(attribute.maps); + bytes_allocated += sizeof(ContainerType) + (vec.capacity() * sizeof(T)); + bucket_count = vec.size(); +} + +void TrieDictionary::calculateBytesAllocated() +{ + bytes_allocated += attributes.size() * sizeof(attributes.front()); + + for (const auto & attribute : attributes) + { + switch (attribute.type) + { + case AttributeUnderlyingType::UInt8: addAttributeSize(attribute); break; + case AttributeUnderlyingType::UInt16: addAttributeSize(attribute); break; + case AttributeUnderlyingType::UInt32: addAttributeSize(attribute); break; + case AttributeUnderlyingType::UInt64: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Int8: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Int16: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Int32: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Int64: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Float32: addAttributeSize(attribute); break; + case AttributeUnderlyingType::Float64: addAttributeSize(attribute); break; + case AttributeUnderlyingType::String: + { + addAttributeSize(attribute); + bytes_allocated += sizeof(Arena) + attribute.string_arena->size(); + + break; + } + } + } + + bytes_allocated += btrie_allocated(trie); +} + +void TrieDictionary::validateKeyTypes(const DataTypes & key_types) const +{ + if (key_types.size() != 1) + throw Exception{ + "Expected a single IP address", + ErrorCodes::TYPE_MISMATCH}; + + const auto & actual_type = key_types[0]->getName(); + + if (actual_type != "UInt32" && actual_type != "FixedString(16)") + throw Exception{ + "Key does not match, expected either UInt32 or FixedString(16)", + ErrorCodes::TYPE_MISMATCH}; +} + + +template +void TrieDictionary::createAttributeImpl(Attribute & attribute, const Field & null_value) +{ + std::get(attribute.null_values) = null_value.get::Type>(); + std::get>(attribute.maps) = std::make_unique>(); +} + +TrieDictionary::Attribute TrieDictionary::createAttributeWithType(const AttributeUnderlyingType type, const Field & null_value) +{ + Attribute attr{type}; + + switch (type) + { + case AttributeUnderlyingType::UInt8: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::UInt16: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::UInt32: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::UInt64: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Int8: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Int16: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Int32: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Int64: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Float32: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::Float64: createAttributeImpl(attr, null_value); break; + case AttributeUnderlyingType::String: + { + std::get(attr.null_values) = null_value.get(); + std::get>(attr.maps) = std::make_unique>(); + attr.string_arena = std::make_unique(); + break; + } + } + + return attr; +} + + +template +void TrieDictionary::getItemsNumber( + const Attribute & attribute, + const ConstColumnPlainPtrs & key_columns, + ValueSetter && set_value, + DefaultGetter && get_default) const +{ + if (false) {} +#define DISPATCH(TYPE) \ + else if (attribute.type == AttributeUnderlyingType::TYPE) \ + getItemsImpl(attribute, key_columns, std::forward(set_value), std::forward(get_default)); + DISPATCH(UInt8) + DISPATCH(UInt16) + DISPATCH(UInt32) + DISPATCH(UInt64) + DISPATCH(Int8) + DISPATCH(Int16) + DISPATCH(Int32) + DISPATCH(Int64) + DISPATCH(Float32) + DISPATCH(Float64) +#undef DISPATCH + else + throw Exception("Unexpected type of attribute: " + toString(attribute.type), ErrorCodes::LOGICAL_ERROR); +} + +template +void TrieDictionary::getItemsImpl( + const Attribute & attribute, + const ConstColumnPlainPtrs & key_columns, + ValueSetter && set_value, + DefaultGetter && get_default) const +{ + auto & vec = *std::get>(attribute.maps); + + const auto first_column = key_columns.front(); + const auto rows = first_column->size(); + if (first_column->isNumeric()) + { + for (const auto i : ext::range(0, rows)) + { + auto addr = Int32(first_column->get64(i)); + uintptr_t slot = btrie_find(trie, addr); + set_value(i, slot != BTRIE_NULL ? vec[slot] : get_default(i)); + } + } + else + { + for (const auto i : ext::range(0, rows)) + { + auto addr = first_column->getDataAt(i); + if (addr.size != 16) + throw Exception("Expected key to be FixedString(16)", ErrorCodes::LOGICAL_ERROR); + + uintptr_t slot = btrie_find_a6(trie, reinterpret_cast(addr.data)); + set_value(i, slot != BTRIE_NULL ? vec[slot] : get_default(i)); + } + } + + query_count.fetch_add(rows, std::memory_order_relaxed); +} + + +template +bool TrieDictionary::setAttributeValueImpl(Attribute & attribute, const StringRef key, const T value) +{ + // Insert value into appropriate vector type + auto & vec = *std::get>(attribute.maps); + size_t row = vec.size(); + vec.push_back(value); + + // Parse IP address and subnet length from string (e.g. 2a02:6b8::3/64) + Poco::Net::IPAddress addr, mask; + std::string addr_str(key.toString()); + size_t pos = addr_str.find('/'); + if (pos != std::string::npos) + { + + addr = Poco::Net::IPAddress(addr_str.substr(0, pos)); + mask = Poco::Net::IPAddress(std::stoi(addr_str.substr(pos + 1), nullptr, 10), addr.family()); + } + else + { + addr = Poco::Net::IPAddress(addr_str); + mask = Poco::Net::IPAddress(addr.length() * 8, addr.family()); + } + + /* + * Here we might overwrite the same key with the same slot as each key can map to multiple attributes. + * However, all columns have equal number of rows so it is okay to store only row number for each key + * instead of building a trie for each column. This comes at the cost of additional lookup in attribute + * vector on lookup time to return cell from row + column. The reason for this is to save space, + * and build only single trie instead of trie for each column. + */ + if (addr.family() == Poco::Net::IPAddress::IPv4) + { + UInt32 addr_v4 = Poco::ByteOrder::toNetwork(*reinterpret_cast(addr.addr())); + UInt32 mask_v4 = Poco::ByteOrder::toNetwork(*reinterpret_cast(mask.addr())); + return btrie_insert(trie, addr_v4, mask_v4, row) == 0; + } + + const uint8_t* addr_v6 = reinterpret_cast(addr.addr()); + const uint8_t* mask_v6 = reinterpret_cast(mask.addr()); + return btrie_insert_a6(trie, addr_v6, mask_v6, row) == 0; +} + +bool TrieDictionary::setAttributeValue(Attribute & attribute, const StringRef key, const Field & value) +{ + switch (attribute.type) + { + case AttributeUnderlyingType::UInt8: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::UInt16: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::UInt32: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::UInt64: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Int8: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Int16: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Int32: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Int64: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Float32: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::Float64: return setAttributeValueImpl(attribute, key, value.get()); + case AttributeUnderlyingType::String: + { + const auto & string = value.get(); + const auto string_in_arena = attribute.string_arena->insert(string.data(), string.size()); + setAttributeValueImpl(attribute, key, StringRef{string_in_arena, string.size()}); + return true; + } + } + + return {}; +} + +const TrieDictionary::Attribute & TrieDictionary::getAttribute(const std::string & attribute_name) const +{ + const auto it = attribute_index_by_name.find(attribute_name); + if (it == std::end(attribute_index_by_name)) + throw Exception{ + name + ": no such attribute '" + attribute_name + "'", + ErrorCodes::BAD_ARGUMENTS}; + + return attributes[it->second]; +} + +template +void TrieDictionary::has(const Attribute & attribute, const ConstColumnPlainPtrs & key_columns, PaddedPODArray & out) const +{ + const auto first_column = key_columns.front(); + const auto rows = first_column->size(); + if (first_column->isNumeric()) + { + for (const auto i : ext::range(0, rows)) + { + auto addr = Int32(first_column->get64(i)); + uintptr_t slot = btrie_find(trie, addr); + out[i] = (slot != BTRIE_NULL); + } + } + else + { + for (const auto i : ext::range(0, rows)) + { + auto addr = first_column->getDataAt(i); + if (unlikely(addr.size != 16)) + throw Exception("Expected key to be FixedString(16)", ErrorCodes::LOGICAL_ERROR); + + uintptr_t slot = btrie_find_a6(trie, reinterpret_cast(addr.data)); + out[i] = (slot != BTRIE_NULL); + } + } + + query_count.fetch_add(rows, std::memory_order_relaxed);} + +} diff --git a/dbms/src/Dictionaries/TrieDictionary.h b/dbms/src/Dictionaries/TrieDictionary.h new file mode 100644 index 00000000000..09f745f012b --- /dev/null +++ b/dbms/src/Dictionaries/TrieDictionary.h @@ -0,0 +1,216 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace DB +{ + +class TrieDictionary final : public IDictionaryBase +{ +public: + TrieDictionary( + const std::string & name, const DictionaryStructure & dict_struct, DictionarySourcePtr source_ptr, + const DictionaryLifetime dict_lifetime, bool require_nonempty); + + TrieDictionary(const TrieDictionary & other); + + ~TrieDictionary(); + + std::string getKeyDescription() const { return key_description; }; + + std::exception_ptr getCreationException() const override { return creation_exception; } + + std::string getName() const override { return name; } + + std::string getTypeName() const override { return "Trie"; } + + std::size_t getBytesAllocated() const override { return bytes_allocated; } + + std::size_t getQueryCount() const override { return query_count.load(std::memory_order_relaxed); } + + double getHitRate() const override { return 1.0; } + + std::size_t getElementCount() const override { return element_count; } + + double getLoadFactor() const override { return static_cast(element_count) / bucket_count; } + + bool isCached() const override { return false; } + + DictionaryPtr clone() const override { return std::make_unique(*this); } + + const IDictionarySource * getSource() const override { return source_ptr.get(); } + + const DictionaryLifetime & getLifetime() const override { return dict_lifetime; } + + const DictionaryStructure & getStructure() const override { return dict_struct; } + + std::chrono::time_point getCreationTime() const override + { + return creation_time; + } + + bool isInjective(const std::string & attribute_name) const override + { + return dict_struct.attributes[&getAttribute(attribute_name) - attributes.data()].injective; + } + +#define DECLARE(TYPE)\ + void get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + PaddedPODArray & out) const; + DECLARE(UInt8) + DECLARE(UInt16) + DECLARE(UInt32) + DECLARE(UInt64) + DECLARE(Int8) + DECLARE(Int16) + DECLARE(Int32) + DECLARE(Int64) + DECLARE(Float32) + DECLARE(Float64) +#undef DECLARE + + void getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + ColumnString * out) const; + +#define DECLARE(TYPE)\ + void get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + const PaddedPODArray & def, PaddedPODArray & out) const; + DECLARE(UInt8) + DECLARE(UInt16) + DECLARE(UInt32) + DECLARE(UInt64) + DECLARE(Int8) + DECLARE(Int16) + DECLARE(Int32) + DECLARE(Int64) + DECLARE(Float32) + DECLARE(Float64) +#undef DECLARE + + void getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + const ColumnString * const def, ColumnString * const out) const; + +#define DECLARE(TYPE)\ + void get##TYPE(\ + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types,\ + const TYPE def, PaddedPODArray & out) const; + DECLARE(UInt8) + DECLARE(UInt16) + DECLARE(UInt32) + DECLARE(UInt64) + DECLARE(Int8) + DECLARE(Int16) + DECLARE(Int32) + DECLARE(Int64) + DECLARE(Float32) + DECLARE(Float64) +#undef DECLARE + + void getString( + const std::string & attribute_name, const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, + const String & def, ColumnString * const out) const; + + void has(const ConstColumnPlainPtrs & key_columns, const DataTypes & key_types, PaddedPODArray & out) const; + +private: + template using ContainerType = std::vector; + template using ContainerPtrType = std::unique_ptr>; + + struct Attribute final + { + AttributeUnderlyingType type; + std::tuple< + UInt8, UInt16, UInt32, UInt64, + Int8, Int16, Int32, Int64, + Float32, Float64, + String> null_values; + std::tuple< + ContainerPtrType, ContainerPtrType, ContainerPtrType, ContainerPtrType, + ContainerPtrType, ContainerPtrType, ContainerPtrType, ContainerPtrType, + ContainerPtrType, ContainerPtrType, + ContainerPtrType> maps; + std::unique_ptr string_arena; + }; + + void createAttributes(); + + void loadData(); + + template + void addAttributeSize(const Attribute & attribute); + + void calculateBytesAllocated(); + + void validateKeyTypes(const DataTypes & key_types) const; + + template + void createAttributeImpl(Attribute & attribute, const Field & null_value); + + Attribute createAttributeWithType(const AttributeUnderlyingType type, const Field & null_value); + + + template + void getItemsNumber( + const Attribute & attribute, + const ConstColumnPlainPtrs & key_columns, + ValueSetter && set_value, + DefaultGetter && get_default) const; + + template + void getItemsImpl( + const Attribute & attribute, + const ConstColumnPlainPtrs & key_columns, + ValueSetter && set_value, + DefaultGetter && get_default) const; + + + template + bool setAttributeValueImpl(Attribute & attribute, const StringRef key, const T value); + + bool setAttributeValue(Attribute & attribute, const StringRef key, const Field & value); + + const Attribute & getAttribute(const std::string & attribute_name) const; + + template + void has(const Attribute & attribute, const ConstColumnPlainPtrs & key_columns, PaddedPODArray & out) const; + + const std::string name; + const DictionaryStructure dict_struct; + const DictionarySourcePtr source_ptr; + const DictionaryLifetime dict_lifetime; + const bool require_nonempty; + const std::string key_description{dict_struct.getKeyDescription()}; + + + btrie_t *trie; + std::map attribute_index_by_name; + std::vector attributes; + + std::size_t bytes_allocated = 0; + std::size_t element_count = 0; + std::size_t bucket_count = 0; + mutable std::atomic query_count{0}; + + std::chrono::time_point creation_time; + + std::exception_ptr creation_exception; +}; + + +} diff --git a/dbms/src/Functions/FunctionsExternalDictionaries.h b/dbms/src/Functions/FunctionsExternalDictionaries.h index 06e829d51cb..817466fd75d 100644 --- a/dbms/src/Functions/FunctionsExternalDictionaries.h +++ b/dbms/src/Functions/FunctionsExternalDictionaries.h @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -102,7 +103,8 @@ private: !executeDispatchSimple(block, arguments, result, dict_ptr) && !executeDispatchSimple(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && - !executeDispatchComplex(block, arguments, result, dict_ptr)) + !executeDispatchComplex(block, arguments, result, dict_ptr) && + !executeDispatchComplex(block, arguments, result, dict_ptr)) throw Exception{ "Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; @@ -285,6 +287,7 @@ private: !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && + !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchRange(block, arguments, result, dict_ptr)) throw Exception{ "Unsupported dictionary type " + dict_ptr->getTypeName(), @@ -551,7 +554,8 @@ private: !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && - !executeDispatchComplex(block, arguments, result, dict_ptr)) + !executeDispatchComplex(block, arguments, result, dict_ptr) && + !executeDispatchComplex(block, arguments, result, dict_ptr)) throw Exception{ "Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; @@ -844,6 +848,7 @@ private: !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && + !executeDispatchComplex(block, arguments, result, dict_ptr) && !executeDispatchRange(block, arguments, result, dict_ptr)) throw Exception{ "Unsupported dictionary type " + dict_ptr->getTypeName(), @@ -1153,7 +1158,8 @@ private: !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) && !executeDispatchComplex(block, arguments, result, dict_ptr) && - !executeDispatchComplex(block, arguments, result, dict_ptr)) + !executeDispatchComplex(block, arguments, result, dict_ptr) && + !executeDispatchComplex(block, arguments, result, dict_ptr)) throw Exception{ "Unsupported dictionary type " + dict_ptr->getTypeName(), ErrorCodes::UNKNOWN_TYPE}; diff --git a/dbms/src/Interpreters/DictionaryFactory.cpp b/dbms/src/Interpreters/DictionaryFactory.cpp index 2d1f7d34bd9..a160c763971 100644 --- a/dbms/src/Interpreters/DictionaryFactory.cpp +++ b/dbms/src/Interpreters/DictionaryFactory.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,15 @@ DictionaryPtr DictionaryFactory::create(const std::string & name, Poco::Util::Ab return std::make_unique(name, dict_struct, std::move(source_ptr), dict_lifetime, size); } + else if ("ip_trie" == layout_type) + { + if (!dict_struct.key) + throw Exception{"'key' is required for dictionary of layout 'ip_trie'", + ErrorCodes::BAD_ARGUMENTS}; + + // This is specialised trie for storing IPv4 and IPv6 prefixes. + return std::make_unique(name, dict_struct, std::move(source_ptr), dict_lifetime, require_nonempty); + } else { if (dict_struct.key) diff --git a/docs/en/dicts/external_dicts.rst b/docs/en/dicts/external_dicts.rst index c2c871192a9..39b59501da7 100644 --- a/docs/en/dicts/external_dicts.rst +++ b/docs/en/dicts/external_dicts.rst @@ -101,7 +101,10 @@ The dictionary config file has the following format: 1000000000 - --> + + or + + --> @@ -243,6 +246,58 @@ Example of a dictionary by ranges: +ip_trie +------- +The table stores IP prefixes for each key (IP address), which makes it possible to map IP addresses to metadata such as ASN or threat score. + +Example: in the table there are prefixes matches to AS number and country: +:: + prefix asn cca2 + 202.79.32.0/20 17501 NP + 2620:0:870::/48 3856 US + 2a02:6b8:1::/48 13238 RU + 2001:db8::/32 65536 ZZ + + +When using such a layout, the structure should have the "key" element. + +Example: + +.. code-block:: xml + + + + + prefix + String + + + + asn + UInt32 + + + + cca2 + String + ?? + + ... + +These key must have only one attribute of type String, containing a valid IP prefix. Other types are not yet supported. + +For querying, same functions (dictGetT with tuple) as for complex key dictionaries have to be used: + +``dictGetT('dict_name', 'attr_name', tuple(ip))`` + +The function accepts either UInt32 for IPv4 address or FixedString(16) for IPv6 address in wire format: + +``dictGetString('prefix', 'asn', tuple(IPv6StringToNum('2001:db8::1')))`` + +No other type is supported. The function returns attribute for a prefix matching the given IP address. If there are overlapping prefixes, the most specific one is returned. + +The data is stored currently in a bitwise trie, it has to fit in memory. + complex_key_hashed ---------------- From c2651b4197906ec193268ddfb2bc37d4a60287ac Mon Sep 17 00:00:00 2001 From: Veniamin Gvozdikov Date: Mon, 15 May 2017 15:28:08 +0300 Subject: [PATCH 72/76] Fix missed dependency --- docker/server/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile index 599e944d0ff..531e727360d 100644 --- a/docker/server/Dockerfile +++ b/docker/server/Dockerfile @@ -4,7 +4,7 @@ ARG repository="deb https://repo.yandex.ru/clickhouse/xenial/ dists/stable/main/ ARG version=\* RUN apt-get update && \ - apt-get install -y apt-transport-https && \ + apt-get install -y apt-transport-https tzdata && \ mkdir -p /etc/apt/sources.list.d && \ echo $repository | tee /etc/apt/sources.list.d/clickhouse.list && \ apt-get update && \ From 496357a69185699b0fafc1d557d039633cf7a19a Mon Sep 17 00:00:00 2001 From: Veniamin Gvozdikov Date: Mon, 15 May 2017 15:44:43 +0300 Subject: [PATCH 73/76] Fix docker clickhouse client --- docker/client/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile index e28997ecef8..aab26246d29 100644 --- a/docker/client/Dockerfile +++ b/docker/client/Dockerfile @@ -4,7 +4,7 @@ ARG repository="deb https://repo.yandex.ru/clickhouse/xenial/ dists/stable/main/ ARG version=\* RUN apt-get update && \ - apt-get install -y apt-transport-https && \ + apt-get install -y apt-transport-https tzdata && \ mkdir -p /etc/apt/sources.list.d && \ echo $repository | tee /etc/apt/sources.list.d/clickhouse.list && \ apt-get update && \ From da830363266ddf8547cf557e88056591879ea2cc Mon Sep 17 00:00:00 2001 From: orantius Date: Mon, 15 May 2017 21:26:46 +0300 Subject: [PATCH 74/76] Add age 55 for function roundAge. [#CLICKHOUSE-3001] --- dbms/src/Functions/FunctionsRound.h | 5 +++-- docs/en/functions/rounding_functions.rst | 2 +- docs/ru/functions/rounding_functions.rst | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dbms/src/Functions/FunctionsRound.h b/dbms/src/Functions/FunctionsRound.h index 8051380ac87..6bb176d5ac9 100644 --- a/dbms/src/Functions/FunctionsRound.h +++ b/dbms/src/Functions/FunctionsRound.h @@ -18,7 +18,7 @@ namespace DB /** Функции округления: * roundToExp2 - вниз до ближайшей степени двойки; * roundDuration - вниз до ближайшего из: 0, 1, 10, 30, 60, 120, 180, 240, 300, 600, 1200, 1800, 3600, 7200, 18000, 36000; - * roundAge - вниз до ближайшего из: 0, 18, 25, 35, 45. + * roundAge - вниз до ближайшего из: 0, 18, 25, 35, 45, 55. * * round(x, N) - арифметическое округление (N = 0 по умолчанию). * ceil(x, N) - наименьшее число, которое не меньше x (N = 0 по умолчанию). @@ -101,7 +101,8 @@ struct RoundAgeImpl : (x < 25 ? 18 : (x < 35 ? 25 : (x < 45 ? 35 - : 45)))); + : (x < 55 ? 45 + : 55))))); } }; diff --git a/docs/en/functions/rounding_functions.rst b/docs/en/functions/rounding_functions.rst index b4be1e121e8..b17b40b357b 100644 --- a/docs/en/functions/rounding_functions.rst +++ b/docs/en/functions/rounding_functions.rst @@ -35,4 +35,4 @@ Accepts a number. If the number is less than one, it returns 0. Otherwise, it ro roundAge(num) ~~~~~~~ -Accepts a number. If the number is less than 18, it returns 0. Otherwise, it rounds the number down to numbers from the set: 18, 25, 35, 45. This function is specific to Yandex.Metrica and used for implementing the report on user age. +Accepts a number. If the number is less than 18, it returns 0. Otherwise, it rounds the number down to numbers from the set: 18, 25, 35, 45, 55. This function is specific to Yandex.Metrica and used for implementing the report on user age. diff --git a/docs/ru/functions/rounding_functions.rst b/docs/ru/functions/rounding_functions.rst index 3d421ab5af2..1503c5b07da 100644 --- a/docs/ru/functions/rounding_functions.rst +++ b/docs/ru/functions/rounding_functions.rst @@ -36,4 +36,4 @@ roundDuration(num) roundAge(num) ~~~~~~~~~~~~~ -Принимает число. Если число меньше 18 - возвращает 0. Иначе округляет число вниз до чисел из набора: 18, 25, 35, 45. Эта функция специфична для Яндекс.Метрики и предназначена для реализации отчёта по возрасту посетителей. +Принимает число. Если число меньше 18 - возвращает 0. Иначе округляет число вниз до чисел из набора: 18, 25, 35, 45, 55. Эта функция специфична для Яндекс.Метрики и предназначена для реализации отчёта по возрасту посетителей. From 82ee94a3bb26bdb1e016fc9d8d805afe410f78d1 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Tue, 16 May 2017 00:42:14 +0500 Subject: [PATCH 75/76] optimized logo.png using "optipng", use more elegant "apt-add-repository" repo management. --- website/index.html | 6 ++---- website/logo.png | Bin 1043 -> 377 bytes 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/website/index.html b/website/index.html index 3bd7111b220..43e5b452847 100644 --- a/website/index.html +++ b/website/index.html @@ -770,12 +770,10 @@
 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E0C56BD4    # optional
 
-sudo mkdir -p /etc/apt/sources.list.d
-echo "deb http://repo.yandex.ru/clickhouse/trusty stable main" |
-    sudo tee /etc/apt/sources.list.d/clickhouse.list
+sudo apt-add-repository "deb http://repo.yandex.ru/clickhouse/trusty stable main"
 sudo apt-get update
 
-sudo apt-get install clickhouse-server-common clickhouse-client
+sudo apt-get install clickhouse-server-common clickhouse-client -y
 
 sudo service clickhouse-server start
 clickhouse-client
diff --git a/website/logo.png b/website/logo.png
index 7056d35aef7d09592e4a47285295d00a4adab64c..552637796d655b238468957043f815ecf0b54424 100644
GIT binary patch
literal 377
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58CaNs)Vi3hp+Jhc*vT`5gM;JtL;nXrE@y#9
zWHAGS=OqwkT;baF11Kn2;u=vBoS#-wo>-L1P+nfHmzkGcoSayYs+V7sKKq@G6i|^w
zfKP}kkp6#y;r}^?|7RHf1KBV#-=@m}D92V3mmtT}V`<;yx0|WB}
zPZ!6KiaBqu9SjUf6mYv(7cAVS;&|5S3^VgYi#ZM^{HcbnLIQ0^iy007KHaUotlsFb+4g;d4x%9iv4TKP^-3KjtiUiBL<9t@6MO%;4$j
K=d#Wzp$PzCAv;?D


From 4cc10af7b700aba52befba5d6e87f1d9cdf7fa96 Mon Sep 17 00:00:00 2001
From: Dmitry Luhtionov 
Date: Mon, 15 May 2017 17:52:47 +0300
Subject: [PATCH 76/76] Add MACStringToOUI function

---
 dbms/src/Functions/FunctionsCoding.cpp |  1 +
 dbms/src/Functions/FunctionsCoding.h   | 97 ++++++++++++++++++++++++++
 docs/en/functions/other_functions.rst  |  8 ++-
 docs/ru/functions/other_functions.rst  |  8 ++-
 4 files changed, 110 insertions(+), 4 deletions(-)

diff --git a/dbms/src/Functions/FunctionsCoding.cpp b/dbms/src/Functions/FunctionsCoding.cpp
index 12f3f7c315f..f8d089bb774 100644
--- a/dbms/src/Functions/FunctionsCoding.cpp
+++ b/dbms/src/Functions/FunctionsCoding.cpp
@@ -16,6 +16,7 @@ void registerFunctionsCoding(FunctionFactory & factory)
     factory.registerFunction();
     factory.registerFunction();
     factory.registerFunction();
+    factory.registerFunction();
     factory.registerFunction();
     factory.registerFunction();
     factory.registerFunction();
diff --git a/dbms/src/Functions/FunctionsCoding.h b/dbms/src/Functions/FunctionsCoding.h
index 3258608ad9c..afa4df73083 100644
--- a/dbms/src/Functions/FunctionsCoding.h
+++ b/dbms/src/Functions/FunctionsCoding.h
@@ -1189,6 +1189,103 @@ public:
     }
 };
 
+class FunctionMACStringToOUI : public IFunction
+{
+public:
+    static constexpr auto name = "MACStringToOUI";
+    static FunctionPtr create(const Context & context) { return std::make_shared(); }
+
+    String getName() const override
+    {
+        return name;
+    }
+
+    size_t getNumberOfArguments() const override { return 1; }
+
+    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
+    {
+        if (!typeid_cast(&*arguments[0]))
+            throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(),
+            ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
+
+        return std::make_shared();
+    }
+
+    static UInt64 parseMAC(const char * pos)
+    {
+
+        /// get integer value for a hexademical char digit, or -1
+        const auto number_by_char = [] (const char ch)
+        {
+            if ('A' <= ch && ch <= 'F')
+                return 10 + ch - 'A';
+
+            if ('a' <= ch && ch <= 'f')
+                return 10 + ch - 'a';
+
+            if ('0' <= ch && ch <= '9')
+                return ch - '0';
+
+            return -1;
+        };
+
+        UInt64 res = 0;
+        for (int offset = 40; offset >= 0; offset -= 8)
+        {
+            UInt64 value = 0;
+            size_t len = 0;
+            int val = 0;
+            while ((val = number_by_char(*pos)) >= 0 && len <= 2)
+            {
+                value = value * 16 + val;
+                ++len;
+                ++pos;
+            }
+            if (len == 0 || value > 255 || (offset > 0 && *pos != ':'))
+                return 0;
+            res |= value << offset;
+            ++pos;
+        }
+        if (*(pos - 1) != '\0')
+            return 0;
+        res = res >> 24;
+        return res;
+    }
+
+    void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
+    {
+        const ColumnPtr & column = block.safeGetByPosition(arguments[0]).column;
+
+        if (const ColumnString * col = typeid_cast(column.get()))
+        {
+            auto col_res = std::make_shared();
+            block.safeGetByPosition(result).column = col_res;
+
+            ColumnUInt64::Container_t & vec_res = col_res->getData();
+            vec_res.resize(col->size());
+
+            const ColumnString::Chars_t & vec_src = col->getChars();
+            const ColumnString::Offsets_t & offsets_src = col->getOffsets();
+            size_t prev_offset = 0;
+
+            for (size_t i = 0; i < vec_res.size(); ++i)
+            {
+                vec_res[i] = parseMAC(reinterpret_cast(&vec_src[prev_offset]));
+                prev_offset = offsets_src[i];
+            }
+        }
+        else if (const ColumnConstString * col = typeid_cast(column.get()))
+        {
+            auto col_res = std::make_shared>(col->size(), parseMAC(col->getData().c_str()));
+            block.safeGetByPosition(result).column = col_res;
+        }
+        else
+            throw Exception("Illegal column " + block.safeGetByPosition(arguments[0]).column->getName()
+            + " of argument of function " + getName(),
+                            ErrorCodes::ILLEGAL_COLUMN);
+    }
+};
+
 
 class FunctionUUIDNumToString : public IFunction
 {
diff --git a/docs/en/functions/other_functions.rst b/docs/en/functions/other_functions.rst
index be5947c9048..04bc62663ab 100644
--- a/docs/en/functions/other_functions.rst
+++ b/docs/en/functions/other_functions.rst
@@ -259,10 +259,14 @@ Example:
   └─────────┴─────────────────────┴───────┘
   
 MACNumToString(num)
-~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~
 Takes a UInt64 number. Interprets it as an MAC address in big endian. Returns a string containing the corresponding MAC address in the format AA:BB:CC:DD:EE:FF (colon-separated numbers in hexadecimal form).
 
 MACStringToNum(s)
-~~~~~~~~
+~~~~~~~~~~~~~~~~~
 The reverse function of MACNumToString. If the MAC address has an invalid format, it returns 0.
+
+MACStringToOUI(s)
+~~~~~~~~~~~~~~~~~
+Takes MAC address in the format AA:BB:CC:DD:EE:FF (colon-separated numbers in hexadecimal form). Returns first three octets as UInt64 number. If the MAC address has an invalid format, it returns 0.
   
\ No newline at end of file
diff --git a/docs/ru/functions/other_functions.rst b/docs/ru/functions/other_functions.rst
index ecaff8f327a..bee2f135e9e 100644
--- a/docs/ru/functions/other_functions.rst
+++ b/docs/ru/functions/other_functions.rst
@@ -261,10 +261,14 @@ runningDifference(x)
   └─────────┴─────────────────────┴───────┘
   
 MACNumToString(num)
-~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~
 Принимает число типа UInt64. Интерпретирует его, как MAC-адрес в big endian. Возвращает строку, содержащую соответствующий MAC-адрес в формате AA:BB:CC:DD:EE:FF (числа в шестнадцатеричной форме через двоеточие).
 
 MACStringToNum(s)
-~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~
 Функция, обратная к MACNumToString. Если MAC адрес в неправильном формате, то возвращает 0.
+
+MACStringToOUI(s)
+~~~~~~~~~~~~~~~~~
+Принимает MAC адрес в формате AA:BB:CC:DD:EE:FF (числа в шестнадцатеричной форме через двоеточие). Возвращает первые три октета как число в формате UInt64. Если MAC адрес в неправильном формате, то возвращает 0.
   
\ No newline at end of file