Merge remote-tracking branch 'upstream/master' into fix27

This commit is contained in:
proller 2019-12-28 15:12:17 +03:00
commit a4c8d29c96
10 changed files with 232 additions and 73 deletions

View File

@ -217,9 +217,18 @@ const SettingsConstraints::Constraint * SettingsConstraints::tryGetConstraint(si
void SettingsConstraints::setProfile(const String & profile_name, const Poco::Util::AbstractConfiguration & config) void SettingsConstraints::setProfile(const String & profile_name, const Poco::Util::AbstractConfiguration & config)
{ {
String parent_profile = "profiles." + profile_name + ".profile"; String elem = "profiles." + profile_name;
if (config.has(parent_profile))
setProfile(parent_profile, config); // Inheritance of one profile from another. Poco::Util::AbstractConfiguration::Keys config_keys;
config.keys(elem, config_keys);
for (const std::string & key : config_keys)
{
if (key == "profile" || 0 == key.compare(0, strlen("profile["), "profile[")) /// Inheritance of profiles from the current one.
setProfile(config.getString(elem + "." + key), config);
else
continue;
}
String path_to_constraints = "profiles." + profile_name + ".constraints"; String path_to_constraints = "profiles." + profile_name + ".constraints";
if (config.has(path_to_constraints)) if (config.has(path_to_constraints))

View File

@ -37,7 +37,7 @@ void Settings::setProfile(const String & profile_name, const Poco::Util::Abstrac
{ {
if (key == "constraints") if (key == "constraints")
continue; continue;
if (key == "profile") /// Inheritance of one profile from another. if (key == "profile" || 0 == key.compare(0, strlen("profile["), "profile[")) /// Inheritance of profiles from the current one.
setProfile(config.getString(elem + "." + key), config); setProfile(config.getString(elem + "." + key), config);
else else
set(key, config.getString(elem + "." + key)); set(key, config.getString(elem + "." + key));

View File

@ -534,7 +534,7 @@ void StorageReplicatedMergeTree::setTableStructure(ColumnsDescription new_column
if (metadata_diff.ttl_table_changed) if (metadata_diff.ttl_table_changed)
{ {
ParserExpression parser; ParserTTLExpressionList parser;
new_ttl_table_ast = parseQuery(parser, metadata_diff.new_ttl_table, 0); new_ttl_table_ast = parseQuery(parser, metadata_diff.new_ttl_table, 0);
} }

View File

@ -0,0 +1,59 @@
<yandex>
<profiles>
<profile_1>
<max_parallel_replicas>2</max_parallel_replicas>
<!-- max_query_size is inherited one by one and final should be 400000000 -->
<max_query_size>200000000</max_query_size>
<constraints>
<max_memory_usage>
<min>100000000</min>
</max_memory_usage>
<max_parallel_replicas>
<readonly/>
</max_parallel_replicas>
</constraints>
</profile_1>
<profile_2>
<max_network_bytes>1234567890</max_network_bytes>
<max_query_size>300000000</max_query_size>
<constraints>
<max_memory_usage>
<min>200000000</min>
</max_memory_usage>
<max_network_bytes>
<min>1234567889</min>
<max>1234567891</max>
</max_network_bytes>
</constraints>
</profile_2>
<profile_3>
<max_insert_block_size>654321</max_insert_block_size>
<max_query_size>400000000</max_query_size>
<constraints>
<max_memory_usage>
<min>300000000</min>
</max_memory_usage>
<max_insert_block_size>
<min>654320</min>
<max>654322</max>
</max_insert_block_size>
</constraints>
</profile_3>
<combined_profile>
<profile>profile_1</profile>
<profile>profile_2</profile>
<profile>profile_3</profile>
<readonly>2</readonly>
</combined_profile>
</profiles>
<users>
<test_combined_profile>
<password></password>
<networks>
<ip>::/0</ip>
</networks>
<quota>default</quota>
<profile>combined_profile</profile>
</test_combined_profile>
</users>
</yandex>

View File

@ -0,0 +1,74 @@
import pytest
from helpers.client import QueryRuntimeException
from helpers.cluster import ClickHouseCluster
from helpers.test_tools import TSV
cluster = ClickHouseCluster(__file__)
instance = cluster.add_instance('instance',
user_configs=['configs/combined_profile.xml'])
q = instance.query
@pytest.fixture(scope="module")
def started_cluster():
try:
cluster.start()
yield cluster
finally:
cluster.shutdown()
def test_combined_profile(started_cluster):
settings = q('''
SELECT name, value FROM system.settings
WHERE name IN
('max_insert_block_size', 'max_network_bytes', 'max_query_size',
'max_parallel_replicas', 'readonly')
AND changed
ORDER BY name
''', user='test_combined_profile')
expected1 = '''\
max_insert_block_size 654321
max_network_bytes 1234567890
max_parallel_replicas 2
max_query_size 400000000
readonly 2'''
assert TSV(settings) == TSV(expected1)
with pytest.raises(QueryRuntimeException) as exc:
q('''
SET max_insert_block_size = 1000;
''', user='test_combined_profile')
assert ("max_insert_block_size shouldn't be less than 654320." in
str(exc.value))
with pytest.raises(QueryRuntimeException) as exc:
q('''
SET max_network_bytes = 2000000000;
''', user='test_combined_profile')
assert ("max_network_bytes shouldn't be greater than 1234567891." in
str(exc.value))
with pytest.raises(QueryRuntimeException) as exc:
q('''
SET max_parallel_replicas = 1000;
''', user='test_combined_profile')
assert ('max_parallel_replicas should not be changed.' in
str(exc.value))
with pytest.raises(QueryRuntimeException) as exc:
q('''
SET max_memory_usage = 1000;
''', user='test_combined_profile')
assert ("max_memory_usage shouldn't be less than 300000000." in
str(exc.value))

View File

@ -538,3 +538,85 @@ def test_ttls_do_not_work_after_alter(started_cluster, name, engine, positive):
finally: finally:
node1.query("DROP TABLE IF EXISTS {}".format(name)) node1.query("DROP TABLE IF EXISTS {}".format(name))
@pytest.mark.parametrize("name,engine,positive", [
("mt_test_alter_multiple_ttls_positive", "MergeTree()", True),
("mt_replicated_test_alter_multiple_ttls_positive", "ReplicatedMergeTree('/clickhouse/replicated_test_alter_multiple_ttls_positive', '1')", True),
("mt_test_alter_multiple_ttls_negative", "MergeTree()", False),
("mt_replicated_test_alter_multiple_ttls_negative", "ReplicatedMergeTree('/clickhouse/replicated_test_alter_multiple_ttls_negative', '1')", False),
])
def test_alter_multiple_ttls(started_cluster, name, engine, positive):
"""Copyright 2019, Altinity LTD
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License."""
"""Check that when multiple TTL expressions are set
and before any parts are inserted the TTL expressions
are changed with ALTER command then all old
TTL expressions are removed and the
the parts are moved to the specified disk or volume or
deleted if the new TTL expression is triggered
and are not moved or deleted when it is not.
"""
now = time.time()
try:
node1.query("""
CREATE TABLE {name} (
p1 Int64,
s1 String,
d1 DateTime
) ENGINE = {engine}
ORDER BY tuple()
PARTITION BY p1
TTL d1 + INTERVAL 30 SECOND TO DISK 'jbod2',
d1 + INTERVAL 60 SECOND TO VOLUME 'external'
SETTINGS storage_policy='jbods_with_external', merge_with_ttl_timeout=0
""".format(name=name, engine=engine))
node1.query("""
ALTER TABLE {name} MODIFY
TTL d1 + INTERVAL 0 SECOND TO DISK 'jbod2',
d1 + INTERVAL 5 SECOND TO VOLUME 'external',
d1 + INTERVAL 10 SECOND DELETE
""".format(name=name))
for p in range(3):
data = [] # 6MB in total
now = time.time()
for i in range(2):
p1 = p
s1 = get_random_string(1024 * 1024) # 1MB
d1 = now - 1 if i > 0 or positive else now + 300
data.append("({}, '{}', toDateTime({}))".format(p1, s1, d1))
node1.query("INSERT INTO {name} (p1, s1, d1) VALUES {values}".format(name=name, values=",".join(data)))
used_disks = get_used_disks_for_table(node1, name)
assert set(used_disks) == {"jbod2"} if positive else {"jbod1", "jbod2"}
assert node1.query("SELECT count() FROM {name}".format(name=name)).splitlines() == ["6"]
time.sleep(5)
used_disks = get_used_disks_for_table(node1, name)
assert set(used_disks) == {"external"} if positive else {"jbod1", "jbod2"}
assert node1.query("SELECT count() FROM {name}".format(name=name)).splitlines() == ["6"]
time.sleep(5)
node1.query("OPTIMIZE TABLE {name} FINAL".format(name=name))
assert node1.query("SELECT count() FROM {name}".format(name=name)).splitlines() == ["0"] if positive else ["3"]
finally:
node1.query("DROP TABLE IF EXISTS {name}".format(name=name))

View File

@ -60,7 +60,7 @@ Example:
The example specifies two profiles: `default` and `web`. The `default` profile has a special purpose: it must always be present and is applied when starting the server. In other words, the `default` profile contains default settings. The `web` profile is a regular profile that can be set using the `SET` query or using a URL parameter in an HTTP query. The example specifies two profiles: `default` and `web`. The `default` profile has a special purpose: it must always be present and is applied when starting the server. In other words, the `default` profile contains default settings. The `web` profile is a regular profile that can be set using the `SET` query or using a URL parameter in an HTTP query.
Settings profiles can inherit from each other. To use inheritance, indicate the `profile` setting before the other settings that are listed in the profile. Settings profiles can inherit from each other. To use inheritance, indicate one or multiple `profile` settings before the other settings that are listed in the profile. In case when one setting is defined in different profiles, the latest defined is used.
[Original article](https://clickhouse.yandex/docs/en/operations/settings/settings_profiles/) <!--hide--> [Original article](https://clickhouse.yandex/docs/en/operations/settings/settings_profiles/) <!--hide-->

View File

@ -60,6 +60,6 @@ SET profile = 'web'
В примере задано два профиля: `default` и `web`. Профиль `default` имеет специальное значение - он всегда обязан присутствовать и применяется при запуске сервера. То есть, профиль `default` содержит настройки по умолчанию. Профиль `web` - обычный профиль, который может быть установлен с помощью запроса `SET` или с помощью параметра URL при запросе по HTTP. В примере задано два профиля: `default` и `web`. Профиль `default` имеет специальное значение - он всегда обязан присутствовать и применяется при запуске сервера. То есть, профиль `default` содержит настройки по умолчанию. Профиль `web` - обычный профиль, который может быть установлен с помощью запроса `SET` или с помощью параметра URL при запросе по HTTP.
Профили настроек могут наследоваться от друг-друга - это реализуется указанием настройки `profile` перед остальными настройками, перечисленными в профиле. Профили настроек могут наследоваться от друг-друга - это реализуется указанием одной или нескольких настроек `profile` перед остальными настройками, перечисленными в профиле. Если одна настройка указана в нескольких профилях, используется последнее из значений.
[Оригинальная статья](https://clickhouse.yandex/docs/ru/operations/settings/settings_profiles/) <!--hide--> [Оригинальная статья](https://clickhouse.yandex/docs/ru/operations/settings/settings_profiles/) <!--hide-->

View File

@ -1,66 +0,0 @@
# Settings profiles
A settings profile is a collection of settings grouped under the same name. Each ClickHouse user has a profile.
To apply all the settings in a profile, set the `profile` setting.
Example:
Install the `web` profile.
``` sql
SET profile = 'web'
```
Settings profiles are declared in the user config file. This is usually `users.xml`.
Example:
```xml
<!-- Settings profiles -->
<profiles>
<!-- Default settings -->
<default>
<!-- The maximum number of threads when running a single query. -->
<max_threads>8</max_threads>
</default>
<!-- Settings for quries from the user interface -->
<web>
<max_rows_to_read>1000000000</max_rows_to_read>
<max_bytes_to_read>100000000000</max_bytes_to_read>
<max_rows_to_group_by>1000000</max_rows_to_group_by>
<group_by_overflow_mode>any</group_by_overflow_mode>
<max_rows_to_sort>1000000</max_rows_to_sort>
<max_bytes_to_sort>1000000000</max_bytes_to_sort>
<max_result_rows>100000</max_result_rows>
<max_result_bytes>100000000</max_result_bytes>
<result_overflow_mode>break</result_overflow_mode>
<max_execution_time>600</max_execution_time>
<min_execution_speed>1000000</min_execution_speed>
<timeout_before_checking_execution_speed>15</timeout_before_checking_execution_speed>
<max_columns_to_read>25</max_columns_to_read>
<max_temporary_columns>100</max_temporary_columns>
<max_temporary_non_const_columns>50</max_temporary_non_const_columns>
<max_subquery_depth>2</max_subquery_depth>
<max_pipeline_depth>25</max_pipeline_depth>
<max_ast_depth>50</max_ast_depth>
<max_ast_elements>100</max_ast_elements>
<readonly>1</readonly>
</web>
</profiles>
```
The example specifies two profiles: `default` and `web`. The `default` profile has a special purpose: it must always be present and is applied when starting the server. In other words, the `default` profile contains default settings. The `web` profile is a regular profile that can be set using the `SET` query or using a URL parameter in an HTTP query.
Settings profiles can inherit from each other. To use inheritance, indicate the `profile` setting before the other settings that are listed in the profile.
[Original article](https://clickhouse.yandex/docs/en/operations/settings/settings_profiles/) <!--hide-->

View File

@ -0,0 +1 @@
../../../en/operations/settings/settings_profiles.md