From 43ee50e512e92fa8b067e53ad0d3c907f98e1c69 Mon Sep 17 00:00:00 2001 From: dimarub2000 Date: Tue, 13 Aug 2019 22:12:31 +0300 Subject: [PATCH 01/21] QuantileExactExclusive function added. --- .../AggregateFunctionQuantile.cpp | 7 ++ .../AggregateFunctionQuantile.h | 6 +- dbms/src/AggregateFunctions/QuantileExact.h | 70 +++++++++++++++++-- 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp index d41654daee5..9d07286371c 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp @@ -24,6 +24,9 @@ template using FuncQuantilesDeterministic = A template using FuncQuantileExact = AggregateFunctionQuantile, NameQuantileExact, false, void, false>; template using FuncQuantilesExact = AggregateFunctionQuantile, NameQuantilesExact, false, void, true>; +template using FuncQuantileExactExclusive = AggregateFunctionQuantile, NameQuantileExactExclusive, false, Float64, false>; +template using FuncQuantilesExactExclusive = AggregateFunctionQuantile, NameQuantilesExactExclusive, false, Float64, true>; + template using FuncQuantileExactWeighted = AggregateFunctionQuantile, NameQuantileExactWeighted, true, void, false>; template using FuncQuantilesExactWeighted = AggregateFunctionQuantile, NameQuantilesExactWeighted, true, void, true>; @@ -92,6 +95,10 @@ void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory) factory.registerFunction(NameQuantileExact::name, createAggregateFunctionQuantile); factory.registerFunction(NameQuantilesExact::name, createAggregateFunctionQuantile); + factory.registerFunction(NameQuantileExactExclusive::name, createAggregateFunctionQuantile); + factory.registerFunction(NameQuantilesExactExclusive::name, createAggregateFunctionQuantile); + + factory.registerFunction(NameQuantileExactWeighted::name, createAggregateFunctionQuantile); factory.registerFunction(NameQuantilesExactWeighted::name, createAggregateFunctionQuantile); diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h index 2e9ec914b99..4fdac6cdd53 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h @@ -199,8 +199,12 @@ struct NameQuantileDeterministic { static constexpr auto name = "quantileDetermi struct NameQuantilesDeterministic { static constexpr auto name = "quantilesDeterministic"; }; struct NameQuantileExact { static constexpr auto name = "quantileExact"; }; -struct NameQuantileExactWeighted { static constexpr auto name = "quantileExactWeighted"; }; struct NameQuantilesExact { static constexpr auto name = "quantilesExact"; }; + +struct NameQuantileExactExclusive { static constexpr auto name = "quantileExactExclusive"; }; +struct NameQuantilesExactExclusive { static constexpr auto name = "quantilesExactExclusive"; }; + +struct NameQuantileExactWeighted { static constexpr auto name = "quantileExactWeighted"; }; struct NameQuantilesExactWeighted { static constexpr auto name = "quantilesExactWeighted"; }; struct NameQuantileTiming { static constexpr auto name = "quantileTiming"; }; diff --git a/dbms/src/AggregateFunctions/QuantileExact.h b/dbms/src/AggregateFunctions/QuantileExact.h index a5b616669b9..b23a2975487 100644 --- a/dbms/src/AggregateFunctions/QuantileExact.h +++ b/dbms/src/AggregateFunctions/QuantileExact.h @@ -64,7 +64,7 @@ struct QuantileExact } /// Get the value of the `level` quantile. The level must be between 0 and 1. - Value get(Float64 level) + virtual Value get(Float64 level) { if (!array.empty()) { @@ -81,7 +81,7 @@ struct QuantileExact /// Get the `size` values of `levels` quantiles. Write `size` results starting with `result` address. /// indices - an array of index levels such that the corresponding elements will go in ascending order. - void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) + virtual void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) { if (!array.empty()) { @@ -108,15 +108,77 @@ struct QuantileExact } /// The same, but in the case of an empty state, NaN is returned. - Float64 getFloat(Float64) const + virtual Float64 getFloat(Float64) { throw Exception("Method getFloat is not implemented for QuantileExact", ErrorCodes::NOT_IMPLEMENTED); } - void getManyFloat(const Float64 *, const size_t *, size_t, Float64 *) const + virtual void getManyFloat(const Float64 *, const size_t *, size_t, Float64 *) { throw Exception("Method getManyFloat is not implemented for QuantileExact", ErrorCodes::NOT_IMPLEMENTED); } + + virtual ~QuantileExact() = default; +}; + +template +struct QuantileExactExclusive : public QuantileExact +{ + using QuantileExact::array; + /// Get the value of the `level` quantile. The level must be between 0 and 1. + Float64 getFloat(Float64 level) override + { + if (!array.empty()) + { + Float64 h = level * (array.size() + 1); + auto n = static_cast(h); + + if (n >= array.size()) + return array[array.size() - 1]; + else if (n < 1) + return array[0]; + + std::nth_element(array.begin(), array.begin() + n - 1, array.end()); + std::nth_element(array.begin() + n, array.begin() + n, array.end()); + + return array[n - 1] + (h - n) * (array[n] - array[n - 1]); + } + + return std::numeric_limits::quiet_NaN(); + } + + void getManyFloat(const Float64 * levels, const size_t * indices, size_t size, Float64 * result) override + { + if (!array.empty()) + { + size_t prev_n = 0; + for (size_t i = 0; i < size; ++i) + { + auto level = levels[indices[i]]; + + Float64 h = level * (array.size() + 1); + auto n = static_cast(h); + + if (n >= array.size()) + result[indices[i]] = array[array.size() - 1]; + else if (n < 1) + result[indices[i]] = array[0]; + else + { + std::nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end()); + std::nth_element(array.begin() + n, array.begin() + n, array.end()); + + result[indices[i]] = array[n - 1] + (h - n) * (array[n] - array[n - 1]); + prev_n = n; + } + } + } + else + { + for (size_t i = 0; i < size; ++i) + result[i] = std::numeric_limits::quiet_NaN(); + } + } }; } From 6b6e477c76d103ba110de38c36b86b659d136935 Mon Sep 17 00:00:00 2001 From: dimarub2000 Date: Wed, 14 Aug 2019 14:13:04 +0300 Subject: [PATCH 02/21] Added QuantileExactInclusive function. Deleted redundant virtuals. --- .../AggregateFunctionQuantile.cpp | 5 ++ .../AggregateFunctionQuantile.h | 3 + dbms/src/AggregateFunctions/QuantileExact.h | 88 +++++++++++++++++-- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp index 9d07286371c..e3d0cbdc289 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.cpp @@ -27,6 +27,9 @@ template using FuncQuantilesExact = AggregateFunctionQu template using FuncQuantileExactExclusive = AggregateFunctionQuantile, NameQuantileExactExclusive, false, Float64, false>; template using FuncQuantilesExactExclusive = AggregateFunctionQuantile, NameQuantilesExactExclusive, false, Float64, true>; +template using FuncQuantileExactInclusive = AggregateFunctionQuantile, NameQuantileExactInclusive, false, Float64, false>; +template using FuncQuantilesExactInclusive = AggregateFunctionQuantile, NameQuantilesExactInclusive, false, Float64, true>; + template using FuncQuantileExactWeighted = AggregateFunctionQuantile, NameQuantileExactWeighted, true, void, false>; template using FuncQuantilesExactWeighted = AggregateFunctionQuantile, NameQuantilesExactWeighted, true, void, true>; @@ -98,6 +101,8 @@ void registerAggregateFunctionsQuantile(AggregateFunctionFactory & factory) factory.registerFunction(NameQuantileExactExclusive::name, createAggregateFunctionQuantile); factory.registerFunction(NameQuantilesExactExclusive::name, createAggregateFunctionQuantile); + factory.registerFunction(NameQuantileExactInclusive::name, createAggregateFunctionQuantile); + factory.registerFunction(NameQuantilesExactInclusive::name, createAggregateFunctionQuantile); factory.registerFunction(NameQuantileExactWeighted::name, createAggregateFunctionQuantile); factory.registerFunction(NameQuantilesExactWeighted::name, createAggregateFunctionQuantile); diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h index 4fdac6cdd53..718bf419dd0 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantile.h @@ -204,6 +204,9 @@ struct NameQuantilesExact { static constexpr auto name = "quantilesExact"; }; struct NameQuantileExactExclusive { static constexpr auto name = "quantileExactExclusive"; }; struct NameQuantilesExactExclusive { static constexpr auto name = "quantilesExactExclusive"; }; +struct NameQuantileExactInclusive { static constexpr auto name = "quantileExactInclusive"; }; +struct NameQuantilesExactInclusive { static constexpr auto name = "quantilesExactInclusive"; }; + struct NameQuantileExactWeighted { static constexpr auto name = "quantileExactWeighted"; }; struct NameQuantilesExactWeighted { static constexpr auto name = "quantilesExactWeighted"; }; diff --git a/dbms/src/AggregateFunctions/QuantileExact.h b/dbms/src/AggregateFunctions/QuantileExact.h index b23a2975487..ffa12640f8e 100644 --- a/dbms/src/AggregateFunctions/QuantileExact.h +++ b/dbms/src/AggregateFunctions/QuantileExact.h @@ -14,6 +14,7 @@ namespace DB namespace ErrorCodes { extern const int NOT_IMPLEMENTED; + extern const int BAD_ARGUMENTS; } /** Calculates quantile by collecting all values into array @@ -64,7 +65,7 @@ struct QuantileExact } /// Get the value of the `level` quantile. The level must be between 0 and 1. - virtual Value get(Float64 level) + Value get(Float64 level) { if (!array.empty()) { @@ -81,7 +82,7 @@ struct QuantileExact /// Get the `size` values of `levels` quantiles. Write `size` results starting with `result` address. /// indices - an array of index levels such that the corresponding elements will go in ascending order. - virtual void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) + void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) { if (!array.empty()) { @@ -121,13 +122,18 @@ struct QuantileExact virtual ~QuantileExact() = default; }; +/// QuantileExactInclusive is equivalent to Excel PERCENTILE.EXC, R-6, SAS-4, SciPy-(0,0) template struct QuantileExactExclusive : public QuantileExact { using QuantileExact::array; - /// Get the value of the `level` quantile. The level must be between 0 and 1. + + /// Get the value of the `level` quantile. The level must be between 0 and 1 excluding bounds. Float64 getFloat(Float64 level) override { + if (level == 0. || level == 1.) + throw Exception("QuantileExactExclusive cannot interpolate for the percentiles 1 and 0", ErrorCodes::BAD_ARGUMENTS); + if (!array.empty()) { Float64 h = level * (array.size() + 1); @@ -139,9 +145,73 @@ struct QuantileExactExclusive : public QuantileExact return array[0]; std::nth_element(array.begin(), array.begin() + n - 1, array.end()); - std::nth_element(array.begin() + n, array.begin() + n, array.end()); + auto nth_element = std::min_element(array.begin() + n, array.end()); - return array[n - 1] + (h - n) * (array[n] - array[n - 1]); + return array[n - 1] + (h - n) * (*nth_element - array[n - 1]); + } + + return std::numeric_limits::quiet_NaN(); + } + + void getManyFloat(const Float64 * levels, const size_t * indices, size_t size, Float64 * result) override + { + if (!array.empty()) + { + size_t prev_n = 0; + for (size_t i = 0; i < size; ++i) + { + auto level = levels[indices[i]]; + if (level == 0. || level == 1.) + throw Exception("QuantileExactExclusive cannot interpolate for the percentiles 1 and 0", ErrorCodes::BAD_ARGUMENTS); + + Float64 h = level * (array.size() + 1); + auto n = static_cast(h); + + if (n >= array.size()) + result[indices[i]] = array[array.size() - 1]; + else if (n < 1) + result[indices[i]] = array[0]; + else + { + std::nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end()); + auto nth_element = std::min_element(array.begin() + n, array.end()); + + result[indices[i]] = array[n - 1] + (h - n) * (*nth_element - array[n - 1]); + prev_n = n - 1; + } + } + } + else + { + for (size_t i = 0; i < size; ++i) + result[i] = std::numeric_limits::quiet_NaN(); + } + } +}; + +/// QuantileExactInclusive is equivalent to Excel PERCENTILE and PERCENTILE.INC, R-7, SciPy-(1,1) +template +struct QuantileExactInclusive : public QuantileExact +{ + using QuantileExact::array; + + /// Get the value of the `level` quantile. The level must be between 0 and 1 including bounds. + Float64 getFloat(Float64 level) override + { + if (!array.empty()) + { + Float64 h = level * (array.size() - 1) + 1; + auto n = static_cast(h); + + if (n >= array.size()) + return array[array.size() - 1]; + else if (n < 1) + return array[0]; + + std::nth_element(array.begin(), array.begin() + n - 1, array.end()); + auto nth_element = std::min_element(array.begin() + n, array.end()); + + return array[n - 1] + (h - n) * (*nth_element - array[n - 1]); } return std::numeric_limits::quiet_NaN(); @@ -156,7 +226,7 @@ struct QuantileExactExclusive : public QuantileExact { auto level = levels[indices[i]]; - Float64 h = level * (array.size() + 1); + Float64 h = level * (array.size() - 1) + 1; auto n = static_cast(h); if (n >= array.size()) @@ -166,10 +236,10 @@ struct QuantileExactExclusive : public QuantileExact else { std::nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end()); - std::nth_element(array.begin() + n, array.begin() + n, array.end()); + auto nth_element = std::min_element(array.begin() + n, array.end()); - result[indices[i]] = array[n - 1] + (h - n) * (array[n] - array[n - 1]); - prev_n = n; + result[indices[i]] = array[n - 1] + (h - n) * (*nth_element - array[n - 1]); + prev_n = n - 1; } } } From 73e208917c8a97eeeedf22a661fd1d1a0f6588b8 Mon Sep 17 00:00:00 2001 From: dimarub2000 Date: Wed, 14 Aug 2019 14:18:46 +0300 Subject: [PATCH 03/21] Fixed comment --- dbms/src/AggregateFunctions/QuantileExact.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/src/AggregateFunctions/QuantileExact.h b/dbms/src/AggregateFunctions/QuantileExact.h index ffa12640f8e..058c433e992 100644 --- a/dbms/src/AggregateFunctions/QuantileExact.h +++ b/dbms/src/AggregateFunctions/QuantileExact.h @@ -122,7 +122,7 @@ struct QuantileExact virtual ~QuantileExact() = default; }; -/// QuantileExactInclusive is equivalent to Excel PERCENTILE.EXC, R-6, SAS-4, SciPy-(0,0) +/// QuantileExactExclusive is equivalent to Excel PERCENTILE.EXC, R-6, SAS-4, SciPy-(0,0) template struct QuantileExactExclusive : public QuantileExact { @@ -131,11 +131,11 @@ struct QuantileExactExclusive : public QuantileExact /// Get the value of the `level` quantile. The level must be between 0 and 1 excluding bounds. Float64 getFloat(Float64 level) override { - if (level == 0. || level == 1.) - throw Exception("QuantileExactExclusive cannot interpolate for the percentiles 1 and 0", ErrorCodes::BAD_ARGUMENTS); - if (!array.empty()) { + if (level == 0. || level == 1.) + throw Exception("QuantileExactExclusive cannot interpolate for the percentiles 1 and 0", ErrorCodes::BAD_ARGUMENTS); + Float64 h = level * (array.size() + 1); auto n = static_cast(h); From e56f6264309429fac145b817baee4330c8bcbda5 Mon Sep 17 00:00:00 2001 From: Dmitry Rubashkin Date: Wed, 14 Aug 2019 16:45:04 +0300 Subject: [PATCH 04/21] Tests --- ...79_quantileExcatExclusive_and_Inclusive.reference | 6 ++++++ .../00979_quantileExcatExclusive_and_Inclusive.sql | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference create mode 100644 dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql diff --git a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference new file mode 100644 index 00000000000..1ac0dd60fca --- /dev/null +++ b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference @@ -0,0 +1,6 @@ +[249.25,499.5,749.75,899.9,949.9499999999999,989.99,998.999] +[249.75,499.5,749.25,899.1,949.05,989.01,998.001] +[250,500,750,900,950,990,999] +599.6 +599.6 +600 diff --git a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql new file mode 100644 index 00000000000..9652fbbb664 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql @@ -0,0 +1,12 @@ +DROP TABLE IF EXISTS num; +CREATE TABLE num AS numbers(1000); + +SELECT quantilesExactExclusive(0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999)(x) FROM (SELECT number AS x FROM num); +SELECT quantilesExactInclusive(0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999)(x) FROM (SELECT number AS x FROM num); +SELECT quantilesExact(0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999)(x) FROM (SELECT number AS x FROM num); + +SELECT quantileExactExclusive(0.6)(x) FROM (SELECT number AS x FROM num); +SELECT quantileExactExclusive(0.6)(x) FROM (SELECT number AS x FROM num); +SELECT quantileExact(0.6)(x) FROM (SELECT number AS x FROM num); + +DROP TABLE num; From 4090e89410d9809df358268bc5de26d4af4d93c8 Mon Sep 17 00:00:00 2001 From: Dmitry Rubashkin Date: Wed, 14 Aug 2019 16:47:48 +0300 Subject: [PATCH 05/21] Tests fixed --- .../00979_quantileExcatExclusive_and_Inclusive.reference | 2 +- .../0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference index 1ac0dd60fca..8689402746e 100644 --- a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference +++ b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.reference @@ -2,5 +2,5 @@ [249.75,499.5,749.25,899.1,949.05,989.01,998.001] [250,500,750,900,950,990,999] 599.6 -599.6 +599.4 600 diff --git a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql index 9652fbbb664..99cbcfbd6b9 100644 --- a/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql +++ b/dbms/tests/queries/0_stateless/00979_quantileExcatExclusive_and_Inclusive.sql @@ -6,7 +6,7 @@ SELECT quantilesExactInclusive(0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999)(x) FROM SELECT quantilesExact(0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.999)(x) FROM (SELECT number AS x FROM num); SELECT quantileExactExclusive(0.6)(x) FROM (SELECT number AS x FROM num); -SELECT quantileExactExclusive(0.6)(x) FROM (SELECT number AS x FROM num); +SELECT quantileExactInclusive(0.6)(x) FROM (SELECT number AS x FROM num); SELECT quantileExact(0.6)(x) FROM (SELECT number AS x FROM num); DROP TABLE num; From 8bbcecf3b1c58aa3220d36ee09ea8ac38ab7e872 Mon Sep 17 00:00:00 2001 From: Alexander Tokmakov Date: Fri, 16 Aug 2019 19:14:08 +0300 Subject: [PATCH 06/21] add test --- .../__init__.py | 0 .../configs/remote_servers.xml | 19 ++++++ .../test.py | 59 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 dbms/tests/integration/test_inconsistent_parts_after_clone_replica/__init__.py create mode 100644 dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml create mode 100644 dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/__init__.py b/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml b/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml new file mode 100644 index 00000000000..a6e80ce2b08 --- /dev/null +++ b/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml @@ -0,0 +1,19 @@ + + + + + true + + shard_0 + node1 + 9000 + + + shard_0 + node2 + 9000 + + + + + diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py b/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py new file mode 100644 index 00000000000..c1513798189 --- /dev/null +++ b/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py @@ -0,0 +1,59 @@ +import pytest + +from helpers.cluster import ClickHouseCluster +from helpers.network import PartitionManager +from helpers.test_tools import assert_eq_with_retry + + +def fill_nodes(nodes, shard): + for node in nodes: + node.query( + ''' + CREATE DATABASE test; + CREATE TABLE test_table(date Date, id UInt32) + ENGINE = ReplicatedMergeTree('/clickhouse/tables/test{shard}/replicated', '{replica}') + ORDER BY id PARTITION BY toYYYYMM(date) + SETTINGS min_replicated_logs_to_keep=3, max_replicated_logs_to_keep=5, cleanup_delay_period=0, cleanup_delay_period_random_add=0; + '''.format(shard=shard, replica=node.name)) + + +cluster = ClickHouseCluster(__file__) +node1 = cluster.add_instance('node1', main_configs=['configs/remote_servers.xml'], with_zookeeper=True) +node2 = cluster.add_instance('node2', main_configs=['configs/remote_servers.xml'], with_zookeeper=True) + +@pytest.fixture(scope="module") +def start_cluster(): + try: + cluster.start() + fill_nodes([node1, node2], 1) + yield cluster + except Exception as ex: + print ex + finally: + cluster.shutdown() + + +def test_inconsistent_parts_if_drop_while_replica_not_active(start_cluster): + with PartitionManager() as pm: + # insert into all replicas + node1.query("INSERT INTO test_table VALUES ('2019-08-16', 100)") + assert_eq_with_retry(node2, "SELECT count(*) FROM test_table", node1.query("SELECT count(*) FROM test_table")) + + # disable network on the first replica + pm.partition_instances(node1, node2) + pm.drop_instance_zk_connections(node1) + + # drop all parts on the second replica + node2.query_with_retry("ALTER TABLE test_table DROP PARTITION 201908") + assert_eq_with_retry(node2, "SELECT count(*) FROM test_table", "0") + + # insert into the second replica + # DROP_RANGE will be removed from the replication log and the first replica will be lost + for i in range(100): + node2.query("INSERT INTO test_table VALUES ('2019-08-16', {})".format(i)) + + # the first replica will be cloned from the second + pm.heal_all() + assert_eq_with_retry(node1, "SELECT count(*) FROM test_table", node2.query("SELECT count(*) FROM test_table")) + + From c70d5851698ea36c77866b1f058631d56d390aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=B5=D0=BE=D1=80=D0=B3=D0=B8=D0=B9=20=D0=9A=D0=BE?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B0=D1=82=D1=8C=D0=B5=D0=B2?= Date: Mon, 19 Aug 2019 05:13:39 +0000 Subject: [PATCH 07/21] DEVTOOLS-5755 Remove odbc-bridge.cpp from clickhouse-lib odbc-bridge.cpp defines main() so it should not be included in clickhouse-lib. --- dbms/programs/odbc-bridge/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/programs/odbc-bridge/CMakeLists.txt b/dbms/programs/odbc-bridge/CMakeLists.txt index 060a36e9275..444d6e8d8e0 100644 --- a/dbms/programs/odbc-bridge/CMakeLists.txt +++ b/dbms/programs/odbc-bridge/CMakeLists.txt @@ -5,7 +5,6 @@ set(CLICKHOUSE_ODBC_BRIDGE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/IdentifierQuoteHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ODBCBlockInputStream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/odbc-bridge.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ODBCBridge.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PingHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/validateODBCConnectionString.cpp From 6991683a5f6c72dc465528905f8c46253558e73e Mon Sep 17 00:00:00 2001 From: Alexander Tokmakov Date: Mon, 19 Aug 2019 15:06:44 +0300 Subject: [PATCH 08/21] remove local parts which source replica doesnt have --- .../Storages/StorageReplicatedMergeTree.cpp | 31 +++++++++++++++++-- .../__init__.py | 0 .../configs/remote_servers.xml | 0 .../test.py | 7 +++-- 4 files changed, 33 insertions(+), 5 deletions(-) rename dbms/tests/integration/{test_inconsistent_parts_after_clone_replica => test_consistent_parts_after_clone_replica}/__init__.py (100%) rename dbms/tests/integration/{test_inconsistent_parts_after_clone_replica => test_consistent_parts_after_clone_replica}/configs/remote_servers.xml (100%) rename dbms/tests/integration/{test_inconsistent_parts_after_clone_replica => test_consistent_parts_after_clone_replica}/test.py (93%) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index a436d426202..8ba8daca413 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -1942,10 +1942,37 @@ void StorageReplicatedMergeTree::cloneReplica(const String & source_replica, Coo } /// Add to the queue jobs to receive all the active parts that the reference/master replica has. - Strings parts = zookeeper->getChildren(source_path + "/parts"); - ActiveDataPartSet active_parts_set(format_version, parts); + Strings source_replica_parts = zookeeper->getChildren(source_path + "/parts"); + ActiveDataPartSet active_parts_set(format_version, source_replica_parts); Strings active_parts = active_parts_set.getParts(); + + /// Remove local parts if source replica does not have them, because such parts will never be fetched by other replicas. + Strings local_parts_in_zk = zookeeper->getChildren(replica_path + "/parts"); + Strings parts_to_remove_from_zk; + for (const auto & part : local_parts_in_zk) + { + if (active_parts_set.getContainingPart(part).empty()) + { + queue.remove(zookeeper, part); + parts_to_remove_from_zk.emplace_back(part); + LOG_WARNING(log, "Source replica does not have part " << part << ". Removing it from ZooKeeper."); + } + } + tryRemovePartsFromZooKeeperWithRetries(parts_to_remove_from_zk); + + auto local_active_parts = getDataParts(); + DataPartsVector parts_to_remove_from_working_set; + for (const auto & part : local_active_parts) + { + if (active_parts_set.getContainingPart(part->name).empty()) + { + parts_to_remove_from_working_set.emplace_back(part); + LOG_WARNING(log, "Source replica does not have part " << part->name << ". Removing it from working set."); + } + } + removePartsFromWorkingSet(parts_to_remove_from_working_set, true); + for (const String & name : active_parts) { LogEntry log_entry; diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/__init__.py b/dbms/tests/integration/test_consistent_parts_after_clone_replica/__init__.py similarity index 100% rename from dbms/tests/integration/test_inconsistent_parts_after_clone_replica/__init__.py rename to dbms/tests/integration/test_consistent_parts_after_clone_replica/__init__.py diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml b/dbms/tests/integration/test_consistent_parts_after_clone_replica/configs/remote_servers.xml similarity index 100% rename from dbms/tests/integration/test_inconsistent_parts_after_clone_replica/configs/remote_servers.xml rename to dbms/tests/integration/test_consistent_parts_after_clone_replica/configs/remote_servers.xml diff --git a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py b/dbms/tests/integration/test_consistent_parts_after_clone_replica/test.py similarity index 93% rename from dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py rename to dbms/tests/integration/test_consistent_parts_after_clone_replica/test.py index c1513798189..b8a58242ad1 100644 --- a/dbms/tests/integration/test_inconsistent_parts_after_clone_replica/test.py +++ b/dbms/tests/integration/test_consistent_parts_after_clone_replica/test.py @@ -36,7 +36,8 @@ def start_cluster(): def test_inconsistent_parts_if_drop_while_replica_not_active(start_cluster): with PartitionManager() as pm: # insert into all replicas - node1.query("INSERT INTO test_table VALUES ('2019-08-16', 100)") + for i in range(50): + node1.query("INSERT INTO test_table VALUES ('2019-08-16', {})".format(i)) assert_eq_with_retry(node2, "SELECT count(*) FROM test_table", node1.query("SELECT count(*) FROM test_table")) # disable network on the first replica @@ -49,8 +50,8 @@ def test_inconsistent_parts_if_drop_while_replica_not_active(start_cluster): # insert into the second replica # DROP_RANGE will be removed from the replication log and the first replica will be lost - for i in range(100): - node2.query("INSERT INTO test_table VALUES ('2019-08-16', {})".format(i)) + for i in range(50): + node2.query("INSERT INTO test_table VALUES ('2019-08-16', {})".format(50 + i)) # the first replica will be cloned from the second pm.heal_all() From 61769865d8b81b9fe4e94bdf04352425f025c9f3 Mon Sep 17 00:00:00 2001 From: "philip.han" Date: Mon, 19 Aug 2019 22:12:25 +0900 Subject: [PATCH 09/21] Added 'strict' parameter in windowFunnel() and added testcases. --- .../AggregateFunctionWindowFunnel.cpp | 4 ++-- .../AggregateFunctionWindowFunnel.h | 16 +++++++++++++++- .../00632_aggregation_window_funnel.sql | 11 ++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.cpp b/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.cpp index 4cf7784342c..56ee5dcb012 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.cpp +++ b/dbms/src/AggregateFunctions/AggregateFunctionWindowFunnel.cpp @@ -17,8 +17,8 @@ namespace template