mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
Merge branch 'master' into return-not-nullable-from-count-distinct
This commit is contained in:
commit
add7b76b83
@ -97,5 +97,37 @@ if (USE_INTERNAL_BOOST_LIBRARY)
|
|||||||
add_library (boost::system ALIAS _boost_system)
|
add_library (boost::system ALIAS _boost_system)
|
||||||
target_include_directories (_boost_system PRIVATE ${LIBRARY_DIR})
|
target_include_directories (_boost_system PRIVATE ${LIBRARY_DIR})
|
||||||
else ()
|
else ()
|
||||||
message (FATAL_ERROR "TODO: external Boost library is not supported!")
|
# 1.70 like in contrib/boost
|
||||||
|
# 1.67 on CI
|
||||||
|
set(BOOST_VERSION 1.67)
|
||||||
|
|
||||||
|
find_package(Boost ${BOOST_VERSION} COMPONENTS
|
||||||
|
system
|
||||||
|
filesystem
|
||||||
|
iostreams
|
||||||
|
program_options
|
||||||
|
regex
|
||||||
|
REQUIRED)
|
||||||
|
|
||||||
|
add_library (_boost_headers_only INTERFACE)
|
||||||
|
add_library (boost::headers_only ALIAS _boost_headers_only)
|
||||||
|
target_include_directories (_boost_headers_only SYSTEM BEFORE INTERFACE ${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_library (_boost_filesystem INTERFACE)
|
||||||
|
add_library (_boost_iostreams INTERFACE)
|
||||||
|
add_library (_boost_program_options INTERFACE)
|
||||||
|
add_library (_boost_regex INTERFACE)
|
||||||
|
add_library (_boost_system INTERFACE)
|
||||||
|
|
||||||
|
target_link_libraries (_boost_filesystem INTERFACE ${Boost_FILESYSTEM_LIBRARY})
|
||||||
|
target_link_libraries (_boost_iostreams INTERFACE ${Boost_IOSTREAMS_LIBRARY})
|
||||||
|
target_link_libraries (_boost_program_options INTERFACE ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||||
|
target_link_libraries (_boost_regex INTERFACE ${Boost_REGEX_LIBRARY})
|
||||||
|
target_link_libraries (_boost_system INTERFACE ${Boost_SYSTEM_LIBRARY})
|
||||||
|
|
||||||
|
add_library (boost::filesystem ALIAS _boost_filesystem)
|
||||||
|
add_library (boost::iostreams ALIAS _boost_iostreams)
|
||||||
|
add_library (boost::program_options ALIAS _boost_program_options)
|
||||||
|
add_library (boost::regex ALIAS _boost_regex)
|
||||||
|
add_library (boost::system ALIAS _boost_system)
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/"
|
ARG repository="deb https://repo.clickhouse.tech/deb/stable/ main/"
|
||||||
ARG version=20.5.1.*
|
ARG version=20.5.1.*
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
|
@ -54,6 +54,8 @@ RUN apt-get --allow-unauthenticated update -y \
|
|||||||
libboost-system-dev \
|
libboost-system-dev \
|
||||||
libboost-filesystem-dev \
|
libboost-filesystem-dev \
|
||||||
libboost-thread-dev \
|
libboost-thread-dev \
|
||||||
|
libboost-iostreams-dev \
|
||||||
|
libboost-regex-dev \
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
liblz4-dev \
|
liblz4-dev \
|
||||||
libdouble-conversion-dev \
|
libdouble-conversion-dev \
|
||||||
|
@ -142,7 +142,7 @@ def parse_env_variables(build_type, compiler, sanitizer, package_type, image_typ
|
|||||||
|
|
||||||
if unbundled:
|
if unbundled:
|
||||||
# TODO: fix build with ENABLE_RDKAFKA
|
# TODO: fix build with ENABLE_RDKAFKA
|
||||||
cmake_flags.append('-DUNBUNDLED=1 -DENABLE_MYSQL=0 -DENABLE_ODBC=0 -DENABLE_REPLXX=0 -DENABLE_RDKAFKA=0 -DUSE_INTERNAL_BOOST_LIBRARY=1')
|
cmake_flags.append('-DUNBUNDLED=1 -DENABLE_MYSQL=0 -DENABLE_ODBC=0 -DENABLE_REPLXX=0 -DENABLE_RDKAFKA=0')
|
||||||
|
|
||||||
if split_binary:
|
if split_binary:
|
||||||
cmake_flags.append('-DUSE_STATIC_LIBRARIES=0 -DSPLIT_SHARED_LIBRARIES=1 -DCLICKHOUSE_SPLIT_BINARY=1')
|
cmake_flags.append('-DUSE_STATIC_LIBRARIES=0 -DSPLIT_SHARED_LIBRARIES=1 -DCLICKHOUSE_SPLIT_BINARY=1')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/"
|
ARG repository="deb https://repo.clickhouse.tech/deb/stable/ main/"
|
||||||
ARG version=20.5.1.*
|
ARG version=20.5.1.*
|
||||||
ARG gosu_ver=1.10
|
ARG gosu_ver=1.10
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ if [ -n "$(ls /docker-entrypoint-initdb.d/)" ] || [ -n "$CLICKHOUSE_DB" ]; then
|
|||||||
# create default database, if defined
|
# create default database, if defined
|
||||||
if [ -n "$CLICKHOUSE_DB" ]; then
|
if [ -n "$CLICKHOUSE_DB" ]; then
|
||||||
echo "$0: create database '$CLICKHOUSE_DB'"
|
echo "$0: create database '$CLICKHOUSE_DB'"
|
||||||
"${clickhouseclient[@]}" "CREATE DATABASE IF NOT EXISTS $CLICKHOUSE_DB";
|
"${clickhouseclient[@]}" -q "CREATE DATABASE IF NOT EXISTS $CLICKHOUSE_DB";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for f in /docker-entrypoint-initdb.d/*; do
|
for f in /docker-entrypoint-initdb.d/*; do
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/"
|
ARG repository="deb https://repo.clickhouse.tech/deb/stable/ main/"
|
||||||
ARG version=20.5.1.*
|
ARG version=20.5.1.*
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
|
@ -198,12 +198,14 @@ function get_profiles
|
|||||||
clickhouse-client --port 9001 --query "select * from system.trace_log format TSVWithNamesAndTypes" > left-trace-log.tsv ||: &
|
clickhouse-client --port 9001 --query "select * from system.trace_log format TSVWithNamesAndTypes" > left-trace-log.tsv ||: &
|
||||||
clickhouse-client --port 9001 --query "select arrayJoin(trace) addr, concat(splitByChar('/', addressToLine(addr))[-1], '#', demangle(addressToSymbol(addr)) ) name from system.trace_log group by addr format TSVWithNamesAndTypes" > left-addresses.tsv ||: &
|
clickhouse-client --port 9001 --query "select arrayJoin(trace) addr, concat(splitByChar('/', addressToLine(addr))[-1], '#', demangle(addressToSymbol(addr)) ) name from system.trace_log group by addr format TSVWithNamesAndTypes" > left-addresses.tsv ||: &
|
||||||
clickhouse-client --port 9001 --query "select * from system.metric_log format TSVWithNamesAndTypes" > left-metric-log.tsv ||: &
|
clickhouse-client --port 9001 --query "select * from system.metric_log format TSVWithNamesAndTypes" > left-metric-log.tsv ||: &
|
||||||
|
clickhouse-client --port 9001 --query "select * from system.asynchronous_metric_log format TSVWithNamesAndTypes" > left-async-metric-log.tsv ||: &
|
||||||
|
|
||||||
clickhouse-client --port 9002 --query "select * from system.query_log where type = 2 format TSVWithNamesAndTypes" > right-query-log.tsv ||: &
|
clickhouse-client --port 9002 --query "select * from system.query_log where type = 2 format TSVWithNamesAndTypes" > right-query-log.tsv ||: &
|
||||||
clickhouse-client --port 9002 --query "select * from system.query_thread_log format TSVWithNamesAndTypes" > right-query-thread-log.tsv ||: &
|
clickhouse-client --port 9002 --query "select * from system.query_thread_log format TSVWithNamesAndTypes" > right-query-thread-log.tsv ||: &
|
||||||
clickhouse-client --port 9002 --query "select * from system.trace_log format TSVWithNamesAndTypes" > right-trace-log.tsv ||: &
|
clickhouse-client --port 9002 --query "select * from system.trace_log format TSVWithNamesAndTypes" > right-trace-log.tsv ||: &
|
||||||
clickhouse-client --port 9002 --query "select arrayJoin(trace) addr, concat(splitByChar('/', addressToLine(addr))[-1], '#', demangle(addressToSymbol(addr)) ) name from system.trace_log group by addr format TSVWithNamesAndTypes" > right-addresses.tsv ||: &
|
clickhouse-client --port 9002 --query "select arrayJoin(trace) addr, concat(splitByChar('/', addressToLine(addr))[-1], '#', demangle(addressToSymbol(addr)) ) name from system.trace_log group by addr format TSVWithNamesAndTypes" > right-addresses.tsv ||: &
|
||||||
clickhouse-client --port 9002 --query "select * from system.metric_log format TSVWithNamesAndTypes" > right-metric-log.tsv ||: &
|
clickhouse-client --port 9002 --query "select * from system.metric_log format TSVWithNamesAndTypes" > right-metric-log.tsv ||: &
|
||||||
|
clickhouse-client --port 9002 --query "select * from system.asynchronous_metric_log format TSVWithNamesAndTypes" > right-async-metric-log.tsv ||: &
|
||||||
|
|
||||||
wait
|
wait
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ then
|
|||||||
# tests for use by compare.sh. Compare to merge base, because master might be
|
# tests for use by compare.sh. Compare to merge base, because master might be
|
||||||
# far in the future and have unrelated test changes.
|
# far in the future and have unrelated test changes.
|
||||||
base=$(git -C ch merge-base "$SHA_TO_TEST" master)
|
base=$(git -C ch merge-base "$SHA_TO_TEST" master)
|
||||||
git -C ch diff --name-only "$SHA_TO_TEST" "$base" | tee changed-tests.txt
|
git -C ch diff --name-only "$base" "$SHA_TO_TEST" | tee changed-tests.txt
|
||||||
if grep -vq '^tests/performance' changed-tests.txt
|
if grep -vq '^tests/performance' changed-tests.txt
|
||||||
then
|
then
|
||||||
# Have some other changes besides the tests, so truncate the test list,
|
# Have some other changes besides the tests, so truncate the test list,
|
||||||
@ -131,5 +131,5 @@ done
|
|||||||
|
|
||||||
dmesg -T > dmesg.log
|
dmesg -T > dmesg.log
|
||||||
|
|
||||||
7z a '-x!*/tmp' /output/output.7z ./*.{log,tsv,html,txt,rep,svg,columns} {right,left}/{performance,db/preprocessed_configs,scripts} report analyze
|
7z a '-x!*/tmp' /output/output.7z ./*.{log,tsv,html,txt,rep,svg,columns} {right,left}/{performance,db/preprocessed_configs,scripts} report analyze benchmark
|
||||||
cp compare.log /output
|
cp compare.log /output
|
||||||
|
@ -64,7 +64,7 @@ You can also download and install packages manually from [here](https://repo.cli
|
|||||||
|
|
||||||
It is recommended to use official pre-compiled `tgz` archives for all Linux distributions, where installation of `deb` or `rpm` packages is not possible.
|
It is recommended to use official pre-compiled `tgz` archives for all Linux distributions, where installation of `deb` or `rpm` packages is not possible.
|
||||||
|
|
||||||
The required version can be downloaded with `curl` or `wget` from repository https://repo.yandex.ru/clickhouse/tgz/.
|
The required version can be downloaded with `curl` or `wget` from repository https://repo.clickhouse.tech/tgz/.
|
||||||
After that downloaded archives should be unpacked and installed with installation scripts. Example for the latest version:
|
After that downloaded archives should be unpacked and installed with installation scripts. Example for the latest version:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -83,6 +83,10 @@ SELECT * FROM system.asynchronous_metrics LIMIT 10
|
|||||||
- [system.events](#system_tables-events) — Contains a number of events that have occurred.
|
- [system.events](#system_tables-events) — Contains a number of events that have occurred.
|
||||||
- [system.metric\_log](#system_tables-metric_log) — Contains a history of metrics values from tables `system.metrics` и `system.events`.
|
- [system.metric\_log](#system_tables-metric_log) — Contains a history of metrics values from tables `system.metrics` и `system.events`.
|
||||||
|
|
||||||
|
## system.asynchronous_metric_log {#system-tables-async-log}
|
||||||
|
|
||||||
|
Contains the historical values for `system.asynchronous_log` (see [system.asynchronous_metrics](#system_tables-asynchronous_metrics))
|
||||||
|
|
||||||
## system.clusters {#system-clusters}
|
## system.clusters {#system-clusters}
|
||||||
|
|
||||||
Contains information about clusters available in the config file and the servers in them.
|
Contains information about clusters available in the config file and the servers in them.
|
||||||
|
@ -316,7 +316,7 @@ Result:
|
|||||||
The function takes as arguments a set of conditions from 1 to 32 arguments of type `UInt8` that indicate whether a certain condition was met for the event.
|
The function takes as arguments a set of conditions from 1 to 32 arguments of type `UInt8` that indicate whether a certain condition was met for the event.
|
||||||
Any condition can be specified as an argument (as in [WHERE](../../sql-reference/statements/select/where.md#select-where)).
|
Any condition can be specified as an argument (as in [WHERE](../../sql-reference/statements/select/where.md#select-where)).
|
||||||
|
|
||||||
The conditions, except the first, apply in pairs: the result of the second will be true if the first and second are true, of the third if the first and fird are true, etc.
|
The conditions, except the first, apply in pairs: the result of the second will be true if the first and second are true, of the third if the first and third are true, etc.
|
||||||
|
|
||||||
**Syntax**
|
**Syntax**
|
||||||
|
|
||||||
|
@ -1805,7 +1805,7 @@ For more information see [parameters](#agg_functions-stochasticlinearregression-
|
|||||||
stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Fitting
|
**1.** Fitting
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
@ -1813,7 +1813,7 @@ stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
|||||||
|
|
||||||
Predicted labels have to be in \[-1, 1\].
|
Predicted labels have to be in \[-1, 1\].
|
||||||
|
|
||||||
1. Predicting
|
**2.** Predicting
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ CREATE TABLE t
|
|||||||
) ENGINE = ...
|
) ENGINE = ...
|
||||||
```
|
```
|
||||||
|
|
||||||
[uniq](../../sql-reference/aggregate-functions/reference.md#agg_function-uniq), anyIf ([any](../../sql-reference/aggregate-functions/reference.md#agg_function-any)+[If](../../sql-reference/aggregate-functions/combinators.md#agg-functions-combinator-if)) and [quantiles](../../sql-reference/aggregate-functions/reference.md) are the aggregate functions supported in ClickHouse.
|
[uniq](../../sql-reference/aggregate-functions/reference.md#agg_function-uniq), anyIf ([any](../../sql-reference/aggregate-functions/reference.md#agg_function-any)+[If](../../sql-reference/aggregate-functions/combinators.md#agg-functions-combinator-if)) and [quantiles](../../sql-reference/aggregate-functions/reference.md#quantiles) are the aggregate functions supported in ClickHouse.
|
||||||
|
|
||||||
## Usage {#usage}
|
## Usage {#usage}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ También puede descargar e instalar paquetes manualmente desde [aqui](https://re
|
|||||||
|
|
||||||
Se recomienda utilizar pre-compilado oficial `tgz` para todas las distribuciones de Linux, donde la instalación de `deb` o `rpm` paquetes no es posible.
|
Se recomienda utilizar pre-compilado oficial `tgz` para todas las distribuciones de Linux, donde la instalación de `deb` o `rpm` paquetes no es posible.
|
||||||
|
|
||||||
La versión requerida se puede descargar con `curl` o `wget` desde el repositorio https://repo.yandex.ru/clickhouse/tgz/.
|
La versión requerida se puede descargar con `curl` o `wget` desde el repositorio https://repo.clickhouse.tech/tgz/.
|
||||||
Después de eso, los archivos descargados deben desempaquetarse e instalarse con scripts de instalación. Ejemplo para la última versión:
|
Después de eso, los archivos descargados deben desempaquetarse e instalarse con scripts de instalación. Ejemplo para la última versión:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -67,7 +67,7 @@ sudo yum install clickhouse-server clickhouse-client
|
|||||||
|
|
||||||
توصیه می شود به استفاده از رسمی از پیش وارد شده `tgz` بایگانی برای همه توزیع های لینوکس, که نصب و راه اندازی `deb` یا `rpm` بسته امکان پذیر نیست.
|
توصیه می شود به استفاده از رسمی از پیش وارد شده `tgz` بایگانی برای همه توزیع های لینوکس, که نصب و راه اندازی `deb` یا `rpm` بسته امکان پذیر نیست.
|
||||||
|
|
||||||
نسخه مورد نیاز را می توان با دانلود `curl` یا `wget` از مخزن https://repo.yandex.ru/clickhouse/tgz/.
|
نسخه مورد نیاز را می توان با دانلود `curl` یا `wget` از مخزن https://repo.clickhouse.tech/tgz/.
|
||||||
پس از که دانلود بایگانی باید غیر بستهای و نصب شده با اسکریپت نصب و راه اندازی. به عنوان مثال برای جدیدترین نسخه:
|
پس از که دانلود بایگانی باید غیر بستهای و نصب شده با اسکریپت نصب و راه اندازی. به عنوان مثال برای جدیدترین نسخه:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -66,7 +66,7 @@ Vous pouvez également télécharger et installer des paquets manuellement à pa
|
|||||||
|
|
||||||
Il est recommandé d'utiliser officiel pré-compilé `tgz` archives pour toutes les distributions Linux, où l'installation de `deb` ou `rpm` les emballages n'est pas possible.
|
Il est recommandé d'utiliser officiel pré-compilé `tgz` archives pour toutes les distributions Linux, où l'installation de `deb` ou `rpm` les emballages n'est pas possible.
|
||||||
|
|
||||||
La version requise peut être téléchargée avec `curl` ou `wget` depuis le référentiel https://repo.yandex.ru/clickhouse/tgz/.
|
La version requise peut être téléchargée avec `curl` ou `wget` depuis le référentiel https://repo.clickhouse.tech/tgz/.
|
||||||
Après cela, les archives téléchargées doivent être décompressées et installées avec des scripts d'installation. Exemple pour la dernière version:
|
Après cela, les archives téléchargées doivent être décompressées et installées avec des scripts d'installation. Exemple pour la dernière version:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -66,7 +66,7 @@ sudo yum install clickhouse-server clickhouse-client
|
|||||||
|
|
||||||
公式の事前コンパイルを使用することをお勧めします `tgz` のインストール `deb` または `rpm` パッケージはできません。
|
公式の事前コンパイルを使用することをお勧めします `tgz` のインストール `deb` または `rpm` パッケージはできません。
|
||||||
|
|
||||||
必要なバージョンは次のとおりです `curl` または `wget` リポジトリからhttps://repo.yandex.ru/clickhouse/tgz/.
|
必要なバージョンは次のとおりです `curl` または `wget` リポジトリからhttps://repo.clickhouse.tech/tgz/.
|
||||||
その後、アーカイブをダウンロードは開梱と設置と設置のためのイントロダクションです。 最新バージョンの例:
|
その後、アーカイブをダウンロードは開梱と設置と設置のためのイントロダクションです。 最新バージョンの例:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -34,8 +34,8 @@ $ grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not
|
|||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
sudo yum install yum-utils
|
sudo yum install yum-utils
|
||||||
sudo rpm --import https://repo.yandex.ru/clickhouse/CLICKHOUSE-KEY.GPG
|
sudo rpm --import https://repo.clickhouse.tech/CLICKHOUSE-KEY.GPG
|
||||||
sudo yum-config-manager --add-repo https://repo.yandex.ru/clickhouse/rpm/stable/x86_64
|
sudo yum-config-manager --add-repo https://repo.clickhouse.tech/rpm/stable/x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
Для использования наиболее свежих версий нужно заменить `stable` на `testing` (рекомендуется для тестовых окружений). Также иногда доступен `prestable`.
|
Для использования наиболее свежих версий нужно заменить `stable` на `testing` (рекомендуется для тестовых окружений). Также иногда доступен `prestable`.
|
||||||
@ -46,21 +46,21 @@ sudo yum-config-manager --add-repo https://repo.yandex.ru/clickhouse/rpm/stable/
|
|||||||
sudo yum install clickhouse-server clickhouse-client
|
sudo yum install clickhouse-server clickhouse-client
|
||||||
```
|
```
|
||||||
|
|
||||||
Также есть возможность установить пакеты вручную, скачав отсюда: https://repo.yandex.ru/clickhouse/rpm/stable/x86\_64.
|
Также есть возможность установить пакеты вручную, скачав отсюда: https://repo.clickhouse.tech/rpm/stable/x86\_64.
|
||||||
|
|
||||||
### Из Tgz архивов {#from-tgz-archives}
|
### Из Tgz архивов {#from-tgz-archives}
|
||||||
|
|
||||||
Команда ClickHouse в Яндексе рекомендует использовать предкомпилированные бинарники из `tgz` архивов для всех дистрибутивов, где невозможна установка `deb` и `rpm` пакетов.
|
Команда ClickHouse в Яндексе рекомендует использовать предкомпилированные бинарники из `tgz` архивов для всех дистрибутивов, где невозможна установка `deb` и `rpm` пакетов.
|
||||||
|
|
||||||
Интересующую версию архивов можно скачать вручную с помощью `curl` или `wget` из репозитория https://repo.yandex.ru/clickhouse/tgz/.
|
Интересующую версию архивов можно скачать вручную с помощью `curl` или `wget` из репозитория https://repo.clickhouse.tech/tgz/.
|
||||||
После этого архивы нужно распаковать и воспользоваться скриптами установки. Пример установки самой свежей версии:
|
После этого архивы нужно распаковать и воспользоваться скриптами установки. Пример установки самой свежей версии:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
export LATEST_VERSION=`curl https://api.github.com/repos/ClickHouse/ClickHouse/tags 2>/dev/null | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1`
|
export LATEST_VERSION=`curl https://api.github.com/repos/ClickHouse/ClickHouse/tags 2>/dev/null | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1`
|
||||||
curl -O https://repo.yandex.ru/clickhouse/tgz/clickhouse-common-static-$LATEST_VERSION.tgz
|
curl -O https://repo.clickhouse.tech/tgz/clickhouse-common-static-$LATEST_VERSION.tgz
|
||||||
curl -O https://repo.yandex.ru/clickhouse/tgz/clickhouse-common-static-dbg-$LATEST_VERSION.tgz
|
curl -O https://repo.clickhouse.tech/tgz/clickhouse-common-static-dbg-$LATEST_VERSION.tgz
|
||||||
curl -O https://repo.yandex.ru/clickhouse/tgz/clickhouse-server-$LATEST_VERSION.tgz
|
curl -O https://repo.clickhouse.tech/tgz/clickhouse-server-$LATEST_VERSION.tgz
|
||||||
curl -O https://repo.yandex.ru/clickhouse/tgz/clickhouse-client-$LATEST_VERSION.tgz
|
curl -O https://repo.clickhouse.tech/tgz/clickhouse-client-$LATEST_VERSION.tgz
|
||||||
|
|
||||||
tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz
|
tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz
|
||||||
sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh
|
sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh
|
||||||
|
@ -92,9 +92,11 @@ def test_single_page(input_path, lang):
|
|||||||
logging.warning('Found %d duplicate anchor points' % duplicate_anchor_points)
|
logging.warning('Found %d duplicate anchor points' % duplicate_anchor_points)
|
||||||
|
|
||||||
if links_to_nowhere:
|
if links_to_nowhere:
|
||||||
logging.warning(f'Found {links_to_nowhere} links to nowhere in {lang}')
|
|
||||||
if lang == 'en': # TODO: check all languages again
|
if lang == 'en': # TODO: check all languages again
|
||||||
|
logging.error(f'Found {links_to_nowhere} links to nowhere in {lang}')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
logging.warning(f'Found {links_to_nowhere} links to nowhere in {lang}')
|
||||||
|
|
||||||
if len(anchor_points) <= 10:
|
if len(anchor_points) <= 10:
|
||||||
logging.error('Html parsing is probably broken')
|
logging.error('Html parsing is probably broken')
|
||||||
|
@ -66,7 +66,7 @@ Ayrıca paketleri manuel olarak indirebilir ve yükleyebilirsiniz [burada](https
|
|||||||
|
|
||||||
Resmi önceden derlenmiş kullanılması tavsiye edilir `tgz` Arch ,iv ,es for tüm Linux dağıtım installationları, kurulumu `deb` veya `rpm` paketler mümkün değildir.
|
Resmi önceden derlenmiş kullanılması tavsiye edilir `tgz` Arch ,iv ,es for tüm Linux dağıtım installationları, kurulumu `deb` veya `rpm` paketler mümkün değildir.
|
||||||
|
|
||||||
Gerekli sürümü ile indirilebilir `curl` veya `wget` depo fromdan https://repo.yandex.ru/clickhouse/tgz/.
|
Gerekli sürümü ile indirilebilir `curl` veya `wget` depo fromdan https://repo.clickhouse.tech/tgz/.
|
||||||
Bundan sonra indirilen arşivler açılmalı ve kurulum komut dosyaları ile kurulmalıdır. En son sürüm için örnek:
|
Bundan sonra indirilen arşivler açılmalı ve kurulum komut dosyaları ile kurulmalıdır. En son sürüm için örnek:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_priority: 31
|
toc_priority: 31
|
||||||
toc_title: "\u61D2\u60F0"
|
toc_title: "\u61D2\u60F0"
|
||||||
---
|
---
|
||||||
|
|
||||||
# 懒惰 {#lazy}
|
# 延时引擎Lazy {#lazy}
|
||||||
|
|
||||||
仅将表保留在RAM中 `expiration_time_in_seconds` 上次访问后几秒钟。 只能与\*日志表一起使用。
|
在距最近一次访问间隔`expiration_time_in_seconds`时间段内,将表保存在内存中,仅适用于 \*Log引擎表
|
||||||
|
|
||||||
它针对存储许多小\*日志表进行了优化,访问之间存在较长的时间间隔。
|
由于针对这类表的访问间隔较长,对保存大量小的 \*Log引擎表进行了优化,
|
||||||
|
|
||||||
## 创建数据库 {#creating-a-database}
|
## 创建数据库 {#creating-a-database}
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ Yandex ClickHouse团队建议使用官方预编译的`rpm`软件包,用于Cent
|
|||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
sudo yum install yum-utils
|
sudo yum install yum-utils
|
||||||
sudo rpm --import https://repo.yandex.ru/clickhouse/CLICKHOUSE-KEY.GPG
|
sudo rpm --import https://repo.clickhouse.tech/CLICKHOUSE-KEY.GPG
|
||||||
sudo yum-config-manager --add-repo https://repo.yandex.ru/clickhouse/rpm/stable/x86_64
|
sudo yum-config-manager --add-repo https://repo.clickhouse.tech/rpm/stable/x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
如果您想使用最新版本,请将`stable`替换为`testing`(建议您在测试环境中使用)。
|
如果您想使用最新版本,请将`stable`替换为`testing`(建议您在测试环境中使用)。
|
||||||
@ -46,7 +46,7 @@ sudo yum-config-manager --add-repo https://repo.yandex.ru/clickhouse/rpm/stable/
|
|||||||
sudo yum install clickhouse-server clickhouse-client
|
sudo yum install clickhouse-server clickhouse-client
|
||||||
```
|
```
|
||||||
|
|
||||||
您也可以从此处手动下载和安装软件包:https://repo.yandex.ru/clickhouse/rpm/stable/x86_64。
|
您也可以从此处手动下载和安装软件包:https://repo.clickhouse.tech/rpm/stable/x86_64。
|
||||||
|
|
||||||
### 来自Docker {#from-docker-image}
|
### 来自Docker {#from-docker-image}
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_priority: 61
|
toc_priority: 61
|
||||||
toc_title: "\uFF82\u6697\uFF6A\uFF82\u6C3E\u73AF\u50AC\uFF82\u56E3"
|
toc_title: "性能测试"
|
||||||
---
|
---
|
||||||
|
|
||||||
# ツ暗ェツ氾环催ツ団 {#clickhouse-benchmark}
|
# 性能测试 {#clickhouse-benchmark}
|
||||||
|
|
||||||
连接到ClickHouse服务器并重复发送指定的查询。
|
连接到ClickHouse服务器并重复发送指定的查询。
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ $ echo "single query" | clickhouse-benchmark [keys]
|
|||||||
$ clickhouse-benchmark [keys] <<< "single query"
|
$ clickhouse-benchmark [keys] <<< "single query"
|
||||||
```
|
```
|
||||||
|
|
||||||
如果要发送一组查询,请创建一个文本文件,并将每个查询放在此文件中的单个字符串上。 例如:
|
如果要发送一组查询,请创建一个文本文件,并将每个查询的字符串放在此文件中。 例如:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT * FROM system.numbers LIMIT 10000000
|
SELECT * FROM system.numbers LIMIT 10000000
|
||||||
@ -34,15 +32,15 @@ SELECT 1
|
|||||||
clickhouse-benchmark [keys] < queries_file
|
clickhouse-benchmark [keys] < queries_file
|
||||||
```
|
```
|
||||||
|
|
||||||
## 键 {#clickhouse-benchmark-keys}
|
## keys参数 {#clickhouse-benchmark-keys}
|
||||||
|
|
||||||
- `-c N`, `--concurrency=N` — Number of queries that `clickhouse-benchmark` 同时发送。 默认值:1。
|
- `-c N`, `--concurrency=N` — Number of queries that `clickhouse-benchmark` 同时发送。 默认值:1。
|
||||||
- `-d N`, `--delay=N` — Interval in seconds between intermediate reports (set 0 to disable reports). Default value: 1.
|
- `-d N`, `--delay=N` — Interval in seconds between intermediate reports (set 0 to disable reports). Default value: 1.
|
||||||
- `-h WORD`, `--host=WORD` — Server host. Default value: `localhost`. 为 [比较模式](#clickhouse-benchmark-comparison-mode) 您可以使用多个 `-h` 钥匙
|
- `-h WORD`, `--host=WORD` — Server host. Default value: `localhost`. 为 [比较模式](#clickhouse-benchmark-comparison-mode) 您可以使用多个 `-h` 参数
|
||||||
- `-p N`, `--port=N` — Server port. Default value: 9000. For the [比较模式](#clickhouse-benchmark-comparison-mode) 您可以使用多个 `-p` 钥匙
|
- `-p N`, `--port=N` — Server port. Default value: 9000. For the [比较模式](#clickhouse-benchmark-comparison-mode) 您可以使用多个 `-p` 钥匙
|
||||||
- `-i N`, `--iterations=N` — Total number of queries. Default value: 0.
|
- `-i N`, `--iterations=N` — 查询的总次数. Default value: 0.
|
||||||
- `-r`, `--randomize` — Random order of queries execution if there is more then one input query.
|
- `-r`, `--randomize` — 有多个查询时,以随机顺序执行.
|
||||||
- `-s`, `--secure` — Using TLS connection.
|
- `-s`, `--secure` — 使用TLS安全连接.
|
||||||
- `-t N`, `--timelimit=N` — Time limit in seconds. `clickhouse-benchmark` 达到指定的时间限制时停止发送查询。 默认值:0(禁用时间限制)。
|
- `-t N`, `--timelimit=N` — Time limit in seconds. `clickhouse-benchmark` 达到指定的时间限制时停止发送查询。 默认值:0(禁用时间限制)。
|
||||||
- `--confidence=N` — Level of confidence for T-test. Possible values: 0 (80%), 1 (90%), 2 (95%), 3 (98%), 4 (99%), 5 (99.5%). Default value: 5. In the [比较模式](#clickhouse-benchmark-comparison-mode) `clickhouse-benchmark` 执行 [独立双样本学生的t测试](https://en.wikipedia.org/wiki/Student%27s_t-test#Independent_two-sample_t-test) 测试以确定两个分布是否与所选置信水平没有不同。
|
- `--confidence=N` — Level of confidence for T-test. Possible values: 0 (80%), 1 (90%), 2 (95%), 3 (98%), 4 (99%), 5 (99.5%). Default value: 5. In the [比较模式](#clickhouse-benchmark-comparison-mode) `clickhouse-benchmark` 执行 [独立双样本学生的t测试](https://en.wikipedia.org/wiki/Student%27s_t-test#Independent_two-sample_t-test) 测试以确定两个分布是否与所选置信水平没有不同。
|
||||||
- `--cumulative` — Printing cumulative data instead of data per interval.
|
- `--cumulative` — Printing cumulative data instead of data per interval.
|
||||||
@ -51,14 +49,14 @@ clickhouse-benchmark [keys] < queries_file
|
|||||||
- `--user=USERNAME` — ClickHouse user name. Default value: `default`.
|
- `--user=USERNAME` — ClickHouse user name. Default value: `default`.
|
||||||
- `--password=PSWD` — ClickHouse user password. Default value: empty string.
|
- `--password=PSWD` — ClickHouse user password. Default value: empty string.
|
||||||
- `--stacktrace` — Stack traces output. When the key is set, `clickhouse-bencmark` 输出异常的堆栈跟踪。
|
- `--stacktrace` — Stack traces output. When the key is set, `clickhouse-bencmark` 输出异常的堆栈跟踪。
|
||||||
- `--stage=WORD` — Query processing stage at server. ClickHouse stops query processing and returns answer to `clickhouse-benchmark` 在指定的阶段。 可能的值: `complete`, `fetch_columns`, `with_mergeable_state`. 默认值: `complete`.
|
- `--stage=WORD` — 查询请求的服务端处理状态. 在特定阶段Clickhouse会停止查询处理,并返回结果给`clickhouse-benchmark`。 可能的值: `complete`, `fetch_columns`, `with_mergeable_state`. 默认值: `complete`.
|
||||||
- `--help` — Shows the help message.
|
- `--help` — Shows the help message.
|
||||||
|
|
||||||
如果你想申请一些 [设置](../../operations/settings/index.md) 对于查询,请将它们作为键传递 `--<session setting name>= SETTING_VALUE`. 例如, `--max_memory_usage=1048576`.
|
如果你想在查询时应用上述的部分参数 [设置](../../operations/settings/index.md) ,请将它们作为键传递 `--<session setting name>= SETTING_VALUE`. 例如, `--max_memory_usage=1048576`.
|
||||||
|
|
||||||
## 输出 {#clickhouse-benchmark-output}
|
## 输出 {#clickhouse-benchmark-output}
|
||||||
|
|
||||||
默认情况下, `clickhouse-benchmark` 每个报表 `--delay` 间隔。
|
默认情况下, `clickhouse-benchmark` 按照 `--delay` 参数间隔输出结果。
|
||||||
|
|
||||||
报告示例:
|
报告示例:
|
||||||
|
|
||||||
@ -83,27 +81,27 @@ localhost:9000, queries 10, QPS: 6.772, RPS: 67904487.440, MiB/s: 518.070, resul
|
|||||||
99.990% 0.150 sec.
|
99.990% 0.150 sec.
|
||||||
```
|
```
|
||||||
|
|
||||||
在报告中,您可以找到:
|
在结果报告中,您可以找到:
|
||||||
|
|
||||||
- 在查询的数量 `Queries executed:` 场。
|
- 查询数量:参见`Queries executed:`字段。
|
||||||
|
|
||||||
- 状态字符串包含(按顺序):
|
- 状态码(按顺序给出):
|
||||||
|
|
||||||
- ClickHouse服务器的端点。
|
- ClickHouse服务器的连接信息。
|
||||||
- 已处理的查询数。
|
- 已处理的查询数。
|
||||||
- QPS:QPS:在指定的时间段内每秒执行多少个查询服务器 `--delay` 争论。
|
- QPS:服务端每秒处理的查询数量
|
||||||
- RPS:在指定的时间段内,服务器每秒读取多少行 `--delay` 争论。
|
- RPS:服务器每秒读取多少行
|
||||||
- MiB/s:在指定的时间段内每秒读取多少mebibytes服务器 `--delay` 争论。
|
- MiB/s:服务器每秒读取多少字节的数据
|
||||||
- 结果RPS:在指定的时间段内,服务器每秒放置到查询结果的行数 `--delay` 争论。
|
- 结果RPS:服务端每秒生成多少行的结果集数据
|
||||||
- 结果MiB/s.在指定的时间段内,服务器每秒将多少mebibytes放置到查询结果中 `--delay` 争论。
|
- 结果MiB/s.服务端每秒生成多少字节的结果集数据
|
||||||
|
|
||||||
- 查询执行时间的百分位数。
|
- 查询执行时间的百分比。
|
||||||
|
|
||||||
## 比较模式 {#clickhouse-benchmark-comparison-mode}
|
## 对比模式 {#clickhouse-benchmark-comparison-mode}
|
||||||
|
|
||||||
`clickhouse-benchmark` 可以比较两个正在运行的ClickHouse服务器的性能。
|
`clickhouse-benchmark` 可以比较两个正在运行的ClickHouse服务器的性能。
|
||||||
|
|
||||||
要使用比较模式,请通过以下两对指定两个服务器的端点 `--host`, `--port` 钥匙 键在参数列表中的位置匹配在一起,第一 `--host` 与第一匹配 `--port` 等等。 `clickhouse-benchmark` 建立到两个服务器的连接,然后发送查询。 每个查询寻址到随机选择的服务器。 每个服务器的结果分别显示。
|
要使用对比模式,分别为每个服务器配置各自的`--host`, `--port`参数。`clickhouse-benchmark` 会根据设置的参数建立到各个Server的连接并发送请求。每个查询请求会随机发送到某个服务器。输出结果会按服务器分组输出
|
||||||
|
|
||||||
## 示例 {#clickhouse-benchmark-example}
|
## 示例 {#clickhouse-benchmark-example}
|
||||||
|
|
||||||
|
@ -1,51 +1,49 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_priority: 37
|
toc_priority: 37
|
||||||
toc_title: "\u7EC4\u5408\u5668"
|
toc_title: 聚合函数组合器
|
||||||
---
|
---
|
||||||
|
|
||||||
# 聚合函数组合器 {#aggregate_functions_combinators}
|
# 聚合函数组合器 {#aggregate_functions_combinators}
|
||||||
|
|
||||||
聚合函数的名称可以附加一个后缀。 这改变了聚合函数的工作方式。
|
聚合函数的名称可以附加一个后缀。 这改变了聚合函数的工作方式。
|
||||||
|
|
||||||
## -如果 {#agg-functions-combinator-if}
|
## -If {#agg-functions-combinator-if}
|
||||||
|
|
||||||
The suffix -If can be appended to the name of any aggregate function. In this case, the aggregate function accepts an extra argument – a condition (Uint8 type). The aggregate function processes only the rows that trigger the condition. If the condition was not triggered even once, it returns a default value (usually zeros or empty strings).
|
-If可以加到任何聚合函数之后。加了-If之后聚合函数需要接受一个额外的参数,一个条件(Uint8类型),如果条件满足,那聚合函数处理当前的行数据,如果不满足,那返回默认值(通常是0或者空字符串)。
|
||||||
|
|
||||||
例: `sumIf(column, cond)`, `countIf(cond)`, `avgIf(x, cond)`, `quantilesTimingIf(level1, level2)(x, cond)`, `argMinIf(arg, val, cond)` 等等。
|
例: `sumIf(column, cond)`, `countIf(cond)`, `avgIf(x, cond)`, `quantilesTimingIf(level1, level2)(x, cond)`, `argMinIf(arg, val, cond)` 等等。
|
||||||
|
|
||||||
使用条件聚合函数,您可以一次计算多个条件的聚合,而无需使用子查询和 `JOIN`例如,在Yandex的。Metrica,条件聚合函数用于实现段比较功能。
|
使用条件聚合函数,您可以一次计算多个条件的聚合,而无需使用子查询和 `JOIN`例如,在Yandex.Metrica,条件聚合函数用于实现段比较功能。
|
||||||
|
|
||||||
## -阵列 {#agg-functions-combinator-array}
|
## -Array {#agg-functions-combinator-array}
|
||||||
|
|
||||||
-Array后缀可以附加到任何聚合函数。 在这种情况下,聚合函数采用的参数 ‘Array(T)’ 类型(数组)而不是 ‘T’ 类型参数。 如果聚合函数接受多个参数,则它必须是长度相等的数组。 在处理数组时,聚合函数的工作方式与所有数组元素的原始聚合函数类似。
|
-Array后缀可以附加到任何聚合函数。 在这种情况下,聚合函数采用的参数 ‘Array(T)’ 类型(数组)而不是 ‘T’ 类型参数。 如果聚合函数接受多个参数,则它必须是长度相等的数组。 在处理数组时,聚合函数的工作方式与所有数组元素的原始聚合函数类似。
|
||||||
|
|
||||||
示例1: `sumArray(arr)` -总计所有的所有元素 ‘arr’ 阵列。 在这个例子中,它可以更简单地编写: `sum(arraySum(arr))`.
|
示例1: `sumArray(arr)` -总计所有的所有元素 ‘arr’ 阵列。在这个例子中,它可以更简单地编写: `sum(arraySum(arr))`.
|
||||||
|
|
||||||
示例2: `uniqArray(arr)` – Counts the number of unique elements in all ‘arr’ 阵列。 这可以做一个更简单的方法: `uniq(arrayJoin(arr))`,但它并不总是可以添加 ‘arrayJoin’ 到查询。
|
示例2: `uniqArray(arr)` – 计算‘arr’中唯一元素的个数。这可以是一个更简单的方法: `uniq(arrayJoin(arr))`,但它并不总是可以添加 ‘arrayJoin’ 到查询。
|
||||||
|
|
||||||
-如果和-阵列可以组合。 然而, ‘Array’ 必须先来,然后 ‘If’. 例: `uniqArrayIf(arr, cond)`, `quantilesTimingArrayIf(level1, level2)(arr, cond)`. 由于这个顺序,该 ‘cond’ 参数不会是数组。
|
如果和-If组合,‘Array’ 必须先来,然后 ‘If’. 例: `uniqArrayIf(arr, cond)`, `quantilesTimingArrayIf(level1, level2)(arr, cond)`。由于这个顺序,该 ‘cond’ 参数不会是数组。
|
||||||
|
|
||||||
## -州 {#agg-functions-combinator-state}
|
## -State {#agg-functions-combinator-state}
|
||||||
|
|
||||||
如果应用此combinator,则聚合函数不会返回结果值(例如唯一值的数量 [uniq](reference.md#agg_function-uniq) 函数),但聚合的中间状态(用于 `uniq`,这是用于计算唯一值的数量的散列表)。 这是一个 `AggregateFunction(...)` 可用于进一步处理或存储在表中以完成聚合。
|
如果应用此combinator,则聚合函数不会返回结果值(例如唯一值的数量 [uniq](reference.md#agg_function-uniq) 函数),但是返回聚合的中间状态(对于 `uniq`,返回的是计算唯一值的数量的哈希表)。 这是一个 `AggregateFunction(...)` 可用于进一步处理或存储在表中以完成稍后的聚合。
|
||||||
|
|
||||||
要使用这些状态,请使用:
|
要使用这些状态,请使用:
|
||||||
|
|
||||||
- [AggregatingMergeTree](../../engines/table-engines/mergetree-family/aggregatingmergetree.md) 表引擎。
|
- [AggregatingMergeTree](../../engines/table-engines/mergetree-family/aggregatingmergetree.md) 表引擎。
|
||||||
- [最后聚会](../../sql-reference/functions/other-functions.md#function-finalizeaggregation) 功能。
|
- [finalizeAggregation](../../sql-reference/functions/other-functions.md#function-finalizeaggregation) 功能。
|
||||||
- [跑累积](../../sql-reference/functions/other-functions.md#function-runningaccumulate) 功能。
|
- [runningAccumulate](../../sql-reference/functions/other-functions.md#function-runningaccumulate) 功能。
|
||||||
- [-合并](#aggregate_functions_combinators-merge) combinator
|
- [-Merge](#aggregate_functions_combinators-merge) combinator
|
||||||
- [-MergeState](#aggregate_functions_combinators-mergestate) combinator
|
- [-MergeState](#aggregate_functions_combinators-mergestate) combinator
|
||||||
|
|
||||||
## -合并 {#aggregate_functions_combinators-merge}
|
## -Merge {#aggregate_functions_combinators-merge}
|
||||||
|
|
||||||
如果应用此组合器,则聚合函数将中间聚合状态作为参数,组合状态以完成聚合,并返回结果值。
|
如果应用此组合器,则聚合函数将中间聚合状态作为参数,组合状态以完成聚合,并返回结果值。
|
||||||
|
|
||||||
## -MergeState {#aggregate_functions_combinators-mergestate}
|
## -MergeState {#aggregate_functions_combinators-mergestate}
|
||||||
|
|
||||||
以与-Merge combinator相同的方式合并中间聚合状态。 但是,它不会返回结果值,而是返回中间聚合状态,类似于-State combinator。
|
以与-Merge 相同的方式合并中间聚合状态。 但是,它不会返回结果值,而是返回中间聚合状态,类似于-State。
|
||||||
|
|
||||||
## -ForEach {#agg-functions-combinator-foreach}
|
## -ForEach {#agg-functions-combinator-foreach}
|
||||||
|
|
||||||
@ -55,7 +53,7 @@ The suffix -If can be appended to the name of any aggregate function. In this ca
|
|||||||
|
|
||||||
更改聚合函数的行为。
|
更改聚合函数的行为。
|
||||||
|
|
||||||
如果聚合函数没有输入值,则使用此combinator,它返回其返回数据类型的默认值。 适用于可以采用空输入数据的聚合函数。
|
如果聚合函数没有输入值,则使用此组合器它返回其返回数据类型的默认值。 适用于可以采用空输入数据的聚合函数。
|
||||||
|
|
||||||
`-OrDefault` 可与其他组合器一起使用。
|
`-OrDefault` 可与其他组合器一起使用。
|
||||||
|
|
||||||
@ -67,7 +65,7 @@ The suffix -If can be appended to the name of any aggregate function. In this ca
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `x` — Aggregate function parameters.
|
- `x` — 聚合函数参数。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -174,7 +172,7 @@ FROM
|
|||||||
└────────────────────────────────┘
|
└────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## -重新采样 {#agg-functions-combinator-resample}
|
## -Resample {#agg-functions-combinator-resample}
|
||||||
|
|
||||||
允许您将数据划分为组,然后单独聚合这些组中的数据。 通过将一列中的值拆分为间隔来创建组。
|
允许您将数据划分为组,然后单独聚合这些组中的数据。 通过将一列中的值拆分为间隔来创建组。
|
||||||
|
|
||||||
@ -184,19 +182,19 @@ FROM
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `start` — Starting value of the whole required interval for `resampling_key` 值。
|
- `start` — `resampling_key` 开始值。
|
||||||
- `stop` — Ending value of the whole required interval for `resampling_key` 值。 整个时间间隔不包括 `stop` 价值 `[start, stop)`.
|
- `stop` — `resampling_key` 结束边界。 区间内部不包含 `stop` 值,即 `[start, stop)`.
|
||||||
- `step` — Step for separating the whole interval into subintervals. The `aggFunction` 在每个子区间上独立执行。
|
- `step` — 分组的步长。 The `aggFunction` 在每个子区间上独立执行。
|
||||||
- `resampling_key` — Column whose values are used for separating data into intervals.
|
- `resampling_key` — 取样列,被用来分组.
|
||||||
- `aggFunction_params` — `aggFunction` 参数。
|
- `aggFunction_params` — `aggFunction` 参数。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 阵列 `aggFunction` 每个子区间的结果。
|
- `aggFunction` 每个子区间的结果,结果为数组。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
考虑一下 `people` 具有以下数据的表:
|
考虑一下 `people` 表具有以下数据的表结构:
|
||||||
|
|
||||||
``` text
|
``` text
|
||||||
┌─name───┬─age─┬─wage─┐
|
┌─name───┬─age─┬─wage─┐
|
||||||
@ -209,9 +207,9 @@ FROM
|
|||||||
└────────┴─────┴──────┘
|
└────────┴─────┴──────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
让我们得到的人的名字,他们的年龄在于的时间间隔 `[30,60)` 和 `[60,75)`. 由于我们使用整数表示的年龄,我们得到的年龄 `[30, 59]` 和 `[60,74]` 间隔。
|
让我们得到的人的名字,他们的年龄在于的时间间隔 `[30,60)` 和 `[60,75)`。 由于我们使用整数表示的年龄,我们得到的年龄 `[30, 59]` 和 `[60,74]` 间隔。
|
||||||
|
|
||||||
要在数组中聚合名称,我们使用 [groupArray](reference.md#agg_function-grouparray) 聚合函数。 这需要一个参数。 在我们的例子中,它是 `name` 列。 该 `groupArrayResample` 函数应该使用 `age` 按年龄聚合名称的列。 要定义所需的时间间隔,我们通过 `30, 75, 30` 参数到 `groupArrayResample` 功能。
|
要在数组中聚合名称,我们使用 [groupArray](reference.md#agg_function-grouparray) 聚合函数。 这需要一个参数。 在我们的例子中,它是 `name` 列。 `groupArrayResample` 函数应该使用 `age` 按年龄聚合名称, 要定义所需的时间间隔,我们传入 `30, 75, 30` 参数给 `groupArrayResample` 函数。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT groupArrayResample(30, 75, 30)(name, age) FROM people
|
SELECT groupArrayResample(30, 75, 30)(name, age) FROM people
|
||||||
@ -225,7 +223,7 @@ SELECT groupArrayResample(30, 75, 30)(name, age) FROM people
|
|||||||
|
|
||||||
考虑结果。
|
考虑结果。
|
||||||
|
|
||||||
`Jonh` 是因为他太年轻了 其他人按照指定的年龄间隔进行分配。
|
`Jonh` 没有被选中,因为他太年轻了。 其他人按照指定的年龄间隔进行分配。
|
||||||
|
|
||||||
现在让我们计算指定年龄间隔内的总人数和平均工资。
|
现在让我们计算指定年龄间隔内的总人数和平均工资。
|
||||||
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_folder_title: "\u805A\u5408\u51FD\u6570"
|
|
||||||
toc_priority: 33
|
toc_priority: 33
|
||||||
toc_title: "\u5BFC\u8A00"
|
toc_title: 简介
|
||||||
---
|
---
|
||||||
|
|
||||||
# 聚合函数 {#aggregate-functions}
|
# 聚合函数 {#aggregate-functions}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_priority: 38
|
toc_priority: 38
|
||||||
toc_title: "\u53C2\u6570"
|
toc_title: 参数聚合函数
|
||||||
---
|
---
|
||||||
|
|
||||||
# 参数聚合函数 {#aggregate_functions_parametric}
|
# 参数聚合函数 {#aggregate_functions_parametric}
|
||||||
|
|
||||||
Some aggregate functions can accept not only argument columns (used for compression), but a set of parameters – constants for initialization. The syntax is two pairs of brackets instead of one. The first is for parameters, and the second is for arguments.
|
一些聚合函数不仅可以接受参数列(用于压缩),也可以接收常量的初始化参数。这种语法是接受两个括号的参数,第一个数初始化参数,第二个是入参。
|
||||||
|
|
||||||
## 直方图 {#histogram}
|
## histogram {#histogram}
|
||||||
|
|
||||||
计算自适应直方图。 它不能保证精确的结果。
|
计算自适应直方图。 它不能保证精确的结果。
|
||||||
|
|
||||||
@ -21,20 +19,21 @@ histogram(number_of_bins)(values)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
`number_of_bins` — Upper limit for the number of bins in the histogram. The function automatically calculates the number of bins. It tries to reach the specified number of bins, but if it fails, it uses fewer bins.
|
`number_of_bins` — 直方图bin个数,这个函数会自动计算bin的数量,而且会尽量使用指定值,如果无法做到,那就使用更小的bin个数。
|
||||||
`values` — [表达式](../syntax.md#syntax-expressions) 导致输入值。
|
|
||||||
|
`values` — [表达式](../syntax.md#syntax-expressions) 输入值。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- [阵列](../../sql-reference/data-types/array.md) 的 [元组](../../sql-reference/data-types/tuple.md) 下面的格式:
|
- [Array](../../sql-reference/data-types/array.md) 的 [Tuples](../../sql-reference/data-types/tuple.md) 如下:
|
||||||
|
|
||||||
```
|
```
|
||||||
[(lower_1, upper_1, height_1), ... (lower_N, upper_N, height_N)]
|
[(lower_1, upper_1, height_1), ... (lower_N, upper_N, height_N)]
|
||||||
```
|
```
|
||||||
|
|
||||||
- `lower` — Lower bound of the bin.
|
- `lower` — bin的下边界。
|
||||||
- `upper` — Upper bound of the bin.
|
- `upper` — bin的上边界。
|
||||||
- `height` — Calculated height of the bin.
|
- `height` — bin的计算权重。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ FROM (
|
|||||||
└─────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以使用 [酒吧](../../sql-reference/functions/other-functions.md#function-bar) 功能,例如:
|
您可以使用 [bar](../../sql-reference/functions/other-functions.md#function-bar) 功能,例如:
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
WITH histogram(5)(rand() % 100) AS hist
|
WITH histogram(5)(rand() % 100) AS hist
|
||||||
@ -93,11 +92,11 @@ sequenceMatch(pattern)(timestamp, cond1, cond2, ...)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `pattern` — Pattern string. See [模式语法](#sequence-function-pattern-syntax).
|
- `pattern` — 模式字符串。 参考 [模式语法](#sequence-function-pattern-syntax).
|
||||||
|
|
||||||
- `timestamp` — Column considered to contain time data. Typical data types are `Date` 和 `DateTime`. 您还可以使用任何支持的 [UInt](../../sql-reference/data-types/int-uint.md) 数据类型。
|
- `timestamp` — 包含时间的列。典型的时间类型是: `Date` 和 `DateTime`。您还可以使用任何支持的 [UInt](../../sql-reference/data-types/int-uint.md) 数据类型。
|
||||||
|
|
||||||
- `cond1`, `cond2` — Conditions that describe the chain of events. Data type: `UInt8`. 最多可以传递32个条件参数。 该函数只考虑这些条件中描述的事件。 如果序列包含未在条件中描述的数据,则函数将跳过这些数据。
|
- `cond1`, `cond2` — 事件链的约束条件。 数据类型是: `UInt8`。 最多可以传递32个条件参数。 该函数只考虑这些条件中描述的事件。 如果序列包含未在条件中描述的数据,则函数将跳过这些数据。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -109,11 +108,11 @@ sequenceMatch(pattern)(timestamp, cond1, cond2, ...)
|
|||||||
<a name="sequence-function-pattern-syntax"></a>
|
<a name="sequence-function-pattern-syntax"></a>
|
||||||
**模式语法**
|
**模式语法**
|
||||||
|
|
||||||
- `(?N)` — Matches the condition argument at position `N`. 条件在编号 `[1, 32]` 范围。 例如, `(?1)` 匹配传递给 `cond1` 参数。
|
- `(?N)` — 在位置`N`匹配条件参数。 条件在编号 `[1, 32]` 范围。 例如, `(?1)` 匹配传递给 `cond1` 参数。
|
||||||
|
|
||||||
- `.*` — Matches any number of events. You don't need conditional arguments to match this element of the pattern.
|
- `.*` — 匹配任何事件的数字。 不需要条件参数来匹配这个模式。
|
||||||
|
|
||||||
- `(?t operator value)` — Sets the time in seconds that should separate two events. For example, pattern `(?1)(?t>1800)(?2)` 匹配彼此发生超过1800秒的事件。 这些事件之间可以存在任意数量的任何事件。 您可以使用 `>=`, `>`, `<`, `<=` 运营商。
|
- `(?t operator value)` — 分开两个事件的时间。 例如: `(?1)(?t>1800)(?2)` 匹配彼此发生超过1800秒的事件。 这些事件之间可以存在任意数量的任何事件。 您可以使用 `>=`, `>`, `<`, `<=` 运算符。
|
||||||
|
|
||||||
**例**
|
**例**
|
||||||
|
|
||||||
@ -169,7 +168,7 @@ SELECT sequenceMatch('(?1)(?2)')(time, number = 1, number = 2, number = 4) FROM
|
|||||||
|
|
||||||
## sequenceCount(pattern)(time, cond1, cond2, …) {#function-sequencecount}
|
## sequenceCount(pattern)(time, cond1, cond2, …) {#function-sequencecount}
|
||||||
|
|
||||||
计数与模式匹配的事件链的数量。 该函数搜索不重叠的事件链。 当前链匹配后,它开始搜索下一个链。
|
计算与模式匹配的事件链的数量。该函数搜索不重叠的事件链。当前链匹配后,它开始搜索下一个链。
|
||||||
|
|
||||||
!!! warning "警告"
|
!!! warning "警告"
|
||||||
在同一秒钟发生的事件可能以未定义的顺序排列在序列中,影响结果。
|
在同一秒钟发生的事件可能以未定义的顺序排列在序列中,影响结果。
|
||||||
@ -180,11 +179,11 @@ sequenceCount(pattern)(timestamp, cond1, cond2, ...)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `pattern` — Pattern string. See [模式语法](#sequence-function-pattern-syntax).
|
- `pattern` — 模式字符串。 参考:[模式语法](#sequence-function-pattern-syntax).
|
||||||
|
|
||||||
- `timestamp` — Column considered to contain time data. Typical data types are `Date` 和 `DateTime`. 您还可以使用任何支持的 [UInt](../../sql-reference/data-types/int-uint.md) 数据类型。
|
- `timestamp` — 包含时间的列。典型的时间类型是: `Date` 和 `DateTime`。您还可以使用任何支持的 [UInt](../../sql-reference/data-types/int-uint.md) 数据类型。
|
||||||
|
|
||||||
- `cond1`, `cond2` — Conditions that describe the chain of events. Data type: `UInt8`. 最多可以传递32个条件参数。 该函数只考虑这些条件中描述的事件。 如果序列包含未在条件中描述的数据,则函数将跳过这些数据。
|
- `cond1`, `cond2` — 事件链的约束条件。 数据类型是: `UInt8`。 最多可以传递32个条件参数。该函数只考虑这些条件中描述的事件。 如果序列包含未在条件中描述的数据,则函数将跳过这些数据。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -227,9 +226,9 @@ SELECT sequenceCount('(?1).*(?2)')(time, number = 1, number = 2) FROM t
|
|||||||
|
|
||||||
搜索滑动时间窗中的事件链,并计算从链中发生的最大事件数。
|
搜索滑动时间窗中的事件链,并计算从链中发生的最大事件数。
|
||||||
|
|
||||||
该函数根据算法工作:
|
该函数采用如下算法:
|
||||||
|
|
||||||
- 该函数搜索触发链中的第一个条件并将事件计数器设置为1的数据。 这是滑动窗口启动的时刻。
|
- 该函数搜索触发链中的第一个条件并将事件计数器设置为1。 这是滑动窗口启动的时刻。
|
||||||
|
|
||||||
- 如果来自链的事件在窗口内顺序发生,则计数器将递增。 如果事件序列中断,则计数器不会增加。
|
- 如果来自链的事件在窗口内顺序发生,则计数器将递增。 如果事件序列中断,则计数器不会增加。
|
||||||
|
|
||||||
@ -243,11 +242,11 @@ windowFunnel(window, [mode])(timestamp, cond1, cond2, ..., condN)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `window` — Length of the sliding window in seconds.
|
- `window` — 滑动窗户的大小,单位是秒。
|
||||||
- `mode` -这是一个可选的参数。
|
- `mode` - 这是一个可选的参数。
|
||||||
- `'strict'` -当 `'strict'` 设置时,windowFunnel()仅对唯一值应用条件。
|
- `'strict'` - 当 `'strict'` 设置时,windowFunnel()仅对唯一值应用匹配条件。
|
||||||
- `timestamp` — Name of the column containing the timestamp. Data types supported: [日期](../../sql-reference/data-types/date.md), [日期时间](../../sql-reference/data-types/datetime.md#data_type-datetime) 和其他无符号整数类型(请注意,即使时间戳支持 `UInt64` 类型,它的值不能超过Int64最大值,即2^63-1)。
|
- `timestamp` — 包含时间的列。 数据类型支持: [日期](../../sql-reference/data-types/date.md), [日期时间](../../sql-reference/data-types/datetime.md#data_type-datetime) 和其他无符号整数类型(请注意,即使时间戳支持 `UInt64` 类型,它的值不能超过Int64最大值,即2^63-1)。
|
||||||
- `cond` — Conditions or data describing the chain of events. [UInt8](../../sql-reference/data-types/int-uint.md).
|
- `cond` — 事件链的约束条件。 [UInt8](../../sql-reference/data-types/int-uint.md) 类型。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -284,7 +283,7 @@ windowFunnel(window, [mode])(timestamp, cond1, cond2, ..., condN)
|
|||||||
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
|
└────────────┴─────────┴─────────────────────┴─────────┴─────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
了解用户有多远 `user_id` 可以在2019的1-2月期间通过链条。
|
了解用户`user_id` 可以在2019的1-2月期间通过链条多远。
|
||||||
|
|
||||||
查询:
|
查询:
|
||||||
|
|
||||||
@ -315,10 +314,10 @@ ORDER BY level ASC
|
|||||||
|
|
||||||
## Retention {#retention}
|
## Retention {#retention}
|
||||||
|
|
||||||
该函数将一组条件作为参数,类型为1到32个参数 `UInt8` 表示事件是否满足特定条件。
|
该函数将一组条件作为参数,类型为1到32个 `UInt8` 类型的参数,用来表示事件是否满足特定条件。
|
||||||
任何条件都可以指定为参数(如 [WHERE](../../sql-reference/statements/select/where.md#select-where)).
|
任何条件都可以指定为参数(如 [WHERE](../../sql-reference/statements/select/where.md#select-where)).
|
||||||
|
|
||||||
除了第一个以外,条件成对适用:如果第一个和第二个是真的,第二个结果将是真的,如果第一个和fird是真的,第三个结果将是真的,等等。
|
除了第一个以外,条件成对适用:如果第一个和第二个是真的,第二个结果将是真的,如果第一个和第三个是真的,第三个结果将是真的,等等。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -328,22 +327,22 @@ retention(cond1, cond2, ..., cond32);
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `cond` — an expression that returns a `UInt8` 结果(1或0)。
|
- `cond` — 返回 `UInt8` 结果(1或0)的表达式。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
数组为1或0。
|
数组为1或0。
|
||||||
|
|
||||||
- 1 — condition was met for the event.
|
- 1 — 条件满足。
|
||||||
- 0 — condition wasn't met for the event.
|
- 0 — 条件不满足。
|
||||||
|
|
||||||
类型: `UInt8`.
|
类型: `UInt8`.
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
让我们考虑计算的一个例子 `retention` 功能,以确定网站流量。
|
让我们考虑使用 `retention` 功能的一个例子 ,以确定网站流量。
|
||||||
|
|
||||||
**1.** Сreate a table to illustrate an example.
|
**1.** 举例说明,先创建一张表。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
CREATE TABLE retention_test(date Date, uid Int32) ENGINE = Memory;
|
CREATE TABLE retention_test(date Date, uid Int32) ENGINE = Memory;
|
||||||
@ -402,7 +401,7 @@ SELECT * FROM retention_test
|
|||||||
└────────────┴─────┘
|
└────────────┴─────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**2.** 按唯一ID对用户进行分组 `uid` 使用 `retention` 功能。
|
**2.** 按唯一ID `uid` 对用户进行分组,使用 `retention` 功能。
|
||||||
|
|
||||||
查询:
|
查询:
|
||||||
|
|
||||||
@ -466,7 +465,7 @@ FROM
|
|||||||
└────┴────┴────┘
|
└────┴────┴────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
哪里:
|
条件:
|
||||||
|
|
||||||
- `r1`-2020-01-01期间访问该网站的独立访问者数量( `cond1` 条件)。
|
- `r1`-2020-01-01期间访问该网站的独立访问者数量( `cond1` 条件)。
|
||||||
- `r2`-在2020-01-01和2020-01-02之间的特定时间段内访问该网站的唯一访问者的数量 (`cond1` 和 `cond2` 条件)。
|
- `r2`-在2020-01-01和2020-01-02之间的特定时间段内访问该网站的唯一访问者的数量 (`cond1` 和 `cond2` 条件)。
|
||||||
@ -474,9 +473,9 @@ FROM
|
|||||||
|
|
||||||
## uniqUpTo(N)(x) {#uniquptonx}
|
## uniqUpTo(N)(x) {#uniquptonx}
|
||||||
|
|
||||||
Calculates the number of different argument values if it is less than or equal to N. If the number of different argument values is greater than N, it returns N + 1.
|
计算小于或者等于N的不同参数的个数。如果结果大于N,那返回N+1。
|
||||||
|
|
||||||
建议使用小Ns,高达10。 N的最大值为100。
|
建议使用较小的Ns,比如:10。N的最大值为100。
|
||||||
|
|
||||||
对于聚合函数的状态,它使用的内存量等于1+N\*一个字节值的大小。
|
对于聚合函数的状态,它使用的内存量等于1+N\*一个字节值的大小。
|
||||||
对于字符串,它存储8个字节的非加密哈希。 也就是说,计算是近似的字符串。
|
对于字符串,它存储8个字节的非加密哈希。 也就是说,计算是近似的字符串。
|
||||||
@ -488,12 +487,12 @@ Calculates the number of different argument values if it is less than or e
|
|||||||
用法示例:
|
用法示例:
|
||||||
|
|
||||||
``` text
|
``` text
|
||||||
Problem: Generate a report that shows only keywords that produced at least 5 unique users.
|
问题:产出一个不少于五个唯一用户的关键字报告
|
||||||
Solution: Write in the GROUP BY query SearchPhrase HAVING uniqUpTo(4)(UserID) >= 5
|
解决方案: 写group by查询语句 HAVING uniqUpTo(4)(UserID) >= 5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## sumMapFiltered(keys\_to\_keep)(keys, values) {#summapfilteredkeys-to-keepkeys-values}
|
||||||
|
|
||||||
|
和 [sumMap](reference.md#agg_functions-summap) 基本一致, 除了一个键数组作为参数传递。这在使用高基数key时尤其有用。
|
||||||
|
|
||||||
[原始文章](https://clickhouse.tech/docs/en/query_language/agg_functions/parametric_functions/) <!--hide-->
|
[原始文章](https://clickhouse.tech/docs/en/query_language/agg_functions/parametric_functions/) <!--hide-->
|
||||||
|
|
||||||
## sumMapFiltered(keys\_to\_keep)(键值) {#summapfilteredkeys-to-keepkeys-values}
|
|
||||||
|
|
||||||
同样的行为 [sumMap](reference.md#agg_functions-summap) 除了一个键数组作为参数传递。 这在使用高基数密钥时尤其有用。
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
---
|
---
|
||||||
machine_translated: true
|
|
||||||
machine_translated_rev: 72537a2d527c63c07aa5d2361a8829f3895cf2bd
|
|
||||||
toc_priority: 36
|
toc_priority: 36
|
||||||
toc_title: "\u53C2\u8003\u8D44\u6599"
|
toc_title: 聚合函数
|
||||||
---
|
---
|
||||||
|
|
||||||
# 聚合函数引用 {#aggregate-functions-reference}
|
# 聚合函数引用 {#aggregate-functions-reference}
|
||||||
|
|
||||||
## 计数 {#agg_function-count}
|
## count {#agg_function-count}
|
||||||
|
|
||||||
计数行数或非空值。
|
计数行数或非空值。
|
||||||
|
|
||||||
@ -73,7 +71,7 @@ SELECT count(DISTINCT num) FROM t
|
|||||||
|
|
||||||
这个例子表明 `count(DISTINCT num)` 由执行 `uniqExact` 根据功能 `count_distinct_implementation` 设定值。
|
这个例子表明 `count(DISTINCT num)` 由执行 `uniqExact` 根据功能 `count_distinct_implementation` 设定值。
|
||||||
|
|
||||||
## 任何(x) {#agg_function-any}
|
## any(x) {#agg_function-any}
|
||||||
|
|
||||||
选择第一个遇到的值。
|
选择第一个遇到的值。
|
||||||
查询可以以任何顺序执行,甚至每次都以不同的顺序执行,因此此函数的结果是不确定的。
|
查询可以以任何顺序执行,甚至每次都以不同的顺序执行,因此此函数的结果是不确定的。
|
||||||
@ -115,7 +113,7 @@ FROM ontime
|
|||||||
选择遇到的最后一个值。
|
选择遇到的最后一个值。
|
||||||
其结果是一样不确定的 `any` 功能。
|
其结果是一样不确定的 `any` 功能。
|
||||||
|
|
||||||
## 集团比特 {#groupbitand}
|
## groupBitAnd {#groupbitand}
|
||||||
|
|
||||||
按位应用 `AND` 对于一系列的数字。
|
按位应用 `AND` 对于一系列的数字。
|
||||||
|
|
||||||
@ -337,7 +335,7 @@ SELECT argMin(user, salary) FROM salary
|
|||||||
总计 ‘value’ 数组根据在指定的键 ‘key’ 阵列。
|
总计 ‘value’ 数组根据在指定的键 ‘key’ 阵列。
|
||||||
传递键和值数组的元组与传递两个键和值数组是同义的。
|
传递键和值数组的元组与传递两个键和值数组是同义的。
|
||||||
元素的数量 ‘key’ 和 ‘value’ 总计的每一行必须相同。
|
元素的数量 ‘key’ 和 ‘value’ 总计的每一行必须相同。
|
||||||
Returns a tuple of two arrays: keys in sorted order, and values summed for the corresponding keys.
|
返回两个数组的一个二元组: key是排好序的,value是对应key的求和。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
@ -374,7 +372,7 @@ GROUP BY timeslot
|
|||||||
|
|
||||||
## skewPop {#skewpop}
|
## skewPop {#skewpop}
|
||||||
|
|
||||||
计算 [歪斜](https://en.wikipedia.org/wiki/Skewness) 的序列。
|
计算的序列[偏度](https://en.wikipedia.org/wiki/Skewness)。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
skewPop(expr)
|
skewPop(expr)
|
||||||
@ -386,7 +384,7 @@ skewPop(expr)
|
|||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
The skewness of the given distribution. Type — [Float64](../../sql-reference/data-types/float.md)
|
给定序列的偏度。类型 — [Float64](../../sql-reference/data-types/float.md)
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -410,7 +408,7 @@ skewSamp(expr)
|
|||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
The skewness of the given distribution. Type — [Float64](../../sql-reference/data-types/float.md). 如果 `n <= 1` (`n` 是样本的大小),则该函数返回 `nan`.
|
给定序列的偏度。 类型 — [Float64](../../sql-reference/data-types/float.md). 如果 `n <= 1` (`n` 是样本的大小),则该函数返回 `nan`.
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -432,7 +430,7 @@ kurtPop(expr)
|
|||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
The kurtosis of the given distribution. Type — [Float64](../../sql-reference/data-types/float.md)
|
给定序列的峰度。 类型 — [Float64](../../sql-reference/data-types/float.md)
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -456,7 +454,7 @@ kurtSamp(expr)
|
|||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
The kurtosis of the given distribution. Type — [Float64](../../sql-reference/data-types/float.md). 如果 `n <= 1` (`n` 是样本的大小),则该函数返回 `nan`.
|
给定序列的峰度。类型 — [Float64](../../sql-reference/data-types/float.md). 如果 `n <= 1` (`n` 是样本的大小),则该函数返回 `nan`.
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -533,7 +531,7 @@ FROM (
|
|||||||
只适用于数字。
|
只适用于数字。
|
||||||
结果总是Float64。
|
结果总是Float64。
|
||||||
|
|
||||||
## 平均加权 {#avgweighted}
|
## avgWeighted {#avgweighted}
|
||||||
|
|
||||||
计算 [加权算术平均值](https://en.wikipedia.org/wiki/Weighted_arithmetic_mean).
|
计算 [加权算术平均值](https://en.wikipedia.org/wiki/Weighted_arithmetic_mean).
|
||||||
|
|
||||||
@ -545,10 +543,10 @@ avgWeighted(x, weight)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `x` — Values. [整数](../data-types/int-uint.md) 或 [浮点](../data-types/float.md).
|
- `x` — 值。 [整数](../data-types/int-uint.md) 或 [浮点](../data-types/float.md).
|
||||||
- `weight` — Weights of the values. [整数](../data-types/int-uint.md) 或 [浮点](../data-types/float.md).
|
- `weight` — 值的加权。 [整数](../data-types/int-uint.md) 或 [浮点](../data-types/float.md).
|
||||||
|
|
||||||
类型 `x` 和 `weight` 一定是一样的
|
`x` 和 `weight` 的类型一定是一样的
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -590,7 +588,7 @@ uniq(x[, ...])
|
|||||||
|
|
||||||
- A [UInt64](../../sql-reference/data-types/int-uint.md)-键入号码。
|
- A [UInt64](../../sql-reference/data-types/int-uint.md)-键入号码。
|
||||||
|
|
||||||
**实施细节**
|
**实现细节**
|
||||||
|
|
||||||
功能:
|
功能:
|
||||||
|
|
||||||
@ -598,7 +596,7 @@ uniq(x[, ...])
|
|||||||
|
|
||||||
- 使用自适应采样算法。 对于计算状态,该函数使用最多65536个元素哈希值的样本。
|
- 使用自适应采样算法。 对于计算状态,该函数使用最多65536个元素哈希值的样本。
|
||||||
|
|
||||||
This algorithm is very accurate and very efficient on the CPU. When the query contains several of these functions, using `uniq` is almost as fast as using other aggregate functions.
|
这个算法是非常精确的,并且对于CPU来说非常高效。如果查询包含一些这样的函数,那和其他聚合函数相比 `uniq` 将是几乎一样快。
|
||||||
|
|
||||||
- 确定性地提供结果(它不依赖于查询处理顺序)。
|
- 确定性地提供结果(它不依赖于查询处理顺序)。
|
||||||
|
|
||||||
@ -629,17 +627,17 @@ uniqCombined(HLL_precision)(x[, ...])
|
|||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 一个数字 [UInt64](../../sql-reference/data-types/int-uint.md)-键入号码。
|
- 一个[UInt64](../../sql-reference/data-types/int-uint.md)类型的数字。
|
||||||
|
|
||||||
**实施细节**
|
**实现细节**
|
||||||
|
|
||||||
功能:
|
功能:
|
||||||
|
|
||||||
- 计算散列(64位散列 `String` 否则32位)对于聚合中的所有参数,然后在计算中使用它。
|
- 计算散列(64位散列 `String` 否则32位)对于聚合中的所有参数,然后在计算中使用它。
|
||||||
|
|
||||||
- 使用三种算法的组合:数组、哈希表和HyperLogLog与error错表。
|
- 使用三种算法的组合:数组、哈希表和包含错误修正表的HyperLogLog。
|
||||||
|
|
||||||
For a small number of distinct elements, an array is used. When the set size is larger, a hash table is used. For a larger number of elements, HyperLogLog is used, which will occupy a fixed amount of memory.
|
少量的不同的值,使用数组。 值再多一些,使用哈希表。对于大量的数据来说,使用HyperLogLog,HyperLogLog占用一个固定的内存空间。
|
||||||
|
|
||||||
- 确定性地提供结果(它不依赖于查询处理顺序)。
|
- 确定性地提供结果(它不依赖于查询处理顺序)。
|
||||||
|
|
||||||
@ -650,7 +648,7 @@ uniqCombined(HLL_precision)(x[, ...])
|
|||||||
|
|
||||||
- 消耗少几倍的内存。
|
- 消耗少几倍的内存。
|
||||||
- 计算精度高出几倍。
|
- 计算精度高出几倍。
|
||||||
- 通常具有略低的性能。 在某些情况下, `uniqCombined` 可以表现得比 `uniq`,例如,使用通过网络传输大量聚合状态的分布式查询。
|
- 通常具有略低的性能。 在某些情况下, `uniqCombined` 可以表现得比 `uniq` 好,例如,使用通过网络传输大量聚合状态的分布式查询。
|
||||||
|
|
||||||
**另请参阅**
|
**另请参阅**
|
||||||
|
|
||||||
@ -679,7 +677,7 @@ uniqHLL12(x[, ...])
|
|||||||
|
|
||||||
- A [UInt64](../../sql-reference/data-types/int-uint.md)-键入号码。
|
- A [UInt64](../../sql-reference/data-types/int-uint.md)-键入号码。
|
||||||
|
|
||||||
**实施细节**
|
**实现细节**
|
||||||
|
|
||||||
功能:
|
功能:
|
||||||
|
|
||||||
@ -707,9 +705,9 @@ uniqHLL12(x[, ...])
|
|||||||
uniqExact(x[, ...])
|
uniqExact(x[, ...])
|
||||||
```
|
```
|
||||||
|
|
||||||
使用 `uniqExact` 功能,如果你绝对需要一个确切的结果。 否则使用 [uniq](#agg_function-uniq) 功能。
|
如果你绝对需要一个确切的结果,使用 `uniqExact` 功能。 否则使用 [uniq](#agg_function-uniq) 功能。
|
||||||
|
|
||||||
该 `uniqExact` 功能使用更多的内存比 `uniq`,因为状态的大小随着不同值的数量的增加而无界增长。
|
`uniqExact` 比 `uniq` 使用更多的内存,因为状态的大小随着不同值的数量的增加而无界增长。
|
||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
@ -721,7 +719,7 @@ uniqExact(x[, ...])
|
|||||||
- [uniqCombined](#agg_function-uniqcombined)
|
- [uniqCombined](#agg_function-uniqcombined)
|
||||||
- [uniqHLL12](#agg_function-uniqhll12)
|
- [uniqHLL12](#agg_function-uniqhll12)
|
||||||
|
|
||||||
## 群交(x),群交(max\_size)(x) {#agg_function-grouparray}
|
## groupArray(x), groupArray(max\_size)(x) {#agg_function-grouparray}
|
||||||
|
|
||||||
创建参数值的数组。
|
创建参数值的数组。
|
||||||
值可以按任何(不确定)顺序添加到数组中。
|
值可以按任何(不确定)顺序添加到数组中。
|
||||||
@ -748,10 +746,10 @@ groupArrayInsertAt(default_x, size)(x, pos);
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `x` — Value to be inserted. [表达式](../syntax.md#syntax-expressions) 导致的一个 [支持的数据类型](../../sql-reference/data-types/index.md).
|
- `x` — 被插入的值。[表达式](../syntax.md#syntax-expressions) 导致的一个 [支持的数据类型](../../sql-reference/data-types/index.md).
|
||||||
- `pos` — Position at which the specified element `x` 将被插入。 数组中的索引编号从零开始。 [UInt32](../../sql-reference/data-types/int-uint.md#uint-ranges).
|
- `pos` — `x` 将被插入的位置。 数组中的索引编号从零开始。 [UInt32](../../sql-reference/data-types/int-uint.md#uint-ranges).
|
||||||
- `default_x`— Default value for substituting in empty positions. Optional parameter. [表达式](../syntax.md#syntax-expressions) 导致为配置的数据类型 `x` 参数。 如果 `default_x` 未定义,则 [默认值](../../sql-reference/statements/create.md#create-default-values) 被使用。
|
- `default_x`— 如果代入值为空,则使用默认值。可选参数。[表达式](../syntax.md#syntax-expressions) 为 `x` 数据类型的数据。 如果 `default_x` 未定义,则 [默认值](../../sql-reference/statements/create.md#create-default-values) 被使用。
|
||||||
- `size`— Length of the resulting array. Optional parameter. When using this parameter, the default value `default_x` 必须指定。 [UInt32](../../sql-reference/data-types/int-uint.md#uint-ranges).
|
- `size`— 结果数组的长度。可选参数。如果使用该参数,`default_x` 必须指定。 [UInt32](../../sql-reference/data-types/int-uint.md#uint-ranges).
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -803,7 +801,7 @@ SELECT groupArrayInsertAt('-', 5)(toString(number), number * 2) FROM numbers(5);
|
|||||||
└───────────────────────────────────────────────────────────────────┘
|
└───────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
元件的多线程插入到一个位置。
|
在一个位置多线程插入数据。
|
||||||
|
|
||||||
查询:
|
查询:
|
||||||
|
|
||||||
@ -832,8 +830,8 @@ groupArrayMovingSum(window_size)(numbers_for_summing)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `numbers_for_summing` — [表达式](../syntax.md#syntax-expressions) 生成数值数据类型值。
|
- `numbers_for_summing` — [表达式](../syntax.md#syntax-expressions) 为数值数据类型值。
|
||||||
- `window_size` — Size of the calculation window.
|
- `window_size` — 窗口大小。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -906,13 +904,13 @@ groupArrayMovingAvg(window_size)(numbers_for_summing)
|
|||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `numbers_for_summing` — [表达式](../syntax.md#syntax-expressions) 生成数值数据类型值。
|
- `numbers_for_summing` — [表达式](../syntax.md#syntax-expressions) 生成数值数据类型值。
|
||||||
- `window_size` — Size of the calculation window.
|
- `window_size` — 窗口大小。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 与输入数据大小和类型相同的数组。
|
- 与输入数据大小和类型相同的数组。
|
||||||
|
|
||||||
该函数使用 [四舍五入到零](https://en.wikipedia.org/wiki/Rounding#Rounding_towards_zero). 它截断结果数据类型的小数位数。
|
该函数使用 [四舍五入到零](https://en.wikipedia.org/wiki/Rounding#Rounding_towards_zero). 它截断无意义的小数位来保证结果的数据类型。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -967,20 +965,20 @@ FROM t
|
|||||||
└───────────┴──────────────────────────────────┴───────────────────────┘
|
└───────────┴──────────────────────────────────┴───────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## 禄,赂麓ta脌麓,):脡,,拢脢,group媒group)galaxy s8碌胫脢)禄煤)酶脱脩) {#groupuniqarrayx-groupuniqarraymax-sizex}
|
## groupUniqArray(x), groupUniqArray(max\_size)(x) {#groupuniqarrayx-groupuniqarraymax-sizex}
|
||||||
|
|
||||||
从不同的参数值创建一个数组。 内存消耗是一样的 `uniqExact` 功能。
|
从不同的参数值创建一个数组。 内存消耗是一样的 `uniqExact` 功能。
|
||||||
|
|
||||||
第二个版本(与 `max_size` 参数)将结果数组的大小限制为 `max_size` 元素。
|
第二个版本(`max_size` 参数)将结果数组的大小限制为 `max_size` 元素。
|
||||||
例如, `groupUniqArray(1)(x)` 相当于 `[any(x)]`.
|
例如, `groupUniqArray(1)(x)` 相当于 `[any(x)]`.
|
||||||
|
|
||||||
## 分位数 {#quantile}
|
## quantile {#quantile}
|
||||||
|
|
||||||
计算近似值 [分位数](https://en.wikipedia.org/wiki/Quantile) 的数字数据序列。
|
计算数字序列的近似[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
此功能适用 [油藏采样](https://en.wikipedia.org/wiki/Reservoir_sampling) 随着储存器大小高达8192和随机数发生器进行采样。 结果是非确定性的。 要获得精确的分位数,请使用 [quantileExact](#quantileexact) 功能。
|
此功能适用 [水塘抽样(](https://en.wikipedia.org/wiki/Reservoir_sampling),使用储存器最大到8192和随机数发生器进行采样。 结果是非确定性的。 要获得精确的分位数,请使用 [quantileExact](#quantileexact) 功能。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -992,12 +990,12 @@ quantile(level)(expr)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的近似分位数。
|
- 指定层次的近似分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1037,13 +1035,13 @@ SELECT quantile(val) FROM t
|
|||||||
- [中位数](#median)
|
- [中位数](#median)
|
||||||
- [分位数](#quantiles)
|
- [分位数](#quantiles)
|
||||||
|
|
||||||
## 量化确定 {#quantiledeterministic}
|
## quantileDeterministic {#quantiledeterministic}
|
||||||
|
|
||||||
计算近似值 [分位数](https://en.wikipedia.org/wiki/Quantile) 的数字数据序列。
|
计算数字序列的近似[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
此功能适用 [油藏采样](https://en.wikipedia.org/wiki/Reservoir_sampling) 与储层大小高达8192和采样的确定性算法。 结果是确定性的。 要获得精确的分位数,请使用 [quantileExact](#quantileexact) 功能。
|
此功能适用 [水塘抽样(](https://en.wikipedia.org/wiki/Reservoir_sampling),使用储存器最大到8192和随机数发生器进行采样。 结果是非确定性的。 要获得精确的分位数,请使用 [quantileExact](#quantileexact) 功能。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1055,13 +1053,13 @@ quantileDeterministic(level)(expr, determinator)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
- `determinator` — Number whose hash is used instead of a random number generator in the reservoir sampling algorithm to make the result of sampling deterministic. As a determinator you can use any deterministic positive number, for example, a user id or an event id. If the same determinator value occures too often, the function works incorrectly.
|
- `determinator` — 一个数字,其hash被用来代替在水塘抽样中随机生成的数字,这样可以保证取样的确定性。你可以使用用户ID或者事件ID等任何正数,但是如果相同的 `determinator` 出现多次,那结果很可能不正确。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的近似分位数。
|
- 指定层次的近似分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1103,11 +1101,11 @@ SELECT quantileDeterministic(val, 1) FROM t
|
|||||||
|
|
||||||
## quantileExact {#quantileexact}
|
## quantileExact {#quantileexact}
|
||||||
|
|
||||||
正是计算 [分位数](https://en.wikipedia.org/wiki/Quantile) 的数字数据序列。
|
准确计算数字序列的[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
To get exact value, all the passed values are combined into an array, which is then partially sorted. Therefore, the function consumes `O(n)` 内存,其中 `n` 是传递的多个值。 然而,对于少量的值,该函数是非常有效的。
|
为了准确计算,所有输入的数据被合并为一个数组,并且部分的排序。因此该函数需要 `O(n)` 的内存,n为输入数据的个数。但是对于少量数据来说,该函数还是非常有效的。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1119,12 +1117,12 @@ quantileExact(level)(expr)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1153,13 +1151,13 @@ SELECT quantileExact(number) FROM numbers(10)
|
|||||||
- [中位数](#median)
|
- [中位数](#median)
|
||||||
- [分位数](#quantiles)
|
- [分位数](#quantiles)
|
||||||
|
|
||||||
## 分位数加权 {#quantileexactweighted}
|
## quantileExactWeighted {#quantileexactweighted}
|
||||||
|
|
||||||
正是计算 [分位数](https://en.wikipedia.org/wiki/Quantile) 数值数据序列,考虑到每个元素的权重。
|
考虑到每个元素的权重,然后准确计算数值序列的[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
To get exact value, all the passed values are combined into an array, which is then partially sorted. Each value is counted with its weight, as if it is present `weight` times. A hash table is used in the algorithm. Because of this, if the passed values are frequently repeated, the function consumes less RAM than [quantileExact](#quantileexact). 您可以使用此功能,而不是 `quantileExact` 并指定重量1。
|
为了准确计算,所有输入的数据被合并为一个数组,并且部分的排序。每个输入值需要根据 `weight` 计算求和。该算法使用哈希表。正因为如此,在数据重复较多的时候使用的内存是少于[quantileExact](#quantileexact)的。 您可以使用此函数代替 `quantileExact` 并指定重量1。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1171,13 +1169,13 @@ quantileExactWeighted(level)(expr, weight)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
- `weight` — Column with weights of sequence members. Weight is a number of value occurrences.
|
- `weight` — 权重序列。 权重是一个数据出现的数值。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1217,13 +1215,13 @@ SELECT quantileExactWeighted(n, val) FROM t
|
|||||||
- [中位数](#median)
|
- [中位数](#median)
|
||||||
- [分位数](#quantiles)
|
- [分位数](#quantiles)
|
||||||
|
|
||||||
## 分位定时 {#quantiletiming}
|
## quantileTiming {#quantiletiming}
|
||||||
|
|
||||||
随着确定的精度计算 [分位数](https://en.wikipedia.org/wiki/Quantile) 的数字数据序列。
|
使用确定的精度计算数字数据序列的[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
结果是确定性的(它不依赖于查询处理顺序)。 该函数针对描述加载网页时间或后端响应时间等分布的序列进行了优化。
|
结果是确定性的(它不依赖于查询处理顺序)。 该函数针对描述加载网页时间或后端响应时间等分布的序列进行了优化。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1235,12 +1233,12 @@ quantileTiming(level)(expr)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
|
|
||||||
- `expr` — [表达式](../syntax.md#syntax-expressions) 在一个列值返回 [浮动\*](../../sql-reference/data-types/float.md)-键入号码。
|
- `expr` — [表达式](../syntax.md#syntax-expressions),返回 [浮动\*](../../sql-reference/data-types/float.md)类型数据。
|
||||||
|
|
||||||
- If negative values are passed to the function, the behavior is undefined.
|
- 如果输入负值,那结果是不可预期的。
|
||||||
- If the value is greater than 30,000 (a page loading time of more than 30 seconds), it is assumed to be 30,000.
|
- 如果输入值大于30000(页面加载时间大于30s),那我们假设为30000。
|
||||||
|
|
||||||
**精度**
|
**精度**
|
||||||
|
|
||||||
@ -1252,16 +1250,16 @@ quantileTiming(level)(expr)
|
|||||||
否则,计算结果将四舍五入到16毫秒的最接近倍数。
|
否则,计算结果将四舍五入到16毫秒的最接近倍数。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
对于计算页面加载时间分位数,此函数比 [分位数](#quantile).
|
对于计算页面加载时间分位数,此函数比 [分位数](#quantile)更有效和准确。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型: `Float32`.
|
类型: `Float32`.
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
如果没有值传递给函数(当使用 `quantileTimingIf`), [阿南](../../sql-reference/data-types/float.md#data_type-float-nan-inf) 被返回。 这样做的目的是将这些案例与导致零的案例区分开来。 看 [按条款订购](../statements/select/order-by.md#select-order-by) 对于排序注意事项 `NaN` 值。
|
如果没有值传递给函数(当使用 `quantileTimingIf`), [NaN](../../sql-reference/data-types/float.md#data_type-float-nan-inf) 被返回。 这样做的目的是将这些案例与导致零的案例区分开来。 看 [ORDER BY clause](../statements/select/order-by.md#select-order-by) 对于 `NaN` 值排序注意事项。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -1300,13 +1298,13 @@ SELECT quantileTiming(response_time) FROM t
|
|||||||
- [中位数](#median)
|
- [中位数](#median)
|
||||||
- [分位数](#quantiles)
|
- [分位数](#quantiles)
|
||||||
|
|
||||||
## 分位时间加权 {#quantiletimingweighted}
|
## quantileTimingWeighted {#quantiletimingweighted}
|
||||||
|
|
||||||
随着确定的精度计算 [分位数](https://en.wikipedia.org/wiki/Quantile) 根据每个序列成员的权重对数字数据序列进行处理。
|
根据每个序列成员的权重,使用确定的精度计算数字序列的[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
结果是确定性的(它不依赖于查询处理顺序)。 该函数针对描述加载网页时间或后端响应时间等分布的序列进行了优化。
|
结果是确定性的(它不依赖于查询处理顺序)。 该函数针对描述加载网页时间或后端响应时间等分布的序列进行了优化。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1318,14 +1316,14 @@ quantileTimingWeighted(level)(expr, weight)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
|
|
||||||
- `expr` — [表达式](../syntax.md#syntax-expressions) 在一个列值返回 [浮动\*](../../sql-reference/data-types/float.md)-键入号码。
|
- `expr` — [表达式](../syntax.md#syntax-expressions),返回 [浮动\*](../../sql-reference/data-types/float.md)类型数据。
|
||||||
|
|
||||||
- If negative values are passed to the function, the behavior is undefined.
|
- 如果输入负值,那结果是不可预期的。
|
||||||
- If the value is greater than 30,000 (a page loading time of more than 30 seconds), it is assumed to be 30,000.
|
- 如果输入值大于30000(页面加载时间大于30s),那我们假设为30000。
|
||||||
|
|
||||||
- `weight` — Column with weights of sequence elements. Weight is a number of value occurrences.
|
- `weight` — 权重序列。 权重是一个数据出现的数值。
|
||||||
|
|
||||||
**精度**
|
**精度**
|
||||||
|
|
||||||
@ -1337,16 +1335,16 @@ quantileTimingWeighted(level)(expr, weight)
|
|||||||
否则,计算结果将四舍五入到16毫秒的最接近倍数。
|
否则,计算结果将四舍五入到16毫秒的最接近倍数。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
对于计算页面加载时间分位数,此函数比 [分位数](#quantile).
|
对于计算页面加载时间分位数,此函数比 [分位数](#quantile)更高效和准确。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型: `Float32`.
|
类型: `Float32`.
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
如果没有值传递给函数(当使用 `quantileTimingIf`), [阿南](../../sql-reference/data-types/float.md#data_type-float-nan-inf) 被返回。 这样做的目的是将这些案例与导致零的案例区分开来。 看 [按条款订购](../statements/select/order-by.md#select-order-by) 对于排序注意事项 `NaN` 值。
|
如果没有值传递给函数(当使用 `quantileTimingIf`), [NaN](../../sql-reference/data-types/float.md#data_type-float-nan-inf) 被返回。 这样做的目的是将这些案例与导致零的案例区分开来。看 [ORDER BY clause](../statements/select/order-by.md#select-order-by) 对于 `NaN` 值排序注意事项。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -1384,13 +1382,13 @@ SELECT quantileTimingWeighted(response_time, weight) FROM t
|
|||||||
|
|
||||||
## quantileTDigest {#quantiletdigest}
|
## quantileTDigest {#quantiletdigest}
|
||||||
|
|
||||||
计算近似值 [分位数](https://en.wikipedia.org/wiki/Quantile) 使用的数字数据序列 [t-digest](https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf) 算法。
|
使用[t-digest](https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf) 算法计算近似[分位数](https://en.wikipedia.org/wiki/Quantile)。
|
||||||
|
|
||||||
最大误差为1%。 内存消耗 `log(n)`,哪里 `n` 是多个值。 结果取决于运行查询的顺序,并且是不确定的。
|
最大误差为1%。 内存消耗 `log(n)`,这里 `n` 是值的个数。 结果取决于运行查询的顺序,并且是不确定的。
|
||||||
|
|
||||||
该功能的性能低于性能 [分位数](#quantile) 或 [分位定时](#quantiletiming). 在状态大小与精度的比率方面,这个函数比 `quantile`.
|
该功能的性能低于性能 [分位数](#quantile) 或 [时间分位](#quantiletiming). 在状态大小与精度的比率方面,这个函数比 `quantile`更优秀。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1402,12 +1400,12 @@ quantileTDigest(level)(expr)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
|
|
||||||
**回值**
|
**回值**
|
||||||
|
|
||||||
- 指定电平的近似分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1438,13 +1436,13 @@ SELECT quantileTDigest(number) FROM numbers(10)
|
|||||||
|
|
||||||
## quantileTDigestWeighted {#quantiletdigestweighted}
|
## quantileTDigestWeighted {#quantiletdigestweighted}
|
||||||
|
|
||||||
计算近似值 [分位数](https://en.wikipedia.org/wiki/Quantile) 使用的数字数据序列 [t-digest](https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf) 算法。 该函数考虑了每个序列成员的权重。 最大误差为1%。 内存消耗 `log(n)`,哪里 `n` 是多个值。
|
使用[t-digest](https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf) 算法计算近似[分位数](https://en.wikipedia.org/wiki/Quantile)。 该函数考虑了每个序列成员的权重。最大误差为1%。 内存消耗 `log(n)`,这里 `n` 是值的个数。
|
||||||
|
|
||||||
该功能的性能低于性能 [分位数](#quantile) 或 [分位定时](#quantiletiming). 在状态大小与精度的比率方面,这个函数比 `quantile`.
|
该功能的性能低于性能 [分位数](#quantile) 或 [时间分位](#quantiletiming). 在状态大小与精度的比率方面,这个函数比 `quantile`更优秀。
|
||||||
|
|
||||||
结果取决于运行查询的顺序,并且是不确定的。
|
结果取决于运行查询的顺序,并且是不确定的。
|
||||||
|
|
||||||
当使用多个 `quantile*` 在查询中具有不同级别的函数,内部状态不会被组合(即查询的工作效率低于它可以)。 在这种情况下,使用 [分位数](#quantiles) 功能。
|
当在一个查询中使用多个不同层次的 `quantile*` 时,内部状态不会被组合(即查询的工作效率低于组合情况)。在这种情况下,使用[分位数](#quantiles)功能
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1456,13 +1454,13 @@ quantileTDigest(level)(expr)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `level` — Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a `level` 值的范围 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
- `level` — 分位数层次。可选参数。 从0到1的一个float类型的常量。 我们推荐 `level` 值的范围为 `[0.01, 0.99]`. 默认值:0.5。 在 `level=0.5` 该函数计算 [中位数](https://en.wikipedia.org/wiki/Median).
|
||||||
- `expr` — Expression over the column values resulting in numeric [数据类型](../../sql-reference/data-types/index.md#data_types), [日期](../../sql-reference/data-types/date.md) 或 [日期时间](../../sql-reference/data-types/datetime.md).
|
- `expr` — 求职表达式,类型为:数值[数据类型](../../sql-reference/data-types/index.md#data_types),[日期](../../sql-reference/data-types/date.md)数据类型或[时间](../../sql-reference/data-types/datetime.md)数据类型。
|
||||||
- `weight` — Column with weights of sequence elements. Weight is a number of value occurrences.
|
- `weight` — 权重序列。 权重是一个数据出现的数值。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
- 指定电平的近似分位数。
|
- 指定层次的分位数。
|
||||||
|
|
||||||
类型:
|
类型:
|
||||||
|
|
||||||
@ -1491,20 +1489,20 @@ SELECT quantileTDigestWeighted(number, 1) FROM numbers(10)
|
|||||||
- [中位数](#median)
|
- [中位数](#median)
|
||||||
- [分位数](#quantiles)
|
- [分位数](#quantiles)
|
||||||
|
|
||||||
## 中位数 {#median}
|
## median {#median}
|
||||||
|
|
||||||
该 `median*` 函数是相应的别名 `quantile*` 功能。 它们计算数字数据样本的中位数。
|
`median*` 函数是 `quantile*` 函数的别名。 它们计算数字数据样本的中位数。
|
||||||
|
|
||||||
功能:
|
函数:
|
||||||
|
|
||||||
- `median` — Alias for [分位数](#quantile).
|
- `median` — [quantile](#quantile)别名。
|
||||||
- `medianDeterministic` — Alias for [量化确定](#quantiledeterministic).
|
- `medianDeterministic` — [quantileDeterministic](#quantiledeterministic)别名。
|
||||||
- `medianExact` — Alias for [quantileExact](#quantileexact).
|
- `medianExact` — [quantileExact](#quantileexact)别名。
|
||||||
- `medianExactWeighted` — Alias for [分位数加权](#quantileexactweighted).
|
- `medianExactWeighted` — [quantileExactWeighted](#quantileexactweighted)别名。
|
||||||
- `medianTiming` — Alias for [分位定时](#quantiletiming).
|
- `medianTiming` — [quantileTiming](#quantiletiming)别名。
|
||||||
- `medianTimingWeighted` — Alias for [分位时间加权](#quantiletimingweighted).
|
- `medianTimingWeighted` — [quantileTimingWeighted](#quantiletimingweighted)别名。
|
||||||
- `medianTDigest` — Alias for [quantileTDigest](#quantiletdigest).
|
- `medianTDigest` — [quantileTDigest](#quantiletdigest)别名。
|
||||||
- `medianTDigestWeighted` — Alias for [quantileTDigestWeighted](#quantiletdigestweighted).
|
- `medianTDigestWeighted` — [quantileTDigestWeighted](#quantiletdigestweighted)别名。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
@ -1535,11 +1533,11 @@ SELECT medianDeterministic(val, 1) FROM t
|
|||||||
|
|
||||||
## quantiles(level1, level2, …)(x) {#quantiles}
|
## quantiles(level1, level2, …)(x) {#quantiles}
|
||||||
|
|
||||||
所有分位数函数也具有相应的分位数函数: `quantiles`, `quantilesDeterministic`, `quantilesTiming`, `quantilesTimingWeighted`, `quantilesExact`, `quantilesExactWeighted`, `quantilesTDigest`. 这些函数在一遍中计算所列电平的所有分位数,并返回结果值的数组。
|
所有分位数函数也有相应的函数: `quantiles`, `quantilesDeterministic`, `quantilesTiming`, `quantilesTimingWeighted`, `quantilesExact`, `quantilesExactWeighted`, `quantilesTDigest`。这些函数一次计算所列层次的所有分位数,并返回结果值的数组。
|
||||||
|
|
||||||
## varSamp(x) {#varsampx}
|
## varSamp(x) {#varsampx}
|
||||||
|
|
||||||
计算金额 `Σ((x - x̅)^2) / (n - 1)`,哪里 `n` 是样本大小和 `x̅`是平均值 `x`.
|
计算 `Σ((x - x̅)^2) / (n - 1)`,这里 `n` 是样本大小, `x̅`是`x`的平均值。
|
||||||
|
|
||||||
它表示随机变量的方差的无偏估计,如果传递的值形成其样本。
|
它表示随机变量的方差的无偏估计,如果传递的值形成其样本。
|
||||||
|
|
||||||
@ -1550,23 +1548,23 @@ SELECT medianDeterministic(val, 1) FROM t
|
|||||||
|
|
||||||
## varPop(x) {#varpopx}
|
## varPop(x) {#varpopx}
|
||||||
|
|
||||||
计算金额 `Σ((x - x̅)^2) / n`,哪里 `n` 是样本大小和 `x̅`是平均值 `x`.
|
计算 `Σ((x - x̅)^2) / n`,这里 `n` 是样本大小, `x̅`是`x`的平均值。
|
||||||
|
|
||||||
换句话说,分散为一组值。 返回 `Float64`.
|
换句话说,计算一组数据的离差。 返回 `Float64`。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `varPopStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `varPopStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
||||||
|
|
||||||
## stddevSamp(x) {#stddevsampx}
|
## stddevSamp(x) {#stddevsampx}
|
||||||
|
|
||||||
结果等于平方根 `varSamp(x)`.
|
结果等于平方根 `varSamp(x)`。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `stddevSampStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `stddevSampStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
||||||
|
|
||||||
## stddevPop(x) {#stddevpopx}
|
## stddevPop(x) {#stddevpopx}
|
||||||
|
|
||||||
结果等于平方根 `varPop(x)`.
|
结果等于平方根 `varPop(x)`。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `stddevPopStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `stddevPopStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
||||||
@ -1575,15 +1573,15 @@ SELECT medianDeterministic(val, 1) FROM t
|
|||||||
|
|
||||||
返回指定列中近似最常见值的数组。 生成的数组按值的近似频率降序排序(而不是值本身)。
|
返回指定列中近似最常见值的数组。 生成的数组按值的近似频率降序排序(而不是值本身)。
|
||||||
|
|
||||||
实现了 [过滤节省空间](http://www.l2f.inesc-id.pt/~fmmb/wiki/uploads/Work/misnis.ref0a.pdf) 基于reduce-and-combine算法的TopK分析算法 [并行节省空间](https://arxiv.org/pdf/1401.0702.pdf).
|
实现了[过滤节省空间](http://www.l2f.inesc-id.pt/~fmmb/wiki/uploads/Work/misnis.ref0a.pdf)算法, 使用基于reduce-and-combine的算法,借鉴[并行节省空间](https://arxiv.org/pdf/1401.0702.pdf).
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
topK(N)(column)
|
topK(N)(column)
|
||||||
```
|
```
|
||||||
|
|
||||||
此函数不提供保证的结果。 在某些情况下,可能会发生错误,并且可能会返回不是最常见值的常见值。
|
此函数不提供保证的结果。 在某些情况下,可能会发生错误,并且可能会返回不是最高频的值。
|
||||||
|
|
||||||
我们建议使用 `N < 10` 值;性能降低了大 `N` 值。 的最大值 `N = 65536`.
|
我们建议使用 `N < 10` 值,`N` 值越大,性能越低。最大值 `N = 65536`。
|
||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
@ -1593,11 +1591,11 @@ topK(N)(column)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- ' x ' – The value to calculate frequency.
|
- ' x ' – 计算的频率值。
|
||||||
|
|
||||||
**示例**
|
**示例**
|
||||||
|
|
||||||
就拿 [时间](../../getting-started/example-datasets/ontime.md) 数据集,并选择在三个最频繁出现的值 `AirlineID` 列。
|
就拿 [OnTime](../../getting-started/example-datasets/ontime.md) 数据集来说,选择`AirlineID` 列中出现最频繁的三个。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT topK(3)(AirlineID) AS res
|
SELECT topK(3)(AirlineID) AS res
|
||||||
@ -1612,7 +1610,7 @@ FROM ontime
|
|||||||
|
|
||||||
## topKWeighted {#topkweighted}
|
## topKWeighted {#topkweighted}
|
||||||
|
|
||||||
类似于 `topK` 但需要一个整数类型的附加参数 - `weight`. 每个价值都被记入 `weight` 次频率计算。
|
类似于 `topK` 但需要一个整数类型的附加参数 - `weight`. 每个输入都被记入 `weight` 次频率计算。
|
||||||
|
|
||||||
**语法**
|
**语法**
|
||||||
|
|
||||||
@ -1622,12 +1620,12 @@ topKWeighted(N)(x, weight)
|
|||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `N` — The number of elements to return.
|
- `N` — 返回值个数。
|
||||||
|
|
||||||
**参数**
|
**参数**
|
||||||
|
|
||||||
- `x` – The value.
|
- `x` – 输入值。
|
||||||
- `weight` — The weight. [UInt8](../../sql-reference/data-types/int-uint.md).
|
- `weight` — 权重。 [UInt8](../../sql-reference/data-types/int-uint.md)类型。
|
||||||
|
|
||||||
**返回值**
|
**返回值**
|
||||||
|
|
||||||
@ -1651,36 +1649,36 @@ SELECT topKWeighted(10)(number, number) FROM numbers(1000)
|
|||||||
|
|
||||||
## covarSamp(x,y) {#covarsampx-y}
|
## covarSamp(x,y) {#covarsampx-y}
|
||||||
|
|
||||||
计算的值 `Σ((x - x̅)(y - y̅)) / (n - 1)`.
|
计算 `Σ((x - x̅)(y - y̅)) / (n - 1)`。
|
||||||
|
|
||||||
返回Float64。 当 `n <= 1`, returns +∞.
|
返回Float64。 当 `n <= 1`, returns +∞。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `covarSampStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `covarSampStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
||||||
|
|
||||||
## covarPop(x,y) {#covarpopx-y}
|
## covarPop(x,y) {#covarpopx-y}
|
||||||
|
|
||||||
计算的值 `Σ((x - x̅)(y - y̅)) / n`.
|
计算 `Σ((x - x̅)(y - y̅)) / n`。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `covarPopStable` 功能。 它的工作速度较慢,但提供了较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `covarPopStable` 功能。 它的工作速度较慢,但提供了较低的计算错误。
|
||||||
|
|
||||||
## corr(x,y) {#corrx-y}
|
## corr(x,y) {#corrx-y}
|
||||||
|
|
||||||
计算Pearson相关系数: `Σ((x - x̅)(y - y̅)) / sqrt(Σ((x - x̅)^2) * Σ((y - y̅)^2))`.
|
计算Pearson相关系数: `Σ((x - x̅)(y - y̅)) / sqrt(Σ((x - x̅)^2) * Σ((y - y̅)^2))`。
|
||||||
|
|
||||||
!!! note "注"
|
!!! note "注"
|
||||||
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `corrStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
该函数使用数值不稳定的算法。 如果你需要 [数值稳定性](https://en.wikipedia.org/wiki/Numerical_stability) 在计算中,使用 `corrStable` 功能。 它的工作速度较慢,但提供较低的计算错误。
|
||||||
|
|
||||||
## categoricalInformationValue {#categoricalinformationvalue}
|
## categoricalInformationValue {#categoricalinformationvalue}
|
||||||
|
|
||||||
计算的值 `(P(tag = 1) - P(tag = 0))(log(P(tag = 1)) - log(P(tag = 0)))` 对于每个类别。
|
对于每个类别计算 `(P(tag = 1) - P(tag = 0))(log(P(tag = 1)) - log(P(tag = 0)))` 。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
categoricalInformationValue(category1, category2, ..., tag)
|
categoricalInformationValue(category1, category2, ..., tag)
|
||||||
```
|
```
|
||||||
|
|
||||||
结果指示离散(分类)要素如何使用 `[category1, category2, ...]` 有助于预测的价值的学习模型 `tag`.
|
结果指示离散(分类)要素如何使用 `[category1, category2, ...]` 有助于使用学习模型预测`tag`的值。
|
||||||
|
|
||||||
## simpleLinearRegression {#simplelinearregression}
|
## simpleLinearRegression {#simplelinearregression}
|
||||||
|
|
||||||
@ -1692,12 +1690,12 @@ simpleLinearRegression(x, y)
|
|||||||
|
|
||||||
参数:
|
参数:
|
||||||
|
|
||||||
- `x` — Column with dependent variable values.
|
- `x` — x轴。
|
||||||
- `y` — Column with explanatory variable values.
|
- `y` — y轴。
|
||||||
|
|
||||||
返回值:
|
返回值:
|
||||||
|
|
||||||
常量 `(a, b)` 结果行的 `y = a*x + b`.
|
符合`y = a*x + b`的常量 `(a, b)` 。
|
||||||
|
|
||||||
**例**
|
**例**
|
||||||
|
|
||||||
@ -1721,9 +1719,9 @@ SELECT arrayReduce('simpleLinearRegression', [0, 1, 2, 3], [3, 4, 5, 6])
|
|||||||
└───────────────────────────────────────────────────────────────────┘
|
└───────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## 随机指标线上回归 {#agg_functions-stochasticlinearregression}
|
## stochasticLinearRegression {#agg_functions-stochasticlinearregression}
|
||||||
|
|
||||||
该函数实现随机线性回归。 它支持自定义参数的学习率,L2正则化系数,迷你批量大小,并具有更新权重的方法很少 ([亚当](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Adam) (默认使用), [简单SGD](https://en.wikipedia.org/wiki/Stochastic_gradient_descent), [动量](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Momentum), [Nesterov](https://mipt.ru/upload/medialibrary/d7e/41-91.pdf)).
|
该函数实现随机线性回归。 它支持自定义参数的学习率、L2正则化系数、微批,并且具有少量更新权重的方法([Adam](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Adam) (默认), [simple SGD](https://en.wikipedia.org/wiki/Stochastic_gradient_descent), [Momentum](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Momentum), [Nesterov](https://mipt.ru/upload/medialibrary/d7e/41-91.pdf))。
|
||||||
|
|
||||||
### 参数 {#agg_functions-stochasticlinearregression-parameters}
|
### 参数 {#agg_functions-stochasticlinearregression-parameters}
|
||||||
|
|
||||||
@ -1738,14 +1736,14 @@ stochasticLinearRegression(1.0, 1.0, 10, 'SGD')
|
|||||||
3. `mini-batch size` 设置元素的数量,这些元素将被计算和求和以执行梯度下降的一个步骤。 纯随机下降使用一个元素,但是具有小批量(约10个元素)使梯度步骤更稳定。 默认值为 `15`.
|
3. `mini-batch size` 设置元素的数量,这些元素将被计算和求和以执行梯度下降的一个步骤。 纯随机下降使用一个元素,但是具有小批量(约10个元素)使梯度步骤更稳定。 默认值为 `15`.
|
||||||
4. `method for updating weights` 他们是: `Adam` (默认情况下), `SGD`, `Momentum`, `Nesterov`. `Momentum` 和 `Nesterov` 需要更多的计算和内存,但是它们恰好在收敛速度和随机梯度方法的稳定性方面是有用的。
|
4. `method for updating weights` 他们是: `Adam` (默认情况下), `SGD`, `Momentum`, `Nesterov`. `Momentum` 和 `Nesterov` 需要更多的计算和内存,但是它们恰好在收敛速度和随机梯度方法的稳定性方面是有用的。
|
||||||
|
|
||||||
### 用途 {#agg_functions-stochasticlinearregression-usage}
|
### 用法 {#agg_functions-stochasticlinearregression-usage}
|
||||||
|
|
||||||
`stochasticLinearRegression` 用于两个步骤:拟合模型和预测新数据。 为了拟合模型并保存其状态以供以后使用,我们使用 `-State` combinator,它基本上保存了状态(模型权重等)。
|
`stochasticLinearRegression` 用于两个步骤:拟合模型和预测新数据。 为了拟合模型并保存其状态以供以后使用,我们使用 `-State` combinator,它基本上保存了状态(模型权重等)。
|
||||||
为了预测我们使用函数 [evalMLMethod](../functions/machine-learning-functions.md#machine_learning_methods-evalmlmethod),这需要一个状态作为参数以及特征来预测。
|
为了预测我们使用函数 [evalMLMethod](../functions/machine-learning-functions.md#machine_learning_methods-evalmlmethod),这需要一个状态作为参数以及特征来预测。
|
||||||
|
|
||||||
<a name="stochasticlinearregression-usage-fitting"></a>
|
<a name="stochasticlinearregression-usage-fitting"></a>
|
||||||
|
|
||||||
**1.** 适合
|
**1.** 安装
|
||||||
|
|
||||||
可以使用这种查询。
|
可以使用这种查询。
|
||||||
|
|
||||||
@ -1807,28 +1805,28 @@ evalMLMethod(model, param1, param2) FROM test_data
|
|||||||
stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
||||||
```
|
```
|
||||||
|
|
||||||
1. 适合
|
**1.** 安装
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
See the `Fitting` section in the [stochasticLinearRegression](#stochasticlinearregression-usage-fitting) description.
|
参考stochasticLinearRegression相关文档
|
||||||
|
|
||||||
Predicted labels have to be in \[-1, 1\].
|
预测标签的取值范围为[-1, 1]
|
||||||
|
|
||||||
1. 预测
|
**2.** 预测
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
Using saved state we can predict probability of object having label `1`.
|
使用已经保存的state我们可以预测标签为 `1` 的对象的概率。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
WITH (SELECT state FROM your_model) AS model SELECT
|
WITH (SELECT state FROM your_model) AS model SELECT
|
||||||
evalMLMethod(model, param1, param2) FROM test_data
|
evalMLMethod(model, param1, param2) FROM test_data
|
||||||
```
|
```
|
||||||
|
|
||||||
The query will return a column of probabilities. Note that first argument of `evalMLMethod` is `AggregateFunctionState` object, next are columns of features.
|
查询结果返回一个列的概率。注意 `evalMLMethod` 的第一个参数是 `AggregateFunctionState` 对象,接下来的参数是列的特性。
|
||||||
|
|
||||||
We can also set a bound of probability, which assigns elements to different labels.
|
我们也可以设置概率的范围, 这样需要给元素指定不同的标签。
|
||||||
|
|
||||||
``` sql
|
``` sql
|
||||||
SELECT ans < 1.1 AND ans > 0.5 FROM
|
SELECT ans < 1.1 AND ans > 0.5 FROM
|
||||||
@ -1836,14 +1834,14 @@ stochasticLogisticRegression(1.0, 1.0, 10, 'SGD')
|
|||||||
evalMLMethod(model, param1, param2) AS ans FROM test_data)
|
evalMLMethod(model, param1, param2) AS ans FROM test_data)
|
||||||
```
|
```
|
||||||
|
|
||||||
Then the result will be labels.
|
结果是标签。
|
||||||
|
|
||||||
`test_data` is a table like `train_data` but may not contain target value.
|
`test_data` 是一个像 `train_data` 一样的表,但是不包含目标值。
|
||||||
|
|
||||||
**另请参阅**
|
**另请参阅**
|
||||||
|
|
||||||
- [随机指标线上回归](#agg_functions-stochasticlinearregression)
|
- [随机指标线上回归](#agg_functions-stochasticlinearregression)
|
||||||
- [线性回归和逻辑回归之间的差异。](https://stackoverflow.com/questions/12146914/what-is-the-difference-between-linear-regression-and-logistic-regression)
|
- [线性回归和逻辑回归之间的差异](https://stackoverflow.com/questions/12146914/what-is-the-difference-between-linear-regression-and-logistic-regression)
|
||||||
|
|
||||||
## groupBitmapAnd {#groupbitmapand}
|
## groupBitmapAnd {#groupbitmapand}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ private:
|
|||||||
const auto & info = infos[i];
|
const auto & info = infos[i];
|
||||||
|
|
||||||
json_out << double_quote << connections[i]->getDescription() << ": {\n";
|
json_out << double_quote << connections[i]->getDescription() << ": {\n";
|
||||||
json_out << double_quote << "statistics: {\n";
|
json_out << double_quote << "statistics" << ": {\n";
|
||||||
|
|
||||||
print_key_value("QPS", info->queries / info->work_time);
|
print_key_value("QPS", info->queries / info->work_time);
|
||||||
print_key_value("RPS", info->read_rows / info->work_time);
|
print_key_value("RPS", info->read_rows / info->work_time);
|
||||||
@ -479,7 +479,7 @@ private:
|
|||||||
print_key_value("num_queries", info->queries.load(), false);
|
print_key_value("num_queries", info->queries.load(), false);
|
||||||
|
|
||||||
json_out << "},\n";
|
json_out << "},\n";
|
||||||
json_out << double_quote << "query_time_percentiles: {\n";
|
json_out << double_quote << "query_time_percentiles" << ": {\n";
|
||||||
|
|
||||||
for (int percent = 0; percent <= 90; percent += 10)
|
for (int percent = 0; percent <= 90; percent += 10)
|
||||||
print_percentile(*info, percent);
|
print_percentile(*info, percent);
|
||||||
|
@ -1920,7 +1920,11 @@ public:
|
|||||||
std::string text = e.displayText();
|
std::string text = e.displayText();
|
||||||
std::cerr << "Code: " << e.code() << ". " << text << std::endl;
|
std::cerr << "Code: " << e.code() << ". " << text << std::endl;
|
||||||
std::cerr << "Table №" << i << std::endl << std::endl;
|
std::cerr << "Table №" << i << std::endl << std::endl;
|
||||||
exit(e.code());
|
/// Avoid the case when error exit code can possibly overflow to normal (zero).
|
||||||
|
auto exit_code = e.code() % 256;
|
||||||
|
if (exit_code == 0)
|
||||||
|
exit_code = 255;
|
||||||
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ void ClusterCopier::init()
|
|||||||
|
|
||||||
task_description_watch_callback = [this] (const Coordination::WatchResponse & response)
|
task_description_watch_callback = [this] (const Coordination::WatchResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error != Coordination::ZOK)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
return;
|
return;
|
||||||
UInt64 version = ++task_description_version;
|
UInt64 version = ++task_description_version;
|
||||||
LOG_DEBUG(log, "Task description should be updated, local version {}", version);
|
LOG_DEBUG(log, "Task description should be updated, local version {}", version);
|
||||||
@ -206,11 +206,11 @@ void ClusterCopier::uploadTaskDescription(const std::string & task_path, const s
|
|||||||
|
|
||||||
zookeeper->createAncestors(local_task_description_path);
|
zookeeper->createAncestors(local_task_description_path);
|
||||||
auto code = zookeeper->tryCreate(local_task_description_path, task_config_str, zkutil::CreateMode::Persistent);
|
auto code = zookeeper->tryCreate(local_task_description_path, task_config_str, zkutil::CreateMode::Persistent);
|
||||||
if (code && force)
|
if (code != Coordination::Error::ZOK && force)
|
||||||
zookeeper->createOrUpdate(local_task_description_path, task_config_str, zkutil::CreateMode::Persistent);
|
zookeeper->createOrUpdate(local_task_description_path, task_config_str, zkutil::CreateMode::Persistent);
|
||||||
|
|
||||||
LOG_DEBUG(log, "Task description {} uploaded to {} with result {} ({})",
|
LOG_DEBUG(log, "Task description {} uploaded to {} with result {} ({})",
|
||||||
((code && !force) ? "not " : ""), local_task_description_path, code, zookeeper->error2string(code));
|
((code != Coordination::Error::ZOK && !force) ? "not " : ""), local_task_description_path, code, Coordination::errorMessage(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClusterCopier::reloadTaskDescription()
|
void ClusterCopier::reloadTaskDescription()
|
||||||
@ -220,10 +220,10 @@ void ClusterCopier::reloadTaskDescription()
|
|||||||
|
|
||||||
String task_config_str;
|
String task_config_str;
|
||||||
Coordination::Stat stat{};
|
Coordination::Stat stat{};
|
||||||
int code;
|
Coordination::Error code;
|
||||||
|
|
||||||
zookeeper->tryGetWatch(task_description_path, task_config_str, &stat, task_description_watch_callback, &code);
|
zookeeper->tryGetWatch(task_description_path, task_config_str, &stat, task_description_watch_callback, &code);
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
throw Exception("Can't get description node " + task_description_path, ErrorCodes::BAD_ARGUMENTS);
|
throw Exception("Can't get description node " + task_description_path, ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
LOG_DEBUG(log, "Loading description, zxid={}", task_description_current_stat.czxid);
|
LOG_DEBUG(log, "Loading description, zxid={}", task_description_current_stat.czxid);
|
||||||
@ -376,10 +376,10 @@ zkutil::EphemeralNodeHolder::Ptr ClusterCopier::createTaskWorkerNodeAndWaitIfNee
|
|||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
auto code = zookeeper->tryMulti(ops, responses);
|
auto code = zookeeper->tryMulti(ops, responses);
|
||||||
|
|
||||||
if (code == Coordination::ZOK || code == Coordination::ZNODEEXISTS)
|
if (code == Coordination::Error::ZOK || code == Coordination::Error::ZNODEEXISTS)
|
||||||
return std::make_shared<zkutil::EphemeralNodeHolder>(current_worker_path, *zookeeper, false, false, description);
|
return std::make_shared<zkutil::EphemeralNodeHolder>(current_worker_path, *zookeeper, false, false, description);
|
||||||
|
|
||||||
if (code == Coordination::ZBADVERSION)
|
if (code == Coordination::Error::ZBADVERSION)
|
||||||
{
|
{
|
||||||
++num_bad_version_errors;
|
++num_bad_version_errors;
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ TaskStatus ClusterCopier::tryMoveAllPiecesToDestinationTable(const TaskTable & t
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNODEEXISTS)
|
if (e.code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(log, "Someone is already moving pieces {}", current_partition_attach_is_active);
|
LOG_DEBUG(log, "Someone is already moving pieces {}", current_partition_attach_is_active);
|
||||||
return TaskStatus::Active;
|
return TaskStatus::Active;
|
||||||
@ -745,7 +745,7 @@ bool ClusterCopier::tryDropPartitionPiece(
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNODEEXISTS)
|
if (e.code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(log, "Partition {} piece {} is cleaning now by somebody, sleep", task_partition.name, toString(current_piece_number));
|
LOG_DEBUG(log, "Partition {} piece {} is cleaning now by somebody, sleep", task_partition.name, toString(current_piece_number));
|
||||||
std::this_thread::sleep_for(default_sleep_time);
|
std::this_thread::sleep_for(default_sleep_time);
|
||||||
@ -778,7 +778,7 @@ bool ClusterCopier::tryDropPartitionPiece(
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNODEEXISTS)
|
if (e.code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(log, "Partition {} is being filled now by somebody, sleep", task_partition.name);
|
LOG_DEBUG(log, "Partition {} is being filled now by somebody, sleep", task_partition.name);
|
||||||
return false;
|
return false;
|
||||||
@ -795,7 +795,7 @@ bool ClusterCopier::tryDropPartitionPiece(
|
|||||||
/// Remove all status nodes
|
/// Remove all status nodes
|
||||||
{
|
{
|
||||||
Strings children;
|
Strings children;
|
||||||
if (zookeeper->tryGetChildren(current_shards_path, children) == Coordination::ZOK)
|
if (zookeeper->tryGetChildren(current_shards_path, children) == Coordination::Error::ZOK)
|
||||||
for (const auto & child : children)
|
for (const auto & child : children)
|
||||||
{
|
{
|
||||||
zookeeper->removeRecursive(current_shards_path + "/" + child);
|
zookeeper->removeRecursive(current_shards_path + "/" + child);
|
||||||
@ -845,7 +845,7 @@ bool ClusterCopier::tryDropPartitionPiece(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(log, "Partition {} piece {} was dropped on cluster {}", task_partition.name, toString(current_piece_number), task_table.cluster_push_name);
|
LOG_INFO(log, "Partition {} piece {} was dropped on cluster {}", task_partition.name, toString(current_piece_number), task_table.cluster_push_name);
|
||||||
if (zookeeper->tryCreate(current_shards_path, host_id, zkutil::CreateMode::Persistent) == Coordination::ZNODEEXISTS)
|
if (zookeeper->tryCreate(current_shards_path, host_id, zkutil::CreateMode::Persistent) == Coordination::Error::ZNODEEXISTS)
|
||||||
zookeeper->set(current_shards_path, host_id);
|
zookeeper->set(current_shards_path, host_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1233,7 +1233,7 @@ TaskStatus ClusterCopier::processPartitionPieceTaskImpl(
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNODEEXISTS)
|
if (e.code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(log, "Someone is already processing {}", current_task_piece_is_active_path);
|
LOG_DEBUG(log, "Someone is already processing {}", current_task_piece_is_active_path);
|
||||||
return TaskStatus::Active;
|
return TaskStatus::Active;
|
||||||
@ -1271,9 +1271,9 @@ TaskStatus ClusterCopier::processPartitionPieceTaskImpl(
|
|||||||
{
|
{
|
||||||
String state_finished = TaskStateWithOwner::getData(TaskState::Finished, host_id);
|
String state_finished = TaskStateWithOwner::getData(TaskState::Finished, host_id);
|
||||||
auto res = zookeeper->tryCreate(current_task_piece_status_path, state_finished, zkutil::CreateMode::Persistent);
|
auto res = zookeeper->tryCreate(current_task_piece_status_path, state_finished, zkutil::CreateMode::Persistent);
|
||||||
if (res == Coordination::ZNODEEXISTS)
|
if (res == Coordination::Error::ZNODEEXISTS)
|
||||||
LOG_DEBUG(log, "Partition {} piece {} is absent on current replica of a shard. But other replicas have already marked it as done.", task_partition.name, current_piece_number);
|
LOG_DEBUG(log, "Partition {} piece {} is absent on current replica of a shard. But other replicas have already marked it as done.", task_partition.name, current_piece_number);
|
||||||
if (res == Coordination::ZOK)
|
if (res == Coordination::Error::ZOK)
|
||||||
LOG_DEBUG(log, "Partition {} piece {} is absent on current replica of a shard. Will mark it as done. Other replicas will do the same.", task_partition.name, current_piece_number);
|
LOG_DEBUG(log, "Partition {} piece {} is absent on current replica of a shard. Will mark it as done. Other replicas will do the same.", task_partition.name, current_piece_number);
|
||||||
return TaskStatus::Finished;
|
return TaskStatus::Finished;
|
||||||
}
|
}
|
||||||
@ -1429,7 +1429,7 @@ TaskStatus ClusterCopier::processPartitionPieceTaskImpl(
|
|||||||
{
|
{
|
||||||
Coordination::ExistsResponse status = future_is_dirty_checker.get();
|
Coordination::ExistsResponse status = future_is_dirty_checker.get();
|
||||||
|
|
||||||
if (status.error != Coordination::ZNONODE)
|
if (status.error != Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
LogicalClock dirt_discovery_epoch (status.stat.mzxid);
|
LogicalClock dirt_discovery_epoch (status.stat.mzxid);
|
||||||
if (dirt_discovery_epoch == clean_state_clock.discovery_zxid)
|
if (dirt_discovery_epoch == clean_state_clock.discovery_zxid)
|
||||||
|
@ -178,7 +178,7 @@ public:
|
|||||||
[stale = stale] (const Coordination::WatchResponse & rsp)
|
[stale = stale] (const Coordination::WatchResponse & rsp)
|
||||||
{
|
{
|
||||||
auto logger = &Poco::Logger::get("ClusterCopier");
|
auto logger = &Poco::Logger::get("ClusterCopier");
|
||||||
if (rsp.error == Coordination::ZOK)
|
if (rsp.error == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
switch (rsp.type)
|
switch (rsp.type)
|
||||||
{
|
{
|
||||||
|
@ -604,7 +604,8 @@ int Server::main(const std::vector<std::string> & /*args*/)
|
|||||||
if (uncompressed_cache_size > max_cache_size)
|
if (uncompressed_cache_size > max_cache_size)
|
||||||
{
|
{
|
||||||
uncompressed_cache_size = max_cache_size;
|
uncompressed_cache_size = max_cache_size;
|
||||||
LOG_INFO(log, "Uncompressed cache size was lowered to {} because the system has low amount of memory", formatReadableSizeWithBinarySuffix(uncompressed_cache_size));
|
LOG_INFO(log, "Uncompressed cache size was lowered to {} because the system has low amount of memory",
|
||||||
|
formatReadableSizeWithBinarySuffix(uncompressed_cache_size));
|
||||||
}
|
}
|
||||||
global_context->setUncompressedCache(uncompressed_cache_size);
|
global_context->setUncompressedCache(uncompressed_cache_size);
|
||||||
|
|
||||||
@ -619,7 +620,8 @@ int Server::main(const std::vector<std::string> & /*args*/)
|
|||||||
if (mark_cache_size > max_cache_size)
|
if (mark_cache_size > max_cache_size)
|
||||||
{
|
{
|
||||||
mark_cache_size = max_cache_size;
|
mark_cache_size = max_cache_size;
|
||||||
LOG_INFO(log, "Mark cache size was lowered to {} because the system has low amount of memory", formatReadableSizeWithBinarySuffix(uncompressed_cache_size));
|
LOG_INFO(log, "Mark cache size was lowered to {} because the system has low amount of memory",
|
||||||
|
formatReadableSizeWithBinarySuffix(mark_cache_size));
|
||||||
}
|
}
|
||||||
global_context->setMarkCache(mark_cache_size);
|
global_context->setMarkCache(mark_cache_size);
|
||||||
|
|
||||||
|
@ -481,6 +481,20 @@
|
|||||||
<collect_interval_milliseconds>1000</collect_interval_milliseconds>
|
<collect_interval_milliseconds>1000</collect_interval_milliseconds>
|
||||||
</metric_log>
|
</metric_log>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Asynchronous metric log contains values of metrics from
|
||||||
|
system.asynchronous_metrics.
|
||||||
|
-->
|
||||||
|
<asynchronous_metric_log>
|
||||||
|
<database>system</database>
|
||||||
|
<table>asynchronous_metric_log</table>
|
||||||
|
<!--
|
||||||
|
Asynchronous metrics are updated once a minute, so there is
|
||||||
|
no need to flush more often.
|
||||||
|
-->
|
||||||
|
<flush_interval_milliseconds>60000</flush_interval_milliseconds>
|
||||||
|
</asynchronous_metric_log>
|
||||||
|
|
||||||
<!-- Parameters for embedded dictionaries, used in Yandex.Metrica.
|
<!-- Parameters for embedded dictionaries, used in Yandex.Metrica.
|
||||||
See https://clickhouse.yandex/docs/en/dicts/internal_dicts/
|
See https://clickhouse.yandex/docs/en/dicts/internal_dicts/
|
||||||
-->
|
-->
|
||||||
|
7
programs/server/users.d/access_management.xml
Normal file
7
programs/server/users.d/access_management.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<yandex>
|
||||||
|
<users>
|
||||||
|
<default>
|
||||||
|
<access_management>1</access_management>
|
||||||
|
</default>
|
||||||
|
</users>
|
||||||
|
</yandex>
|
@ -38,6 +38,7 @@ void OptimizedRegularExpressionImpl<thread_safe>::analyze(
|
|||||||
required_substring_is_prefix = false;
|
required_substring_is_prefix = false;
|
||||||
required_substring.clear();
|
required_substring.clear();
|
||||||
bool has_alternative_on_depth_0 = false;
|
bool has_alternative_on_depth_0 = false;
|
||||||
|
bool has_case_insensitive_flag = false;
|
||||||
|
|
||||||
/// Substring with a position.
|
/// Substring with a position.
|
||||||
using Substring = std::pair<std::string, size_t>;
|
using Substring = std::pair<std::string, size_t>;
|
||||||
@ -65,7 +66,17 @@ void OptimizedRegularExpressionImpl<thread_safe>::analyze(
|
|||||||
|
|
||||||
switch (*pos)
|
switch (*pos)
|
||||||
{
|
{
|
||||||
case '|': case '(': case ')': case '^': case '$': case '.': case '[': case '?': case '*': case '+': case '{':
|
case '|':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '^':
|
||||||
|
case '$':
|
||||||
|
case '.':
|
||||||
|
case '[':
|
||||||
|
case '?':
|
||||||
|
case '*':
|
||||||
|
case '+':
|
||||||
|
case '{':
|
||||||
if (depth == 0 && !in_curly_braces && !in_square_braces)
|
if (depth == 0 && !in_curly_braces && !in_square_braces)
|
||||||
{
|
{
|
||||||
if (last_substring->first.empty())
|
if (last_substring->first.empty())
|
||||||
@ -110,6 +121,28 @@ void OptimizedRegularExpressionImpl<thread_safe>::analyze(
|
|||||||
trivial_substrings.resize(trivial_substrings.size() + 1);
|
trivial_substrings.resize(trivial_substrings.size() + 1);
|
||||||
last_substring = &trivial_substrings.back();
|
last_substring = &trivial_substrings.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check for case-insensitive flag.
|
||||||
|
if (pos + 1 < end && pos[1] == '?')
|
||||||
|
{
|
||||||
|
for (size_t offset = 2; pos + offset < end; ++offset)
|
||||||
|
{
|
||||||
|
if (pos[offset] == '-' /// it means flag negation
|
||||||
|
/// various possible flags, actually only imsU are supported by re2
|
||||||
|
|| (pos[offset] >= 'a' && pos[offset] <= 'z')
|
||||||
|
|| (pos[offset] >= 'A' && pos[offset] <= 'Z'))
|
||||||
|
{
|
||||||
|
if (pos[offset] == 'i')
|
||||||
|
{
|
||||||
|
/// Actually it can be negated case-insensitive flag. But we don't care.
|
||||||
|
has_case_insensitive_flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++pos;
|
++pos;
|
||||||
break;
|
break;
|
||||||
@ -209,7 +242,7 @@ void OptimizedRegularExpressionImpl<thread_safe>::analyze(
|
|||||||
|
|
||||||
if (!is_trivial)
|
if (!is_trivial)
|
||||||
{
|
{
|
||||||
if (!has_alternative_on_depth_0)
|
if (!has_alternative_on_depth_0 && !has_case_insensitive_flag)
|
||||||
{
|
{
|
||||||
/// We choose the non-alternative substring of the maximum length for first search.
|
/// We choose the non-alternative substring of the maximum length for first search.
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ namespace ProfileEvents
|
|||||||
namespace Coordination
|
namespace Coordination
|
||||||
{
|
{
|
||||||
|
|
||||||
Exception::Exception(const std::string & msg, const int32_t code_, int)
|
Exception::Exception(const std::string & msg, const Error code_, int)
|
||||||
: DB::Exception(msg, DB::ErrorCodes::KEEPER_EXCEPTION), code(code_)
|
: DB::Exception(msg, DB::ErrorCodes::KEEPER_EXCEPTION), code(code_)
|
||||||
{
|
{
|
||||||
if (Coordination::isUserError(code))
|
if (Coordination::isUserError(code))
|
||||||
@ -34,17 +34,17 @@ Exception::Exception(const std::string & msg, const int32_t code_, int)
|
|||||||
ProfileEvents::increment(ProfileEvents::ZooKeeperOtherExceptions);
|
ProfileEvents::increment(ProfileEvents::ZooKeeperOtherExceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception::Exception(const std::string & msg, const int32_t code_)
|
Exception::Exception(const std::string & msg, const Error code_)
|
||||||
: Exception(msg + " (" + errorMessage(code_) + ")", code_, 0)
|
: Exception(msg + " (" + errorMessage(code_) + ")", code_, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception::Exception(const int32_t code_)
|
Exception::Exception(const Error code_)
|
||||||
: Exception(errorMessage(code_), code_, 0)
|
: Exception(errorMessage(code_), code_, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Exception::Exception(const int32_t code_, const std::string & path)
|
Exception::Exception(const Error code_, const std::string & path)
|
||||||
: Exception(std::string{errorMessage(code_)} + ", path: " + path, code_, 0)
|
: Exception(std::string{errorMessage(code_)} + ", path: " + path, code_, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -58,10 +58,10 @@ using namespace DB;
|
|||||||
static void addRootPath(String & path, const String & root_path)
|
static void addRootPath(String & path, const String & root_path)
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
throw Exception("Path cannot be empty", ZBADARGUMENTS);
|
throw Exception("Path cannot be empty", Error::ZBADARGUMENTS);
|
||||||
|
|
||||||
if (path[0] != '/')
|
if (path[0] != '/')
|
||||||
throw Exception("Path must begin with /", ZBADARGUMENTS);
|
throw Exception("Path must begin with /", Error::ZBADARGUMENTS);
|
||||||
|
|
||||||
if (root_path.empty())
|
if (root_path.empty())
|
||||||
return;
|
return;
|
||||||
@ -78,64 +78,62 @@ static void removeRootPath(String & path, const String & root_path)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (path.size() <= root_path.size())
|
if (path.size() <= root_path.size())
|
||||||
throw Exception("Received path is not longer than root_path", ZDATAINCONSISTENCY);
|
throw Exception("Received path is not longer than root_path", Error::ZDATAINCONSISTENCY);
|
||||||
|
|
||||||
path = path.substr(root_path.size());
|
path = path.substr(root_path.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char * errorMessage(int32_t code)
|
const char * errorMessage(Error code)
|
||||||
{
|
{
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case ZOK: return "Ok";
|
case Error::ZOK: return "Ok";
|
||||||
case ZSYSTEMERROR: return "System error";
|
case Error::ZSYSTEMERROR: return "System error";
|
||||||
case ZRUNTIMEINCONSISTENCY: return "Run time inconsistency";
|
case Error::ZRUNTIMEINCONSISTENCY: return "Run time inconsistency";
|
||||||
case ZDATAINCONSISTENCY: return "Data inconsistency";
|
case Error::ZDATAINCONSISTENCY: return "Data inconsistency";
|
||||||
case ZCONNECTIONLOSS: return "Connection loss";
|
case Error::ZCONNECTIONLOSS: return "Connection loss";
|
||||||
case ZMARSHALLINGERROR: return "Marshalling error";
|
case Error::ZMARSHALLINGERROR: return "Marshalling error";
|
||||||
case ZUNIMPLEMENTED: return "Unimplemented";
|
case Error::ZUNIMPLEMENTED: return "Unimplemented";
|
||||||
case ZOPERATIONTIMEOUT: return "Operation timeout";
|
case Error::ZOPERATIONTIMEOUT: return "Operation timeout";
|
||||||
case ZBADARGUMENTS: return "Bad arguments";
|
case Error::ZBADARGUMENTS: return "Bad arguments";
|
||||||
case ZINVALIDSTATE: return "Invalid zhandle state";
|
case Error::ZINVALIDSTATE: return "Invalid zhandle state";
|
||||||
case ZAPIERROR: return "API error";
|
case Error::ZAPIERROR: return "API error";
|
||||||
case ZNONODE: return "No node";
|
case Error::ZNONODE: return "No node";
|
||||||
case ZNOAUTH: return "Not authenticated";
|
case Error::ZNOAUTH: return "Not authenticated";
|
||||||
case ZBADVERSION: return "Bad version";
|
case Error::ZBADVERSION: return "Bad version";
|
||||||
case ZNOCHILDRENFOREPHEMERALS: return "No children for ephemerals";
|
case Error::ZNOCHILDRENFOREPHEMERALS: return "No children for ephemerals";
|
||||||
case ZNODEEXISTS: return "Node exists";
|
case Error::ZNODEEXISTS: return "Node exists";
|
||||||
case ZNOTEMPTY: return "Not empty";
|
case Error::ZNOTEMPTY: return "Not empty";
|
||||||
case ZSESSIONEXPIRED: return "Session expired";
|
case Error::ZSESSIONEXPIRED: return "Session expired";
|
||||||
case ZINVALIDCALLBACK: return "Invalid callback";
|
case Error::ZINVALIDCALLBACK: return "Invalid callback";
|
||||||
case ZINVALIDACL: return "Invalid ACL";
|
case Error::ZINVALIDACL: return "Invalid ACL";
|
||||||
case ZAUTHFAILED: return "Authentication failed";
|
case Error::ZAUTHFAILED: return "Authentication failed";
|
||||||
case ZCLOSING: return "ZooKeeper is closing";
|
case Error::ZCLOSING: return "ZooKeeper is closing";
|
||||||
case ZNOTHING: return "(not error) no server responses to process";
|
case Error::ZNOTHING: return "(not error) no server responses to process";
|
||||||
case ZSESSIONMOVED: return "Session moved to another server, so operation is ignored";
|
case Error::ZSESSIONMOVED: return "Session moved to another server, so operation is ignored";
|
||||||
}
|
}
|
||||||
if (code > 0)
|
|
||||||
return strerror(code);
|
|
||||||
|
|
||||||
return "unknown error";
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isHardwareError(int32_t zk_return_code)
|
bool isHardwareError(Error zk_return_code)
|
||||||
{
|
{
|
||||||
return zk_return_code == ZINVALIDSTATE
|
return zk_return_code == Error::ZINVALIDSTATE
|
||||||
|| zk_return_code == ZSESSIONEXPIRED
|
|| zk_return_code == Error::ZSESSIONEXPIRED
|
||||||
|| zk_return_code == ZSESSIONMOVED
|
|| zk_return_code == Error::ZSESSIONMOVED
|
||||||
|| zk_return_code == ZCONNECTIONLOSS
|
|| zk_return_code == Error::ZCONNECTIONLOSS
|
||||||
|| zk_return_code == ZMARSHALLINGERROR
|
|| zk_return_code == Error::ZMARSHALLINGERROR
|
||||||
|| zk_return_code == ZOPERATIONTIMEOUT;
|
|| zk_return_code == Error::ZOPERATIONTIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUserError(int32_t zk_return_code)
|
bool isUserError(Error zk_return_code)
|
||||||
{
|
{
|
||||||
return zk_return_code == ZNONODE
|
return zk_return_code == Error::ZNONODE
|
||||||
|| zk_return_code == ZBADVERSION
|
|| zk_return_code == Error::ZBADVERSION
|
||||||
|| zk_return_code == ZNOCHILDRENFOREPHEMERALS
|
|| zk_return_code == Error::ZNOCHILDRENFOREPHEMERALS
|
||||||
|| zk_return_code == ZNODEEXISTS
|
|| zk_return_code == Error::ZNODEEXISTS
|
||||||
|| zk_return_code == ZNOTEMPTY;
|
|| zk_return_code == Error::ZNOTEMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,6 +53,57 @@ struct Stat
|
|||||||
int64_t pzxid;
|
int64_t pzxid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Error : int32_t
|
||||||
|
{
|
||||||
|
ZOK = 0,
|
||||||
|
|
||||||
|
/** System and server-side errors.
|
||||||
|
* This is never thrown by the server, it shouldn't be used other than
|
||||||
|
* to indicate a range. Specifically error codes greater than this
|
||||||
|
* value, but lesser than ZAPIERROR, are system errors.
|
||||||
|
*/
|
||||||
|
ZSYSTEMERROR = -1,
|
||||||
|
|
||||||
|
ZRUNTIMEINCONSISTENCY = -2, /// A runtime inconsistency was found
|
||||||
|
ZDATAINCONSISTENCY = -3, /// A data inconsistency was found
|
||||||
|
ZCONNECTIONLOSS = -4, /// Connection to the server has been lost
|
||||||
|
ZMARSHALLINGERROR = -5, /// Error while marshalling or unmarshalling data
|
||||||
|
ZUNIMPLEMENTED = -6, /// Operation is unimplemented
|
||||||
|
ZOPERATIONTIMEOUT = -7, /// Operation timeout
|
||||||
|
ZBADARGUMENTS = -8, /// Invalid arguments
|
||||||
|
ZINVALIDSTATE = -9, /// Invliad zhandle state
|
||||||
|
|
||||||
|
/** API errors.
|
||||||
|
* This is never thrown by the server, it shouldn't be used other than
|
||||||
|
* to indicate a range. Specifically error codes greater than this
|
||||||
|
* value are API errors.
|
||||||
|
*/
|
||||||
|
ZAPIERROR = -100,
|
||||||
|
|
||||||
|
ZNONODE = -101, /// Node does not exist
|
||||||
|
ZNOAUTH = -102, /// Not authenticated
|
||||||
|
ZBADVERSION = -103, /// Version conflict
|
||||||
|
ZNOCHILDRENFOREPHEMERALS = -108, /// Ephemeral nodes may not have children
|
||||||
|
ZNODEEXISTS = -110, /// The node already exists
|
||||||
|
ZNOTEMPTY = -111, /// The node has children
|
||||||
|
ZSESSIONEXPIRED = -112, /// The session has been expired by the server
|
||||||
|
ZINVALIDCALLBACK = -113, /// Invalid callback specified
|
||||||
|
ZINVALIDACL = -114, /// Invalid ACL specified
|
||||||
|
ZAUTHFAILED = -115, /// Client authentication failed
|
||||||
|
ZCLOSING = -116, /// ZooKeeper is closing
|
||||||
|
ZNOTHING = -117, /// (not error) no server responses to process
|
||||||
|
ZSESSIONMOVED = -118 /// Session moved to another server, so operation is ignored
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Network errors and similar. You should reinitialize ZooKeeper session in case of these errors
|
||||||
|
bool isHardwareError(Error code);
|
||||||
|
|
||||||
|
/// Valid errors sent from the server about database state (like "no node"). Logical and authentication errors (like "bad arguments") are not here.
|
||||||
|
bool isUserError(Error code);
|
||||||
|
|
||||||
|
const char * errorMessage(Error code);
|
||||||
|
|
||||||
|
|
||||||
struct Request;
|
struct Request;
|
||||||
using RequestPtr = std::shared_ptr<Request>;
|
using RequestPtr = std::shared_ptr<Request>;
|
||||||
using Requests = std::vector<RequestPtr>;
|
using Requests = std::vector<RequestPtr>;
|
||||||
@ -74,7 +125,7 @@ using ResponseCallback = std::function<void(const Response &)>;
|
|||||||
|
|
||||||
struct Response
|
struct Response
|
||||||
{
|
{
|
||||||
int32_t error = 0;
|
Error error = Error::ZOK;
|
||||||
Response() = default;
|
Response() = default;
|
||||||
Response(const Response &) = default;
|
Response(const Response &) = default;
|
||||||
Response & operator=(const Response &) = default;
|
Response & operator=(const Response &) = default;
|
||||||
@ -225,56 +276,6 @@ using CheckCallback = std::function<void(const CheckResponse &)>;
|
|||||||
using MultiCallback = std::function<void(const MultiResponse &)>;
|
using MultiCallback = std::function<void(const MultiResponse &)>;
|
||||||
|
|
||||||
|
|
||||||
enum Error
|
|
||||||
{
|
|
||||||
ZOK = 0,
|
|
||||||
|
|
||||||
/** System and server-side errors.
|
|
||||||
* This is never thrown by the server, it shouldn't be used other than
|
|
||||||
* to indicate a range. Specifically error codes greater than this
|
|
||||||
* value, but lesser than ZAPIERROR, are system errors.
|
|
||||||
*/
|
|
||||||
ZSYSTEMERROR = -1,
|
|
||||||
|
|
||||||
ZRUNTIMEINCONSISTENCY = -2, /// A runtime inconsistency was found
|
|
||||||
ZDATAINCONSISTENCY = -3, /// A data inconsistency was found
|
|
||||||
ZCONNECTIONLOSS = -4, /// Connection to the server has been lost
|
|
||||||
ZMARSHALLINGERROR = -5, /// Error while marshalling or unmarshalling data
|
|
||||||
ZUNIMPLEMENTED = -6, /// Operation is unimplemented
|
|
||||||
ZOPERATIONTIMEOUT = -7, /// Operation timeout
|
|
||||||
ZBADARGUMENTS = -8, /// Invalid arguments
|
|
||||||
ZINVALIDSTATE = -9, /// Invliad zhandle state
|
|
||||||
|
|
||||||
/** API errors.
|
|
||||||
* This is never thrown by the server, it shouldn't be used other than
|
|
||||||
* to indicate a range. Specifically error codes greater than this
|
|
||||||
* value are API errors.
|
|
||||||
*/
|
|
||||||
ZAPIERROR = -100,
|
|
||||||
|
|
||||||
ZNONODE = -101, /// Node does not exist
|
|
||||||
ZNOAUTH = -102, /// Not authenticated
|
|
||||||
ZBADVERSION = -103, /// Version conflict
|
|
||||||
ZNOCHILDRENFOREPHEMERALS = -108, /// Ephemeral nodes may not have children
|
|
||||||
ZNODEEXISTS = -110, /// The node already exists
|
|
||||||
ZNOTEMPTY = -111, /// The node has children
|
|
||||||
ZSESSIONEXPIRED = -112, /// The session has been expired by the server
|
|
||||||
ZINVALIDCALLBACK = -113, /// Invalid callback specified
|
|
||||||
ZINVALIDACL = -114, /// Invalid ACL specified
|
|
||||||
ZAUTHFAILED = -115, /// Client authentication failed
|
|
||||||
ZCLOSING = -116, /// ZooKeeper is closing
|
|
||||||
ZNOTHING = -117, /// (not error) no server responses to process
|
|
||||||
ZSESSIONMOVED = -118 /// Session moved to another server, so operation is ignored
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Network errors and similar. You should reinitialize ZooKeeper session in case of these errors
|
|
||||||
bool isHardwareError(int32_t code);
|
|
||||||
|
|
||||||
/// Valid errors sent from the server about database state (like "no node"). Logical and authentication errors (like "bad arguments") are not here.
|
|
||||||
bool isUserError(int32_t code);
|
|
||||||
|
|
||||||
const char * errorMessage(int32_t code);
|
|
||||||
|
|
||||||
/// For watches.
|
/// For watches.
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
@ -301,19 +302,19 @@ class Exception : public DB::Exception
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/// Delegate constructor, used to minimize repetition; last parameter used for overload resolution.
|
/// Delegate constructor, used to minimize repetition; last parameter used for overload resolution.
|
||||||
Exception(const std::string & msg, const int32_t code_, int);
|
Exception(const std::string & msg, const Error code_, int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Exception(const int32_t code_);
|
explicit Exception(const Error code_);
|
||||||
Exception(const std::string & msg, const int32_t code_);
|
Exception(const std::string & msg, const Error code_);
|
||||||
Exception(const int32_t code_, const std::string & path);
|
Exception(const Error code_, const std::string & path);
|
||||||
Exception(const Exception & exc);
|
Exception(const Exception & exc);
|
||||||
|
|
||||||
const char * name() const throw() override { return "Coordination::Exception"; }
|
const char * name() const throw() override { return "Coordination::Exception"; }
|
||||||
const char * className() const throw() override { return "Coordination::Exception"; }
|
const char * className() const throw() override { return "Coordination::Exception"; }
|
||||||
Exception * clone() const override { return new Exception(*this); }
|
Exception * clone() const override { return new Exception(*this); }
|
||||||
|
|
||||||
const int32_t code;
|
const Error code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,11 +29,11 @@ public:
|
|||||||
if (zookeeper->tryGet(path, result_str, &stat))
|
if (zookeeper->tryGet(path, result_str, &stat))
|
||||||
{
|
{
|
||||||
result = std::stol(result_str) + 1;
|
result = std::stol(result_str) + 1;
|
||||||
success = zookeeper->trySet(path, std::to_string(result), stat.version) == Coordination::ZOK;
|
success = zookeeper->trySet(path, std::to_string(result), stat.version) == Coordination::Error::ZOK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
success = zookeeper->tryCreate(path, std::to_string(result), zkutil::CreateMode::Persistent) == Coordination::ZOK;
|
success = zookeeper->tryCreate(path, std::to_string(result), zkutil::CreateMode::Persistent) == Coordination::Error::ZOK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!success);
|
while (!success);
|
||||||
|
@ -21,12 +21,12 @@ public:
|
|||||||
|
|
||||||
/// If it is user error throws KeeperMultiException else throws ordinary KeeperException
|
/// If it is user error throws KeeperMultiException else throws ordinary KeeperException
|
||||||
/// If it is ZOK does nothing
|
/// If it is ZOK does nothing
|
||||||
static void check(int32_t code, const Coordination::Requests & requests, const Coordination::Responses & responses);
|
static void check(Coordination::Error code, const Coordination::Requests & requests, const Coordination::Responses & responses);
|
||||||
|
|
||||||
KeeperMultiException(int32_t code, const Coordination::Requests & requests, const Coordination::Responses & responses);
|
KeeperMultiException(Coordination::Error code, const Coordination::Requests & requests, const Coordination::Responses & responses);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static size_t getFailedOpIndex(int32_t code, const Coordination::Responses & responses);
|
static size_t getFailedOpIndex(Coordination::Error code, const Coordination::Responses & responses);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,12 @@ public:
|
|||||||
* It means that different participants of leader election have different identifiers
|
* It means that different participants of leader election have different identifiers
|
||||||
* and existence of more than one ephemeral node with same identifier indicates an error.
|
* and existence of more than one ephemeral node with same identifier indicates an error.
|
||||||
*/
|
*/
|
||||||
LeaderElection(DB::BackgroundSchedulePool & pool_, const std::string & path_, ZooKeeper & zookeeper_, LeadershipHandler handler_, const std::string & identifier_ = "")
|
LeaderElection(
|
||||||
|
DB::BackgroundSchedulePool & pool_,
|
||||||
|
const std::string & path_,
|
||||||
|
ZooKeeper & zookeeper_,
|
||||||
|
LeadershipHandler handler_,
|
||||||
|
const std::string & identifier_)
|
||||||
: pool(pool_), path(path_), zookeeper(zookeeper_), handler(handler_), identifier(identifier_)
|
: pool(pool_), path(path_), zookeeper(zookeeper_), handler(handler_), identifier(identifier_)
|
||||||
, log_name("LeaderElection (" + path + ")")
|
, log_name("LeaderElection (" + path + ")")
|
||||||
, log(&Poco::Logger::get(log_name))
|
, log(&Poco::Logger::get(log_name))
|
||||||
@ -121,7 +126,7 @@ private:
|
|||||||
{
|
{
|
||||||
DB::tryLogCurrentException(log);
|
DB::tryLogCurrentException(log);
|
||||||
|
|
||||||
if (e.code == Coordination::ZSESSIONEXPIRED)
|
if (e.code == Coordination::Error::ZSESSIONEXPIRED)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -16,13 +16,13 @@ bool Lock::tryLock()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string dummy;
|
std::string dummy;
|
||||||
int32_t code = zookeeper->tryCreate(lock_path, lock_message, zkutil::CreateMode::Ephemeral, dummy);
|
Coordination::Error code = zookeeper->tryCreate(lock_path, lock_message, zkutil::CreateMode::Ephemeral, dummy);
|
||||||
|
|
||||||
if (code == Coordination::ZNODEEXISTS)
|
if (code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
locked.reset();
|
locked.reset();
|
||||||
}
|
}
|
||||||
else if (code == Coordination::ZOK)
|
else if (code == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
locked = std::make_unique<ZooKeeperHandler>(zookeeper);
|
locked = std::make_unique<ZooKeeperHandler>(zookeeper);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ struct TestKeeperMultiRequest final : MultiRequest, TestKeeperRequest
|
|||||||
requests.push_back(std::make_shared<TestKeeperCheckRequest>(*concrete_request_check));
|
requests.push_back(std::make_shared<TestKeeperCheckRequest>(*concrete_request_check));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Exception("Illegal command as part of multi ZooKeeper request", ZBADARGUMENTS);
|
throw Exception("Illegal command as part of multi ZooKeeper request", Error::ZBADARGUMENTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ ResponsePtr TestKeeperListRequest::process(TestKeeper::Container & container, in
|
|||||||
{
|
{
|
||||||
auto path_prefix = path;
|
auto path_prefix = path;
|
||||||
if (path_prefix.empty())
|
if (path_prefix.empty())
|
||||||
throw Exception("Logical error: path cannot be empty", ZSESSIONEXPIRED);
|
throw Exception("Logical error: path cannot be empty", Error::ZSESSIONEXPIRED);
|
||||||
|
|
||||||
if (path_prefix.back() != '/')
|
if (path_prefix.back() != '/')
|
||||||
path_prefix += '/';
|
path_prefix += '/';
|
||||||
@ -514,7 +514,7 @@ void TestKeeper::finalize()
|
|||||||
WatchResponse response;
|
WatchResponse response;
|
||||||
response.type = SESSION;
|
response.type = SESSION;
|
||||||
response.state = EXPIRED_SESSION;
|
response.state = EXPIRED_SESSION;
|
||||||
response.error = ZSESSIONEXPIRED;
|
response.error = Error::ZSESSIONEXPIRED;
|
||||||
|
|
||||||
for (auto & callback : path_watch.second)
|
for (auto & callback : path_watch.second)
|
||||||
{
|
{
|
||||||
@ -541,7 +541,7 @@ void TestKeeper::finalize()
|
|||||||
if (info.callback)
|
if (info.callback)
|
||||||
{
|
{
|
||||||
ResponsePtr response = info.request->createResponse();
|
ResponsePtr response = info.request->createResponse();
|
||||||
response->error = ZSESSIONEXPIRED;
|
response->error = Error::ZSESSIONEXPIRED;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info.callback(*response);
|
info.callback(*response);
|
||||||
@ -556,7 +556,7 @@ void TestKeeper::finalize()
|
|||||||
WatchResponse response;
|
WatchResponse response;
|
||||||
response.type = SESSION;
|
response.type = SESSION;
|
||||||
response.state = EXPIRED_SESSION;
|
response.state = EXPIRED_SESSION;
|
||||||
response.error = ZSESSIONEXPIRED;
|
response.error = Error::ZSESSIONEXPIRED;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info.watch(response);
|
info.watch(response);
|
||||||
@ -587,10 +587,10 @@ void TestKeeper::pushRequest(RequestInfo && request)
|
|||||||
std::lock_guard lock(push_request_mutex);
|
std::lock_guard lock(push_request_mutex);
|
||||||
|
|
||||||
if (expired)
|
if (expired)
|
||||||
throw Exception("Session expired", ZSESSIONEXPIRED);
|
throw Exception("Session expired", Error::ZSESSIONEXPIRED);
|
||||||
|
|
||||||
if (!requests_queue.tryPush(std::move(request), operation_timeout.totalMilliseconds()))
|
if (!requests_queue.tryPush(std::move(request), operation_timeout.totalMilliseconds()))
|
||||||
throw Exception("Cannot push request to queue within operation timeout", ZOPERATIONTIMEOUT);
|
throw Exception("Cannot push request to queue within operation timeout", Error::ZOPERATIONTIMEOUT);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -38,9 +38,9 @@ const int CreateMode::PersistentSequential = 2;
|
|||||||
const int CreateMode::EphemeralSequential = 3;
|
const int CreateMode::EphemeralSequential = 3;
|
||||||
|
|
||||||
|
|
||||||
static void check(int32_t code, const std::string & path)
|
static void check(Coordination::Error code, const std::string & path)
|
||||||
{
|
{
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ void ZooKeeper::init(const std::string & implementation_, const std::string & ho
|
|||||||
if (implementation == "zookeeper")
|
if (implementation == "zookeeper")
|
||||||
{
|
{
|
||||||
if (hosts.empty())
|
if (hosts.empty())
|
||||||
throw KeeperException("No hosts passed to ZooKeeper constructor.", Coordination::ZBADARGUMENTS);
|
throw KeeperException("No hosts passed to ZooKeeper constructor.", Coordination::Error::ZBADARGUMENTS);
|
||||||
|
|
||||||
std::vector<std::string> hosts_strings;
|
std::vector<std::string> hosts_strings;
|
||||||
splitInto<','>(hosts_strings, hosts);
|
splitInto<','>(hosts_strings, hosts);
|
||||||
@ -84,7 +84,7 @@ void ZooKeeper::init(const std::string & implementation_, const std::string & ho
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.empty())
|
if (nodes.empty())
|
||||||
throw KeeperException("Cannot use any of provided ZooKeeper nodes", Coordination::ZBADARGUMENTS);
|
throw KeeperException("Cannot use any of provided ZooKeeper nodes", Coordination::Error::ZBADARGUMENTS);
|
||||||
|
|
||||||
impl = std::make_unique<Coordination::ZooKeeper>(
|
impl = std::make_unique<Coordination::ZooKeeper>(
|
||||||
nodes,
|
nodes,
|
||||||
@ -112,7 +112,7 @@ void ZooKeeper::init(const std::string & implementation_, const std::string & ho
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!chroot.empty() && !exists("/"))
|
if (!chroot.empty() && !exists("/"))
|
||||||
throw KeeperException("Zookeeper root doesn't exist. You should create root node " + chroot + " before start.", Coordination::ZNONODE);
|
throw KeeperException("Zookeeper root doesn't exist. You should create root node " + chroot + " before start.", Coordination::Error::ZNONODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZooKeeper::ZooKeeper(const std::string & hosts_, const std::string & identity_, int32_t session_timeout_ms_,
|
ZooKeeper::ZooKeeper(const std::string & hosts_, const std::string & identity_, int32_t session_timeout_ms_,
|
||||||
@ -164,7 +164,7 @@ struct ZooKeeperArgs
|
|||||||
implementation = config.getString(config_name + "." + key);
|
implementation = config.getString(config_name + "." + key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw KeeperException(std::string("Unknown key ") + key + " in config file", Coordination::ZBADARGUMENTS);
|
throw KeeperException(std::string("Unknown key ") + key + " in config file", Coordination::Error::ZBADARGUMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shuffle the hosts to distribute the load among ZooKeeper nodes.
|
/// Shuffle the hosts to distribute the load among ZooKeeper nodes.
|
||||||
@ -182,7 +182,7 @@ struct ZooKeeperArgs
|
|||||||
if (!chroot.empty())
|
if (!chroot.empty())
|
||||||
{
|
{
|
||||||
if (chroot.front() != '/')
|
if (chroot.front() != '/')
|
||||||
throw KeeperException(std::string("Root path in config file should start with '/', but got ") + chroot, Coordination::ZBADARGUMENTS);
|
throw KeeperException(std::string("Root path in config file should start with '/', but got ") + chroot, Coordination::Error::ZBADARGUMENTS);
|
||||||
if (chroot.back() == '/')
|
if (chroot.back() == '/')
|
||||||
chroot.pop_back();
|
chroot.pop_back();
|
||||||
}
|
}
|
||||||
@ -211,17 +211,17 @@ static Coordination::WatchCallback callbackForEvent(const EventPtr & watch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t ZooKeeper::getChildrenImpl(const std::string & path, Strings & res,
|
Coordination::Error ZooKeeper::getChildrenImpl(const std::string & path, Strings & res,
|
||||||
Coordination::Stat * stat,
|
Coordination::Stat * stat,
|
||||||
Coordination::WatchCallback watch_callback)
|
Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::ListResponse & response)
|
auto callback = [&](const Coordination::ListResponse & response)
|
||||||
{
|
{
|
||||||
code = response.error;
|
code = response.error;
|
||||||
if (!code)
|
if (code == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
res = response.names;
|
res = response.names;
|
||||||
if (stat)
|
if (stat)
|
||||||
@ -251,37 +251,37 @@ Strings ZooKeeper::getChildrenWatch(
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryGetChildren(const std::string & path, Strings & res,
|
Coordination::Error ZooKeeper::tryGetChildren(const std::string & path, Strings & res,
|
||||||
Coordination::Stat * stat, const EventPtr & watch)
|
Coordination::Stat * stat, const EventPtr & watch)
|
||||||
{
|
{
|
||||||
int32_t code = getChildrenImpl(path, res, stat, callbackForEvent(watch));
|
Coordination::Error code = getChildrenImpl(path, res, stat, callbackForEvent(watch));
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK || code == Coordination::ZNONODE))
|
if (!(code == Coordination::Error::ZOK || code == Coordination::Error::ZNONODE))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryGetChildrenWatch(const std::string & path, Strings & res,
|
Coordination::Error ZooKeeper::tryGetChildrenWatch(const std::string & path, Strings & res,
|
||||||
Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = getChildrenImpl(path, res, stat, watch_callback);
|
Coordination::Error code = getChildrenImpl(path, res, stat, watch_callback);
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK || code == Coordination::ZNONODE))
|
if (!(code == Coordination::Error::ZOK || code == Coordination::Error::ZNONODE))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created)
|
Coordination::Error ZooKeeper::createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::CreateResponse & response)
|
auto callback = [&](const Coordination::CreateResponse & response)
|
||||||
{
|
{
|
||||||
code = response.error;
|
code = response.error;
|
||||||
if (!code)
|
if (code == Coordination::Error::ZOK)
|
||||||
path_created = response.path_created;
|
path_created = response.path_created;
|
||||||
event.set();
|
event.set();
|
||||||
};
|
};
|
||||||
@ -298,20 +298,20 @@ std::string ZooKeeper::create(const std::string & path, const std::string & data
|
|||||||
return path_created;
|
return path_created;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & path_created)
|
Coordination::Error ZooKeeper::tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & path_created)
|
||||||
{
|
{
|
||||||
int32_t code = createImpl(path, data, mode, path_created);
|
Coordination::Error code = createImpl(path, data, mode, path_created);
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK ||
|
if (!(code == Coordination::Error::ZOK ||
|
||||||
code == Coordination::ZNONODE ||
|
code == Coordination::Error::ZNONODE ||
|
||||||
code == Coordination::ZNODEEXISTS ||
|
code == Coordination::Error::ZNODEEXISTS ||
|
||||||
code == Coordination::ZNOCHILDRENFOREPHEMERALS))
|
code == Coordination::Error::ZNOCHILDRENFOREPHEMERALS))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryCreate(const std::string & path, const std::string & data, int32_t mode)
|
Coordination::Error ZooKeeper::tryCreate(const std::string & path, const std::string & data, int32_t mode)
|
||||||
{
|
{
|
||||||
std::string path_created;
|
std::string path_created;
|
||||||
return tryCreate(path, data, mode, path_created);
|
return tryCreate(path, data, mode, path_created);
|
||||||
@ -320,9 +320,9 @@ int32_t ZooKeeper::tryCreate(const std::string & path, const std::string & data,
|
|||||||
void ZooKeeper::createIfNotExists(const std::string & path, const std::string & data)
|
void ZooKeeper::createIfNotExists(const std::string & path, const std::string & data)
|
||||||
{
|
{
|
||||||
std::string path_created;
|
std::string path_created;
|
||||||
int32_t code = createImpl(path, data, CreateMode::Persistent, path_created);
|
Coordination::Error code = createImpl(path, data, CreateMode::Persistent, path_created);
|
||||||
|
|
||||||
if (code == Coordination::ZOK || code == Coordination::ZNODEEXISTS)
|
if (code == Coordination::Error::ZOK || code == Coordination::Error::ZNODEEXISTS)
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
@ -341,14 +341,14 @@ void ZooKeeper::createAncestors(const std::string & path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::removeImpl(const std::string & path, int32_t version)
|
Coordination::Error ZooKeeper::removeImpl(const std::string & path, int32_t version)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::RemoveResponse & response)
|
auto callback = [&](const Coordination::RemoveResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
code = response.error;
|
code = response.error;
|
||||||
event.set();
|
event.set();
|
||||||
};
|
};
|
||||||
@ -363,26 +363,26 @@ void ZooKeeper::remove(const std::string & path, int32_t version)
|
|||||||
check(tryRemove(path, version), path);
|
check(tryRemove(path, version), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryRemove(const std::string & path, int32_t version)
|
Coordination::Error ZooKeeper::tryRemove(const std::string & path, int32_t version)
|
||||||
{
|
{
|
||||||
int32_t code = removeImpl(path, version);
|
Coordination::Error code = removeImpl(path, version);
|
||||||
if (!(code == Coordination::ZOK ||
|
if (!(code == Coordination::Error::ZOK ||
|
||||||
code == Coordination::ZNONODE ||
|
code == Coordination::Error::ZNONODE ||
|
||||||
code == Coordination::ZBADVERSION ||
|
code == Coordination::Error::ZBADVERSION ||
|
||||||
code == Coordination::ZNOTEMPTY))
|
code == Coordination::Error::ZNOTEMPTY))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::existsImpl(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
Coordination::Error ZooKeeper::existsImpl(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::ExistsResponse & response)
|
auto callback = [&](const Coordination::ExistsResponse & response)
|
||||||
{
|
{
|
||||||
code = response.error;
|
code = response.error;
|
||||||
if (!code && stat)
|
if (code == Coordination::Error::ZOK && stat)
|
||||||
*stat = response.stat;
|
*stat = response.stat;
|
||||||
event.set();
|
event.set();
|
||||||
};
|
};
|
||||||
@ -399,22 +399,22 @@ bool ZooKeeper::exists(const std::string & path, Coordination::Stat * stat, cons
|
|||||||
|
|
||||||
bool ZooKeeper::existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
bool ZooKeeper::existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = existsImpl(path, stat, watch_callback);
|
Coordination::Error code = existsImpl(path, stat, watch_callback);
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK || code == Coordination::ZNONODE))
|
if (!(code == Coordination::Error::ZOK || code == Coordination::Error::ZNONODE))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
return code != Coordination::ZNONODE;
|
return code != Coordination::Error::ZNONODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::getImpl(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
Coordination::Error ZooKeeper::getImpl(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::GetResponse & response)
|
auto callback = [&](const Coordination::GetResponse & response)
|
||||||
{
|
{
|
||||||
code = response.error;
|
code = response.error;
|
||||||
if (!code)
|
if (code == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
res = response.data;
|
res = response.data;
|
||||||
if (stat)
|
if (stat)
|
||||||
@ -431,7 +431,7 @@ int32_t ZooKeeper::getImpl(const std::string & path, std::string & res, Coordina
|
|||||||
|
|
||||||
std::string ZooKeeper::get(const std::string & path, Coordination::Stat * stat, const EventPtr & watch)
|
std::string ZooKeeper::get(const std::string & path, Coordination::Stat * stat, const EventPtr & watch)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
std::string res;
|
std::string res;
|
||||||
if (tryGet(path, res, stat, watch, &code))
|
if (tryGet(path, res, stat, watch, &code))
|
||||||
return res;
|
return res;
|
||||||
@ -441,7 +441,7 @@ std::string ZooKeeper::get(const std::string & path, Coordination::Stat * stat,
|
|||||||
|
|
||||||
std::string ZooKeeper::getWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
std::string ZooKeeper::getWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
std::string res;
|
std::string res;
|
||||||
if (tryGetWatch(path, res, stat, watch_callback, &code))
|
if (tryGetWatch(path, res, stat, watch_callback, &code))
|
||||||
return res;
|
return res;
|
||||||
@ -449,34 +449,44 @@ std::string ZooKeeper::getWatch(const std::string & path, Coordination::Stat * s
|
|||||||
throw KeeperException("Can't get data for node " + path + ": node doesn't exist", code);
|
throw KeeperException("Can't get data for node " + path + ": node doesn't exist", code);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZooKeeper::tryGet(const std::string & path, std::string & res, Coordination::Stat * stat, const EventPtr & watch, int * return_code)
|
bool ZooKeeper::tryGet(
|
||||||
|
const std::string & path,
|
||||||
|
std::string & res,
|
||||||
|
Coordination::Stat * stat,
|
||||||
|
const EventPtr & watch,
|
||||||
|
Coordination::Error * return_code)
|
||||||
{
|
{
|
||||||
return tryGetWatch(path, res, stat, callbackForEvent(watch), return_code);
|
return tryGetWatch(path, res, stat, callbackForEvent(watch), return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZooKeeper::tryGetWatch(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback, int * return_code)
|
bool ZooKeeper::tryGetWatch(
|
||||||
|
const std::string & path,
|
||||||
|
std::string & res,
|
||||||
|
Coordination::Stat * stat,
|
||||||
|
Coordination::WatchCallback watch_callback,
|
||||||
|
Coordination::Error * return_code)
|
||||||
{
|
{
|
||||||
int32_t code = getImpl(path, res, stat, watch_callback);
|
Coordination::Error code = getImpl(path, res, stat, watch_callback);
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK || code == Coordination::ZNONODE))
|
if (!(code == Coordination::Error::ZOK || code == Coordination::Error::ZNONODE))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
|
|
||||||
if (return_code)
|
if (return_code)
|
||||||
*return_code = code;
|
*return_code = code;
|
||||||
|
|
||||||
return code == Coordination::ZOK;
|
return code == Coordination::Error::ZOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::setImpl(const std::string & path, const std::string & data,
|
Coordination::Error ZooKeeper::setImpl(const std::string & path, const std::string & data,
|
||||||
int32_t version, Coordination::Stat * stat)
|
int32_t version, Coordination::Stat * stat)
|
||||||
{
|
{
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::SetResponse & response)
|
auto callback = [&](const Coordination::SetResponse & response)
|
||||||
{
|
{
|
||||||
code = response.error;
|
code = response.error;
|
||||||
if (!code && stat)
|
if (code == Coordination::Error::ZOK && stat)
|
||||||
*stat = response.stat;
|
*stat = response.stat;
|
||||||
event.set();
|
event.set();
|
||||||
};
|
};
|
||||||
@ -493,34 +503,34 @@ void ZooKeeper::set(const std::string & path, const std::string & data, int32_t
|
|||||||
|
|
||||||
void ZooKeeper::createOrUpdate(const std::string & path, const std::string & data, int32_t mode)
|
void ZooKeeper::createOrUpdate(const std::string & path, const std::string & data, int32_t mode)
|
||||||
{
|
{
|
||||||
int32_t code = trySet(path, data, -1);
|
Coordination::Error code = trySet(path, data, -1);
|
||||||
if (code == Coordination::ZNONODE)
|
if (code == Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
create(path, data, mode);
|
create(path, data, mode);
|
||||||
}
|
}
|
||||||
else if (code != Coordination::ZOK)
|
else if (code != Coordination::Error::ZOK)
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::trySet(const std::string & path, const std::string & data,
|
Coordination::Error ZooKeeper::trySet(const std::string & path, const std::string & data,
|
||||||
int32_t version, Coordination::Stat * stat)
|
int32_t version, Coordination::Stat * stat)
|
||||||
{
|
{
|
||||||
int32_t code = setImpl(path, data, version, stat);
|
Coordination::Error code = setImpl(path, data, version, stat);
|
||||||
|
|
||||||
if (!(code == Coordination::ZOK ||
|
if (!(code == Coordination::Error::ZOK ||
|
||||||
code == Coordination::ZNONODE ||
|
code == Coordination::Error::ZNONODE ||
|
||||||
code == Coordination::ZBADVERSION))
|
code == Coordination::Error::ZBADVERSION))
|
||||||
throw KeeperException(code, path);
|
throw KeeperException(code, path);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t ZooKeeper::multiImpl(const Coordination::Requests & requests, Coordination::Responses & responses)
|
Coordination::Error ZooKeeper::multiImpl(const Coordination::Requests & requests, Coordination::Responses & responses)
|
||||||
{
|
{
|
||||||
if (requests.empty())
|
if (requests.empty())
|
||||||
return Coordination::ZOK;
|
return Coordination::Error::ZOK;
|
||||||
|
|
||||||
int32_t code = 0;
|
Coordination::Error code = Coordination::Error::ZOK;
|
||||||
Poco::Event event;
|
Poco::Event event;
|
||||||
|
|
||||||
auto callback = [&](const Coordination::MultiResponse & response)
|
auto callback = [&](const Coordination::MultiResponse & response)
|
||||||
@ -538,15 +548,15 @@ int32_t ZooKeeper::multiImpl(const Coordination::Requests & requests, Coordinati
|
|||||||
Coordination::Responses ZooKeeper::multi(const Coordination::Requests & requests)
|
Coordination::Responses ZooKeeper::multi(const Coordination::Requests & requests)
|
||||||
{
|
{
|
||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
int32_t code = multiImpl(requests, responses);
|
Coordination::Error code = multiImpl(requests, responses);
|
||||||
KeeperMultiException::check(code, requests, responses);
|
KeeperMultiException::check(code, requests, responses);
|
||||||
return responses;
|
return responses;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryMulti(const Coordination::Requests & requests, Coordination::Responses & responses)
|
Coordination::Error ZooKeeper::tryMulti(const Coordination::Requests & requests, Coordination::Responses & responses)
|
||||||
{
|
{
|
||||||
int32_t code = multiImpl(requests, responses);
|
Coordination::Error code = multiImpl(requests, responses);
|
||||||
if (code && !Coordination::isUserError(code))
|
if (code != Coordination::Error::ZOK && !Coordination::isUserError(code))
|
||||||
throw KeeperException(code);
|
throw KeeperException(code);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@ -587,7 +597,7 @@ void ZooKeeper::removeChildrenRecursive(const std::string & path)
|
|||||||
void ZooKeeper::tryRemoveChildrenRecursive(const std::string & path)
|
void ZooKeeper::tryRemoveChildrenRecursive(const std::string & path)
|
||||||
{
|
{
|
||||||
Strings children;
|
Strings children;
|
||||||
if (tryGetChildren(path, children) != Coordination::ZOK)
|
if (tryGetChildren(path, children) != Coordination::Error::ZOK)
|
||||||
return;
|
return;
|
||||||
while (!children.empty())
|
while (!children.empty())
|
||||||
{
|
{
|
||||||
@ -609,7 +619,7 @@ void ZooKeeper::tryRemoveChildrenRecursive(const std::string & path)
|
|||||||
/// this means someone is concurrently removing these children and we will have
|
/// this means someone is concurrently removing these children and we will have
|
||||||
/// to remove them one by one.
|
/// to remove them one by one.
|
||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
if (tryMulti(ops, responses) != Coordination::ZOK)
|
if (tryMulti(ops, responses) != Coordination::Error::ZOK)
|
||||||
for (const std::string & child : batch)
|
for (const std::string & child : batch)
|
||||||
tryRemove(child);
|
tryRemove(child);
|
||||||
}
|
}
|
||||||
@ -645,7 +655,7 @@ bool ZooKeeper::waitForDisappear(const std::string & path, const WaitCondition &
|
|||||||
|
|
||||||
auto callback = [state](const Coordination::ExistsResponse & response)
|
auto callback = [state](const Coordination::ExistsResponse & response)
|
||||||
{
|
{
|
||||||
state->code = response.error;
|
state->code = int32_t(response.error);
|
||||||
if (state->code)
|
if (state->code)
|
||||||
state->event.set();
|
state->event.set();
|
||||||
};
|
};
|
||||||
@ -654,7 +664,7 @@ bool ZooKeeper::waitForDisappear(const std::string & path, const WaitCondition &
|
|||||||
{
|
{
|
||||||
if (!state->code)
|
if (!state->code)
|
||||||
{
|
{
|
||||||
state->code = response.error;
|
state->code = int32_t(response.error);
|
||||||
if (!state->code)
|
if (!state->code)
|
||||||
state->event_type = response.type;
|
state->event_type = response.type;
|
||||||
state->event.set();
|
state->event.set();
|
||||||
@ -670,11 +680,11 @@ bool ZooKeeper::waitForDisappear(const std::string & path, const WaitCondition &
|
|||||||
else if (!state->event.tryWait(1000))
|
else if (!state->event.tryWait(1000))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (state->code == Coordination::ZNONODE)
|
if (state->code == int32_t(Coordination::Error::ZNONODE))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (state->code)
|
if (state->code)
|
||||||
throw KeeperException(state->code, path);
|
throw KeeperException(static_cast<Coordination::Error>(state->code.load(std::memory_order_seq_cst)), path);
|
||||||
|
|
||||||
if (state->event_type == Coordination::DELETED)
|
if (state->event_type == Coordination::DELETED)
|
||||||
return true;
|
return true;
|
||||||
@ -688,11 +698,6 @@ ZooKeeperPtr ZooKeeper::startNewSession() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string ZooKeeper::error2string(int32_t code)
|
|
||||||
{
|
|
||||||
return Coordination::errorMessage(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZooKeeper::expired()
|
bool ZooKeeper::expired()
|
||||||
{
|
{
|
||||||
return impl->isExpired();
|
return impl->isExpired();
|
||||||
@ -712,7 +717,7 @@ std::future<Coordination::CreateResponse> ZooKeeper::asyncCreate(const std::stri
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::CreateResponse & response) mutable
|
auto callback = [promise, path](const Coordination::CreateResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -730,7 +735,7 @@ std::future<Coordination::GetResponse> ZooKeeper::asyncGet(const std::string & p
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::GetResponse & response) mutable
|
auto callback = [promise, path](const Coordination::GetResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -748,7 +753,7 @@ std::future<Coordination::GetResponse> ZooKeeper::asyncTryGet(const std::string
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::GetResponse & response) mutable
|
auto callback = [promise, path](const Coordination::GetResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error && response.error != Coordination::ZNONODE)
|
if (response.error != Coordination::Error::ZOK && response.error != Coordination::Error::ZNONODE)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -765,7 +770,7 @@ std::future<Coordination::ExistsResponse> ZooKeeper::asyncExists(const std::stri
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::ExistsResponse & response) mutable
|
auto callback = [promise, path](const Coordination::ExistsResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error && response.error != Coordination::ZNONODE)
|
if (response.error != Coordination::Error::ZOK && response.error != Coordination::Error::ZNONODE)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -782,7 +787,7 @@ std::future<Coordination::SetResponse> ZooKeeper::asyncSet(const std::string & p
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::SetResponse & response) mutable
|
auto callback = [promise, path](const Coordination::SetResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -799,7 +804,7 @@ std::future<Coordination::ListResponse> ZooKeeper::asyncGetChildren(const std::s
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::ListResponse & response) mutable
|
auto callback = [promise, path](const Coordination::ListResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -816,7 +821,7 @@ std::future<Coordination::RemoveResponse> ZooKeeper::asyncRemove(const std::stri
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::RemoveResponse & response) mutable
|
auto callback = [promise, path](const Coordination::RemoveResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -833,8 +838,13 @@ std::future<Coordination::RemoveResponse> ZooKeeper::asyncTryRemove(const std::s
|
|||||||
|
|
||||||
auto callback = [promise, path](const Coordination::RemoveResponse & response) mutable
|
auto callback = [promise, path](const Coordination::RemoveResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error && response.error != Coordination::ZNONODE && response.error != Coordination::ZBADVERSION && response.error != Coordination::ZNOTEMPTY)
|
if (response.error != Coordination::Error::ZOK
|
||||||
|
&& response.error != Coordination::Error::ZNONODE
|
||||||
|
&& response.error != Coordination::Error::ZBADVERSION
|
||||||
|
&& response.error != Coordination::Error::ZNOTEMPTY)
|
||||||
|
{
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(path, response.error)));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
};
|
};
|
||||||
@ -864,7 +874,7 @@ std::future<Coordination::MultiResponse> ZooKeeper::asyncMulti(const Coordinatio
|
|||||||
|
|
||||||
auto callback = [promise](const Coordination::MultiResponse & response) mutable
|
auto callback = [promise](const Coordination::MultiResponse & response) mutable
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
promise->set_exception(std::make_exception_ptr(KeeperException(response.error)));
|
promise->set_exception(std::make_exception_ptr(KeeperException(response.error)));
|
||||||
else
|
else
|
||||||
promise->set_value(response);
|
promise->set_value(response);
|
||||||
@ -874,7 +884,7 @@ std::future<Coordination::MultiResponse> ZooKeeper::asyncMulti(const Coordinatio
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t ZooKeeper::tryMultiNoThrow(const Coordination::Requests & requests, Coordination::Responses & responses)
|
Coordination::Error ZooKeeper::tryMultiNoThrow(const Coordination::Requests & requests, Coordination::Responses & responses)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -887,24 +897,24 @@ int32_t ZooKeeper::tryMultiNoThrow(const Coordination::Requests & requests, Coor
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t KeeperMultiException::getFailedOpIndex(int32_t exception_code, const Coordination::Responses & responses)
|
size_t KeeperMultiException::getFailedOpIndex(Coordination::Error exception_code, const Coordination::Responses & responses)
|
||||||
{
|
{
|
||||||
if (responses.empty())
|
if (responses.empty())
|
||||||
throw DB::Exception("Responses for multi transaction is empty", DB::ErrorCodes::LOGICAL_ERROR);
|
throw DB::Exception("Responses for multi transaction is empty", DB::ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
for (size_t index = 0, size = responses.size(); index < size; ++index)
|
for (size_t index = 0, size = responses.size(); index < size; ++index)
|
||||||
if (responses[index]->error)
|
if (responses[index]->error != Coordination::Error::ZOK)
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
if (!Coordination::isUserError(exception_code))
|
if (!Coordination::isUserError(exception_code))
|
||||||
throw DB::Exception("There are no failed OPs because '" + ZooKeeper::error2string(exception_code) + "' is not valid response code for that",
|
throw DB::Exception("There are no failed OPs because '" + std::string(Coordination::errorMessage(exception_code)) + "' is not valid response code for that",
|
||||||
DB::ErrorCodes::LOGICAL_ERROR);
|
DB::ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
throw DB::Exception("There is no failed OpResult", DB::ErrorCodes::LOGICAL_ERROR);
|
throw DB::Exception("There is no failed OpResult", DB::ErrorCodes::LOGICAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KeeperMultiException::KeeperMultiException(int32_t exception_code, const Coordination::Requests & requests_, const Coordination::Responses & responses_)
|
KeeperMultiException::KeeperMultiException(Coordination::Error exception_code, const Coordination::Requests & requests_, const Coordination::Responses & responses_)
|
||||||
: KeeperException("Transaction failed", exception_code),
|
: KeeperException("Transaction failed", exception_code),
|
||||||
requests(requests_), responses(responses_), failed_op_index(getFailedOpIndex(exception_code, responses))
|
requests(requests_), responses(responses_), failed_op_index(getFailedOpIndex(exception_code, responses))
|
||||||
{
|
{
|
||||||
@ -917,9 +927,10 @@ std::string KeeperMultiException::getPathForFirstFailedOp() const
|
|||||||
return requests[failed_op_index]->getPath();
|
return requests[failed_op_index]->getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeeperMultiException::check(int32_t exception_code, const Coordination::Requests & requests, const Coordination::Responses & responses)
|
void KeeperMultiException::check(
|
||||||
|
Coordination::Error exception_code, const Coordination::Requests & requests, const Coordination::Responses & responses)
|
||||||
{
|
{
|
||||||
if (!exception_code)
|
if (exception_code == Coordination::Error::ZOK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Coordination::isUserError(exception_code))
|
if (Coordination::isUserError(exception_code))
|
||||||
|
@ -99,8 +99,8 @@ public:
|
|||||||
/// * The parent is ephemeral.
|
/// * The parent is ephemeral.
|
||||||
/// * The node already exists.
|
/// * The node already exists.
|
||||||
/// In case of other errors throws an exception.
|
/// In case of other errors throws an exception.
|
||||||
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
|
Coordination::Error tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
|
||||||
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode);
|
Coordination::Error tryCreate(const std::string & path, const std::string & data, int32_t mode);
|
||||||
|
|
||||||
/// Create a Persistent node.
|
/// Create a Persistent node.
|
||||||
/// Does nothing if the node already exists.
|
/// Does nothing if the node already exists.
|
||||||
@ -117,7 +117,7 @@ public:
|
|||||||
/// * The node doesn't exist
|
/// * The node doesn't exist
|
||||||
/// * Versions don't match
|
/// * Versions don't match
|
||||||
/// * The node has children.
|
/// * The node has children.
|
||||||
int32_t tryRemove(const std::string & path, int32_t version = -1);
|
Coordination::Error tryRemove(const std::string & path, int32_t version = -1);
|
||||||
|
|
||||||
bool exists(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
bool exists(const std::string & path, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr);
|
||||||
bool existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
bool existsWatch(const std::string & path, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
||||||
@ -127,9 +127,11 @@ public:
|
|||||||
|
|
||||||
/// Doesn't not throw in the following cases:
|
/// Doesn't not throw in the following cases:
|
||||||
/// * The node doesn't exist. Returns false in this case.
|
/// * The node doesn't exist. Returns false in this case.
|
||||||
bool tryGet(const std::string & path, std::string & res, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr, int * code = nullptr);
|
bool tryGet(const std::string & path, std::string & res, Coordination::Stat * stat = nullptr, const EventPtr & watch = nullptr,
|
||||||
|
Coordination::Error * code = nullptr);
|
||||||
|
|
||||||
bool tryGetWatch(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback, int * code = nullptr);
|
bool tryGetWatch(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback,
|
||||||
|
Coordination::Error * code = nullptr);
|
||||||
|
|
||||||
void set(const std::string & path, const std::string & data,
|
void set(const std::string & path, const std::string & data,
|
||||||
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
||||||
@ -140,7 +142,7 @@ public:
|
|||||||
/// Doesn't not throw in the following cases:
|
/// Doesn't not throw in the following cases:
|
||||||
/// * The node doesn't exist.
|
/// * The node doesn't exist.
|
||||||
/// * Versions do not match.
|
/// * Versions do not match.
|
||||||
int32_t trySet(const std::string & path, const std::string & data,
|
Coordination::Error trySet(const std::string & path, const std::string & data,
|
||||||
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
int32_t version = -1, Coordination::Stat * stat = nullptr);
|
||||||
|
|
||||||
Strings getChildren(const std::string & path,
|
Strings getChildren(const std::string & path,
|
||||||
@ -153,11 +155,11 @@ public:
|
|||||||
|
|
||||||
/// Doesn't not throw in the following cases:
|
/// Doesn't not throw in the following cases:
|
||||||
/// * The node doesn't exist.
|
/// * The node doesn't exist.
|
||||||
int32_t tryGetChildren(const std::string & path, Strings & res,
|
Coordination::Error tryGetChildren(const std::string & path, Strings & res,
|
||||||
Coordination::Stat * stat = nullptr,
|
Coordination::Stat * stat = nullptr,
|
||||||
const EventPtr & watch = nullptr);
|
const EventPtr & watch = nullptr);
|
||||||
|
|
||||||
int32_t tryGetChildrenWatch(const std::string & path, Strings & res,
|
Coordination::Error tryGetChildrenWatch(const std::string & path, Strings & res,
|
||||||
Coordination::Stat * stat,
|
Coordination::Stat * stat,
|
||||||
Coordination::WatchCallback watch_callback);
|
Coordination::WatchCallback watch_callback);
|
||||||
|
|
||||||
@ -166,9 +168,9 @@ public:
|
|||||||
Coordination::Responses multi(const Coordination::Requests & requests);
|
Coordination::Responses multi(const Coordination::Requests & requests);
|
||||||
/// Throws only if some operation has returned an "unexpected" error
|
/// Throws only if some operation has returned an "unexpected" error
|
||||||
/// - an error that would cause the corresponding try- method to throw.
|
/// - an error that would cause the corresponding try- method to throw.
|
||||||
int32_t tryMulti(const Coordination::Requests & requests, Coordination::Responses & responses);
|
Coordination::Error tryMulti(const Coordination::Requests & requests, Coordination::Responses & responses);
|
||||||
/// Throws nothing (even session expired errors)
|
/// Throws nothing (even session expired errors)
|
||||||
int32_t tryMultiNoThrow(const Coordination::Requests & requests, Coordination::Responses & responses);
|
Coordination::Error tryMultiNoThrow(const Coordination::Requests & requests, Coordination::Responses & responses);
|
||||||
|
|
||||||
Int64 getClientID();
|
Int64 getClientID();
|
||||||
|
|
||||||
@ -238,8 +240,6 @@ public:
|
|||||||
/// Like the previous one but don't throw any exceptions on future.get()
|
/// Like the previous one but don't throw any exceptions on future.get()
|
||||||
FutureMulti tryAsyncMulti(const Coordination::Requests & ops);
|
FutureMulti tryAsyncMulti(const Coordination::Requests & ops);
|
||||||
|
|
||||||
static std::string error2string(int32_t code);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class EphemeralNodeHolder;
|
friend class EphemeralNodeHolder;
|
||||||
|
|
||||||
@ -250,13 +250,15 @@ private:
|
|||||||
void tryRemoveChildrenRecursive(const std::string & path);
|
void tryRemoveChildrenRecursive(const std::string & path);
|
||||||
|
|
||||||
/// The following methods don't throw exceptions but return error codes.
|
/// The following methods don't throw exceptions but return error codes.
|
||||||
int32_t createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
|
Coordination::Error createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
|
||||||
int32_t removeImpl(const std::string & path, int32_t version);
|
Coordination::Error removeImpl(const std::string & path, int32_t version);
|
||||||
int32_t getImpl(const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
Coordination::Error getImpl(
|
||||||
int32_t setImpl(const std::string & path, const std::string & data, int32_t version, Coordination::Stat * stat);
|
const std::string & path, std::string & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
||||||
int32_t getChildrenImpl(const std::string & path, Strings & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
Coordination::Error setImpl(const std::string & path, const std::string & data, int32_t version, Coordination::Stat * stat);
|
||||||
int32_t multiImpl(const Coordination::Requests & requests, Coordination::Responses & responses);
|
Coordination::Error getChildrenImpl(
|
||||||
int32_t existsImpl(const std::string & path, Coordination::Stat * stat_, Coordination::WatchCallback watch_callback);
|
const std::string & path, Strings & res, Coordination::Stat * stat, Coordination::WatchCallback watch_callback);
|
||||||
|
Coordination::Error multiImpl(const Coordination::Requests & requests, Coordination::Responses & responses);
|
||||||
|
Coordination::Error existsImpl(const std::string & path, Coordination::Stat * stat_, Coordination::WatchCallback watch_callback);
|
||||||
|
|
||||||
std::unique_ptr<Coordination::IKeeper> impl;
|
std::unique_ptr<Coordination::IKeeper> impl;
|
||||||
|
|
||||||
|
@ -52,13 +52,6 @@ namespace CurrentMetrics
|
|||||||
extern const Metric ZooKeeperWatch;
|
extern const Metric ZooKeeperWatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace DB
|
|
||||||
{
|
|
||||||
namespace ErrorCodes
|
|
||||||
{
|
|
||||||
extern const int SUPPORT_IS_DISABLED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ZooKeeper wire protocol.
|
/** ZooKeeper wire protocol.
|
||||||
|
|
||||||
@ -335,6 +328,13 @@ static void read(int32_t & x, ReadBuffer & in)
|
|||||||
x = __builtin_bswap32(x);
|
x = __builtin_bswap32(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void read(Error & x, ReadBuffer & in)
|
||||||
|
{
|
||||||
|
int32_t code;
|
||||||
|
read(code, in);
|
||||||
|
x = Error(code);
|
||||||
|
}
|
||||||
|
|
||||||
static void read(bool & x, ReadBuffer & in)
|
static void read(bool & x, ReadBuffer & in)
|
||||||
{
|
{
|
||||||
readBinary(x, in);
|
readBinary(x, in);
|
||||||
@ -353,10 +353,10 @@ static void read(String & s, ReadBuffer & in)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
throw Exception("Negative size while reading string from ZooKeeper", ZMARSHALLINGERROR);
|
throw Exception("Negative size while reading string from ZooKeeper", Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
if (size > MAX_STRING_OR_ARRAY_SIZE)
|
if (size > MAX_STRING_OR_ARRAY_SIZE)
|
||||||
throw Exception("Too large string size while reading from ZooKeeper", ZMARSHALLINGERROR);
|
throw Exception("Too large string size while reading from ZooKeeper", Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
s.resize(size);
|
s.resize(size);
|
||||||
in.read(s.data(), size);
|
in.read(s.data(), size);
|
||||||
@ -367,7 +367,7 @@ template <size_t N> void read(std::array<char, N> & s, ReadBuffer & in)
|
|||||||
int32_t size = 0;
|
int32_t size = 0;
|
||||||
read(size, in);
|
read(size, in);
|
||||||
if (size != N)
|
if (size != N)
|
||||||
throw Exception("Unexpected array size while reading from ZooKeeper", ZMARSHALLINGERROR);
|
throw Exception("Unexpected array size while reading from ZooKeeper", Error::ZMARSHALLINGERROR);
|
||||||
in.read(s.data(), N);
|
in.read(s.data(), N);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,9 +391,9 @@ template <typename T> void read(std::vector<T> & arr, ReadBuffer & in)
|
|||||||
int32_t size = 0;
|
int32_t size = 0;
|
||||||
read(size, in);
|
read(size, in);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
throw Exception("Negative size while reading array from ZooKeeper", ZMARSHALLINGERROR);
|
throw Exception("Negative size while reading array from ZooKeeper", Error::ZMARSHALLINGERROR);
|
||||||
if (size > MAX_STRING_OR_ARRAY_SIZE)
|
if (size > MAX_STRING_OR_ARRAY_SIZE)
|
||||||
throw Exception("Too large array size while reading from ZooKeeper", ZMARSHALLINGERROR);
|
throw Exception("Too large array size while reading from ZooKeeper", Error::ZMARSHALLINGERROR);
|
||||||
arr.resize(size);
|
arr.resize(size);
|
||||||
for (auto & elem : arr)
|
for (auto & elem : arr)
|
||||||
read(elem, in);
|
read(elem, in);
|
||||||
@ -489,7 +489,7 @@ struct ZooKeeperCloseResponse final : ZooKeeperResponse
|
|||||||
{
|
{
|
||||||
void readImpl(ReadBuffer &) override
|
void readImpl(ReadBuffer &) override
|
||||||
{
|
{
|
||||||
throw Exception("Received response for close request", ZRUNTIMEINCONSISTENCY);
|
throw Exception("Received response for close request", Error::ZRUNTIMEINCONSISTENCY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -650,12 +650,12 @@ struct ZooKeeperErrorResponse final : ErrorResponse, ZooKeeperResponse
|
|||||||
{
|
{
|
||||||
void readImpl(ReadBuffer & in) override
|
void readImpl(ReadBuffer & in) override
|
||||||
{
|
{
|
||||||
int32_t read_error;
|
Coordination::Error read_error;
|
||||||
Coordination::read(read_error, in);
|
Coordination::read(read_error, in);
|
||||||
|
|
||||||
if (read_error != error)
|
if (read_error != error)
|
||||||
throw Exception("Error code in ErrorResponse (" + toString(read_error) + ") doesn't match error code in header (" + toString(error) + ")",
|
throw Exception(fmt::format("Error code in ErrorResponse ({}) doesn't match error code in header ({})", read_error, error),
|
||||||
ZMARSHALLINGERROR);
|
Error::ZMARSHALLINGERROR);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -691,7 +691,7 @@ struct ZooKeeperMultiRequest final : MultiRequest, ZooKeeperRequest
|
|||||||
requests.push_back(std::make_shared<ZooKeeperCheckRequest>(*concrete_request_check));
|
requests.push_back(std::make_shared<ZooKeeperCheckRequest>(*concrete_request_check));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Exception("Illegal command as part of multi ZooKeeper request", ZBADARGUMENTS);
|
throw Exception("Illegal command as part of multi ZooKeeper request", Error::ZBADARGUMENTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,14 +739,14 @@ struct ZooKeeperMultiResponse final : MultiResponse, ZooKeeperResponse
|
|||||||
{
|
{
|
||||||
ZooKeeper::OpNum op_num;
|
ZooKeeper::OpNum op_num;
|
||||||
bool done;
|
bool done;
|
||||||
int32_t op_error;
|
Error op_error;
|
||||||
|
|
||||||
Coordination::read(op_num, in);
|
Coordination::read(op_num, in);
|
||||||
Coordination::read(done, in);
|
Coordination::read(done, in);
|
||||||
Coordination::read(op_error, in);
|
Coordination::read(op_error, in);
|
||||||
|
|
||||||
if (done)
|
if (done)
|
||||||
throw Exception("Not enough results received for multi transaction", ZMARSHALLINGERROR);
|
throw Exception("Not enough results received for multi transaction", Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
/// op_num == -1 is special for multi transaction.
|
/// op_num == -1 is special for multi transaction.
|
||||||
/// For unknown reason, error code is duplicated in header and in response body.
|
/// For unknown reason, error code is duplicated in header and in response body.
|
||||||
@ -754,18 +754,18 @@ struct ZooKeeperMultiResponse final : MultiResponse, ZooKeeperResponse
|
|||||||
if (op_num == -1)
|
if (op_num == -1)
|
||||||
response = std::make_shared<ZooKeeperErrorResponse>();
|
response = std::make_shared<ZooKeeperErrorResponse>();
|
||||||
|
|
||||||
if (op_error)
|
if (op_error != Error::ZOK)
|
||||||
{
|
{
|
||||||
response->error = op_error;
|
response->error = op_error;
|
||||||
|
|
||||||
/// Set error for whole transaction.
|
/// Set error for whole transaction.
|
||||||
/// If some operations fail, ZK send global error as zero and then send details about each operation.
|
/// If some operations fail, ZK send global error as zero and then send details about each operation.
|
||||||
/// It will set error code for first failed operation and it will set special "runtime inconsistency" code for other operations.
|
/// It will set error code for first failed operation and it will set special "runtime inconsistency" code for other operations.
|
||||||
if (!error && op_error != ZRUNTIMEINCONSISTENCY)
|
if (error == Error::ZOK && op_error != Error::ZRUNTIMEINCONSISTENCY)
|
||||||
error = op_error;
|
error = op_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!op_error || op_num == -1)
|
if (op_error == Error::ZOK || op_num == -1)
|
||||||
dynamic_cast<ZooKeeperResponse &>(*response).readImpl(in);
|
dynamic_cast<ZooKeeperResponse &>(*response).readImpl(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,11 +780,11 @@ struct ZooKeeperMultiResponse final : MultiResponse, ZooKeeperResponse
|
|||||||
Coordination::read(error_read, in);
|
Coordination::read(error_read, in);
|
||||||
|
|
||||||
if (!done)
|
if (!done)
|
||||||
throw Exception("Too many results received for multi transaction", ZMARSHALLINGERROR);
|
throw Exception("Too many results received for multi transaction", Error::ZMARSHALLINGERROR);
|
||||||
if (op_num != -1)
|
if (op_num != -1)
|
||||||
throw Exception("Unexpected op_num received at the end of results for multi transaction", ZMARSHALLINGERROR);
|
throw Exception("Unexpected op_num received at the end of results for multi transaction", Error::ZMARSHALLINGERROR);
|
||||||
if (error_read != -1)
|
if (error_read != -1)
|
||||||
throw Exception("Unexpected error value received at the end of results for multi transaction", ZMARSHALLINGERROR);
|
throw Exception("Unexpected error value received at the end of results for multi transaction", Error::ZMARSHALLINGERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -883,7 +883,7 @@ void ZooKeeper::connect(
|
|||||||
Poco::Timespan connection_timeout)
|
Poco::Timespan connection_timeout)
|
||||||
{
|
{
|
||||||
if (nodes.empty())
|
if (nodes.empty())
|
||||||
throw Exception("No nodes passed to ZooKeeper constructor", ZBADARGUMENTS);
|
throw Exception("No nodes passed to ZooKeeper constructor", Error::ZBADARGUMENTS);
|
||||||
|
|
||||||
static constexpr size_t num_tries = 3;
|
static constexpr size_t num_tries = 3;
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
@ -901,7 +901,8 @@ void ZooKeeper::connect(
|
|||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
socket = Poco::Net::SecureStreamSocket();
|
socket = Poco::Net::SecureStreamSocket();
|
||||||
#else
|
#else
|
||||||
throw Exception{"Communication with ZooKeeper over SSL is disabled because poco library was built without NetSSL support.", ErrorCodes::SUPPORT_IS_DISABLED};
|
throw Poco::Exception(
|
||||||
|
"Communication with ZooKeeper over SSL is disabled because poco library was built without NetSSL support.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -970,7 +971,7 @@ void ZooKeeper::connect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
message << fail_reasons.str() << "\n";
|
message << fail_reasons.str() << "\n";
|
||||||
throw Exception(message.str(), ZCONNECTIONLOSS);
|
throw Exception(message.str(), Error::ZCONNECTIONLOSS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1005,11 +1006,11 @@ void ZooKeeper::receiveHandshake()
|
|||||||
|
|
||||||
read(handshake_length);
|
read(handshake_length);
|
||||||
if (handshake_length != 36)
|
if (handshake_length != 36)
|
||||||
throw Exception("Unexpected handshake length received: " + toString(handshake_length), ZMARSHALLINGERROR);
|
throw Exception("Unexpected handshake length received: " + toString(handshake_length), Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
read(protocol_version_read);
|
read(protocol_version_read);
|
||||||
if (protocol_version_read != protocol_version)
|
if (protocol_version_read != protocol_version)
|
||||||
throw Exception("Unexpected protocol version: " + toString(protocol_version_read), ZMARSHALLINGERROR);
|
throw Exception("Unexpected protocol version: " + toString(protocol_version_read), Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
read(timeout);
|
read(timeout);
|
||||||
if (timeout != session_timeout.totalMilliseconds())
|
if (timeout != session_timeout.totalMilliseconds())
|
||||||
@ -1032,7 +1033,7 @@ void ZooKeeper::sendAuth(const String & scheme, const String & data)
|
|||||||
int32_t length;
|
int32_t length;
|
||||||
XID read_xid;
|
XID read_xid;
|
||||||
int64_t zxid;
|
int64_t zxid;
|
||||||
int32_t err;
|
Error err;
|
||||||
|
|
||||||
read(length);
|
read(length);
|
||||||
size_t count_before_event = in->count();
|
size_t count_before_event = in->count();
|
||||||
@ -1042,16 +1043,16 @@ void ZooKeeper::sendAuth(const String & scheme, const String & data)
|
|||||||
|
|
||||||
if (read_xid != auth_xid)
|
if (read_xid != auth_xid)
|
||||||
throw Exception("Unexpected event received in reply to auth request: " + toString(read_xid),
|
throw Exception("Unexpected event received in reply to auth request: " + toString(read_xid),
|
||||||
ZMARSHALLINGERROR);
|
Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
int32_t actual_length = in->count() - count_before_event;
|
int32_t actual_length = in->count() - count_before_event;
|
||||||
if (length != actual_length)
|
if (length != actual_length)
|
||||||
throw Exception("Response length doesn't match. Expected: " + toString(length) + ", actual: " + toString(actual_length),
|
throw Exception("Response length doesn't match. Expected: " + toString(length) + ", actual: " + toString(actual_length),
|
||||||
ZMARSHALLINGERROR);
|
Error::ZMARSHALLINGERROR);
|
||||||
|
|
||||||
if (err)
|
if (err != Error::ZOK)
|
||||||
throw Exception("Error received in reply to auth request. Code: " + toString(err) + ". Message: " + String(errorMessage(err)),
|
throw Exception("Error received in reply to auth request. Code: " + toString(int32_t(err)) + ". Message: " + String(errorMessage(err)),
|
||||||
ZMARSHALLINGERROR);
|
Error::ZMARSHALLINGERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1154,7 +1155,7 @@ void ZooKeeper::receiveThread()
|
|||||||
earliest_operation = operations.begin()->second;
|
earliest_operation = operations.begin()->second;
|
||||||
auto earliest_operation_deadline = earliest_operation->time + std::chrono::microseconds(operation_timeout.totalMicroseconds());
|
auto earliest_operation_deadline = earliest_operation->time + std::chrono::microseconds(operation_timeout.totalMicroseconds());
|
||||||
if (now > earliest_operation_deadline)
|
if (now > earliest_operation_deadline)
|
||||||
throw Exception("Operation timeout (deadline already expired) for path: " + earliest_operation->request->getPath(), ZOPERATIONTIMEOUT);
|
throw Exception("Operation timeout (deadline already expired) for path: " + earliest_operation->request->getPath(), Error::ZOPERATIONTIMEOUT);
|
||||||
max_wait = std::chrono::duration_cast<std::chrono::microseconds>(earliest_operation_deadline - now).count();
|
max_wait = std::chrono::duration_cast<std::chrono::microseconds>(earliest_operation_deadline - now).count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1170,10 +1171,10 @@ void ZooKeeper::receiveThread()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (earliest_operation)
|
if (earliest_operation)
|
||||||
throw Exception("Operation timeout (no response) for path: " + earliest_operation->request->getPath(), ZOPERATIONTIMEOUT);
|
throw Exception("Operation timeout (no response) for path: " + earliest_operation->request->getPath(), Error::ZOPERATIONTIMEOUT);
|
||||||
waited += max_wait;
|
waited += max_wait;
|
||||||
if (waited >= session_timeout.totalMicroseconds())
|
if (waited >= session_timeout.totalMicroseconds())
|
||||||
throw Exception("Nothing is received in session timeout", ZOPERATIONTIMEOUT);
|
throw Exception("Nothing is received in session timeout", Error::ZOPERATIONTIMEOUT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,7 +1194,7 @@ void ZooKeeper::receiveEvent()
|
|||||||
int32_t length;
|
int32_t length;
|
||||||
XID xid;
|
XID xid;
|
||||||
int64_t zxid;
|
int64_t zxid;
|
||||||
int32_t err;
|
Error err;
|
||||||
|
|
||||||
read(length);
|
read(length);
|
||||||
size_t count_before_event = in->count();
|
size_t count_before_event = in->count();
|
||||||
@ -1206,8 +1207,8 @@ void ZooKeeper::receiveEvent()
|
|||||||
|
|
||||||
if (xid == ping_xid)
|
if (xid == ping_xid)
|
||||||
{
|
{
|
||||||
if (err)
|
if (err != Error::ZOK)
|
||||||
throw Exception("Received error in heartbeat response: " + String(errorMessage(err)), ZRUNTIMEINCONSISTENCY);
|
throw Exception("Received error in heartbeat response: " + String(errorMessage(err)), Error::ZRUNTIMEINCONSISTENCY);
|
||||||
|
|
||||||
response = std::make_shared<ZooKeeperHeartbeatResponse>();
|
response = std::make_shared<ZooKeeperHeartbeatResponse>();
|
||||||
}
|
}
|
||||||
@ -1252,7 +1253,7 @@ void ZooKeeper::receiveEvent()
|
|||||||
|
|
||||||
auto it = operations.find(xid);
|
auto it = operations.find(xid);
|
||||||
if (it == operations.end())
|
if (it == operations.end())
|
||||||
throw Exception("Received response for unknown xid", ZRUNTIMEINCONSISTENCY);
|
throw Exception("Received response for unknown xid", Error::ZRUNTIMEINCONSISTENCY);
|
||||||
|
|
||||||
/// After this point, we must invoke callback, that we've grabbed from 'operations'.
|
/// After this point, we must invoke callback, that we've grabbed from 'operations'.
|
||||||
/// Invariant: all callbacks are invoked either in case of success or in case of error.
|
/// Invariant: all callbacks are invoked either in case of success or in case of error.
|
||||||
@ -1272,7 +1273,7 @@ void ZooKeeper::receiveEvent()
|
|||||||
if (!response)
|
if (!response)
|
||||||
response = request_info.request->makeResponse();
|
response = request_info.request->makeResponse();
|
||||||
|
|
||||||
if (err)
|
if (err != Error::ZOK)
|
||||||
response->error = err;
|
response->error = err;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1282,7 +1283,7 @@ void ZooKeeper::receiveEvent()
|
|||||||
|
|
||||||
int32_t actual_length = in->count() - count_before_event;
|
int32_t actual_length = in->count() - count_before_event;
|
||||||
if (length != actual_length)
|
if (length != actual_length)
|
||||||
throw Exception("Response length doesn't match. Expected: " + toString(length) + ", actual: " + toString(actual_length), ZMARSHALLINGERROR);
|
throw Exception("Response length doesn't match. Expected: " + toString(length) + ", actual: " + toString(actual_length), Error::ZMARSHALLINGERROR);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -1294,7 +1295,7 @@ void ZooKeeper::receiveEvent()
|
|||||||
|
|
||||||
/// In case we cannot read the response, we should indicate it as the error of that type
|
/// In case we cannot read the response, we should indicate it as the error of that type
|
||||||
/// when the user cannot assume whether the request was processed or not.
|
/// when the user cannot assume whether the request was processed or not.
|
||||||
response->error = ZCONNECTIONLOSS;
|
response->error = Error::ZCONNECTIONLOSS;
|
||||||
if (request_info.callback)
|
if (request_info.callback)
|
||||||
request_info.callback(*response);
|
request_info.callback(*response);
|
||||||
|
|
||||||
@ -1361,8 +1362,8 @@ void ZooKeeper::finalize(bool error_send, bool error_receive)
|
|||||||
ResponsePtr response = request_info.request->makeResponse();
|
ResponsePtr response = request_info.request->makeResponse();
|
||||||
|
|
||||||
response->error = request_info.request->probably_sent
|
response->error = request_info.request->probably_sent
|
||||||
? ZCONNECTIONLOSS
|
? Error::ZCONNECTIONLOSS
|
||||||
: ZSESSIONEXPIRED;
|
: Error::ZSESSIONEXPIRED;
|
||||||
|
|
||||||
if (request_info.callback)
|
if (request_info.callback)
|
||||||
{
|
{
|
||||||
@ -1390,7 +1391,7 @@ void ZooKeeper::finalize(bool error_send, bool error_receive)
|
|||||||
WatchResponse response;
|
WatchResponse response;
|
||||||
response.type = SESSION;
|
response.type = SESSION;
|
||||||
response.state = EXPIRED_SESSION;
|
response.state = EXPIRED_SESSION;
|
||||||
response.error = ZSESSIONEXPIRED;
|
response.error = Error::ZSESSIONEXPIRED;
|
||||||
|
|
||||||
for (auto & callback : path_watches.second)
|
for (auto & callback : path_watches.second)
|
||||||
{
|
{
|
||||||
@ -1421,7 +1422,7 @@ void ZooKeeper::finalize(bool error_send, bool error_receive)
|
|||||||
ResponsePtr response = info.request->makeResponse();
|
ResponsePtr response = info.request->makeResponse();
|
||||||
if (response)
|
if (response)
|
||||||
{
|
{
|
||||||
response->error = ZSESSIONEXPIRED;
|
response->error = Error::ZSESSIONEXPIRED;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info.callback(*response);
|
info.callback(*response);
|
||||||
@ -1437,7 +1438,7 @@ void ZooKeeper::finalize(bool error_send, bool error_receive)
|
|||||||
WatchResponse response;
|
WatchResponse response;
|
||||||
response.type = SESSION;
|
response.type = SESSION;
|
||||||
response.state = EXPIRED_SESSION;
|
response.state = EXPIRED_SESSION;
|
||||||
response.error = ZSESSIONEXPIRED;
|
response.error = Error::ZSESSIONEXPIRED;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
info.watch(response);
|
info.watch(response);
|
||||||
@ -1466,9 +1467,9 @@ void ZooKeeper::pushRequest(RequestInfo && info)
|
|||||||
{
|
{
|
||||||
info.request->xid = next_xid.fetch_add(1);
|
info.request->xid = next_xid.fetch_add(1);
|
||||||
if (info.request->xid == close_xid)
|
if (info.request->xid == close_xid)
|
||||||
throw Exception("xid equal to close_xid", ZSESSIONEXPIRED);
|
throw Exception("xid equal to close_xid", Error::ZSESSIONEXPIRED);
|
||||||
if (info.request->xid < 0)
|
if (info.request->xid < 0)
|
||||||
throw Exception("XID overflow", ZSESSIONEXPIRED);
|
throw Exception("XID overflow", Error::ZSESSIONEXPIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We must serialize 'pushRequest' and 'finalize' (from sendThread, receiveThread) calls
|
/// We must serialize 'pushRequest' and 'finalize' (from sendThread, receiveThread) calls
|
||||||
@ -1478,10 +1479,10 @@ void ZooKeeper::pushRequest(RequestInfo && info)
|
|||||||
std::lock_guard lock(push_request_mutex);
|
std::lock_guard lock(push_request_mutex);
|
||||||
|
|
||||||
if (expired)
|
if (expired)
|
||||||
throw Exception("Session expired", ZSESSIONEXPIRED);
|
throw Exception("Session expired", Error::ZSESSIONEXPIRED);
|
||||||
|
|
||||||
if (!requests_queue.tryPush(std::move(info), operation_timeout.totalMilliseconds()))
|
if (!requests_queue.tryPush(std::move(info), operation_timeout.totalMilliseconds()))
|
||||||
throw Exception("Cannot push request to queue within operation timeout", ZOPERATIONTIMEOUT);
|
throw Exception("Cannot push request to queue within operation timeout", Error::ZOPERATIONTIMEOUT);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -1651,7 +1652,7 @@ void ZooKeeper::close()
|
|||||||
request_info.request = std::make_shared<ZooKeeperCloseRequest>(std::move(request));
|
request_info.request = std::make_shared<ZooKeeperCloseRequest>(std::move(request));
|
||||||
|
|
||||||
if (!requests_queue.tryPush(std::move(request_info), operation_timeout.totalMilliseconds()))
|
if (!requests_queue.tryPush(std::move(request_info), operation_timeout.totalMilliseconds()))
|
||||||
throw Exception("Cannot push close request to queue within operation timeout", ZOPERATIONTIMEOUT);
|
throw Exception("Cannot push close request to queue within operation timeout", Error::ZOPERATIONTIMEOUT);
|
||||||
|
|
||||||
ProfileEvents::increment(ProfileEvents::ZooKeeperClose);
|
ProfileEvents::increment(ProfileEvents::ZooKeeperClose);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ TEST(zkutil, MultiAsync)
|
|||||||
ops.clear();
|
ops.clear();
|
||||||
|
|
||||||
auto res = fut.get();
|
auto res = fut.get();
|
||||||
ASSERT_EQ(res.error, Coordination::ZOK);
|
ASSERT_EQ(res.error, Coordination::Error::ZOK);
|
||||||
ASSERT_EQ(res.responses.size(), 2);
|
ASSERT_EQ(res.responses.size(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,15 +126,15 @@ TEST(zkutil, MultiAsync)
|
|||||||
|
|
||||||
/// The test is quite heavy. It is normal if session is expired during this test.
|
/// The test is quite heavy. It is normal if session is expired during this test.
|
||||||
/// If we don't check that, the test will be flacky.
|
/// If we don't check that, the test will be flacky.
|
||||||
if (res.error != Coordination::ZSESSIONEXPIRED && res.error != Coordination::ZCONNECTIONLOSS)
|
if (res.error != Coordination::Error::ZSESSIONEXPIRED && res.error != Coordination::Error::ZCONNECTIONLOSS)
|
||||||
{
|
{
|
||||||
ASSERT_EQ(res.error, Coordination::ZNODEEXISTS);
|
ASSERT_EQ(res.error, Coordination::Error::ZNODEEXISTS);
|
||||||
ASSERT_EQ(res.responses.size(), 2);
|
ASSERT_EQ(res.responses.size(), 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code != Coordination::ZSESSIONEXPIRED && e.code != Coordination::ZCONNECTIONLOSS)
|
if (e.code != Coordination::Error::ZSESSIONEXPIRED && e.code != Coordination::Error::ZCONNECTIONLOSS)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,12 @@ int main(int argc, char ** argv)
|
|||||||
ops.emplace_back(zkutil::makeRemoveRequest("/test/zk_expiration_test", -1));
|
ops.emplace_back(zkutil::makeRemoveRequest("/test/zk_expiration_test", -1));
|
||||||
|
|
||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
int32_t code = zk.tryMultiNoThrow(ops, responses);
|
Coordination::Error code = zk.tryMultiNoThrow(ops, responses);
|
||||||
|
|
||||||
std::cout << time(nullptr) - time0 << "s: " << zkutil::ZooKeeper::error2string(code) << std::endl;
|
std::cout << time(nullptr) - time0 << "s: " << Coordination::errorMessage(code) << std::endl;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
std::cout << "Path: " << zkutil::KeeperMultiException(code, ops, responses).getPathForFirstFailedOp() << std::endl;
|
std::cout << "Path: " << zkutil::KeeperMultiException(code, ops, responses).getPathForFirstFailedOp() << std::endl;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -49,8 +49,8 @@ try
|
|||||||
zk.create("/test", "old", false, false, {},
|
zk.create("/test", "old", false, false, {},
|
||||||
[&](const CreateResponse & response)
|
[&](const CreateResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (create) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (create): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Created path: " << response.path_created << '\n';
|
std::cerr << "Created path: " << response.path_created << '\n';
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ try
|
|||||||
zk.get("/test",
|
zk.get("/test",
|
||||||
[&](const GetResponse & response)
|
[&](const GetResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (get) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (get): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Value: " << response.data << '\n';
|
std::cerr << "Value: " << response.data << '\n';
|
||||||
|
|
||||||
@ -73,8 +73,8 @@ try
|
|||||||
},
|
},
|
||||||
[](const WatchResponse & response)
|
[](const WatchResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Watch (get) on /test, Error " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Watch (get) on /test, Error: " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Watch (get) on /test, path: " << response.path << ", type: " << response.type << '\n';
|
std::cerr << "Watch (get) on /test, path: " << response.path << ", type: " << response.type << '\n';
|
||||||
});
|
});
|
||||||
@ -86,8 +86,8 @@ try
|
|||||||
zk.set("/test", "new", -1,
|
zk.set("/test", "new", -1,
|
||||||
[&](const SetResponse & response)
|
[&](const SetResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (set) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (set): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Set\n";
|
std::cerr << "Set\n";
|
||||||
|
|
||||||
@ -101,8 +101,8 @@ try
|
|||||||
zk.list("/",
|
zk.list("/",
|
||||||
[&](const ListResponse & response)
|
[&](const ListResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (list) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (list): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Children:\n";
|
std::cerr << "Children:\n";
|
||||||
@ -114,8 +114,8 @@ try
|
|||||||
},
|
},
|
||||||
[](const WatchResponse & response)
|
[](const WatchResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Watch (list) on /, Error " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Watch (list) on /, Error: " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Watch (list) on /, path: " << response.path << ", type: " << response.type << '\n';
|
std::cerr << "Watch (list) on /, path: " << response.path << ", type: " << response.type << '\n';
|
||||||
});
|
});
|
||||||
@ -127,8 +127,8 @@ try
|
|||||||
zk.exists("/test",
|
zk.exists("/test",
|
||||||
[&](const ExistsResponse & response)
|
[&](const ExistsResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (exists) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (exists): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Exists\n";
|
std::cerr << "Exists\n";
|
||||||
|
|
||||||
@ -136,8 +136,8 @@ try
|
|||||||
},
|
},
|
||||||
[](const WatchResponse & response)
|
[](const WatchResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Watch (exists) on /test, Error " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Watch (exists) on /test, Error: " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Watch (exists) on /test, path: " << response.path << ", type: " << response.type << '\n';
|
std::cerr << "Watch (exists) on /test, path: " << response.path << ", type: " << response.type << '\n';
|
||||||
});
|
});
|
||||||
@ -148,8 +148,8 @@ try
|
|||||||
|
|
||||||
zk.remove("/test", -1, [&](const RemoveResponse & response)
|
zk.remove("/test", -1, [&](const RemoveResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (remove) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (remove): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
std::cerr << "Removed\n";
|
std::cerr << "Removed\n";
|
||||||
|
|
||||||
@ -184,13 +184,13 @@ try
|
|||||||
|
|
||||||
zk.multi(ops, [&](const MultiResponse & response)
|
zk.multi(ops, [&](const MultiResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (multi) " << response.error << ": " << errorMessage(response.error) << '\n';
|
std::cerr << "Error (multi): " << errorMessage(response.error) << '\n';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const auto & elem : response.responses)
|
for (const auto & elem : response.responses)
|
||||||
if (elem->error)
|
if (elem->error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error (elem) " << elem->error << ": " << errorMessage(elem->error) << '\n';
|
std::cerr << "Error (elem): " << errorMessage(elem->error) << '\n';
|
||||||
|
|
||||||
std::cerr << "Created path: " << dynamic_cast<const CreateResponse &>(*response.responses[0]).path_created << '\n';
|
std::cerr << "Created path: " << dynamic_cast<const CreateResponse &>(*response.responses[0]).path_created << '\n';
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ try
|
|||||||
|
|
||||||
zookeeper.create("/test", "hello", false, false, {}, [](const Coordination::CreateResponse & response)
|
zookeeper.create("/test", "hello", false, false, {}, [](const Coordination::CreateResponse & response)
|
||||||
{
|
{
|
||||||
if (response.error)
|
if (response.error != Coordination::Error::ZOK)
|
||||||
std::cerr << "Error " << response.error << ": " << Coordination::errorMessage(response.error) << "\n";
|
std::cerr << "Error: " << Coordination::errorMessage(response.error) << "\n";
|
||||||
else
|
else
|
||||||
std::cerr << "Path created: " << response.path_created << "\n";
|
std::cerr << "Path created: " << response.path_created << "\n";
|
||||||
});
|
});
|
||||||
|
@ -14,11 +14,6 @@ static bool operator==(const IDataType & left, const IDataType & right)
|
|||||||
return left.equals(right);
|
return left.equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream & ostr, const IDataType & dt)
|
|
||||||
{
|
|
||||||
return ostr << dt.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace DB;
|
using namespace DB;
|
||||||
|
@ -68,7 +68,7 @@ ASTPtr DatabaseMemory::getCreateTableQueryImpl(const String & table_name, const
|
|||||||
{
|
{
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
auto it = create_queries.find(table_name);
|
auto it = create_queries.find(table_name);
|
||||||
if (it == create_queries.end())
|
if (it == create_queries.end() || !it->second)
|
||||||
{
|
{
|
||||||
if (throw_on_error)
|
if (throw_on_error)
|
||||||
throw Exception("There is no metadata of table " + table_name + " in database " + database_name, ErrorCodes::UNKNOWN_TABLE);
|
throw Exception("There is no metadata of table " + table_name + " in database " + database_name, ErrorCodes::UNKNOWN_TABLE);
|
||||||
|
@ -122,7 +122,12 @@ String getObjectDefinitionFromCreateQuery(const ASTPtr & query)
|
|||||||
return statement_stream.str();
|
return statement_stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseOnDisk::DatabaseOnDisk(const String & name, const String & metadata_path_, const String & data_path_, const String & logger, const Context & context)
|
DatabaseOnDisk::DatabaseOnDisk(
|
||||||
|
const String & name,
|
||||||
|
const String & metadata_path_,
|
||||||
|
const String & data_path_,
|
||||||
|
const String & logger,
|
||||||
|
const Context & context)
|
||||||
: DatabaseWithOwnTablesBase(name, logger, context)
|
: DatabaseWithOwnTablesBase(name, logger, context)
|
||||||
, metadata_path(metadata_path_)
|
, metadata_path(metadata_path_)
|
||||||
, data_path(data_path_)
|
, data_path(data_path_)
|
||||||
@ -154,7 +159,6 @@ void DatabaseOnDisk::createTable(
|
|||||||
/// A race condition would be possible if a table with the same name is simultaneously created using CREATE and using ATTACH.
|
/// A race condition would be possible if a table with the same name is simultaneously created using CREATE and using ATTACH.
|
||||||
/// But there is protection from it - see using DDLGuard in InterpreterCreateQuery.
|
/// But there is protection from it - see using DDLGuard in InterpreterCreateQuery.
|
||||||
|
|
||||||
|
|
||||||
if (isDictionaryExist(table_name))
|
if (isDictionaryExist(table_name))
|
||||||
throw Exception("Dictionary " + backQuote(getDatabaseName()) + "." + backQuote(table_name) + " already exists.",
|
throw Exception("Dictionary " + backQuote(getDatabaseName()) + "." + backQuote(table_name) + " already exists.",
|
||||||
ErrorCodes::DICTIONARY_ALREADY_EXISTS);
|
ErrorCodes::DICTIONARY_ALREADY_EXISTS);
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
#include <Columns/ColumnString.h>
|
|
||||||
#include <Columns/ColumnArray.h>
|
|
||||||
#include <Columns/ColumnConst.h>
|
|
||||||
#include <DataTypes/DataTypeArray.h>
|
|
||||||
#include <DataTypes/DataTypeString.h>
|
|
||||||
#include <Functions/FunctionFactory.h>
|
|
||||||
#include <Functions/FunctionHelpers.h>
|
|
||||||
#include <Functions/Regexps.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace ErrorCodes
|
|
||||||
{
|
|
||||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
|
||||||
extern const int BAD_ARGUMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Match all groups of given input string with given re, return array of arrays of matches.
|
|
||||||
*
|
|
||||||
* SELECT extractAllGroups('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)')
|
|
||||||
* should produce:
|
|
||||||
* [['abc', '111'], ['def', '222'], ['ghi', '333']]
|
|
||||||
*/
|
|
||||||
class FunctionExtractAllGroups : public IFunction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static constexpr auto name = "extractAllGroups";
|
|
||||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionExtractAllGroups>(); }
|
|
||||||
|
|
||||||
String getName() const override { return name; }
|
|
||||||
|
|
||||||
size_t getNumberOfArguments() const override { return 2; }
|
|
||||||
|
|
||||||
bool useDefaultImplementationForConstants() const override { return false; }
|
|
||||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
|
||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
|
||||||
{
|
|
||||||
FunctionArgumentDescriptors args{
|
|
||||||
{"haystack", isStringOrFixedString, nullptr, "const String or const FixedString"},
|
|
||||||
{"needle", isStringOrFixedString, isColumnConst, "const String or const FixedString"},
|
|
||||||
};
|
|
||||||
validateFunctionArgumentTypes(*this, arguments, args);
|
|
||||||
|
|
||||||
/// Two-dimensional array of strings, each `row` of top array represents matching groups.
|
|
||||||
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
|
|
||||||
{
|
|
||||||
const ColumnPtr column_haystack = block.getByPosition(arguments[0]).column;
|
|
||||||
const ColumnPtr column_needle = block.getByPosition(arguments[1]).column;
|
|
||||||
|
|
||||||
const auto needle = typeid_cast<const ColumnConst &>(*column_needle).getValue<String>();
|
|
||||||
|
|
||||||
if (needle.empty())
|
|
||||||
throw Exception(getName() + " length of 'needle' argument must be greater than 0.", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
||||||
|
|
||||||
const auto regexp = Regexps::get<false, false>(needle);
|
|
||||||
const auto & re2 = regexp->getRE2();
|
|
||||||
|
|
||||||
if (!re2)
|
|
||||||
throw Exception("There is no groups in regexp: " + needle, ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
const size_t groups_count = re2->NumberOfCapturingGroups();
|
|
||||||
|
|
||||||
if (!groups_count)
|
|
||||||
throw Exception("There is no groups in regexp: " + needle, ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
// Including 0-group, which is the whole regexp.
|
|
||||||
PODArrayWithStackMemory<re2_st::StringPiece, 128> matched_groups(groups_count + 1);
|
|
||||||
|
|
||||||
ColumnArray::ColumnOffsets::MutablePtr root_offsets_col = ColumnArray::ColumnOffsets::create();
|
|
||||||
ColumnArray::ColumnOffsets::MutablePtr nested_offsets_col = ColumnArray::ColumnOffsets::create();
|
|
||||||
ColumnString::MutablePtr data_col = ColumnString::create();
|
|
||||||
|
|
||||||
auto & root_offsets_data = root_offsets_col->getData();
|
|
||||||
auto & nested_offsets_data = nested_offsets_col->getData();
|
|
||||||
|
|
||||||
root_offsets_data.resize(input_rows_count);
|
|
||||||
ColumnArray::Offset current_root_offset = 0;
|
|
||||||
ColumnArray::Offset current_nested_offset = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < input_rows_count; ++i)
|
|
||||||
{
|
|
||||||
StringRef current_row = column_haystack->getDataAt(i);
|
|
||||||
|
|
||||||
// Extract all non-intersecting matches from haystack except group #0.
|
|
||||||
const auto * pos = current_row.data;
|
|
||||||
const auto * end = pos + current_row.size;
|
|
||||||
while (pos < end
|
|
||||||
&& re2->Match(re2_st::StringPiece(pos, end - pos),
|
|
||||||
0, end - pos, re2_st::RE2::UNANCHORED, matched_groups.data(), matched_groups.size()))
|
|
||||||
{
|
|
||||||
// 1 is to exclude group #0 which is whole re match.
|
|
||||||
for (size_t group = 1; group <= groups_count; ++group)
|
|
||||||
data_col->insertData(matched_groups[group].data(), matched_groups[group].size());
|
|
||||||
|
|
||||||
pos = matched_groups[0].data() + matched_groups[0].size();
|
|
||||||
|
|
||||||
current_nested_offset += groups_count;
|
|
||||||
nested_offsets_data.push_back(current_nested_offset);
|
|
||||||
|
|
||||||
++current_root_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
root_offsets_data[i] = current_root_offset;
|
|
||||||
}
|
|
||||||
ColumnArray::MutablePtr nested_array_col = ColumnArray::create(std::move(data_col), std::move(nested_offsets_col));
|
|
||||||
ColumnArray::MutablePtr root_array_col = ColumnArray::create(std::move(nested_array_col), std::move(root_offsets_col));
|
|
||||||
block.getByPosition(result).column = std::move(root_array_col);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void registerFunctionExtractAllGroups(FunctionFactory & factory)
|
|
||||||
{
|
|
||||||
factory.registerFunction<FunctionExtractAllGroups>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
237
src/Functions/extractAllGroups.h
Normal file
237
src/Functions/extractAllGroups.h
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include <Columns/ColumnArray.h>
|
||||||
|
#include <Columns/ColumnConst.h>
|
||||||
|
#include <Columns/ColumnString.h>
|
||||||
|
#include <DataTypes/DataTypeArray.h>
|
||||||
|
#include <DataTypes/DataTypeString.h>
|
||||||
|
#include <Functions/FunctionHelpers.h>
|
||||||
|
#include <Functions/IFunctionImpl.h>
|
||||||
|
#include <Functions/Regexps.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Core/iostream_debug_helpers.h>
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int BAD_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum class ExtractAllGroupsResultKind
|
||||||
|
{
|
||||||
|
VERTICAL,
|
||||||
|
HORIZONTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Match all groups of given input string with given re, return array of arrays of matches.
|
||||||
|
*
|
||||||
|
* Depending on `Impl::Kind`, result is either grouped by grop id (Horizontal) or in order of appearance (Vertical):
|
||||||
|
*
|
||||||
|
* SELECT extractAllGroupsVertical('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)')
|
||||||
|
* =>
|
||||||
|
* [['abc', '111'], ['def', '222'], ['ghi', '333']]
|
||||||
|
*
|
||||||
|
* SELECT extractAllGroupsHorizontal('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)')
|
||||||
|
* =>
|
||||||
|
* [['abc', 'def', 'ghi'], ['111', '222', '333']
|
||||||
|
*/
|
||||||
|
template <typename Impl>
|
||||||
|
class FunctionExtractAllGroups : public IFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto Kind = Impl::Kind;
|
||||||
|
static constexpr auto name = Impl::Name;
|
||||||
|
|
||||||
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionExtractAllGroups>(); }
|
||||||
|
|
||||||
|
String getName() const override { return name; }
|
||||||
|
|
||||||
|
size_t getNumberOfArguments() const override { return 2; }
|
||||||
|
|
||||||
|
bool useDefaultImplementationForConstants() const override { return true; }
|
||||||
|
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||||
|
|
||||||
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
|
{
|
||||||
|
FunctionArgumentDescriptors args{
|
||||||
|
{"haystack", isStringOrFixedString, nullptr, "const String or const FixedString"},
|
||||||
|
{"needle", isStringOrFixedString, isColumnConst, "const String or const FixedString"},
|
||||||
|
};
|
||||||
|
validateFunctionArgumentTypes(*this, arguments, args);
|
||||||
|
|
||||||
|
/// Two-dimensional array of strings, each `row` of top array represents matching groups.
|
||||||
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
|
||||||
|
{
|
||||||
|
static const auto MAX_GROUPS_COUNT = 128;
|
||||||
|
|
||||||
|
const ColumnPtr column_haystack = block.getByPosition(arguments[0]).column;
|
||||||
|
const ColumnPtr column_needle = block.getByPosition(arguments[1]).column;
|
||||||
|
|
||||||
|
const auto needle = typeid_cast<const ColumnConst &>(*column_needle).getValue<String>();
|
||||||
|
|
||||||
|
if (needle.empty())
|
||||||
|
throw Exception("Length of 'needle' argument must be greater than 0.", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
using StringPiece = typename Regexps::Regexp::StringPieceType;
|
||||||
|
const auto & regexp = Regexps::get<false, false>(needle)->getRE2();
|
||||||
|
|
||||||
|
if (!regexp)
|
||||||
|
throw Exception("There are no groups in regexp: " + needle, ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
const size_t groups_count = regexp->NumberOfCapturingGroups();
|
||||||
|
|
||||||
|
if (!groups_count)
|
||||||
|
throw Exception("There are no groups in regexp: " + needle, ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
if (groups_count > MAX_GROUPS_COUNT - 1)
|
||||||
|
throw Exception("Too many groups in regexp: " + std::to_string(groups_count)
|
||||||
|
+ ", max: " + std::to_string(MAX_GROUPS_COUNT - 1),
|
||||||
|
ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
// Including 0-group, which is the whole regexp.
|
||||||
|
PODArrayWithStackMemory<StringPiece, MAX_GROUPS_COUNT> matched_groups(groups_count + 1);
|
||||||
|
|
||||||
|
ColumnArray::ColumnOffsets::MutablePtr root_offsets_col = ColumnArray::ColumnOffsets::create();
|
||||||
|
ColumnArray::ColumnOffsets::MutablePtr nested_offsets_col = ColumnArray::ColumnOffsets::create();
|
||||||
|
ColumnString::MutablePtr data_col = ColumnString::create();
|
||||||
|
|
||||||
|
auto & root_offsets_data = root_offsets_col->getData();
|
||||||
|
auto & nested_offsets_data = nested_offsets_col->getData();
|
||||||
|
|
||||||
|
ColumnArray::Offset current_root_offset = 0;
|
||||||
|
ColumnArray::Offset current_nested_offset = 0;
|
||||||
|
|
||||||
|
if constexpr (Kind == ExtractAllGroupsResultKind::VERTICAL)
|
||||||
|
{
|
||||||
|
root_offsets_data.resize(input_rows_count);
|
||||||
|
for (size_t i = 0; i < input_rows_count; ++i)
|
||||||
|
{
|
||||||
|
StringRef current_row = column_haystack->getDataAt(i);
|
||||||
|
|
||||||
|
// Extract all non-intersecting matches from haystack except group #0.
|
||||||
|
const auto * pos = current_row.data;
|
||||||
|
const auto * end = pos + current_row.size;
|
||||||
|
while (pos < end
|
||||||
|
&& regexp->Match({pos, static_cast<size_t>(end - pos)},
|
||||||
|
0, end - pos, regexp->UNANCHORED, matched_groups.data(), matched_groups.size()))
|
||||||
|
{
|
||||||
|
// 1 is to exclude group #0 which is whole re match.
|
||||||
|
for (size_t group = 1; group <= groups_count; ++group)
|
||||||
|
data_col->insertData(matched_groups[group].data(), matched_groups[group].size());
|
||||||
|
|
||||||
|
pos = matched_groups[0].data() + matched_groups[0].size();
|
||||||
|
|
||||||
|
current_nested_offset += groups_count;
|
||||||
|
nested_offsets_data.push_back(current_nested_offset);
|
||||||
|
|
||||||
|
++current_root_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
root_offsets_data[i] = current_root_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<StringPiece> all_matches;
|
||||||
|
// number of times RE matched on each row of haystack column.
|
||||||
|
std::vector<size_t> number_of_matches_per_row;
|
||||||
|
|
||||||
|
// we expect RE to match multiple times on each row, `* 8` is arbitrary to reduce number of re-allocations.
|
||||||
|
all_matches.reserve(input_rows_count * groups_count * 8);
|
||||||
|
number_of_matches_per_row.reserve(input_rows_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < input_rows_count; ++i)
|
||||||
|
{
|
||||||
|
size_t matches_per_row = 0;
|
||||||
|
|
||||||
|
const auto & current_row = column_haystack->getDataAt(i);
|
||||||
|
|
||||||
|
// Extract all non-intersecting matches from haystack except group #0.
|
||||||
|
const auto * pos = current_row.data;
|
||||||
|
const auto * end = pos + current_row.size;
|
||||||
|
while (pos < end
|
||||||
|
&& regexp->Match({pos, static_cast<size_t>(end - pos)},
|
||||||
|
0, end - pos, regexp->UNANCHORED, matched_groups.data(), matched_groups.size()))
|
||||||
|
{
|
||||||
|
// 1 is to exclude group #0 which is whole re match.
|
||||||
|
for (size_t group = 1; group <= groups_count; ++group)
|
||||||
|
all_matches.push_back(matched_groups[group]);
|
||||||
|
|
||||||
|
pos = matched_groups[0].data() + matched_groups[0].size();
|
||||||
|
|
||||||
|
++matches_per_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
number_of_matches_per_row.push_back(matches_per_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t total_matched_groups_string_len = 0;
|
||||||
|
for (const auto & m : all_matches)
|
||||||
|
total_matched_groups_string_len += m.length();
|
||||||
|
|
||||||
|
data_col->reserve(total_matched_groups_string_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_offsets_col->reserve(matched_groups.size());
|
||||||
|
root_offsets_col->reserve(groups_count);
|
||||||
|
|
||||||
|
// Re-arrange `all_matches` from:
|
||||||
|
// [
|
||||||
|
// "ROW 0: 1st group 1st match",
|
||||||
|
// "ROW 0: 2nd group 1st match",
|
||||||
|
// ...,
|
||||||
|
// "ROW 0: 1st group 2nd match",
|
||||||
|
// "ROW 0: 2nd group 2nd match",
|
||||||
|
// ...,
|
||||||
|
// "ROW 1: 1st group 1st match",
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
//
|
||||||
|
// into column of 2D arrays:
|
||||||
|
// [
|
||||||
|
// /* all matchig groups from ROW 0 of haystack column */
|
||||||
|
// ["ROW 0: 1st group 1st match", "ROW 0: 1st group 2nd match", ...],
|
||||||
|
// ["ROW 0: 2nd group 1st match", "ROW 0: 2nd group 2nd match", ...],
|
||||||
|
// ...
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// /* all matchig groups from row 1 of haystack column */
|
||||||
|
// ["ROW 1: 1st group 1st match", ...],
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
|
||||||
|
size_t row_offset = 0;
|
||||||
|
for (const auto matches_per_row : number_of_matches_per_row)
|
||||||
|
{
|
||||||
|
const size_t next_row_offset = row_offset + matches_per_row * groups_count;
|
||||||
|
for (size_t group_id = 0; group_id < groups_count; ++group_id)
|
||||||
|
{
|
||||||
|
for (size_t i = row_offset + group_id; i < next_row_offset && i < all_matches.size(); i += groups_count)
|
||||||
|
{
|
||||||
|
const auto & match = all_matches[i];
|
||||||
|
data_col->insertData(match.begin(), match.length());
|
||||||
|
}
|
||||||
|
nested_offsets_col->insertValue(data_col->size());
|
||||||
|
}
|
||||||
|
root_offsets_col->insertValue(nested_offsets_col->size());
|
||||||
|
row_offset = next_row_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnArray::MutablePtr nested_array_col = ColumnArray::create(std::move(data_col), std::move(nested_offsets_col));
|
||||||
|
ColumnArray::MutablePtr root_array_col = ColumnArray::create(std::move(nested_array_col), std::move(root_offsets_col));
|
||||||
|
block.getByPosition(result).column = std::move(root_array_col);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
23
src/Functions/extractAllGroupsHorizontal.cpp
Normal file
23
src/Functions/extractAllGroupsHorizontal.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <Functions/FunctionFactory.h>
|
||||||
|
#include <Functions/extractAllGroups.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct HorizontalImpl
|
||||||
|
{
|
||||||
|
static constexpr auto Kind = DB::ExtractAllGroupsResultKind::HORIZONTAL;
|
||||||
|
static constexpr auto Name = "extractAllGroupsHorizontal";
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
void registerFunctionExtractAllGroupsHorizontal(FunctionFactory & factory)
|
||||||
|
{
|
||||||
|
factory.registerFunction<FunctionExtractAllGroups<HorizontalImpl>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/Functions/extractAllGroupsVertical.cpp
Normal file
24
src/Functions/extractAllGroupsVertical.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <Functions/FunctionFactory.h>
|
||||||
|
#include <Functions/extractAllGroups.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct VerticalImpl
|
||||||
|
{
|
||||||
|
static constexpr auto Kind = DB::ExtractAllGroupsResultKind::VERTICAL;
|
||||||
|
static constexpr auto Name = "extractAllGroupsVertical";
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
void registerFunctionExtractAllGroupsVertical(FunctionFactory & factory)
|
||||||
|
{
|
||||||
|
factory.registerFunction<FunctionExtractAllGroups<VerticalImpl>>();
|
||||||
|
factory.registerAlias("extractAllGroups", VerticalImpl::Name, FunctionFactory::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,7 +17,6 @@ namespace DB
|
|||||||
|
|
||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
{
|
{
|
||||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
|
||||||
extern const int BAD_ARGUMENTS;
|
extern const int BAD_ARGUMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ public:
|
|||||||
};
|
};
|
||||||
validateFunctionArgumentTypes(*this, arguments, args);
|
validateFunctionArgumentTypes(*this, arguments, args);
|
||||||
|
|
||||||
/// Two-dimensional array of strings, each `row` of top array represents matching groups.
|
|
||||||
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>());
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +59,7 @@ public:
|
|||||||
const auto needle = typeid_cast<const ColumnConst &>(*column_needle).getValue<String>();
|
const auto needle = typeid_cast<const ColumnConst &>(*column_needle).getValue<String>();
|
||||||
|
|
||||||
if (needle.empty())
|
if (needle.empty())
|
||||||
throw Exception(getName() + " length of 'needle' argument must be greater than 0.", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception(getName() + " length of 'needle' argument must be greater than 0.", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
const auto regexp = Regexps::get<false, false>(needle);
|
const auto regexp = Regexps::get<false, false>(needle);
|
||||||
const auto & re2 = regexp->getRE2();
|
const auto & re2 = regexp->getRE2();
|
||||||
|
@ -18,7 +18,8 @@ void registerFunctionMultiFuzzyMatchAny(FunctionFactory &);
|
|||||||
void registerFunctionMultiFuzzyMatchAnyIndex(FunctionFactory &);
|
void registerFunctionMultiFuzzyMatchAnyIndex(FunctionFactory &);
|
||||||
void registerFunctionMultiFuzzyMatchAllIndices(FunctionFactory &);
|
void registerFunctionMultiFuzzyMatchAllIndices(FunctionFactory &);
|
||||||
void registerFunctionExtractGroups(FunctionFactory &);
|
void registerFunctionExtractGroups(FunctionFactory &);
|
||||||
void registerFunctionExtractAllGroups(FunctionFactory &);
|
void registerFunctionExtractAllGroupsVertical(FunctionFactory &);
|
||||||
|
void registerFunctionExtractAllGroupsHorizontal(FunctionFactory &);
|
||||||
|
|
||||||
void registerFunctionsStringRegexp(FunctionFactory & factory)
|
void registerFunctionsStringRegexp(FunctionFactory & factory)
|
||||||
{
|
{
|
||||||
@ -37,7 +38,8 @@ void registerFunctionsStringRegexp(FunctionFactory & factory)
|
|||||||
registerFunctionMultiFuzzyMatchAnyIndex(factory);
|
registerFunctionMultiFuzzyMatchAnyIndex(factory);
|
||||||
registerFunctionMultiFuzzyMatchAllIndices(factory);
|
registerFunctionMultiFuzzyMatchAllIndices(factory);
|
||||||
registerFunctionExtractGroups(factory);
|
registerFunctionExtractGroups(factory);
|
||||||
registerFunctionExtractAllGroups(factory);
|
registerFunctionExtractAllGroupsVertical(factory);
|
||||||
|
registerFunctionExtractAllGroupsHorizontal(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,8 @@ SRCS(
|
|||||||
exp10.cpp
|
exp10.cpp
|
||||||
exp2.cpp
|
exp2.cpp
|
||||||
exp.cpp
|
exp.cpp
|
||||||
extractAllGroups.cpp
|
extractAllGroupsHorizontal.cpp
|
||||||
|
extractAllGroupsVertical.cpp
|
||||||
extract.cpp
|
extract.cpp
|
||||||
extractGroups.cpp
|
extractGroups.cpp
|
||||||
extractTimeZoneFromFunctionArguments.cpp
|
extractTimeZoneFromFunctionArguments.cpp
|
||||||
|
64
src/Interpreters/AsynchronousMetricLog.cpp
Normal file
64
src/Interpreters/AsynchronousMetricLog.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include <Interpreters/AsynchronousMetricLog.h>
|
||||||
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
|
#include <DataTypes/DataTypeDate.h>
|
||||||
|
#include <DataTypes/DataTypeDateTime.h>
|
||||||
|
#include <DataTypes/DataTypeString.h>
|
||||||
|
#include <Interpreters/AsynchronousMetrics.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
Block AsynchronousMetricLogElement::createBlock()
|
||||||
|
{
|
||||||
|
ColumnsWithTypeAndName columns;
|
||||||
|
|
||||||
|
columns.emplace_back(std::make_shared<DataTypeDate>(), "event_date");
|
||||||
|
columns.emplace_back(std::make_shared<DataTypeDateTime>(), "event_time");
|
||||||
|
columns.emplace_back(std::make_shared<DataTypeString>(), "name");
|
||||||
|
columns.emplace_back(std::make_shared<DataTypeFloat64>(), "value");
|
||||||
|
|
||||||
|
return Block(columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsynchronousMetricLogElement::appendToBlock(MutableColumns & columns) const
|
||||||
|
{
|
||||||
|
size_t column_idx = 0;
|
||||||
|
|
||||||
|
columns[column_idx++]->insert(event_date);
|
||||||
|
columns[column_idx++]->insert(event_time);
|
||||||
|
columns[column_idx++]->insert(metric_name);
|
||||||
|
columns[column_idx++]->insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline UInt64 time_in_milliseconds(std::chrono::time_point<std::chrono::system_clock> timepoint)
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::milliseconds>(timepoint.time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline UInt64 time_in_seconds(std::chrono::time_point<std::chrono::system_clock> timepoint)
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::seconds>(timepoint.time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsynchronousMetricLog::addValues(const AsynchronousMetricValues & values)
|
||||||
|
{
|
||||||
|
AsynchronousMetricLogElement element;
|
||||||
|
|
||||||
|
const auto now = std::chrono::system_clock::now();
|
||||||
|
element.event_time = time_in_seconds(now);
|
||||||
|
element.event_date = DateLUT::instance().toDayNum(element.event_time);
|
||||||
|
|
||||||
|
for (const auto & [key, value] : values)
|
||||||
|
{
|
||||||
|
element.metric_name = key;
|
||||||
|
element.value = value;
|
||||||
|
|
||||||
|
add(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/Interpreters/AsynchronousMetricLog.h
Normal file
41
src/Interpreters/AsynchronousMetricLog.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Interpreters/SystemLog.h>
|
||||||
|
#include <Common/ProfileEvents.h>
|
||||||
|
#include <Common/CurrentMetrics.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <atomic>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef double AsynchronousMetricValue;
|
||||||
|
typedef std::unordered_map<std::string, AsynchronousMetricValue> AsynchronousMetricValues;
|
||||||
|
|
||||||
|
/** AsynchronousMetricLog is a log of metric values measured at regular time interval.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AsynchronousMetricLogElement
|
||||||
|
{
|
||||||
|
UInt16 event_date;
|
||||||
|
time_t event_time;
|
||||||
|
std::string metric_name;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
static std::string name() { return "AsynchronousMetricLog"; }
|
||||||
|
static Block createBlock();
|
||||||
|
void appendToBlock(MutableColumns & columns) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsynchronousMetricLog : public SystemLog<AsynchronousMetricLogElement>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using SystemLog<AsynchronousMetricLogElement>::SystemLog;
|
||||||
|
|
||||||
|
void addValues(const AsynchronousMetricValues &);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <Interpreters/AsynchronousMetrics.h>
|
#include <Interpreters/AsynchronousMetrics.h>
|
||||||
|
#include <Interpreters/AsynchronousMetricLog.h>
|
||||||
#include <Interpreters/ExpressionJIT.h>
|
#include <Interpreters/ExpressionJIT.h>
|
||||||
#include <Interpreters/DatabaseCatalog.h>
|
#include <Interpreters/DatabaseCatalog.h>
|
||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
@ -37,7 +38,7 @@ AsynchronousMetrics::~AsynchronousMetrics()
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard lock{wait_mutex};
|
std::lock_guard lock{mutex};
|
||||||
quit = true;
|
quit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,17 +52,10 @@ AsynchronousMetrics::~AsynchronousMetrics()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AsynchronousMetrics::Container AsynchronousMetrics::getValues() const
|
AsynchronousMetricValues AsynchronousMetrics::getValues() const
|
||||||
{
|
{
|
||||||
std::lock_guard lock{container_mutex};
|
std::lock_guard lock{mutex};
|
||||||
return container;
|
return values;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AsynchronousMetrics::set(const std::string & name, Value value)
|
|
||||||
{
|
|
||||||
std::lock_guard lock{container_mutex};
|
|
||||||
container[name] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -69,8 +63,6 @@ void AsynchronousMetrics::run()
|
|||||||
{
|
{
|
||||||
setThreadName("AsyncMetrics");
|
setThreadName("AsyncMetrics");
|
||||||
|
|
||||||
std::unique_lock lock{wait_mutex};
|
|
||||||
|
|
||||||
/// Next minute + 30 seconds. To be distant with moment of transmission of metrics, see MetricsTransmitter.
|
/// Next minute + 30 seconds. To be distant with moment of transmission of metrics, see MetricsTransmitter.
|
||||||
const auto get_next_minute = []
|
const auto get_next_minute = []
|
||||||
{
|
{
|
||||||
@ -89,6 +81,7 @@ void AsynchronousMetrics::run()
|
|||||||
tryLogCurrentException(__PRETTY_FUNCTION__);
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_lock lock{mutex};
|
||||||
if (wait_cond.wait_until(lock, get_next_minute(), [this] { return quit; }))
|
if (wait_cond.wait_until(lock, get_next_minute(), [this] { return quit; }))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -113,41 +106,43 @@ static void calculateMaxAndSum(Max & max, Sum & sum, T x)
|
|||||||
|
|
||||||
void AsynchronousMetrics::update()
|
void AsynchronousMetrics::update()
|
||||||
{
|
{
|
||||||
|
AsynchronousMetricValues new_values;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (auto mark_cache = context.getMarkCache())
|
if (auto mark_cache = context.getMarkCache())
|
||||||
{
|
{
|
||||||
set("MarkCacheBytes", mark_cache->weight());
|
new_values["MarkCacheBytes"] = mark_cache->weight();
|
||||||
set("MarkCacheFiles", mark_cache->count());
|
new_values["MarkCacheFiles"] = mark_cache->count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
if (auto uncompressed_cache = context.getUncompressedCache())
|
if (auto uncompressed_cache = context.getUncompressedCache())
|
||||||
{
|
{
|
||||||
set("UncompressedCacheBytes", uncompressed_cache->weight());
|
new_values["UncompressedCacheBytes"] = uncompressed_cache->weight();
|
||||||
set("UncompressedCacheCells", uncompressed_cache->count());
|
new_values["UncompressedCacheCells"] = uncompressed_cache->count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_EMBEDDED_COMPILER
|
#if USE_EMBEDDED_COMPILER
|
||||||
{
|
{
|
||||||
if (auto compiled_expression_cache = context.getCompiledExpressionCache())
|
if (auto compiled_expression_cache = context.getCompiledExpressionCache())
|
||||||
set("CompiledExpressionCacheCount", compiled_expression_cache->count());
|
new_values["CompiledExpressionCacheCount"] = compiled_expression_cache->count();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
set("Uptime", context.getUptimeSeconds());
|
new_values["Uptime"] = context.getUptimeSeconds();
|
||||||
|
|
||||||
/// Process memory usage according to OS
|
/// Process memory usage according to OS
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
{
|
{
|
||||||
MemoryStatisticsOS::Data data = memory_stat.get();
|
MemoryStatisticsOS::Data data = memory_stat.get();
|
||||||
|
|
||||||
set("MemoryVirtual", data.virt);
|
new_values["MemoryVirtual"] = data.virt;
|
||||||
set("MemoryResident", data.resident);
|
new_values["MemoryResident"] = data.resident;
|
||||||
set("MemoryShared", data.shared);
|
new_values["MemoryShared"] = data.shared;
|
||||||
set("MemoryCode", data.code);
|
new_values["MemoryCode"] = data.code;
|
||||||
set("MemoryDataAndStack", data.data_and_stack);
|
new_values["MemoryDataAndStack"] = data.data_and_stack;
|
||||||
|
|
||||||
/// We must update the value of total_memory_tracker periodically.
|
/// We must update the value of total_memory_tracker periodically.
|
||||||
/// Otherwise it might be calculated incorrectly - it can include a "drift" of memory amount.
|
/// Otherwise it might be calculated incorrectly - it can include a "drift" of memory amount.
|
||||||
@ -228,21 +223,21 @@ void AsynchronousMetrics::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set("ReplicasMaxQueueSize", max_queue_size);
|
new_values["ReplicasMaxQueueSize"] = max_queue_size;
|
||||||
set("ReplicasMaxInsertsInQueue", max_inserts_in_queue);
|
new_values["ReplicasMaxInsertsInQueue"] = max_inserts_in_queue;
|
||||||
set("ReplicasMaxMergesInQueue", max_merges_in_queue);
|
new_values["ReplicasMaxMergesInQueue"] = max_merges_in_queue;
|
||||||
|
|
||||||
set("ReplicasSumQueueSize", sum_queue_size);
|
new_values["ReplicasSumQueueSize"] = sum_queue_size;
|
||||||
set("ReplicasSumInsertsInQueue", sum_inserts_in_queue);
|
new_values["ReplicasSumInsertsInQueue"] = sum_inserts_in_queue;
|
||||||
set("ReplicasSumMergesInQueue", sum_merges_in_queue);
|
new_values["ReplicasSumMergesInQueue"] = sum_merges_in_queue;
|
||||||
|
|
||||||
set("ReplicasMaxAbsoluteDelay", max_absolute_delay);
|
new_values["ReplicasMaxAbsoluteDelay"] = max_absolute_delay;
|
||||||
set("ReplicasMaxRelativeDelay", max_relative_delay);
|
new_values["ReplicasMaxRelativeDelay"] = max_relative_delay;
|
||||||
|
|
||||||
set("MaxPartCountForPartition", max_part_count_for_partition);
|
new_values["MaxPartCountForPartition"] = max_part_count_for_partition;
|
||||||
|
|
||||||
set("NumberOfDatabases", number_of_databases);
|
new_values["NumberOfDatabases"] = number_of_databases;
|
||||||
set("NumberOfTables", total_number_of_tables);
|
new_values["NumberOfTables"] = total_number_of_tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_JEMALLOC && JEMALLOC_VERSION_MAJOR >= 4
|
#if USE_JEMALLOC && JEMALLOC_VERSION_MAJOR >= 4
|
||||||
@ -265,7 +260,7 @@ void AsynchronousMetrics::update()
|
|||||||
TYPE value{}; \
|
TYPE value{}; \
|
||||||
size_t size = sizeof(value); \
|
size_t size = sizeof(value); \
|
||||||
mallctl("stats." NAME, &value, &size, nullptr, 0); \
|
mallctl("stats." NAME, &value, &size, nullptr, 0); \
|
||||||
set("jemalloc." NAME, value); \
|
new_values["jemalloc." NAME] = value; \
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
FOR_EACH_METRIC(GET_METRIC)
|
FOR_EACH_METRIC(GET_METRIC)
|
||||||
@ -276,6 +271,16 @@ void AsynchronousMetrics::update()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Add more metrics as you wish.
|
/// Add more metrics as you wish.
|
||||||
|
|
||||||
|
// Log the new metrics.
|
||||||
|
if (auto log = context.getAsynchronousMetricLog())
|
||||||
|
{
|
||||||
|
log->addValues(new_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, update the current metrics.
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
values = new_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ namespace DB
|
|||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
|
|
||||||
|
typedef double AsynchronousMetricValue;
|
||||||
|
typedef std::unordered_map<std::string, AsynchronousMetricValue> AsynchronousMetricValues;
|
||||||
|
|
||||||
|
|
||||||
/** Periodically (each minute, starting at 30 seconds offset)
|
/** Periodically (each minute, starting at 30 seconds offset)
|
||||||
* calculates and updates some metrics,
|
* calculates and updates some metrics,
|
||||||
@ -29,21 +32,17 @@ public:
|
|||||||
|
|
||||||
~AsynchronousMetrics();
|
~AsynchronousMetrics();
|
||||||
|
|
||||||
using Value = double;
|
|
||||||
using Container = std::unordered_map<std::string, Value>;
|
|
||||||
|
|
||||||
/// Returns copy of all values.
|
/// Returns copy of all values.
|
||||||
Container getValues() const;
|
AsynchronousMetricValues getValues() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Context & context;
|
Context & context;
|
||||||
|
|
||||||
bool quit {false};
|
mutable std::mutex mutex;
|
||||||
std::mutex wait_mutex;
|
|
||||||
std::condition_variable wait_cond;
|
std::condition_variable wait_cond;
|
||||||
|
bool quit {false};
|
||||||
Container container;
|
AsynchronousMetricValues values;
|
||||||
mutable std::mutex container_mutex;
|
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
MemoryStatisticsOS memory_stat;
|
MemoryStatisticsOS memory_stat;
|
||||||
@ -53,8 +52,6 @@ private:
|
|||||||
|
|
||||||
void run();
|
void run();
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
void set(const std::string & name, Value value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,8 @@ public:
|
|||||||
if (!session.unique())
|
if (!session.unique())
|
||||||
throw Exception("Session is locked by a concurrent client.", ErrorCodes::SESSION_IS_LOCKED);
|
throw Exception("Session is locked by a concurrent client.", ErrorCodes::SESSION_IS_LOCKED);
|
||||||
|
|
||||||
|
session->context.client_info = context.client_info;
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1676,6 +1678,17 @@ std::shared_ptr<MetricLog> Context::getMetricLog()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<AsynchronousMetricLog> Context::getAsynchronousMetricLog()
|
||||||
|
{
|
||||||
|
auto lock = getLock();
|
||||||
|
|
||||||
|
if (!shared->system_logs)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return shared->system_logs->asynchronous_metric_log;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CompressionCodecPtr Context::chooseCompressionCodec(size_t part_size, double part_size_ratio) const
|
CompressionCodecPtr Context::chooseCompressionCodec(size_t part_size, double part_size_ratio) const
|
||||||
{
|
{
|
||||||
auto lock = getLock();
|
auto lock = getLock();
|
||||||
|
@ -80,6 +80,7 @@ class PartLog;
|
|||||||
class TextLog;
|
class TextLog;
|
||||||
class TraceLog;
|
class TraceLog;
|
||||||
class MetricLog;
|
class MetricLog;
|
||||||
|
class AsynchronousMetricLog;
|
||||||
struct MergeTreeSettings;
|
struct MergeTreeSettings;
|
||||||
class StorageS3Settings;
|
class StorageS3Settings;
|
||||||
class IDatabase;
|
class IDatabase;
|
||||||
@ -526,6 +527,7 @@ public:
|
|||||||
std::shared_ptr<TraceLog> getTraceLog();
|
std::shared_ptr<TraceLog> getTraceLog();
|
||||||
std::shared_ptr<TextLog> getTextLog();
|
std::shared_ptr<TextLog> getTextLog();
|
||||||
std::shared_ptr<MetricLog> getMetricLog();
|
std::shared_ptr<MetricLog> getMetricLog();
|
||||||
|
std::shared_ptr<AsynchronousMetricLog> getAsynchronousMetricLog();
|
||||||
|
|
||||||
/// Returns an object used to log opertaions with parts if it possible.
|
/// Returns an object used to log opertaions with parts if it possible.
|
||||||
/// Provide table name to make required cheks.
|
/// Provide table name to make required cheks.
|
||||||
|
@ -422,7 +422,7 @@ void DDLWorker::processTasks()
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (server_startup && e.code == Coordination::ZNONODE)
|
if (server_startup && e.code == Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
LOG_WARNING(log, "ZooKeeper NONODE error during startup. Ignoring entry {} ({}) : {}", task.entry_name, task.entry.query, getCurrentExceptionMessage(true));
|
LOG_WARNING(log, "ZooKeeper NONODE error during startup. Ignoring entry {} ({}) : {}", task.entry_name, task.entry.query, getCurrentExceptionMessage(true));
|
||||||
}
|
}
|
||||||
@ -603,15 +603,15 @@ void DDLWorker::processTask(DDLTask & task, const ZooKeeperPtr & zookeeper)
|
|||||||
|
|
||||||
auto code = zookeeper->tryCreate(active_node_path, "", zkutil::CreateMode::Ephemeral, dummy);
|
auto code = zookeeper->tryCreate(active_node_path, "", zkutil::CreateMode::Ephemeral, dummy);
|
||||||
|
|
||||||
if (code == Coordination::ZOK || code == Coordination::ZNODEEXISTS)
|
if (code == Coordination::Error::ZOK || code == Coordination::Error::ZNODEEXISTS)
|
||||||
{
|
{
|
||||||
// Ok
|
// Ok
|
||||||
}
|
}
|
||||||
else if (code == Coordination::ZNONODE)
|
else if (code == Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
/// There is no parent
|
/// There is no parent
|
||||||
createStatusDirs(task.entry_path, zookeeper);
|
createStatusDirs(task.entry_path, zookeeper);
|
||||||
if (Coordination::ZOK != zookeeper->tryCreate(active_node_path, "", zkutil::CreateMode::Ephemeral, dummy))
|
if (Coordination::Error::ZOK != zookeeper->tryCreate(active_node_path, "", zkutil::CreateMode::Ephemeral, dummy))
|
||||||
throw Coordination::Exception(code, active_node_path);
|
throw Coordination::Exception(code, active_node_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -915,8 +915,9 @@ void DDLWorker::createStatusDirs(const std::string & node_path, const ZooKeeperP
|
|||||||
ops.emplace_back(std::make_shared<Coordination::CreateRequest>(std::move(request)));
|
ops.emplace_back(std::make_shared<Coordination::CreateRequest>(std::move(request)));
|
||||||
}
|
}
|
||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
int code = zookeeper->tryMulti(ops, responses);
|
Coordination::Error code = zookeeper->tryMulti(ops, responses);
|
||||||
if (code && code != Coordination::ZNODEEXISTS)
|
if (code != Coordination::Error::ZOK
|
||||||
|
&& code != Coordination::Error::ZNODEEXISTS)
|
||||||
throw Coordination::Exception(code);
|
throw Coordination::Exception(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,7 +1014,7 @@ void DDLWorker::runMainThread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (e.code == Coordination::ZNONODE)
|
else if (e.code == Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
LOG_ERROR(log, "ZooKeeper error: {}", getCurrentExceptionMessage(true));
|
LOG_ERROR(log, "ZooKeeper error: {}", getCurrentExceptionMessage(true));
|
||||||
}
|
}
|
||||||
@ -1201,8 +1202,8 @@ private:
|
|||||||
static Strings getChildrenAllowNoNode(const std::shared_ptr<zkutil::ZooKeeper> & zookeeper, const String & node_path)
|
static Strings getChildrenAllowNoNode(const std::shared_ptr<zkutil::ZooKeeper> & zookeeper, const String & node_path)
|
||||||
{
|
{
|
||||||
Strings res;
|
Strings res;
|
||||||
int code = zookeeper->tryGetChildren(node_path, res);
|
Coordination::Error code = zookeeper->tryGetChildren(node_path, res);
|
||||||
if (code && code != Coordination::ZNONODE)
|
if (code != Coordination::Error::ZOK && code != Coordination::Error::ZNONODE)
|
||||||
throw Coordination::Exception(code, node_path);
|
throw Coordination::Exception(code, node_path);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ bool sanitizeBlock(Block & block)
|
|||||||
return false;
|
return false;
|
||||||
col.column = col.type->createColumn();
|
col.column = col.type->createColumn();
|
||||||
}
|
}
|
||||||
else if (isColumnConst(*col.column) && !col.column->empty())
|
else if (!col.column->empty())
|
||||||
col.column = col.column->cloneEmpty();
|
col.column = col.column->cloneEmpty();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -208,7 +208,9 @@ struct ExpressionAnalysisResult
|
|||||||
const FilterInfoPtr & filter_info,
|
const FilterInfoPtr & filter_info,
|
||||||
const Block & source_header);
|
const Block & source_header);
|
||||||
|
|
||||||
|
/// Filter for row-level security.
|
||||||
bool hasFilter() const { return filter_info.get(); }
|
bool hasFilter() const { return filter_info.get(); }
|
||||||
|
|
||||||
bool hasJoin() const { return before_join.get(); }
|
bool hasJoin() const { return before_join.get(); }
|
||||||
bool hasPrewhere() const { return prewhere_info.get(); }
|
bool hasPrewhere() const { return prewhere_info.get(); }
|
||||||
bool hasWhere() const { return before_where.get(); }
|
bool hasWhere() const { return before_where.get(); }
|
||||||
|
@ -94,7 +94,8 @@ namespace ErrorCodes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Assumes `storage` is set and the table filter (row-level security) is not empty.
|
/// Assumes `storage` is set and the table filter (row-level security) is not empty.
|
||||||
String InterpreterSelectQuery::generateFilterActions(ExpressionActionsPtr & actions, const ASTPtr & row_policy_filter, const Names & prerequisite_columns) const
|
String InterpreterSelectQuery::generateFilterActions(
|
||||||
|
ExpressionActionsPtr & actions, const ASTPtr & row_policy_filter, const Names & prerequisite_columns) const
|
||||||
{
|
{
|
||||||
const auto & db_name = table_id.getDatabaseName();
|
const auto & db_name = table_id.getDatabaseName();
|
||||||
const auto & table_name = table_id.getTableName();
|
const auto & table_name = table_id.getTableName();
|
||||||
@ -474,8 +475,7 @@ Block InterpreterSelectQuery::getSampleBlockImpl()
|
|||||||
second_stage,
|
second_stage,
|
||||||
options.only_analyze,
|
options.only_analyze,
|
||||||
filter_info,
|
filter_info,
|
||||||
source_header
|
source_header);
|
||||||
);
|
|
||||||
|
|
||||||
if (options.to_stage == QueryProcessingStage::Enum::FetchColumns)
|
if (options.to_stage == QueryProcessingStage::Enum::FetchColumns)
|
||||||
{
|
{
|
||||||
@ -979,10 +979,13 @@ void InterpreterSelectQuery::executeFetchColumns(
|
|||||||
|
|
||||||
/// Optimization for trivial query like SELECT count() FROM table.
|
/// Optimization for trivial query like SELECT count() FROM table.
|
||||||
bool optimize_trivial_count =
|
bool optimize_trivial_count =
|
||||||
syntax_analyzer_result->optimize_trivial_count && storage &&
|
syntax_analyzer_result->optimize_trivial_count
|
||||||
processing_stage == QueryProcessingStage::FetchColumns &&
|
&& storage
|
||||||
query_analyzer->hasAggregation() && (query_analyzer->aggregates().size() == 1) &&
|
&& !filter_info
|
||||||
typeid_cast<AggregateFunctionCount *>(query_analyzer->aggregates()[0].function.get());
|
&& processing_stage == QueryProcessingStage::FetchColumns
|
||||||
|
&& query_analyzer->hasAggregation()
|
||||||
|
&& (query_analyzer->aggregates().size() == 1)
|
||||||
|
&& typeid_cast<AggregateFunctionCount *>(query_analyzer->aggregates()[0].function.get());
|
||||||
|
|
||||||
if (optimize_trivial_count)
|
if (optimize_trivial_count)
|
||||||
{
|
{
|
||||||
|
@ -132,7 +132,8 @@ private:
|
|||||||
void executeSubqueriesInSetsAndJoins(QueryPipeline & pipeline, const std::unordered_map<String, SubqueryForSet> & subqueries_for_sets);
|
void executeSubqueriesInSetsAndJoins(QueryPipeline & pipeline, const std::unordered_map<String, SubqueryForSet> & subqueries_for_sets);
|
||||||
void executeMergeSorted(QueryPipeline & pipeline, const SortDescription & sort_description, UInt64 limit);
|
void executeMergeSorted(QueryPipeline & pipeline, const SortDescription & sort_description, UInt64 limit);
|
||||||
|
|
||||||
String generateFilterActions(ExpressionActionsPtr & actions, const ASTPtr & row_policy_filter, const Names & prerequisite_columns = {}) const;
|
String generateFilterActions(
|
||||||
|
ExpressionActionsPtr & actions, const ASTPtr & row_policy_filter, const Names & prerequisite_columns = {}) const;
|
||||||
|
|
||||||
enum class Modificator
|
enum class Modificator
|
||||||
{
|
{
|
||||||
@ -159,6 +160,7 @@ private:
|
|||||||
|
|
||||||
/// Is calculated in getSampleBlock. Is used later in readImpl.
|
/// Is calculated in getSampleBlock. Is used later in readImpl.
|
||||||
ExpressionAnalysisResult analysis_result;
|
ExpressionAnalysisResult analysis_result;
|
||||||
|
/// For row-level security.
|
||||||
FilterInfoPtr filter_info;
|
FilterInfoPtr filter_info;
|
||||||
|
|
||||||
QueryProcessingStage::Enum from_stage = QueryProcessingStage::FetchColumns;
|
QueryProcessingStage::Enum from_stage = QueryProcessingStage::FetchColumns;
|
||||||
|
@ -69,7 +69,7 @@ BlockInputStreamPtr InterpreterShowCreateQuery::executeImpl()
|
|||||||
create_query = DatabaseCatalog::instance().getDatabase(show_query->database)->getCreateDictionaryQuery(show_query->table);
|
create_query = DatabaseCatalog::instance().getDatabase(show_query->database)->getCreateDictionaryQuery(show_query->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!create_query && show_query && show_query->temporary)
|
if (!create_query)
|
||||||
throw Exception("Unable to show the create query of " + show_query->table + ". Maybe it was created by the system.", ErrorCodes::THERE_IS_NO_QUERY);
|
throw Exception("Unable to show the create query of " + show_query->table + ". Maybe it was created by the system.", ErrorCodes::THERE_IS_NO_QUERY);
|
||||||
|
|
||||||
if (!context.getSettingsRef().show_table_uuid_in_table_create_query_if_not_nil)
|
if (!context.getSettingsRef().show_table_uuid_in_table_create_query_if_not_nil)
|
||||||
|
@ -33,6 +33,32 @@ String InterpreterShowTablesQuery::getRewrittenQuery()
|
|||||||
if (query.databases)
|
if (query.databases)
|
||||||
return "SELECT name FROM system.databases";
|
return "SELECT name FROM system.databases";
|
||||||
|
|
||||||
|
/// SHOW CLUSTER/CLUSTERS
|
||||||
|
if (query.clusters)
|
||||||
|
{
|
||||||
|
std::stringstream rewritten_query;
|
||||||
|
rewritten_query << "SELECT DISTINCT cluster FROM system.clusters";
|
||||||
|
|
||||||
|
if (!query.like.empty())
|
||||||
|
{
|
||||||
|
rewritten_query << " WHERE cluster " << (query.not_like ? "NOT " : "") << "LIKE " << std::quoted(query.like, '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.limit_length)
|
||||||
|
rewritten_query << " LIMIT " << query.limit_length;
|
||||||
|
|
||||||
|
return rewritten_query.str();
|
||||||
|
}
|
||||||
|
else if (query.cluster)
|
||||||
|
{
|
||||||
|
std::stringstream rewritten_query;
|
||||||
|
rewritten_query << "SELECT * FROM system.clusters";
|
||||||
|
|
||||||
|
rewritten_query << " WHERE cluster = " << std::quoted(query.cluster_str, '\'');
|
||||||
|
|
||||||
|
return rewritten_query.str();
|
||||||
|
}
|
||||||
|
|
||||||
if (query.temporary && !query.from.empty())
|
if (query.temporary && !query.from.empty())
|
||||||
throw Exception("The `FROM` and `TEMPORARY` cannot be used together in `SHOW TABLES`", ErrorCodes::SYNTAX_ERROR);
|
throw Exception("The `FROM` and `TEMPORARY` cannot be used together in `SHOW TABLES`", ErrorCodes::SYNTAX_ERROR);
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <Interpreters/TraceLog.h>
|
#include <Interpreters/TraceLog.h>
|
||||||
#include <Interpreters/TextLog.h>
|
#include <Interpreters/TextLog.h>
|
||||||
#include <Interpreters/MetricLog.h>
|
#include <Interpreters/MetricLog.h>
|
||||||
|
#include <Interpreters/AsynchronousMetricLog.h>
|
||||||
#include <Access/ContextAccess.h>
|
#include <Access/ContextAccess.h>
|
||||||
#include <Access/AllowedClientHosts.h>
|
#include <Access/AllowedClientHosts.h>
|
||||||
#include <Databases/IDatabase.h>
|
#include <Databases/IDatabase.h>
|
||||||
@ -301,12 +302,13 @@ BlockIO InterpreterSystemQuery::execute()
|
|||||||
case Type::FLUSH_LOGS:
|
case Type::FLUSH_LOGS:
|
||||||
context.checkAccess(AccessType::SYSTEM_FLUSH_LOGS);
|
context.checkAccess(AccessType::SYSTEM_FLUSH_LOGS);
|
||||||
executeCommandsAndThrowIfError(
|
executeCommandsAndThrowIfError(
|
||||||
[&] () { if (auto query_log = context.getQueryLog()) query_log->flush(true); },
|
[&] () { if (auto query_log = context.getQueryLog()) query_log->flush(); },
|
||||||
[&] () { if (auto part_log = context.getPartLog("")) part_log->flush(true); },
|
[&] () { if (auto part_log = context.getPartLog("")) part_log->flush(); },
|
||||||
[&] () { if (auto query_thread_log = context.getQueryThreadLog()) query_thread_log->flush(true); },
|
[&] () { if (auto query_thread_log = context.getQueryThreadLog()) query_thread_log->flush(); },
|
||||||
[&] () { if (auto trace_log = context.getTraceLog()) trace_log->flush(true); },
|
[&] () { if (auto trace_log = context.getTraceLog()) trace_log->flush(); },
|
||||||
[&] () { if (auto text_log = context.getTextLog()) text_log->flush(true); },
|
[&] () { if (auto text_log = context.getTextLog()) text_log->flush(); },
|
||||||
[&] () { if (auto metric_log = context.getMetricLog()) metric_log->flush(true); }
|
[&] () { if (auto metric_log = context.getMetricLog()) metric_log->flush(); },
|
||||||
|
[&] () { if (auto asynchronous_metric_log = context.getAsynchronousMetricLog()) asynchronous_metric_log->flush(); }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Type::STOP_LISTEN_QUERIES:
|
case Type::STOP_LISTEN_QUERIES:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <Interpreters/TextLog.h>
|
#include <Interpreters/TextLog.h>
|
||||||
#include <Interpreters/TraceLog.h>
|
#include <Interpreters/TraceLog.h>
|
||||||
#include <Interpreters/MetricLog.h>
|
#include <Interpreters/MetricLog.h>
|
||||||
|
#include <Interpreters/AsynchronousMetricLog.h>
|
||||||
|
|
||||||
#include <Poco/Util/AbstractConfiguration.h>
|
#include <Poco/Util/AbstractConfiguration.h>
|
||||||
#include <common/logger_useful.h>
|
#include <common/logger_useful.h>
|
||||||
@ -75,6 +76,9 @@ SystemLogs::SystemLogs(Context & global_context, const Poco::Util::AbstractConfi
|
|||||||
trace_log = createSystemLog<TraceLog>(global_context, "system", "trace_log", config, "trace_log");
|
trace_log = createSystemLog<TraceLog>(global_context, "system", "trace_log", config, "trace_log");
|
||||||
text_log = createSystemLog<TextLog>(global_context, "system", "text_log", config, "text_log");
|
text_log = createSystemLog<TextLog>(global_context, "system", "text_log", config, "text_log");
|
||||||
metric_log = createSystemLog<MetricLog>(global_context, "system", "metric_log", config, "metric_log");
|
metric_log = createSystemLog<MetricLog>(global_context, "system", "metric_log", config, "metric_log");
|
||||||
|
asynchronous_metric_log = createSystemLog<AsynchronousMetricLog>(
|
||||||
|
global_context, "system", "asynchronous_metric_log", config,
|
||||||
|
"asynchronous_metric_log");
|
||||||
|
|
||||||
if (query_log)
|
if (query_log)
|
||||||
logs.emplace_back(query_log.get());
|
logs.emplace_back(query_log.get());
|
||||||
@ -88,6 +92,9 @@ SystemLogs::SystemLogs(Context & global_context, const Poco::Util::AbstractConfi
|
|||||||
logs.emplace_back(text_log.get());
|
logs.emplace_back(text_log.get());
|
||||||
if (metric_log)
|
if (metric_log)
|
||||||
logs.emplace_back(metric_log.get());
|
logs.emplace_back(metric_log.get());
|
||||||
|
if (asynchronous_metric_log)
|
||||||
|
logs.emplace_back(asynchronous_metric_log.get());
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -69,6 +69,7 @@ class PartLog;
|
|||||||
class TextLog;
|
class TextLog;
|
||||||
class TraceLog;
|
class TraceLog;
|
||||||
class MetricLog;
|
class MetricLog;
|
||||||
|
class AsynchronousMetricLog;
|
||||||
|
|
||||||
|
|
||||||
class ISystemLog
|
class ISystemLog
|
||||||
@ -76,8 +77,7 @@ class ISystemLog
|
|||||||
public:
|
public:
|
||||||
virtual String getName() = 0;
|
virtual String getName() = 0;
|
||||||
virtual ASTPtr getCreateTableQuery() = 0;
|
virtual ASTPtr getCreateTableQuery() = 0;
|
||||||
//// force -- force table creation (used for SYSTEM FLUSH LOGS)
|
virtual void flush() = 0;
|
||||||
virtual void flush(bool force = false) = 0;
|
|
||||||
virtual void prepareTable() = 0;
|
virtual void prepareTable() = 0;
|
||||||
virtual void startup() = 0;
|
virtual void startup() = 0;
|
||||||
virtual void shutdown() = 0;
|
virtual void shutdown() = 0;
|
||||||
@ -100,6 +100,8 @@ struct SystemLogs
|
|||||||
std::shared_ptr<TraceLog> trace_log; /// Used to log traces from query profiler
|
std::shared_ptr<TraceLog> trace_log; /// Used to log traces from query profiler
|
||||||
std::shared_ptr<TextLog> text_log; /// Used to log all text messages.
|
std::shared_ptr<TextLog> text_log; /// Used to log all text messages.
|
||||||
std::shared_ptr<MetricLog> metric_log; /// Used to log all metrics.
|
std::shared_ptr<MetricLog> metric_log; /// Used to log all metrics.
|
||||||
|
/// Metrics from system.asynchronous_metrics.
|
||||||
|
std::shared_ptr<AsynchronousMetricLog> asynchronous_metric_log;
|
||||||
|
|
||||||
std::vector<ISystemLog *> logs;
|
std::vector<ISystemLog *> logs;
|
||||||
};
|
};
|
||||||
@ -134,7 +136,7 @@ public:
|
|||||||
void stopFlushThread();
|
void stopFlushThread();
|
||||||
|
|
||||||
/// Flush data in the buffer to disk
|
/// Flush data in the buffer to disk
|
||||||
void flush(bool force = false) override;
|
void flush() override;
|
||||||
|
|
||||||
/// Start the background thread.
|
/// Start the background thread.
|
||||||
void startup() override;
|
void startup() override;
|
||||||
@ -167,8 +169,6 @@ private:
|
|||||||
|
|
||||||
/* Data shared between callers of add()/flush()/shutdown(), and the saving thread */
|
/* Data shared between callers of add()/flush()/shutdown(), and the saving thread */
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
/* prepareTable() guard */
|
|
||||||
std::mutex prepare_mutex;
|
|
||||||
// Queue is bounded. But its size is quite large to not block in all normal cases.
|
// Queue is bounded. But its size is quite large to not block in all normal cases.
|
||||||
std::vector<LogElement> queue;
|
std::vector<LogElement> queue;
|
||||||
// An always-incrementing index of the first message currently in the queue.
|
// An always-incrementing index of the first message currently in the queue.
|
||||||
@ -217,7 +217,7 @@ SystemLog<LogElement>::SystemLog(Context & context_,
|
|||||||
template <typename LogElement>
|
template <typename LogElement>
|
||||||
void SystemLog<LogElement>::startup()
|
void SystemLog<LogElement>::startup()
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
saving_thread = ThreadFromGlobalPool([this] { savingThreadFunction(); });
|
saving_thread = ThreadFromGlobalPool([this] { savingThreadFunction(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ void SystemLog<LogElement>::add(const LogElement & element)
|
|||||||
/// Otherwise the tests like 01017_uniqCombined_memory_usage.sql will be flacky.
|
/// Otherwise the tests like 01017_uniqCombined_memory_usage.sql will be flacky.
|
||||||
auto temporarily_disable_memory_tracker = getCurrentMemoryTrackerActionLock();
|
auto temporarily_disable_memory_tracker = getCurrentMemoryTrackerActionLock();
|
||||||
|
|
||||||
std::lock_guard lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
if (is_shutdown)
|
if (is_shutdown)
|
||||||
return;
|
return;
|
||||||
@ -275,16 +275,13 @@ void SystemLog<LogElement>::add(const LogElement & element)
|
|||||||
|
|
||||||
|
|
||||||
template <typename LogElement>
|
template <typename LogElement>
|
||||||
void SystemLog<LogElement>::flush(bool force)
|
void SystemLog<LogElement>::flush()
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
if (is_shutdown)
|
if (is_shutdown)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (force)
|
|
||||||
prepareTable();
|
|
||||||
|
|
||||||
const uint64_t queue_end = queue_front_index + queue.size();
|
const uint64_t queue_end = queue_front_index + queue.size();
|
||||||
|
|
||||||
if (requested_flush_before < queue_end)
|
if (requested_flush_before < queue_end)
|
||||||
@ -310,7 +307,7 @@ template <typename LogElement>
|
|||||||
void SystemLog<LogElement>::stopFlushThread()
|
void SystemLog<LogElement>::stopFlushThread()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
if (!saving_thread.joinable())
|
if (!saving_thread.joinable())
|
||||||
{
|
{
|
||||||
@ -423,7 +420,7 @@ void SystemLog<LogElement>::flushImpl(const std::vector<LogElement> & to_flush,
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
flushed_before = to_flush_end;
|
flushed_before = to_flush_end;
|
||||||
flush_event.notify_all();
|
flush_event.notify_all();
|
||||||
}
|
}
|
||||||
@ -435,8 +432,6 @@ void SystemLog<LogElement>::flushImpl(const std::vector<LogElement> & to_flush,
|
|||||||
template <typename LogElement>
|
template <typename LogElement>
|
||||||
void SystemLog<LogElement>::prepareTable()
|
void SystemLog<LogElement>::prepareTable()
|
||||||
{
|
{
|
||||||
std::lock_guard prepare_lock(prepare_mutex);
|
|
||||||
|
|
||||||
String description = table_id.getNameForLogs();
|
String description = table_id.getNameForLogs();
|
||||||
|
|
||||||
table = DatabaseCatalog::instance().tryGetTable(table_id, context);
|
table = DatabaseCatalog::instance().tryGetTable(table_id, context);
|
||||||
|
@ -105,6 +105,7 @@ SRCS(
|
|||||||
MarkTableIdentifiersVisitor.cpp
|
MarkTableIdentifiersVisitor.cpp
|
||||||
MergeJoin.cpp
|
MergeJoin.cpp
|
||||||
MetricLog.cpp
|
MetricLog.cpp
|
||||||
|
AsynchronousMetricLog.cpp
|
||||||
MutationsInterpreter.cpp
|
MutationsInterpreter.cpp
|
||||||
NullableUtils.cpp
|
NullableUtils.cpp
|
||||||
OptimizeIfChains.cpp
|
OptimizeIfChains.cpp
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <Parsers/ASTShowTablesQuery.h>
|
#include <Parsers/ASTShowTablesQuery.h>
|
||||||
#include <Common/quoteString.h>
|
#include <Common/quoteString.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -20,6 +19,24 @@ void ASTShowTablesQuery::formatQueryImpl(const FormatSettings & settings, Format
|
|||||||
{
|
{
|
||||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW DATABASES" << (settings.hilite ? hilite_none : "");
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW DATABASES" << (settings.hilite ? hilite_none : "");
|
||||||
}
|
}
|
||||||
|
else if (clusters)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW CLUSTERS" << (settings.hilite ? hilite_none : "");
|
||||||
|
if (!like.empty())
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << (not_like ? " NOT" : "") << " LIKE " << (settings.hilite ? hilite_none : "")
|
||||||
|
<< std::quoted(like, '\'');
|
||||||
|
|
||||||
|
if (limit_length)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " LIMIT " << (settings.hilite ? hilite_none : "");
|
||||||
|
limit_length->formatImpl(settings, state, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cluster)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW CLUSTER" << (settings.hilite ? hilite_none : "");
|
||||||
|
settings.ostr << " " << backQuoteIfNeed(cluster_str);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW " << (temporary ? "TEMPORARY " : "") <<
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW " << (temporary ? "TEMPORARY " : "") <<
|
||||||
|
@ -9,14 +9,17 @@ namespace DB
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/** Query SHOW TABLES or SHOW DATABASES
|
/** Query SHOW TABLES or SHOW DATABASES or SHOW CLUSTERS
|
||||||
*/
|
*/
|
||||||
class ASTShowTablesQuery : public ASTQueryWithOutput
|
class ASTShowTablesQuery : public ASTQueryWithOutput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool databases{false};
|
bool databases{false};
|
||||||
|
bool clusters{false};
|
||||||
|
bool cluster{false};
|
||||||
bool dictionaries{false};
|
bool dictionaries{false};
|
||||||
bool temporary{false};
|
bool temporary{false};
|
||||||
|
String cluster_str;
|
||||||
String from;
|
String from;
|
||||||
String like;
|
String like;
|
||||||
bool not_like{false};
|
bool not_like{false};
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <Parsers/ParserShowTablesQuery.h>
|
#include <Parsers/ParserShowTablesQuery.h>
|
||||||
#include <Parsers/ExpressionElementParsers.h>
|
#include <Parsers/ExpressionElementParsers.h>
|
||||||
#include <Parsers/ExpressionListParsers.h>
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
|
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||||
|
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ bool ParserShowTablesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
|||||||
ParserKeyword s_temporary("TEMPORARY");
|
ParserKeyword s_temporary("TEMPORARY");
|
||||||
ParserKeyword s_tables("TABLES");
|
ParserKeyword s_tables("TABLES");
|
||||||
ParserKeyword s_databases("DATABASES");
|
ParserKeyword s_databases("DATABASES");
|
||||||
|
ParserKeyword s_clusters("CLUSTERS");
|
||||||
|
ParserKeyword s_cluster("CLUSTER");
|
||||||
ParserKeyword s_dictionaries("DICTIONARIES");
|
ParserKeyword s_dictionaries("DICTIONARIES");
|
||||||
ParserKeyword s_from("FROM");
|
ParserKeyword s_from("FROM");
|
||||||
ParserKeyword s_in("IN");
|
ParserKeyword s_in("IN");
|
||||||
@ -43,6 +46,36 @@ bool ParserShowTablesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
|||||||
{
|
{
|
||||||
query->databases = true;
|
query->databases = true;
|
||||||
}
|
}
|
||||||
|
else if (s_clusters.ignore(pos))
|
||||||
|
{
|
||||||
|
query->clusters = true;
|
||||||
|
|
||||||
|
if (s_not.ignore(pos, expected))
|
||||||
|
query->not_like = true;
|
||||||
|
|
||||||
|
if (s_like.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
if (!like_p.parse(pos, like, expected))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (query->not_like)
|
||||||
|
return false;
|
||||||
|
if (s_limit.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
if (!exp_elem.parse(pos, query->limit_length, expected))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (s_cluster.ignore(pos))
|
||||||
|
{
|
||||||
|
query->cluster = true;
|
||||||
|
|
||||||
|
String cluster_str;
|
||||||
|
if (!parseIdentifierOrStringLiteral(pos, expected, cluster_str))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
query->cluster_str = std::move(cluster_str);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (s_temporary.ignore(pos))
|
if (s_temporary.ignore(pos))
|
||||||
|
@ -14,7 +14,7 @@ namespace DB
|
|||||||
class ParserShowTablesQuery : public IParserBase
|
class ParserShowTablesQuery : public IParserBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const char * getName() const override { return "SHOW [TEMPORARY] TABLES|DATABASES [[NOT] LIKE 'str'] [LIMIT expr]"; }
|
const char * getName() const override { return "SHOW [TEMPORARY] TABLES|DATABASES|CLUSTERS|CLUSTER 'name' [[NOT] LIKE 'str'] [LIMIT expr]"; }
|
||||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,9 +100,9 @@ void AggregatingInOrderTransform::consume(Chunk chunk)
|
|||||||
params->aggregator.createStatesAndFillKeyColumnsWithSingleKey(variants, key_columns, key_begin, res_key_columns);
|
params->aggregator.createStatesAndFillKeyColumnsWithSingleKey(variants, key_columns, key_begin, res_key_columns);
|
||||||
++cur_block_size;
|
++cur_block_size;
|
||||||
}
|
}
|
||||||
size_t mid = 0;
|
ssize_t mid = 0;
|
||||||
size_t high = 0;
|
ssize_t high = 0;
|
||||||
size_t low = -1;
|
ssize_t low = -1;
|
||||||
/// Will split block into segments with the same key
|
/// Will split block into segments with the same key
|
||||||
while (key_end != rows)
|
while (key_end != rows)
|
||||||
{
|
{
|
||||||
|
@ -104,13 +104,13 @@ EphemeralLocksInAllPartitions::EphemeralLocksInAllPartitions(
|
|||||||
lock_ops.push_back(zkutil::makeCheckRequest(block_numbers_path, partitions_stat.version));
|
lock_ops.push_back(zkutil::makeCheckRequest(block_numbers_path, partitions_stat.version));
|
||||||
|
|
||||||
Coordination::Responses lock_responses;
|
Coordination::Responses lock_responses;
|
||||||
int rc = zookeeper.tryMulti(lock_ops, lock_responses);
|
Coordination::Error rc = zookeeper.tryMulti(lock_ops, lock_responses);
|
||||||
if (rc == Coordination::ZBADVERSION)
|
if (rc == Coordination::Error::ZBADVERSION)
|
||||||
{
|
{
|
||||||
LOG_TRACE(&Poco::Logger::get("EphemeralLocksInAllPartitions"), "Someone has inserted a block in a new partition while we were creating locks. Retry.");
|
LOG_TRACE(&Poco::Logger::get("EphemeralLocksInAllPartitions"), "Someone has inserted a block in a new partition while we were creating locks. Retry.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (rc != Coordination::ZOK)
|
else if (rc != Coordination::Error::ZOK)
|
||||||
throw Coordination::Exception(rc);
|
throw Coordination::Exception(rc);
|
||||||
|
|
||||||
for (size_t i = 0; i < partitions.size(); ++i)
|
for (size_t i = 0; i < partitions.size(); ++i)
|
||||||
|
@ -152,7 +152,8 @@ MergeTreeData::MergeTreeData(
|
|||||||
|
|
||||||
if (metadata.sample_by_ast != nullptr)
|
if (metadata.sample_by_ast != nullptr)
|
||||||
{
|
{
|
||||||
StorageMetadataKeyField candidate_sampling_key = StorageMetadataKeyField::getKeyFromAST(metadata.sample_by_ast, getColumns(), global_context);
|
StorageMetadataKeyField candidate_sampling_key = StorageMetadataKeyField::getKeyFromAST(
|
||||||
|
metadata.sample_by_ast, getColumns(), global_context);
|
||||||
|
|
||||||
const auto & pk_sample_block = getPrimaryKey().sample_block;
|
const auto & pk_sample_block = getPrimaryKey().sample_block;
|
||||||
if (!pk_sample_block.has(candidate_sampling_key.column_names[0]) && !attach
|
if (!pk_sample_block.has(candidate_sampling_key.column_names[0]) && !attach
|
||||||
@ -1304,6 +1305,24 @@ void MergeTreeData::dropAllData()
|
|||||||
LOG_TRACE(log, "dropAllData: done.");
|
LOG_TRACE(log, "dropAllData: done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MergeTreeData::dropIfEmpty()
|
||||||
|
{
|
||||||
|
LOG_TRACE(log, "dropIfEmpty");
|
||||||
|
|
||||||
|
auto lock = lockParts();
|
||||||
|
|
||||||
|
if (!data_parts_by_info.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto & [path, disk] : getRelativeDataPathsWithDisks())
|
||||||
|
{
|
||||||
|
/// Non recursive, exception is thrown if there are more files.
|
||||||
|
disk->remove(path + "format_version.txt");
|
||||||
|
disk->remove(path + "detached");
|
||||||
|
disk->remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -485,6 +485,9 @@ public:
|
|||||||
/// Deletes the data directory and flushes the uncompressed blocks cache and the marks cache.
|
/// Deletes the data directory and flushes the uncompressed blocks cache and the marks cache.
|
||||||
void dropAllData();
|
void dropAllData();
|
||||||
|
|
||||||
|
/// Drop data directories if they are empty. It is safe to call this method if table creation was unsuccessful.
|
||||||
|
void dropIfEmpty();
|
||||||
|
|
||||||
/// Moves the entire data directory.
|
/// Moves the entire data directory.
|
||||||
/// Flushes the uncompressed blocks cache and the marks cache.
|
/// Flushes the uncompressed blocks cache and the marks cache.
|
||||||
/// Must be called with locked lockStructureForAlter().
|
/// Must be called with locked lockStructureForAlter().
|
||||||
|
@ -82,7 +82,6 @@ public:
|
|||||||
const AllowedMergingPredicate & can_merge,
|
const AllowedMergingPredicate & can_merge,
|
||||||
String * out_disable_reason = nullptr);
|
String * out_disable_reason = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/** Select all the parts in the specified partition for merge, if possible.
|
/** Select all the parts in the specified partition for merge, if possible.
|
||||||
* final - choose to merge even a single part - that is, allow to merge one part "with itself".
|
* final - choose to merge even a single part - that is, allow to merge one part "with itself".
|
||||||
*/
|
*/
|
||||||
|
@ -905,7 +905,9 @@ void MergeTreeRangeReader::executePrewhereActionsAndFilterColumns(ReadResult & r
|
|||||||
if (prewhere->remove_prewhere_column)
|
if (prewhere->remove_prewhere_column)
|
||||||
result.columns.erase(result.columns.begin() + prewhere_column_pos);
|
result.columns.erase(result.columns.begin() + prewhere_column_pos);
|
||||||
else
|
else
|
||||||
result.columns[prewhere_column_pos] = DataTypeUInt8().createColumnConst(result.num_rows, 1u)->convertToFullColumnIfConst();
|
result.columns[prewhere_column_pos] =
|
||||||
|
getSampleBlock().getByName(prewhere->prewhere_column_name).type->
|
||||||
|
createColumnConst(result.num_rows, 1u)->convertToFullColumnIfConst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Filter in WHERE instead
|
/// Filter in WHERE instead
|
||||||
|
@ -85,7 +85,7 @@ void ReplicatedMergeTreeBlockOutputStream::checkQuorumPrecondition(zkutil::ZooKe
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
auto quorum_status = quorum_status_future.get();
|
auto quorum_status = quorum_status_future.get();
|
||||||
if (quorum_status.error != Coordination::ZNONODE)
|
if (quorum_status.error != Coordination::Error::ZNONODE)
|
||||||
throw Exception("Quorum for previous write has not been satisfied yet. Status: " + quorum_status.data, ErrorCodes::UNSATISFIED_QUORUM_FOR_PREVIOUS_WRITE);
|
throw Exception("Quorum for previous write has not been satisfied yet. Status: " + quorum_status.data, ErrorCodes::UNSATISFIED_QUORUM_FOR_PREVIOUS_WRITE);
|
||||||
|
|
||||||
/// Both checks are implicitly made also later (otherwise there would be a race condition).
|
/// Both checks are implicitly made also later (otherwise there would be a race condition).
|
||||||
@ -93,7 +93,7 @@ void ReplicatedMergeTreeBlockOutputStream::checkQuorumPrecondition(zkutil::ZooKe
|
|||||||
auto is_active = is_active_future.get();
|
auto is_active = is_active_future.get();
|
||||||
auto host = host_future.get();
|
auto host = host_future.get();
|
||||||
|
|
||||||
if (is_active.error == Coordination::ZNONODE || host.error == Coordination::ZNONODE)
|
if (is_active.error == Coordination::Error::ZNONODE || host.error == Coordination::Error::ZNONODE)
|
||||||
throw Exception("Replica is not active right now", ErrorCodes::READONLY);
|
throw Exception("Replica is not active right now", ErrorCodes::READONLY);
|
||||||
|
|
||||||
quorum_info.is_active_node_value = is_active.data;
|
quorum_info.is_active_node_value = is_active.data;
|
||||||
@ -198,7 +198,8 @@ void ReplicatedMergeTreeBlockOutputStream::writeExistingPart(MergeTreeData::Muta
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zookeeper, MergeTreeData::MutableDataPartPtr & part, const String & block_id)
|
void ReplicatedMergeTreeBlockOutputStream::commitPart(
|
||||||
|
zkutil::ZooKeeperPtr & zookeeper, MergeTreeData::MutableDataPartPtr & part, const String & block_id)
|
||||||
{
|
{
|
||||||
storage.check(part->getColumns());
|
storage.check(part->getColumns());
|
||||||
assertSessionIsNotExpired(zookeeper);
|
assertSessionIsNotExpired(zookeeper);
|
||||||
@ -299,9 +300,9 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
storage.renameTempPartAndAdd(part, nullptr, &transaction);
|
storage.renameTempPartAndAdd(part, nullptr, &transaction);
|
||||||
|
|
||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
int32_t multi_code = zookeeper->tryMultiNoThrow(ops, responses); /// 1 RTT
|
Coordination::Error multi_code = zookeeper->tryMultiNoThrow(ops, responses); /// 1 RTT
|
||||||
|
|
||||||
if (multi_code == Coordination::ZOK)
|
if (multi_code == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
storage.merge_selecting_task->schedule();
|
storage.merge_selecting_task->schedule();
|
||||||
@ -309,8 +310,8 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
/// Lock nodes have been already deleted, do not delete them in destructor
|
/// Lock nodes have been already deleted, do not delete them in destructor
|
||||||
block_number_lock->assumeUnlocked();
|
block_number_lock->assumeUnlocked();
|
||||||
}
|
}
|
||||||
else if (multi_code == Coordination::ZCONNECTIONLOSS
|
else if (multi_code == Coordination::Error::ZCONNECTIONLOSS
|
||||||
|| multi_code == Coordination::ZOPERATIONTIMEOUT)
|
|| multi_code == Coordination::Error::ZOPERATIONTIMEOUT)
|
||||||
{
|
{
|
||||||
/** If the connection is lost, and we do not know if the changes were applied, we can not delete the local part
|
/** If the connection is lost, and we do not know if the changes were applied, we can not delete the local part
|
||||||
* if the changes were applied, the inserted block appeared in `/blocks/`, and it can not be inserted again.
|
* if the changes were applied, the inserted block appeared in `/blocks/`, and it can not be inserted again.
|
||||||
@ -326,7 +327,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
{
|
{
|
||||||
String failed_op_path = zkutil::KeeperMultiException(multi_code, ops, responses).getPathForFirstFailedOp();
|
String failed_op_path = zkutil::KeeperMultiException(multi_code, ops, responses).getPathForFirstFailedOp();
|
||||||
|
|
||||||
if (multi_code == Coordination::ZNODEEXISTS && deduplicate_block && failed_op_path == block_id_path)
|
if (multi_code == Coordination::Error::ZNODEEXISTS && deduplicate_block && failed_op_path == block_id_path)
|
||||||
{
|
{
|
||||||
/// Block with the same id have just appeared in table (or other replica), rollback thee insertion.
|
/// Block with the same id have just appeared in table (or other replica), rollback thee insertion.
|
||||||
LOG_INFO(log, "Block with ID {} already exists; ignoring it (removing part {})", block_id, part->name);
|
LOG_INFO(log, "Block with ID {} already exists; ignoring it (removing part {})", block_id, part->name);
|
||||||
@ -336,7 +337,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
last_block_is_duplicate = true;
|
last_block_is_duplicate = true;
|
||||||
ProfileEvents::increment(ProfileEvents::DuplicatedInsertedBlocks);
|
ProfileEvents::increment(ProfileEvents::DuplicatedInsertedBlocks);
|
||||||
}
|
}
|
||||||
else if (multi_code == Coordination::ZNODEEXISTS && failed_op_path == quorum_info.status_path)
|
else if (multi_code == Coordination::Error::ZNODEEXISTS && failed_op_path == quorum_info.status_path)
|
||||||
{
|
{
|
||||||
transaction.rollback();
|
transaction.rollback();
|
||||||
|
|
||||||
@ -347,7 +348,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
/// NOTE: We could be here if the node with the quorum existed, but was quickly removed.
|
/// NOTE: We could be here if the node with the quorum existed, but was quickly removed.
|
||||||
transaction.rollback();
|
transaction.rollback();
|
||||||
throw Exception("Unexpected logical error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
throw Exception("Unexpected logical error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
||||||
+ zkutil::ZooKeeper::error2string(multi_code) + ", path " + failed_op_path,
|
+ Coordination::errorMessage(multi_code) + ", path " + failed_op_path,
|
||||||
ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,13 +356,13 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo
|
|||||||
{
|
{
|
||||||
transaction.rollback();
|
transaction.rollback();
|
||||||
throw Exception("Unrecoverable network error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
throw Exception("Unrecoverable network error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
||||||
+ zkutil::ZooKeeper::error2string(multi_code), ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
+ Coordination::errorMessage(multi_code), ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
transaction.rollback();
|
transaction.rollback();
|
||||||
throw Exception("Unexpected ZooKeeper error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
throw Exception("Unexpected ZooKeeper error while adding block " + toString(block_number) + " with ID '" + block_id + "': "
|
||||||
+ zkutil::ZooKeeper::error2string(multi_code), ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
+ Coordination::errorMessage(multi_code), ErrorCodes::UNEXPECTED_ZOOKEEPER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quorum)
|
if (quorum)
|
||||||
|
@ -40,7 +40,7 @@ void ReplicatedMergeTreeCleanupThread::run()
|
|||||||
{
|
{
|
||||||
tryLogCurrentException(log, __PRETTY_FUNCTION__);
|
tryLogCurrentException(log, __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
if (e.code == Coordination::ZSESSIONEXPIRED)
|
if (e.code == Coordination::Error::ZSESSIONEXPIRED)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -319,15 +319,15 @@ void ReplicatedMergeTreeCleanupThread::clearOldBlocks()
|
|||||||
for (auto & pair : try_remove_futures)
|
for (auto & pair : try_remove_futures)
|
||||||
{
|
{
|
||||||
const String & path = pair.first;
|
const String & path = pair.first;
|
||||||
int32_t rc = pair.second.get().error;
|
Coordination::Error rc = pair.second.get().error;
|
||||||
if (rc == Coordination::ZNOTEMPTY)
|
if (rc == Coordination::Error::ZNOTEMPTY)
|
||||||
{
|
{
|
||||||
/// Can happen if there are leftover block nodes with children created by previous server versions.
|
/// Can happen if there are leftover block nodes with children created by previous server versions.
|
||||||
zookeeper->removeRecursive(path);
|
zookeeper->removeRecursive(path);
|
||||||
cached_block_stats.erase(first_outdated_block->node);
|
cached_block_stats.erase(first_outdated_block->node);
|
||||||
}
|
}
|
||||||
else if (rc)
|
else if (rc != Coordination::Error::ZOK)
|
||||||
LOG_WARNING(log, "Error while deleting ZooKeeper path `{}`: {}, ignoring.", path, zkutil::ZooKeeper::error2string(rc));
|
LOG_WARNING(log, "Error while deleting ZooKeeper path `{}`: {}, ignoring.", path, Coordination::errorMessage(rc));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/// Successfully removed blocks have to be removed from cache
|
/// Successfully removed blocks have to be removed from cache
|
||||||
@ -348,7 +348,7 @@ void ReplicatedMergeTreeCleanupThread::getBlocksSortedByTime(zkutil::ZooKeeper &
|
|||||||
|
|
||||||
Strings blocks;
|
Strings blocks;
|
||||||
Coordination::Stat stat;
|
Coordination::Stat stat;
|
||||||
if (zookeeper.tryGetChildren(storage.zookeeper_path + "/blocks", blocks, &stat))
|
if (Coordination::Error::ZOK != zookeeper.tryGetChildren(storage.zookeeper_path + "/blocks", blocks, &stat))
|
||||||
throw Exception(storage.zookeeper_path + "/blocks doesn't exist", ErrorCodes::NOT_FOUND_NODE);
|
throw Exception(storage.zookeeper_path + "/blocks doesn't exist", ErrorCodes::NOT_FOUND_NODE);
|
||||||
|
|
||||||
/// Seems like this code is obsolete, because we delete blocks from cache
|
/// Seems like this code is obsolete, because we delete blocks from cache
|
||||||
@ -391,7 +391,7 @@ void ReplicatedMergeTreeCleanupThread::getBlocksSortedByTime(zkutil::ZooKeeper &
|
|||||||
for (auto & elem : exists_futures)
|
for (auto & elem : exists_futures)
|
||||||
{
|
{
|
||||||
auto status = elem.second.get();
|
auto status = elem.second.get();
|
||||||
if (status.error != Coordination::ZNONODE)
|
if (status.error != Coordination::Error::ZNONODE)
|
||||||
{
|
{
|
||||||
cached_block_stats.emplace(elem.first, status.stat.ctime);
|
cached_block_stats.emplace(elem.first, status.stat.ctime);
|
||||||
timed_blocks.emplace_back(elem.first, status.stat.ctime);
|
timed_blocks.emplace_back(elem.first, status.stat.ctime);
|
||||||
|
@ -368,7 +368,7 @@ void ReplicatedMergeTreePartCheckThread::run()
|
|||||||
{
|
{
|
||||||
tryLogCurrentException(log, __PRETTY_FUNCTION__);
|
tryLogCurrentException(log, __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
if (e.code == Coordination::ZSESSIONEXPIRED)
|
if (e.code == Coordination::Error::ZSESSIONEXPIRED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
task->scheduleAfter(PART_CHECK_ERROR_SLEEP_MS);
|
task->scheduleAfter(PART_CHECK_ERROR_SLEEP_MS);
|
||||||
|
@ -319,8 +319,8 @@ void ReplicatedMergeTreeQueue::updateTimesInZooKeeper(
|
|||||||
Coordination::Responses responses;
|
Coordination::Responses responses;
|
||||||
auto code = zookeeper->tryMulti(ops, responses);
|
auto code = zookeeper->tryMulti(ops, responses);
|
||||||
|
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
LOG_ERROR(log, "Couldn't set value of nodes for insert times ({}/min_unprocessed_insert_time, max_processed_insert_time): {}", replica_path, zkutil::ZooKeeper::error2string(code) + ". This shouldn't happen often.");
|
LOG_ERROR(log, "Couldn't set value of nodes for insert times ({}/min_unprocessed_insert_time, max_processed_insert_time): {}. This shouldn't happen often.", replica_path, Coordination::errorMessage(code));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,8 +364,8 @@ void ReplicatedMergeTreeQueue::removeProcessedEntry(zkutil::ZooKeeperPtr zookeep
|
|||||||
notifySubscribers(queue_size);
|
notifySubscribers(queue_size);
|
||||||
|
|
||||||
auto code = zookeeper->tryRemove(replica_path + "/queue/" + entry->znode_name);
|
auto code = zookeeper->tryRemove(replica_path + "/queue/" + entry->znode_name);
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
LOG_ERROR(log, "Couldn't remove {}/queue/{}: {}. This shouldn't happen often.", replica_path, entry->znode_name, zkutil::ZooKeeper::error2string(code));
|
LOG_ERROR(log, "Couldn't remove {}/queue/{}: {}. This shouldn't happen often.", replica_path, entry->znode_name, Coordination::errorMessage(code));
|
||||||
|
|
||||||
updateTimesInZooKeeper(zookeeper, min_unprocessed_insert_time_changed, max_processed_insert_time_changed);
|
updateTimesInZooKeeper(zookeeper, min_unprocessed_insert_time_changed, max_processed_insert_time_changed);
|
||||||
}
|
}
|
||||||
@ -419,7 +419,7 @@ bool ReplicatedMergeTreeQueue::removeFromVirtualParts(const MergeTreePartInfo &
|
|||||||
return virtual_parts.remove(part_info);
|
return virtual_parts.remove(part_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, Coordination::WatchCallback watch_callback)
|
int32_t ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, Coordination::WatchCallback watch_callback)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(pull_logs_to_queue_mutex);
|
std::lock_guard lock(pull_logs_to_queue_mutex);
|
||||||
if (pull_log_blocker.isCancelled())
|
if (pull_log_blocker.isCancelled())
|
||||||
@ -428,6 +428,10 @@ void ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, C
|
|||||||
String index_str = zookeeper->get(replica_path + "/log_pointer");
|
String index_str = zookeeper->get(replica_path + "/log_pointer");
|
||||||
UInt64 index;
|
UInt64 index;
|
||||||
|
|
||||||
|
/// The version of "/log" is modified when new entries to merge/mutate/drop appear.
|
||||||
|
Coordination::Stat stat;
|
||||||
|
zookeeper->get(zookeeper_path + "/log", &stat);
|
||||||
|
|
||||||
Strings log_entries = zookeeper->getChildrenWatch(zookeeper_path + "/log", nullptr, watch_callback);
|
Strings log_entries = zookeeper->getChildrenWatch(zookeeper_path + "/log", nullptr, watch_callback);
|
||||||
|
|
||||||
/// We update mutations after we have loaded the list of log entries, but before we insert them
|
/// We update mutations after we have loaded the list of log entries, but before we insert them
|
||||||
@ -561,6 +565,8 @@ void ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, C
|
|||||||
if (storage.queue_task_handle)
|
if (storage.queue_task_handle)
|
||||||
storage.queue_task_handle->signalReadyToRun();
|
storage.queue_task_handle->signalReadyToRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return stat.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -720,7 +726,7 @@ ReplicatedMergeTreeMutationEntryPtr ReplicatedMergeTreeQueue::removeMutation(
|
|||||||
std::lock_guard lock(update_mutations_mutex);
|
std::lock_guard lock(update_mutations_mutex);
|
||||||
|
|
||||||
auto rc = zookeeper->tryRemove(zookeeper_path + "/mutations/" + mutation_id);
|
auto rc = zookeeper->tryRemove(zookeeper_path + "/mutations/" + mutation_id);
|
||||||
if (rc == Coordination::ZOK)
|
if (rc == Coordination::Error::ZOK)
|
||||||
LOG_DEBUG(log, "Removed mutation {} from ZooKeeper.", mutation_id);
|
LOG_DEBUG(log, "Removed mutation {} from ZooKeeper.", mutation_id);
|
||||||
|
|
||||||
ReplicatedMergeTreeMutationEntryPtr entry;
|
ReplicatedMergeTreeMutationEntryPtr entry;
|
||||||
@ -844,8 +850,8 @@ void ReplicatedMergeTreeQueue::removePartProducingOpsInRange(
|
|||||||
if ((*it)->currently_executing)
|
if ((*it)->currently_executing)
|
||||||
to_wait.push_back(*it);
|
to_wait.push_back(*it);
|
||||||
auto code = zookeeper->tryRemove(replica_path + "/queue/" + (*it)->znode_name);
|
auto code = zookeeper->tryRemove(replica_path + "/queue/" + (*it)->znode_name);
|
||||||
if (code)
|
if (code != Coordination::Error::ZOK)
|
||||||
LOG_INFO(log, "Couldn't remove {}: {}", replica_path + "/queue/" + (*it)->znode_name, zkutil::ZooKeeper::error2string(code));
|
LOG_INFO(log, "Couldn't remove {}: {}", replica_path + "/queue/" + (*it)->znode_name, Coordination::errorMessage(code));
|
||||||
|
|
||||||
updateStateOnQueueEntryRemoval(
|
updateStateOnQueueEntryRemoval(
|
||||||
*it, /* is_successful = */ false,
|
*it, /* is_successful = */ false,
|
||||||
@ -1625,15 +1631,15 @@ ReplicatedMergeTreeMergePredicate::ReplicatedMergeTreeMergePredicate(
|
|||||||
for (auto & block : block_infos)
|
for (auto & block : block_infos)
|
||||||
{
|
{
|
||||||
Coordination::GetResponse resp = block.contents_future.get();
|
Coordination::GetResponse resp = block.contents_future.get();
|
||||||
if (!resp.error && lock_holder_paths.count(resp.data))
|
if (resp.error == Coordination::Error::ZOK && lock_holder_paths.count(resp.data))
|
||||||
committing_blocks[block.partition].insert(block.number);
|
committing_blocks[block.partition].insert(block.number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_.pullLogsToQueue(zookeeper);
|
merges_version = queue_.pullLogsToQueue(zookeeper);
|
||||||
|
|
||||||
Coordination::GetResponse quorum_status_response = quorum_status_future.get();
|
Coordination::GetResponse quorum_status_response = quorum_status_future.get();
|
||||||
if (!quorum_status_response.error)
|
if (quorum_status_response.error == Coordination::Error::ZOK)
|
||||||
{
|
{
|
||||||
ReplicatedMergeTreeQuorumEntry quorum_status;
|
ReplicatedMergeTreeQuorumEntry quorum_status;
|
||||||
quorum_status.fromString(quorum_status_response.data);
|
quorum_status.fromString(quorum_status_response.data);
|
||||||
|
@ -271,8 +271,9 @@ public:
|
|||||||
* If watch_callback is not empty, will call it when new entries appear in the log.
|
* If watch_callback is not empty, will call it when new entries appear in the log.
|
||||||
* If there were new entries, notifies storage.queue_task_handle.
|
* If there were new entries, notifies storage.queue_task_handle.
|
||||||
* Additionally loads mutations (so that the set of mutations is always more recent than the queue).
|
* Additionally loads mutations (so that the set of mutations is always more recent than the queue).
|
||||||
|
* Return the version of "logs" node (that is updated for every merge/mutation/... added to the log)
|
||||||
*/
|
*/
|
||||||
void pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, Coordination::WatchCallback watch_callback = {});
|
int32_t pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, Coordination::WatchCallback watch_callback = {});
|
||||||
|
|
||||||
/// Load new mutation entries. If something new is loaded, schedule storage.merge_selecting_task.
|
/// Load new mutation entries. If something new is loaded, schedule storage.merge_selecting_task.
|
||||||
/// If watch_callback is not empty, will call it when new mutations appear in ZK.
|
/// If watch_callback is not empty, will call it when new mutations appear in ZK.
|
||||||
@ -434,6 +435,9 @@ public:
|
|||||||
|
|
||||||
bool isMutationFinished(const ReplicatedMergeTreeMutationEntry & mutation) const;
|
bool isMutationFinished(const ReplicatedMergeTreeMutationEntry & mutation) const;
|
||||||
|
|
||||||
|
/// The version of "log" node that is used to check that no new merges have appeared.
|
||||||
|
int32_t getVersion() const { return merges_version; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ReplicatedMergeTreeQueue & queue;
|
const ReplicatedMergeTreeQueue & queue;
|
||||||
|
|
||||||
@ -445,6 +449,8 @@ private:
|
|||||||
|
|
||||||
/// Quorum state taken at some later time than prev_virtual_parts.
|
/// Quorum state taken at some later time than prev_virtual_parts.
|
||||||
String inprogress_quorum_part;
|
String inprogress_quorum_part;
|
||||||
|
|
||||||
|
int32_t merges_version = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ void ReplicatedMergeTreeRestartingThread::removeFailedQuorumParts()
|
|||||||
auto zookeeper = storage.getZooKeeper();
|
auto zookeeper = storage.getZooKeeper();
|
||||||
|
|
||||||
Strings failed_parts;
|
Strings failed_parts;
|
||||||
if (zookeeper->tryGetChildren(storage.zookeeper_path + "/quorum/failed_parts", failed_parts) != Coordination::ZOK)
|
if (zookeeper->tryGetChildren(storage.zookeeper_path + "/quorum/failed_parts", failed_parts) != Coordination::Error::ZOK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/// Firstly, remove parts from ZooKeeper
|
/// Firstly, remove parts from ZooKeeper
|
||||||
@ -294,12 +294,12 @@ void ReplicatedMergeTreeRestartingThread::activateReplica()
|
|||||||
{
|
{
|
||||||
auto code = zookeeper->tryRemove(is_active_path, stat.version);
|
auto code = zookeeper->tryRemove(is_active_path, stat.version);
|
||||||
|
|
||||||
if (code == Coordination::ZBADVERSION)
|
if (code == Coordination::Error::ZBADVERSION)
|
||||||
throw Exception("Another instance of replica " + storage.replica_path + " was created just now."
|
throw Exception("Another instance of replica " + storage.replica_path + " was created just now."
|
||||||
" You shouldn't run multiple instances of same replica. You need to check configuration files.",
|
" You shouldn't run multiple instances of same replica. You need to check configuration files.",
|
||||||
ErrorCodes::REPLICA_IS_ALREADY_ACTIVE);
|
ErrorCodes::REPLICA_IS_ALREADY_ACTIVE);
|
||||||
|
|
||||||
if (code && code != Coordination::ZNONODE)
|
if (code != Coordination::Error::ZOK && code != Coordination::Error::ZNONODE)
|
||||||
throw Coordination::Exception(code, is_active_path);
|
throw Coordination::Exception(code, is_active_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ void ReplicatedMergeTreeRestartingThread::activateReplica()
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNODEEXISTS)
|
if (e.code == Coordination::Error::ZNODEEXISTS)
|
||||||
throw Exception("Replica " + storage.replica_path + " appears to be already active. If you're sure it's not, "
|
throw Exception("Replica " + storage.replica_path + " appears to be already active. If you're sure it's not, "
|
||||||
"try again in a minute or remove znode " + storage.replica_path + "/is_active manually", ErrorCodes::REPLICA_IS_ALREADY_ACTIVE);
|
"try again in a minute or remove znode " + storage.replica_path + "/is_active manually", ErrorCodes::REPLICA_IS_ALREADY_ACTIVE);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -291,9 +291,10 @@ private:
|
|||||||
template <class Func>
|
template <class Func>
|
||||||
void foreachCommittedParts(const Func & func) const;
|
void foreachCommittedParts(const Func & func) const;
|
||||||
|
|
||||||
/** Creates the minimum set of nodes in ZooKeeper.
|
/** Creates the minimum set of nodes in ZooKeeper and create first replica.
|
||||||
|
* Returns true if was created, false if exists.
|
||||||
*/
|
*/
|
||||||
void createTableIfNotExists();
|
bool createTableIfNotExists();
|
||||||
|
|
||||||
/** Creates a replica in ZooKeeper and adds to the queue all that it takes to catch up with the rest of the replicas.
|
/** Creates a replica in ZooKeeper and adds to the queue all that it takes to catch up with the rest of the replicas.
|
||||||
*/
|
*/
|
||||||
@ -424,16 +425,23 @@ private:
|
|||||||
* Call when merge_selecting_mutex is locked.
|
* Call when merge_selecting_mutex is locked.
|
||||||
* Returns false if any part is not in ZK.
|
* Returns false if any part is not in ZK.
|
||||||
*/
|
*/
|
||||||
bool createLogEntryToMergeParts(
|
enum class CreateMergeEntryResult { Ok, MissingPart, LogUpdated, Other };
|
||||||
|
|
||||||
|
CreateMergeEntryResult createLogEntryToMergeParts(
|
||||||
zkutil::ZooKeeperPtr & zookeeper,
|
zkutil::ZooKeeperPtr & zookeeper,
|
||||||
const DataPartsVector & parts,
|
const DataPartsVector & parts,
|
||||||
const String & merged_name,
|
const String & merged_name,
|
||||||
const MergeTreeDataPartType & merged_part_type,
|
const MergeTreeDataPartType & merged_part_type,
|
||||||
bool deduplicate,
|
bool deduplicate,
|
||||||
bool force_ttl,
|
bool force_ttl,
|
||||||
ReplicatedMergeTreeLogEntryData * out_log_entry = nullptr);
|
ReplicatedMergeTreeLogEntryData * out_log_entry,
|
||||||
|
int32_t log_version);
|
||||||
|
|
||||||
bool createLogEntryToMutatePart(const IMergeTreeDataPart & part, Int64 mutation_version, int alter_version);
|
CreateMergeEntryResult createLogEntryToMutatePart(
|
||||||
|
const IMergeTreeDataPart & part,
|
||||||
|
Int64 mutation_version,
|
||||||
|
int32_t alter_version,
|
||||||
|
int32_t log_version);
|
||||||
|
|
||||||
/// Exchange parts.
|
/// Exchange parts.
|
||||||
|
|
||||||
|
@ -112,8 +112,13 @@ void StorageSystemZooKeeper::fillData(MutableColumns & res_columns, const Contex
|
|||||||
|
|
||||||
zkutil::ZooKeeperPtr zookeeper = context.getZooKeeper();
|
zkutil::ZooKeeperPtr zookeeper = context.getZooKeeper();
|
||||||
|
|
||||||
|
String path_corrected;
|
||||||
|
/// path should starts with '/', otherwise ZBADARGUMENTS will be thrown in
|
||||||
|
/// ZooKeeper::sendThread and the session will fail.
|
||||||
|
if (path[0] != '/')
|
||||||
|
path_corrected = '/';
|
||||||
|
path_corrected += path;
|
||||||
/// In all cases except the root, path must not end with a slash.
|
/// In all cases except the root, path must not end with a slash.
|
||||||
String path_corrected = path;
|
|
||||||
if (path_corrected != "/" && path_corrected.back() == '/')
|
if (path_corrected != "/" && path_corrected.back() == '/')
|
||||||
path_corrected.resize(path_corrected.size() - 1);
|
path_corrected.resize(path_corrected.size() - 1);
|
||||||
|
|
||||||
@ -131,7 +136,7 @@ void StorageSystemZooKeeper::fillData(MutableColumns & res_columns, const Contex
|
|||||||
for (size_t i = 0, size = nodes.size(); i < size; ++i)
|
for (size_t i = 0, size = nodes.size(); i < size; ++i)
|
||||||
{
|
{
|
||||||
auto res = futures[i].get();
|
auto res = futures[i].get();
|
||||||
if (res.error == Coordination::ZNONODE)
|
if (res.error == Coordination::Error::ZNONODE)
|
||||||
continue; /// Node was deleted meanwhile.
|
continue; /// Node was deleted meanwhile.
|
||||||
|
|
||||||
const Coordination::Stat & stat = res.stat;
|
const Coordination::Stat & stat = res.stat;
|
||||||
|
@ -86,7 +86,7 @@ try
|
|||||||
for (BlockInfo & block : block_infos)
|
for (BlockInfo & block : block_infos)
|
||||||
{
|
{
|
||||||
Coordination::GetResponse resp = block.contents_future.get();
|
Coordination::GetResponse resp = block.contents_future.get();
|
||||||
if (!resp.error && lock_holder_paths.count(resp.data))
|
if (resp.error == Coordination::Error::ZOK && lock_holder_paths.count(resp.data))
|
||||||
{
|
{
|
||||||
++total_count;
|
++total_count;
|
||||||
current_inserts[block.partition].insert(block.number);
|
current_inserts[block.partition].insert(block.number);
|
||||||
|
@ -76,7 +76,7 @@ try
|
|||||||
}
|
}
|
||||||
catch (const Coordination::Exception & e)
|
catch (const Coordination::Exception & e)
|
||||||
{
|
{
|
||||||
if (e.code == Coordination::ZNONODE)
|
if (e.code == Coordination::Error::ZNONODE)
|
||||||
continue;
|
continue;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
# pylint: disable=line-too-long
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
# pylint: disable=redefined-outer-name
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from helpers.cluster import ClickHouseCluster
|
|
||||||
|
|
||||||
cluster = ClickHouseCluster(__file__)
|
|
||||||
node = cluster.add_instance('node_default')
|
|
||||||
|
|
||||||
system_logs = [
|
|
||||||
# disabled by default
|
|
||||||
('system.part_log', 0),
|
|
||||||
('system.text_log', 0),
|
|
||||||
|
|
||||||
# enabled by default
|
|
||||||
('system.query_log', 1),
|
|
||||||
('system.query_thread_log', 1),
|
|
||||||
('system.trace_log', 1),
|
|
||||||
('system.metric_log', 1),
|
|
||||||
]
|
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
|
||||||
def start_cluster():
|
|
||||||
try:
|
|
||||||
cluster.start()
|
|
||||||
node.query('SYSTEM FLUSH LOGS')
|
|
||||||
yield cluster
|
|
||||||
finally:
|
|
||||||
cluster.shutdown()
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('table,exists', system_logs)
|
|
||||||
def test_system_logs(start_cluster, table, exists):
|
|
||||||
q = 'SELECT * FROM {}'.format(table)
|
|
||||||
if exists:
|
|
||||||
node.query(q)
|
|
||||||
else:
|
|
||||||
assert "Table {} doesn't exist".format(table) in node.query_and_get_error(q)
|
|
@ -55,9 +55,13 @@ def test_replica_always_download(started_cluster):
|
|||||||
|
|
||||||
node1.query("SYSTEM START MERGES")
|
node1.query("SYSTEM START MERGES")
|
||||||
|
|
||||||
time.sleep(3)
|
for i in range(30):
|
||||||
|
node1_parts = node1.query("SELECT COUNT() FROM system.parts WHERE table = 'test_table' and active=1").strip()
|
||||||
node1_parts = node1.query("SELECT COUNT() FROM system.parts WHERE table = 'test_table' and active=1").strip()
|
node2_parts = node2.query("SELECT COUNT() FROM system.parts WHERE table = 'test_table' and active=1").strip()
|
||||||
node2_parts = node2.query("SELECT COUNT() FROM system.parts WHERE table = 'test_table' and active=1").strip()
|
if int(node1_parts) < 10 and int(node2_parts) < 10:
|
||||||
assert int(node1_parts) < 10 # something merged
|
break
|
||||||
assert int(node2_parts) < 10
|
else:
|
||||||
|
time.sleep(0.5)
|
||||||
|
else:
|
||||||
|
assert int(node1_parts) < 10
|
||||||
|
assert int(node2_parts) < 10
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user