From dc49f93b9907ed0df00303f2d376da97c6630541 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Mon, 26 Jun 2017 10:14:13 +0300 Subject: [PATCH 001/281] New part "Server configuration parameters" of the document is added. Other changes are made related to this new part. --- docs/ru/dicts/external_dicts.rst | 13 +- docs/ru/operations/configuration_files.rst | 2 +- docs/ru/operations/server_settings/index.rst | 17 + .../operations/server_settings/settings.rst | 804 ++++++++++++++++++ docs/ru/operations/settings/index.rst | 2 + docs/ru/operations/settings/settings.rst | 16 + docs/ru/query_language/queries.rst | 2 + .../system.asynchronous_metrics.rst | 2 + docs/ru/system_tables/system.events.rst | 2 + docs/ru/system_tables/system.metrics.rst | 2 + docs/ru/table_engines/distributed.rst | 2 + docs/ru/table_engines/graphitemergetree.rst | 30 +- docs/ru/table_engines/replication.rst | 2 + docs/ru/table_engines/resharding.rst | 2 + 14 files changed, 875 insertions(+), 23 deletions(-) create mode 100644 docs/ru/operations/server_settings/index.rst create mode 100644 docs/ru/operations/server_settings/settings.rst diff --git a/docs/ru/dicts/external_dicts.rst b/docs/ru/dicts/external_dicts.rst index f8dc1a5fcb6..4001eeff87f 100644 --- a/docs/ru/dicts/external_dicts.rst +++ b/docs/ru/dicts/external_dicts.rst @@ -1,3 +1,5 @@ +.. _dicts-external_dicts: + Внешние словари =============== @@ -5,12 +7,12 @@ Источником данных для словаря может быть файл на локальной файловой системе, сервер ClickHouse, сервер MySQL, MongoDB или любой ODBC источник. Словарь может полностью храниться в оперативке и периодически обновляться, или быть частично закэшированным в оперативке и динамически подгружать отсутствующие значения. -Конфигурация внешних словарей находится в отдельном файле или файлах, указанных в конфигурационном параметре dictionaries_config. -Этот параметр содержит абсолютный или относительный путь к файлу с конфигурацией словарей. Относительный путь - относительно директории с конфигурационным файлом сервера. Путь может содержать wildcard-ы \* и ? - тогда рассматриваются все подходящие файлы. Пример: dictionaries/\*.xml. +Конфигурация внешних словарей находится в отдельном файле или файлах, указанных в конфигурационном параметре :ref:`dictionaries_config `. +Этот параметр содержит абсолютный или относительный путь к файлу с конфигурацией словарей. Относительный путь - относительно директории с конфигурационным файлом сервера. Путь может содержать wildcard-ы \* и ? - тогда рассматриваются все подходящие файлы. Пример: ``dictionaries/*.xml``. Конфигурация словарей, а также множество файлов с конфигурацией, может обновляться без перезапуска сервера. Сервер проверяет обновления каждые 5 секунд. То есть, словари могут подключаться динамически. -Создание словарей может производиться при старте сервера или при первом использовании. Это определяется конфигурационном параметром dictionaries_lazy_load (в основном конфигурационном файле сервера). Параметр не обязателен, по умолчанию - true. Если true, то каждый словарь создаётся при первом использовании; если словарь не удалось создать - вызов функции, использующей словарь, кидает исключение. Если false, то все словари создаются при старте сервера, и в случае ошибки, сервер завершает работу. +Создание словарей может производиться при старте сервера или при первом использовании. Это определяется конфигурационном параметром :ref:`dictionaries_lazy_load ` (в основном конфигурационном файле сервера). Параметр не обязателен, по умолчанию - ``true``. Если true, то каждый словарь создаётся при первом использовании; если словарь не удалось создать - вызов функции, использующей словарь, кидает исключение. Если ``false``, то все словари создаются при старте сервера, и в случае ошибки, сервер завершает работу. Конфигурационный файл словарей имеет вид: @@ -170,7 +172,7 @@ Существует шесть способов размещения словаря в памяти. flat ----- +----- В виде плоских массивов. Самый эффективный способ. Он подходит, если все ключи меньше 500 000. Если при создании словаря обнаружен ключ больше, то кидается исключение и словарь не создаётся. Словарь загружается в оперативку целиком. Словарь использует количество оперативки, пропорциональное максимальному значению ключа. Ввиду ограничения на 500 000, потребление оперативки вряд ли может быть большим. Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. @@ -189,9 +191,6 @@ range_hashed Пример: таблица содержит скидки для каждого рекламодателя в виде: -.. code-block:: text - -.. code-block:: text +------------------+-----------------------------+------------+----------+ | id рекламодателя | дата начала действия скидки | дата конца | величина | diff --git a/docs/ru/operations/configuration_files.rst b/docs/ru/operations/configuration_files.rst index efe396a89fa..2ef120f7e19 100644 --- a/docs/ru/operations/configuration_files.rst +++ b/docs/ru/operations/configuration_files.rst @@ -15,7 +15,7 @@ Если указано ``remove`` - удалить элемент. -Также в конфиге могут быть указаны "подстановки". Если у элемента присутствует атрибут ``incl``, то в качестве значения будет использована соответствующая подстановка из файла. По умолчанию, путь к файлу с подстановками - ``/etc/metrika.xml``. Он может быть изменён в конфиге в элементе ``include_from``. Значения подстановок указываются в элементах ``/yandex/имя_подстановки`` этого файла. +Также в конфиге могут быть указаны "подстановки". Если у элемента присутствует атрибут ``incl``, то в качестве значения будет использована соответствующая подстановка из файла. По умолчанию, путь к файлу с подстановками - ``/etc/metrika.xml``. Он может быть изменён в конфигурации сервера в элементе :ref:`server_settings-include_from`. Значения подстановок указываются в элементах ``/yandex/имя_подстановки`` этого файла. Если подстановка, заданная в ``incl`` отсутствует, то в лог попадает соответствующая запись. Чтобы ClickHouse не писал в лог об отсутствии подстановки, необходимо указать атрибут ``optional="true"`` (например, настройка :ref:`server_settings-macros`). Подстановки могут также выполняться из ZooKeeper. Для этого укажите у элемента атрибут ``from_zk="/path/to/node"``. Значение элемента заменится на содержимое узла ``/path/to/node`` в ZooKeeper. В ZooKeeper-узел также можно положить целое XML-поддерево, оно будет целиком вставлено в исходный элемент. diff --git a/docs/ru/operations/server_settings/index.rst b/docs/ru/operations/server_settings/index.rst new file mode 100644 index 00000000000..490af776729 --- /dev/null +++ b/docs/ru/operations/server_settings/index.rst @@ -0,0 +1,17 @@ +.. _server_settings: + +Конфигурационные параметры сервера +================================== + +Раздел содержит описания настроек сервера, которые не могут изменяться на уровне сессии или запроса. + +Рассмотренные настройки хранятся в файле ``config.xml`` сервера ClickHouse. + +Прочие настройки описаны в разделе :ref:`settings`. + +Перед изучением настроек ознакомьтесь с разделом :ref:`configuration_files`, обратите внимание на использование подстановок (атрибуты ``incl`` и ``optional``). + +.. toctree:: + :glob: + + * diff --git a/docs/ru/operations/server_settings/settings.rst b/docs/ru/operations/server_settings/settings.rst new file mode 100644 index 00000000000..c99054a18fa --- /dev/null +++ b/docs/ru/operations/server_settings/settings.rst @@ -0,0 +1,804 @@ +.. _server_settings-builtin_dictionaries_reload_interval: + +builtin_dictionaries_reload_interval +------------------------------------ +Интервал (в секундах) перезагрузки встроенных словарей. + +ClickHouse перезагружает встроенные словари с заданным интервалом. Это позволяет править словари "на лету" без перезапуска сервера. + +Значение по умолчанию - 3600. + +**Пример** + +.. code-block:: xml + + 3600 + +.. _server_settings-compression: + +compression +----------- +Настройки компрессии данных. + +.. warning:: Не используйте, если вы только начали работать с ClickHouse. + +Общий вид конфигурации: + +.. code-block:: xml + + + + + + ... + + + +Можно сконфигурировать несколько разделов ````. + +Поля блока ````: + ++---------------------+--------------------------------------------------------------------------+ +| Параметр | Описание | ++=====================+==========================================================================+ +| min_part_size | Минимальный размер части таблицы. | ++---------------------+--------------------------------------------------------------------------+ +| min_part_size_ratio | Отношение размера минимальной части таблицы к полному размеру таблицы. | ++---------------------+--------------------------------------------------------------------------+ +| method | Метод сжатия. Возможные значения: ``lz4``, ``zstd`` (экспериментальный). | ++---------------------+--------------------------------------------------------------------------+ + +ClickHouse проверит условия ``min_part_size`` и ``min_part_size_ratio`` и выполнит те блоки ``case``, для которых условия совпали. Если ни один ```` не подходит, то ClickHouse применит алгоритм сжатия ``lz4``. + +**Пример** + +.. code-block:: xml + + + + 10000000000 + 0.01 + zstd + + + + +.. _server_settings-default_database: + +default_database +---------------- +База данных по умолчанию. + +Перечень баз данных можно получить запросом :ref:`query_language_queries_show_databases`. + +**Пример** + +.. code-block:: xml + + default + + + +.. _server_settings-default_profile: + +default_profile +--------------- +Профиль настроек по умолчанию. + +Профили настроек находятся в файле, указанном в параметре :ref:`server_settings-users_config`. + +**Пример** + +.. code-block:: xml + + default + + +.. _server_settings-dictionaries_config: + +dictionaries_config +------------------- +Конфигурация внешних словарей. + +Смотрите раздел :ref:`dicts-external_dicts`. + +**Пример** + +.. code-block:: xml + + *_dictionary.xml + + +.. _server_settings-dictionaries_lazy_load: + +dictionaries_lazy_load +---------------------- + +Отложенная загрузка словарей. + +С установленным параметром словари подгружаются не при запуске сервера, а при первом обращении. + +**Пример** + +.. code-block:: xml + + true + + +.. _server_settings-graphite: + +graphite +-------- +Отправка даных в `Graphite `_. + +Настройки: + ++----------------------+------------------------------------------------------------------------------+ +| Настройка | Описание | ++======================+==============================================================================+ +| host | Сервер Graphite. | ++----------------------+------------------------------------------------------------------------------+ +| port | Порт сервера Graphite. | ++----------------------+------------------------------------------------------------------------------+ +| interval | Период отправки в секундах. | ++----------------------+------------------------------------------------------------------------------+ +| timeout | Таймаут отправки данных в секундах. | ++----------------------+------------------------------------------------------------------------------+ +| root_path | Префикс для ключей. | ++----------------------+------------------------------------------------------------------------------+ +| metrics | Отправка данных из таблицы :ref:`system_tables-system.metrics`. | ++----------------------+------------------------------------------------------------------------------+ +| events | Отправка данных из таблицы :ref:`system_tables-system.events`. | ++----------------------+------------------------------------------------------------------------------+ +| asynchronous_metrics | Отправка данных из таблицы :ref:`system_tables-system.asynchronous_metrics`. | ++----------------------+------------------------------------------------------------------------------+ + + +Можно определить несколько секций ````, например, для передачи различных данных с различной частотой. + +**Пример** + +.. code-block:: xml + + + localhost + 42000 + 0.1 + 60 + one_min + true + true + true + + + +.. _server_settings-graphite_rollup: + +graphite_rollup +--------------- + +Настройка прореживания данных для Graphite. + +Подробнее читайте в разделе :ref:`table_engines-graphitemergetree`. + +**Пример** + +.. code-block:: xml + + + + max + + 0 + 60 + + + 3600 + 300 + + + 86400 + 3600 + + + + + +.. _server_settings-http_port: + +http_port/https_port +-------------------- +Порт для обращений к серверу по протоколу HTTP(s). + +Если указан ``https_port``, то требуется конфигурирование :ref:`server_settings-openSSL`. + +Если указан ``http_port``, то настройка :ref:`server_settings-openSSL` игнорируется, даже если она задана. + +**Пример** + +.. code-block:: xml + + 0000 + + +.. _server_settings-http_server_default_response: + +http_server_default_response +---------------------------- +Страница, показываемая по умолчанию, при обращении к HTTP(s) серверу ClickHouse. + +**Пример** + +Показывает ``https://tabix.io/`` при обращенинии к ``http://localhost:http_port``. + +.. code-block:: xml + + +
]]> +
+ +.. _server_settings-include_from: + +include_from +------------ +Путь к файлу с подстановками. + +Подробности смотрите в разделе :ref:`configuration_files`. + +**Пример** + +.. code-block:: xml + + /etc/metrica.xml + + +.. _server_settings-interserver_http_port: + +interserver_http_port +--------------------- + +Порт для обмена между серверами ClickHouse. + +**Пример** + +.. code-block:: xml + + 9009 + + +.. _server_settings-interserver_http_host: + +interserver_http_host +--------------------- + +Имя хоста, которое могут использовать другие серверы для обращения к этому. + +Если не указано, то определяется аналогично команде ``hostname -f``. + +Удобно использовать, чтобы отвязаться от конкретного сетевого интерфейса. + + +**Пример** + +.. code-block:: xml + + example.yandex.ru + + +.. _server_settings-keep_alive_timeout: + +keep_alive_timeout +------------------ + +Время в миллисекундах, в течение которого ClickHouse ожидает входящих запросов прежде, чем закрыть соединение. + +**Пример** + +.. code-block:: xml + + 3 + + +.. _server_settings-listen_host: + +listen_host +----------- + +Ограничение по хостам, с которых может прийти запрос. Если необходимо, чтобы сервер отвечал всем, то надо указать ``::``. + +Примеры: + +.. code-block:: xml + + ::1 + 127.0.0.1 + + +.. _server_settings-logger: + +logger +------ +Настройки логгирования. + +Ключи: + ++----------+-----------------------------------------------------------------------------------------------------------+ +| Ключ | Описание | ++==========+===========================================================================================================+ +| level | Уровень логгирования. Допустимые значения: ``trace``, ``debug``, ``information``, ``warning``, ``error``. | ++----------+-----------------------------------------------------------------------------------------------------------+ +| log | Файл лога. Содержит все записи согласно ``level``. | ++----------+-----------------------------------------------------------------------------------------------------------+ +| errorlog | Файл лога ошибок. | ++----------+-----------------------------------------------------------------------------------------------------------+ +| size | Размер файла. Действует для ``log`` и ``errorlog``. Как только файл достиг размера ``size``, | +| | ClickHouse архивирует и переименовывает его, а на его месте создает новый файл лога. | ++----------+-----------------------------------------------------------------------------------------------------------+ +| count | Количество заархивированных файлов логов, которые сохраняет ClickHouse. | ++----------+-----------------------------------------------------------------------------------------------------------+ + + +**Пример** + +.. code-block:: xml + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 1000M + 10 + + +.. _server_settings-macros: + +macros +------ +Подстановки параметров реплицируемых таблиц. + +Можно не указывать, если реплицируемых таблицы не используются. + +Подробнее смотрите в разделе :ref:`table_engines-replication-creation_of_rep_tables`. + +**Пример** + +.. code-block:: xml + + + + +.. _server_settings-mark_cache_size: + +mark_cache_size +--------------- +Приблизительный размер (в байтах) кеша "засечек", используемых движками таблиц семейства :ref:`table_engines-mergetree`. + +Кеш общий для сервера, память выделяется по мере необходимости. Кеш не может быть меньше, чем 5368709120. + +**Пример** + +.. code-block:: xml + + 5368709120 + + +.. _server_settings-max_concurrent_queries: + +max_concurrent_queries +---------------------- + +Максимальное количество одновременно обрабатываемых запросов. + +**Пример** + +.. code-block:: xml + + 100 + + +.. _server_settings-max_connections: + +max_connections +--------------- + +Максимальное количество входящих соединений. + +**Пример** + +.. code-block:: xml + + 4096 + +.. _server_settings-max_open_files: + +max_open_files +-------------- + +Максимальное количество открытых файлов. + +По умолчанию - ``maximum``. + +Рекомендуется использовать в Mac OS X, поскольу функция ``getrlimit()`` возвращает некорректное значение. + +**Пример** + +.. code-block:: xml + + 262144 + + +.. _server_settings-max_table_size_to_drop: + +max_table_size_to_drop +---------------------- + +Ограничение на удаление таблиц. + +Если размер таблицы семейства :ref:`table_engines-mergetree` превышает ``max_table_size_to_drop`` (в байтах), то ее нельзя удалить запросом DROP. + +Если таблицу все же необходимо удалить, не перезапуская при этом сервер ClickHouse, то необходимо создать файл ``/flags/force_drop_table`` и выполнить запрос DROP. + +Значение по умолчанию - 50GB. + +Значение 0 означает, что можно удалять все таблицы без ограничений. + +**Пример** + +.. code-block:: xml + + 0 + + +.. _server_settings-merge_tree: + +merge_tree +---------- +Тонкая настройка таблиц семейства :ref:`table_engines-mergetree`. + +Подробнее смотрите в заголовочном файле MergeTreeSettings.h. + +**Пример** + +.. code-block:: xml + + + 5 + + + + +.. _server_settings-openSSL: + +openSSL +------- + +Настройки клиента/сервера SSL. + +Поддержку SSL обеспечивает библиотека ``libpoco``. Описание интерфейса находится в файле `SSLManager.h `_ + +Ключи настроек сервера/клиента: + ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| Ключ | Описание | ++=============================+==========================================================================================================================+ +| privateKeyFile | Путь к файлу с секретным ключем сертификата в формате PEM. Файл может содержать ключ и сертификат одновременно. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| certificateFile | Путь к файлу сертификата клиента/сервера в формате PEM. Можно не указывать, если ``privateKeyFile`` содержит сертификат. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| caConfig | Путь к файлу или каталогу, которые содержат доверенные корневые сертификаты. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| verificationMode | Способ проверки сертификатов узла. Подробности находятся в описании класса | +| | `Context `_. | +| | Допустимые значения: ``none``, ``relaxed``, ``strict``, ``once``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| verificationDepth | Максимальная длина верификационой цепи. | +| | Верификация завершится ошибкой, если длина цепи сертификатов превысит установленное значение. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| loadDefaultCAFile | Признак того, что будут использоваться встроенные CA-сертификаты для OpenSSL. Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| cipherList | Поддерживаемые OpenSSL-шифры. Например, ``ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| cacheSessions | Включение/выключение кеширования сессии. | +| | Использовать обязательно вместе с ``sessionIdContext``. Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| sessionIdContext | Уникальный набор произвольных символов, которые сервер добавляет к каждому сгенерированному идентификатору. | +| | Длина строки не должна превышать ``SSL_MAX_SSL_SESSION_ID_LENGTH``. Рекомендуется к использованию всегда, | +| | поскольку позволяет избежать проблем как в случае, если сервер кеширует сессию, | +| | так и если клиент затребовал кеширование. По умолчанию ``${application.name}``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| sessionCacheSize | Максимальное количество сессий, которые кэширует сервер. | +| | По умолчанию - 1024\*20. 0 - неограниченное количество сессий. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| sessionTimeout | Время кеширования сессии на севрере. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| extendedVerification | Автоматическая расширенная проверка сертификатов после завершении сессии. | +| | Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| requireTLSv1 | Требование соединения TLSv1. Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| requireTLSv1_1 | Требование соединения TLSv1.1. Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| requireTLSv1_2 | Требование соединения TLSv1.2. Допустимые значения: ``true``, ``false``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| fips | Активация режима OpenSSL FIPS. Поддерживается, если версия OpenSSL, с которой собрана библиотека поддерживает fips. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| privateKeyPassphraseHandler | Класс (подкласс PrivateKeyPassphraseHandler)запрашивающий кодовую фразу доступа к | +| | секретному ключу. Например, ```` ``KeyFileHandler`` | +| | ``test`` ````. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| invalidCertificateHandler | Класс (подкласс CertificateHandler) для подтвеждения невалидных сертификатов. | +| | Например, `` ConsoleCertificateHandler ``. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| disableProtocols | Запрещенные к искользованию протоколы. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ +| preferServerCiphers | Предпочтение серверных шифров на клиенте. | ++-----------------------------+--------------------------------------------------------------------------------------------------------------------------+ + + + +**Пример настройки:** + +.. code-block:: xml + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + /etc/clickhouse-server/dhparam.pem + none + true + true + sslv2,sslv3 + true + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + +.. _server_settings-part_log: + +part_log +-------- + +Логгирование событий, связанных с данными типа :ref:`table_engines-mergetree`. Например, события добавления или мержа данных. Лог можно использовать для симуляции алгоритмов слияния, чтобы сравнивать их характеристики. Также, можно визуализировать процесс слияния. + +Запросы логгируются не в отдельный файл, а в таблицу ClickHouse. + +Столбцы лога: + ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| Столбец | Описание | ++===============+=======================================================================================================================+ +| event_time | Дата события. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| duration_ms | Время события. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| event_type | Тип события. 1 - кусок новый, 2 - результат мержа, 3 - кусок скачан с реплики, 4 - кусок удаляется. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| database_name | Имя базы даных. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| table_name | Имя таблицы. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| part_name | Имя куска данных. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| size_in_bytes | Размер куска данных в байтах. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| merged_from | Массив имён кусков, из которых он образован при мерже (так же заполняется в случае скачивания уже смерженного куска). | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ +| merge_time_ms | Время, потраченное на мерж. | ++---------------+-----------------------------------------------------------------------------------------------------------------------+ + +При настройке логгирования используются следующие параметры: + ++-----------------------------+-----------------------------------------------------+ +| Параметр | Описание | ++=============================+=====================================================+ +| database | Имя базы данных. | ++-----------------------------+-----------------------------------------------------+ +| table | Имя таблицы. | ++-----------------------------+-----------------------------------------------------+ +| flush_interval_milliseconds | Период сброса данных из оперативной памяти на диск. | ++-----------------------------+-----------------------------------------------------+ + + +**Пример** + +.. code-block:: xml + + + system + part_log
+ 7500 +
+ + +.. _server_settings-path: + +path +---- +Путь к каталогу с данными. + +.. warning:: Завершающий слеш обязателен. + +**Пример** + +.. code-block:: xml + + /var/lib/clickhouse/ + +.. _server_settings-query_log: + +query_log +--------- + +Настройка логгирования запросов, принятых с настройкой :ref:`log_queries=1 `. + +Запросы логгируются не в отдельный файл, а в таблицу ClickHouse. + +При настройке логгирования используются следующие параметры: + ++-----------------------------+-----------------------------------------------------+ +| Параметр | Описание | ++=============================+=====================================================+ +| database | Имя базы данных. | ++-----------------------------+-----------------------------------------------------+ +| table | Имя таблицы. | ++-----------------------------+-----------------------------------------------------+ +| flush_interval_milliseconds | Период сброса данных из оперативной памяти на диск. | ++-----------------------------+-----------------------------------------------------+ + +Если таблица не существует, то ClickHouse создаст её. Если структура журнала запросов изменилась при обновлении сервера ClickHouse, то таблица со старой структурой переименовывается, а новая таблица создается автоматически. + +**Пример** + +.. code-block:: xml + + + system + query_log
+ 7500 +
+ + +.. _server_settings-remote_servers: + +remote_servers +-------------- +Конфигурация кластеров, которые использует движок таблиц Distributed. + +Пример настройки смотрите в разделе :ref:`Движки таблиц/Distributed `. + +**Пример** + +.. code-block:: xml + + + +Значение атрибута ``incl`` смотрите в разделе :ref:`configuration_files`. + +.. _server_settings-resharding: + +resharding +---------- + +Путь в ZooKeeper к очереди задач. + +Подробнее читайте в разделе :ref:`table_engines-resharding`. + +**Пример** + +.. code-block:: xml + + + /clickhouse/task_queue + + + +.. _server_settings-timezone: + +timezone +-------- +Временная зона сервера. + +Указывается идентификатором IANA в виде часового пояса UTC или географического положения (например, Africa/Abidjan). + +Временная зона необходима при преобразованиях между форматами String и DateTime, которые возникают при выводе полей DateTime в текстовый формат (на экран или в файл) и при получении DateTime из строки. Также, временная зона используется в функциях, которые работают со временем и датой, если они не получили временную зону в параметрах вызова. + +**Пример** + +.. code-block:: xml + + Europe/Moscow + + +.. _server_settings-tcp_port: + +tcp_port +-------- + +Порт для взаимодействия с клиентами по протоколу TCP. + +**Пример** + +.. code-block:: xml + + 9000 + + +.. _server_settings-tmp_path: + +tmp_path +-------- +Путь ко временным данным для обработки больших запросов. + +.. warning:: Завершающий слеш обязателен. + +**Пример** + +.. code-block:: xml + + /var/lib/clickhouse/tmp/ + +.. _server_settings-uncompressed_cache_size: + +uncompressed_cache_size +----------------------- +Размер кеша (в байтах) для несжатых данных, используемых движками таблиц семейства :ref:`table_engines-mergetree`. + +Кеш единый для сервера. Память выделяется по-требованию. Кеш используется в том случае, если включена опция :ref:`settings-use_uncompressed_cache`. + +Несжатый кеш выгодно использовать для очень коротких запросов в отдельных случаях. + +**Пример** + +.. code-block:: xml + + 8589934592 + + +.. _server_settings-users_config: + +users_config +------------ + +Путь к файлу, который содержит: + - Конфигурации пользователей. + - Права доступа. + - Профили настроек. + - Настройки квот. + +**Пример** + +.. code-block:: xml + + users.xml + + +.. _server_settings-zookeeper: + +zookeeper +--------- +Конфигурация серверов ZooKeeper. + +ClickHouse использует ZooKeeper для хранения метаданных о репликах при использовании реплицированных таблиц. + +Параметр можно не указывать, если реплицированные таблицы не используются. + +Подробно о репликации читайте в разделе :ref:`table_engines-replication`. + +**Пример** + +.. code-block:: xml + + \ No newline at end of file diff --git a/docs/ru/operations/settings/index.rst b/docs/ru/operations/settings/index.rst index 8e90e22a3a8..e1e23052f35 100644 --- a/docs/ru/operations/settings/index.rst +++ b/docs/ru/operations/settings/index.rst @@ -1,3 +1,5 @@ +.. _settings: + Настройки ========= diff --git a/docs/ru/operations/settings/settings.rst b/docs/ru/operations/settings/settings.rst index 2110064713c..ed6f78ff00d 100644 --- a/docs/ru/operations/settings/settings.rst +++ b/docs/ru/operations/settings/settings.rst @@ -85,6 +85,19 @@ preferred_block_size_bytes При этом размер блока не может быть более ``max_block_size`` строк. По-умолчанию выключен (равен 0), работает только при чтении из MergeTree-движков. +.. _settings-log_queries: + +log_queries +------------ + +Установка логгирования запроса. + +Запросы, переданные в ClickHouse с этой установкой, логгируются согласно правилам конфигурационного параметра сервера :ref:`server_settings-query_log`. + +**Пример** :: + + log_queries=1 + max_insert_block_size --------------------- Формировать блоки указанного размера, при вставке в таблицу. @@ -157,6 +170,7 @@ max_query_size interactive_delay ----------------- Интервал в микросекундах для проверки, не запрошена ли остановка выполнения запроса, и отправки прогресса. + По умолчанию - 100 000 (проверять остановку запроса и отправлять прогресс десять раз в секунду). connect_timeout @@ -209,6 +223,8 @@ extremes Считать ли экстремальные значения (минимумы и максимумы по столбцам результата запроса). Принимает 0 или 1. По умолчанию - 0 (выключено). Подробнее смотрите раздел "Экстремальные значения". +.. _settings-use_uncompressed_cache: + use_uncompressed_cache ---------------------- Использовать ли кэш разжатых блоков. Принимает 0 или 1. По умолчанию - 0 (выключено). diff --git a/docs/ru/query_language/queries.rst b/docs/ru/query_language/queries.rst index 0b550f57395..90fbbf45d22 100644 --- a/docs/ru/query_language/queries.rst +++ b/docs/ru/query_language/queries.rst @@ -420,6 +420,8 @@ ALTER Для запросов ``ALTER ... ATTACH|DETACH|DROP`` можно настроить ожидание, с помощью настройки ``replication_alter_partitions_sync``. Возможные значения: ``0`` - не ждать, ``1`` - ждать выполнения только у себя (по умолчанию), ``2`` - ждать всех. +.. _query_language_queries_show_databases: + SHOW DATABASES ~~~~~~~~~~~~~~ diff --git a/docs/ru/system_tables/system.asynchronous_metrics.rst b/docs/ru/system_tables/system.asynchronous_metrics.rst index d12131acbd7..38da983aa4b 100644 --- a/docs/ru/system_tables/system.asynchronous_metrics.rst +++ b/docs/ru/system_tables/system.asynchronous_metrics.rst @@ -1,3 +1,5 @@ +.. _system_tables-system.asynchronous_metrics: + system.asynchronous_metrics --------------------------- diff --git a/docs/ru/system_tables/system.events.rst b/docs/ru/system_tables/system.events.rst index 3f4ab0c90f5..8168559d25b 100644 --- a/docs/ru/system_tables/system.events.rst +++ b/docs/ru/system_tables/system.events.rst @@ -1,3 +1,5 @@ +.. _system_tables-system.events: + system.events ------------- diff --git a/docs/ru/system_tables/system.metrics.rst b/docs/ru/system_tables/system.metrics.rst index dee53b399e6..25038d3e92e 100644 --- a/docs/ru/system_tables/system.metrics.rst +++ b/docs/ru/system_tables/system.metrics.rst @@ -1,2 +1,4 @@ +.. _system_tables-system.metrics: + system.metrics -------------- diff --git a/docs/ru/table_engines/distributed.rst b/docs/ru/table_engines/distributed.rst index 75b73737b10..4ab76d1e8c1 100644 --- a/docs/ru/table_engines/distributed.rst +++ b/docs/ru/table_engines/distributed.rst @@ -1,3 +1,5 @@ +.. _table_engines-distributed: + Distributed ----------- diff --git a/docs/ru/table_engines/graphitemergetree.rst b/docs/ru/table_engines/graphitemergetree.rst index d036f267ec6..5b741522061 100644 --- a/docs/ru/table_engines/graphitemergetree.rst +++ b/docs/ru/table_engines/graphitemergetree.rst @@ -1,3 +1,5 @@ +.. _table_engines-graphitemergetree: + GraphiteMergeTree ----------------- @@ -13,7 +15,7 @@ Graphite хранит в ClickHouse полные данные, а получат Используется движок ``GraphiteMergeTree``. -Движок наследует свойства `MergeTree`. Настройки прореживания данных размещаются в :ref:`общей конфигурации ` ClickHouse (config.xml). +Движок наследует свойства `MergeTree`. Настройки прореживания данных задаются параметром :ref:`server_settings-graphite_rollup` в конфигурации сервера . Использование движка ^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +31,7 @@ Graphite хранит в ClickHouse полные данные, а получат .. code-block:: text - pattern + pattern regexp function age -> precision @@ -45,19 +47,17 @@ Graphite хранит в ClickHouse полные данные, а получат Поля шаблона правил. -.. code-block:: text - - +---------------+----------------------------------------------------------------------------------------------------------------------------+ - | Поле | Описание | - +===============+============================================================================================================================+ - | ``age`` | Минимальный возраст данных в секундах. | - +---------------+----------------------------------------------------------------------------------------------------------------------------+ - | ``function`` | Имя агрегирующей функции, которую следует применить к данным, чей возраст оказался в интервале ``[age, age + precision]``. | - +---------------+----------------------------------------------------------------------------------------------------------------------------+ - | ``precision`` | Точность определения возраста данных в секундах. | - +---------------+----------------------------------------------------------------------------------------------------------------------------+ - | ``regexp`` | Шаблон имени метрики. | - +---------------+----------------------------------------------------------------------------------------------------------------------------+ ++---------------+----------------------------------------------------------------------------------------------------------------------------+ +| Поле | Описание | ++===============+============================================================================================================================+ +| ``age`` | Минимальный возраст данных в секундах. | ++---------------+----------------------------------------------------------------------------------------------------------------------------+ +| ``function`` | Имя агрегирующей функции, которую следует применить к данным, чей возраст оказался в интервале ``[age, age + precision]``. | ++---------------+----------------------------------------------------------------------------------------------------------------------------+ +| ``precision`` | Точность определения возраста данных в секундах. | ++---------------+----------------------------------------------------------------------------------------------------------------------------+ +| ``regexp`` | Шаблон имени метрики. | ++---------------+----------------------------------------------------------------------------------------------------------------------------+ Пример настройки: diff --git a/docs/ru/table_engines/replication.rst b/docs/ru/table_engines/replication.rst index c7d8e84dc68..83f97928dea 100644 --- a/docs/ru/table_engines/replication.rst +++ b/docs/ru/table_engines/replication.rst @@ -67,6 +67,8 @@ ReplicatedSummingMergeTree Система следит за синхронностью данных на репликах и умеет восстанавливаться после сбоя. Восстановление после сбоя автоматическое (в случае небольших различий в данных) или полуавтоматическое (когда данные отличаются слишком сильно, что может свидетельствовать об ошибке конфигурации). +.. _table_engines-replication-creation_of_rep_tables: + Создание реплицируемых таблиц ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ru/table_engines/resharding.rst b/docs/ru/table_engines/resharding.rst index af92fc9b127..06ac38967a2 100644 --- a/docs/ru/table_engines/resharding.rst +++ b/docs/ru/table_engines/resharding.rst @@ -1,3 +1,5 @@ +.. _table_engines-resharding: + Перешардирование ---------------- From b3157aebb21f5ae6e44ec12d415b2abba76f2b88 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 25 Jul 2017 22:42:36 +0300 Subject: [PATCH 002/281] added synchronous insert into distributed table [#CLICKHOUSE-3033] --- dbms/src/Interpreters/Settings.h | 10 ++- .../Storages/Distributed/DirectoryMonitor.h | 2 + .../DistributedBlockOutputStream.cpp | 75 ++++++++++++++++++- .../DistributedBlockOutputStream.h | 23 +++++- dbms/src/Storages/StorageDistributed.cpp | 14 ++-- dbms/src/Storages/StorageDistributed.h | 6 +- 6 files changed, 114 insertions(+), 16 deletions(-) diff --git a/dbms/src/Interpreters/Settings.h b/dbms/src/Interpreters/Settings.h index a3bf110aa36..e41d6ec1375 100644 --- a/dbms/src/Interpreters/Settings.h +++ b/dbms/src/Interpreters/Settings.h @@ -286,7 +286,15 @@ struct Settings M(SettingBool, distributed_ddl_allow_replicated_alter, 0) \ /** Limit on max column size in block while reading. Helps to decrease cache misses count. \ * Should be close to L2 cache size. */ \ - M(SettingUInt64, preferred_max_column_in_block_size_bytes, 250000) + M(SettingUInt64, preferred_max_column_in_block_size_bytes, 250000) \ + \ + /** If setting is enabled, insert query into distributed waits until data will be sent to all nodes in cluster. \ + */ \ + M(SettingBool, insert_distributed_sync, 0) \ + /** Timeout for insert query into distributed. Setting is used only with insert_distributed_sync enabled. \ + * Zero value means no timeout. \ + */ \ + M(SettingUInt64, insert_distributed_timeout, 0) /// Possible limits for query execution. diff --git a/dbms/src/Storages/Distributed/DirectoryMonitor.h b/dbms/src/Storages/Distributed/DirectoryMonitor.h index fc34198cdbe..80f6f6ad16d 100644 --- a/dbms/src/Storages/Distributed/DirectoryMonitor.h +++ b/dbms/src/Storages/Distributed/DirectoryMonitor.h @@ -19,6 +19,8 @@ public: StorageDistributedDirectoryMonitor(StorageDistributed & storage, const std::string & name); ~StorageDistributedDirectoryMonitor(); + const ConnectionPoolPtr & getPool() const { return pool; } + private: void run(); ConnectionPoolPtr createPool(const std::string & name); diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index 4eb68848531..e3ce6cf689a 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,25 +8,42 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include +#include #include -#include #include +#include + +namespace CurrentMetrics +{ + extern const Metric DistributedSend; +} namespace DB { -DistributedBlockOutputStream::DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_) - : storage(storage), query_ast(query_ast), cluster(cluster_) +namespace ErrorCodes +{ + extern const int TIMEOUT_EXCEEDED; +} + +DistributedBlockOutputStream::DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, + const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_) + : storage(storage), query_ast(query_ast), cluster(cluster_), insert_sync(insert_sync_), insert_timeout(insert_timeout_), + deadline(std::chrono::system_clock::now() + std::chrono::seconds(insert_timeout)), + log(&Poco::Logger::get("DistributedBlockOutputStream")) { } @@ -36,6 +54,7 @@ void DistributedBlockOutputStream::write(const Block & block) return writeSplit(block); writeImpl(block); + ++blocks_inserted; } @@ -94,6 +113,8 @@ void DistributedBlockOutputStream::writeSplit(const Block & block) for (size_t shard_idx = 0; shard_idx < num_shards; ++shard_idx) if (splitted_blocks[shard_idx].rows()) writeImpl(splitted_blocks[shard_idx], shard_idx); + + ++blocks_inserted; } @@ -105,7 +126,19 @@ void DistributedBlockOutputStream::writeImpl(const Block & block, const size_t s /// dir_names is empty if shard has only local addresses if (!shard_info.dir_names.empty()) - writeToShard(block, shard_info.dir_names); + { + if (!insert_sync) + writeToShard(block, shard_info.dir_names); + else + { + std::atomic timeout_exceeded(false); + auto result = std::async(std::launch::async, &DistributedBlockOutputStream::writeToShardDirect, + this, std::cref(block), std::cref(shard_info.dir_names), std::ref(timeout_exceeded)); + if (insert_timeout && result.wait_until(deadline) == std::future_status::timeout) + timeout_exceeded = true; + result.get(); + } + } } @@ -123,6 +156,40 @@ void DistributedBlockOutputStream::writeToLocal(const Block & block, const size_ } +void DistributedBlockOutputStream::writeToShardDirect(const Block & block, const std::vector & dir_names, std::atomic & timeout_exceeded) +{ + const auto & query_string = queryToString(query_ast); + for (const auto & dir_name : dir_names) + { + auto & monitor = storage.requireDirectoryMonitor(dir_name); + auto & pool = monitor.getPool(); + auto connection = pool->get(); + + CurrentMetrics::Increment metric_increment{CurrentMetrics::DistributedSend}; + + if (timeout_exceeded) + throw Exception("Timeout exceeded. Inserted blocks: " + std::to_string(blocks_inserted), ErrorCodes::TIMEOUT_EXCEEDED); + + try + { + RemoteBlockOutputStream remote{*connection, query_string}; + + remote.writePrefix(); + remote.write(block); + remote.writeSuffix(); + } + catch (Exception & exception) + { + std::string message = "\nWhile insertion to "; + message += connection->getDescription(); + message += " Inserted blocks: " + std::to_string(blocks_inserted); + exception.addMessage(message); + LOG_ERROR(log, message); + exception.rethrow(); + } + } +} + void DistributedBlockOutputStream::writeToShard(const Block & block, const std::vector & dir_names) { /** tmp directory is used to ensure atomicity of transactions diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h index 9b5cf3cbbcc..82cfcc09f76 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h @@ -3,12 +3,21 @@ #include #include #include -#include +#include +#include +#include + +namespace Poco +{ + class Logger; +} namespace DB { class StorageDistributed; +class Cluster; +using ClusterPtr = std::shared_ptr; /** The write is asynchronous - the data is first written to the local filesystem, and then sent to the remote servers. * If the Distributed table uses more than one shard, then in order to support the write, @@ -21,10 +30,12 @@ class StorageDistributed; class DistributedBlockOutputStream : public IBlockOutputStream { public: - DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_); + DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_ = 0); void write(const Block & block) override; + void writePrefix() override { deadline = std::chrono::system_clock::now() + std::chrono::seconds(insert_timeout); } + private: IColumn::Selector createSelector(Block block); @@ -36,10 +47,18 @@ private: void writeToShard(const Block & block, const std::vector & dir_names); + void writeToShardDirect(const Block & block, const std::vector & dir_names, std::atomic & timeout_exceeded); + private: StorageDistributed & storage; ASTPtr query_ast; ClusterPtr cluster; + bool insert_sync = true; + UInt64 insert_timeout = 1; + size_t blocks_inserted = 0; + std::chrono::system_clock::time_point deadline; + + Poco::Logger * log; }; } diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index 02684f706a0..a3a891bad8c 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -245,7 +245,7 @@ BlockOutputStreamPtr StorageDistributed::write(const ASTPtr & query, const Setti /// DistributedBlockOutputStream will not own cluster, but will own ConnectionPools of the cluster return std::make_shared( - *this, rewriteInsertQuery(query, remote_database, remote_table), cluster); + *this, rewriteInsertQuery(query, remote_database, remote_table), cluster, settings.insert_distributed_sync, settings.insert_distributed_timeout); } @@ -456,9 +456,9 @@ bool StorageDistributed::hasColumn(const String & column_name) const } -void StorageDistributed::createDirectoryMonitor(const std::string & name) +StorageDistributedDirectoryMonitor & StorageDistributed::createDirectoryMonitor(const std::string & name) { - directory_monitors.emplace(name, std::make_unique(*this, name)); + return *(directory_monitors.emplace(name, std::make_unique(*this, name)).first->second); } @@ -477,10 +477,12 @@ void StorageDistributed::createDirectoryMonitors() } -void StorageDistributed::requireDirectoryMonitor(const std::string & name) +StorageDistributedDirectoryMonitor & StorageDistributed::requireDirectoryMonitor(const std::string & name) { - if (!directory_monitors.count(name)) - createDirectoryMonitor(name); + auto it = directory_monitors.find(name); + if (it == directory_monitors.end()) + return createDirectoryMonitor(name); + return *it->second; } size_t StorageDistributed::getShardCount() const diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 128f0da1efb..09bec125048 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -118,11 +118,11 @@ private: /// create directory monitor thread by subdirectory name - void createDirectoryMonitor(const std::string & name); + StorageDistributedDirectoryMonitor & createDirectoryMonitor(const std::string & name); /// create directory monitors for each existing subdirectory void createDirectoryMonitors(); - /// ensure directory monitor creation - void requireDirectoryMonitor(const std::string & name); + /// ensure directory monitor creation and return it + StorageDistributedDirectoryMonitor & requireDirectoryMonitor(const std::string & name); ClusterPtr getCluster() const; From 19d3c36871b7520afdc56e58c8d22afa6152cd1b Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 26 Jul 2017 17:41:21 +0300 Subject: [PATCH 003/281] added tests for synchronous insert into distributed table [#CLICKHOUSE-3033] --- dbms/tests/integration/helpers/client.py | 16 +++- .../__init__.py | 0 .../configs/remote_servers.xml | 16 ++++ .../test_sync_insert_into_distributed/test.py | 84 +++++++++++++++++++ 4 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 dbms/tests/integration/test_sync_insert_into_distributed/__init__.py create mode 100644 dbms/tests/integration/test_sync_insert_into_distributed/configs/remote_servers.xml create mode 100644 dbms/tests/integration/test_sync_insert_into_distributed/test.py diff --git a/dbms/tests/integration/helpers/client.py b/dbms/tests/integration/helpers/client.py index a7479efde36..919807919e3 100644 --- a/dbms/tests/integration/helpers/client.py +++ b/dbms/tests/integration/helpers/client.py @@ -19,6 +19,14 @@ class Client: return QueryRequest(self, sql, stdin, timeout) +class QueryTimeoutExceedException(Exception): + pass + + +class QueryRuntimeException(Exception): + pass + + class QueryRequest: def __init__(self, client, sql, stdin=None, timeout=None): self.client = client @@ -61,11 +69,11 @@ class QueryRequest: stdout = self.stdout_file.read() stderr = self.stderr_file.read() - if self.process.returncode != 0 or stderr: - raise Exception('Client failed! Return code: {}, stderr: {}'.format(self.process.returncode, stderr)) - if self.timer is not None and not self.process_finished_before_timeout: - raise Exception('Client timed out!') + raise QueryTimeoutExceedException('Client timed out!') + + if self.process.returncode != 0 or stderr: + raise QueryRuntimeException('Client failed! Return code: {}, stderr: {}'.format(self.process.returncode, stderr)) return stdout diff --git a/dbms/tests/integration/test_sync_insert_into_distributed/__init__.py b/dbms/tests/integration/test_sync_insert_into_distributed/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_sync_insert_into_distributed/configs/remote_servers.xml b/dbms/tests/integration/test_sync_insert_into_distributed/configs/remote_servers.xml new file mode 100644 index 00000000000..3593cbd7f36 --- /dev/null +++ b/dbms/tests/integration/test_sync_insert_into_distributed/configs/remote_servers.xml @@ -0,0 +1,16 @@ + + + + + + node1 + 9000 + + + node2 + 9000 + + + + + diff --git a/dbms/tests/integration/test_sync_insert_into_distributed/test.py b/dbms/tests/integration/test_sync_insert_into_distributed/test.py new file mode 100644 index 00000000000..3af21683e57 --- /dev/null +++ b/dbms/tests/integration/test_sync_insert_into_distributed/test.py @@ -0,0 +1,84 @@ +from contextlib import contextmanager +from helpers.network import PartitionManager + +import pytest + +from helpers.cluster import ClickHouseCluster +from helpers.client import QueryRuntimeException, QueryTimeoutExceedException + +cluster = ClickHouseCluster(__file__) + +node1 = cluster.add_instance('node1', main_configs=['configs/remote_servers.xml']) +node2 = cluster.add_instance('node2', main_configs=['configs/remote_servers.xml']) + +@pytest.fixture(scope="module") +def started_cluster(): + try: + cluster.start() + + for node in (node1, node2): + node.query(''' +CREATE TABLE local_table(date Date, val UInt64) ENGINE = MergeTree(date, (date, val), 8192); +''') + + + node1.query(''' +CREATE TABLE distributed_table(date Date, val UInt64) ENGINE = Distributed(test_cluster, default, local_table) +''') + + yield cluster + + finally: + cluster.shutdown() + + +def test_insertion_sync(started_cluster): + + node1.query('''SET insert_distributed_sync = 1, insert_distributed_timeout = 0; + INSERT INTO distributed_table SELECT today() as date, number as val FROM system.numbers LIMIT 10000''') + + assert node2.query("SELECT count() FROM local_table").rstrip() == '10000' + + node1.query(''' + SET insert_distributed_sync = 1, insert_distributed_timeout = 1; + INSERT INTO distributed_table SELECT today() - 1 as date, number as val FROM system.numbers LIMIT 10000''') + + assert node2.query("SELECT count() FROM local_table").rstrip() == '20000' + +""" +def test_insertion_sync_fails_on_error(started_cluster): + with PartitionManager() as pm: + pm.partition_instances(node2, node1, action='REJECT --reject-with tcp-reset') + with pytest.raises(QueryRuntimeException): + node1.query(''' + SET insert_distributed_sync = 1, insert_distributed_timeout = 0; + INSERT INTO distributed_table SELECT today() as date, number as val FROM system.numbers''', timeout=2) +""" + + +def test_insertion_sync_fails_with_timeout(started_cluster): + with pytest.raises(QueryRuntimeException): + node1.query(''' + SET insert_distributed_sync = 1, insert_distributed_timeout = 1; + INSERT INTO distributed_table SELECT today() as date, number as val FROM system.numbers''', timeout=1.5) + + +def test_insertion_without_sync_ignores_timeout(started_cluster): + with pytest.raises(QueryTimeoutExceedException): + node1.query(''' + SET insert_distributed_sync = 0, insert_distributed_timeout = 1; + INSERT INTO distributed_table SELECT today() as date, number as val FROM system.numbers''', timeout=1.5) + + +def test_insertion_sync_with_disabled_timeout(started_cluster): + with pytest.raises(QueryTimeoutExceedException): + node1.query(''' + SET insert_distributed_sync = 1, insert_distributed_timeout = 0; + INSERT INTO distributed_table SELECT today() as date, number as val FROM system.numbers''', timeout=1) + + +if __name__ == '__main__': + with contextmanager(started_cluster)() as cluster: + for name, instance in cluster.instances.items(): + print name, instance.ip_address + raw_input("Cluster created, press any key to destroy...") From 2f8f199d08c14402bee6e0403749d3edac51dfd2 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 27 Jul 2017 18:24:39 +0300 Subject: [PATCH 004/281] separated connection pool creation from StorageDistributedDirectoryMonitor in StorageDistributed; fixed bugs from review [#CLICKHOUSE-3033] --- dbms/src/Common/ProfileEvents.cpp | 2 + .../Storages/Distributed/DirectoryMonitor.cpp | 12 ++--- .../Storages/Distributed/DirectoryMonitor.h | 5 +- .../DistributedBlockOutputStream.cpp | 46 +++++++++++++------ .../DistributedBlockOutputStream.h | 19 ++++---- dbms/src/Storages/StorageDistributed.cpp | 38 +++++++++------ dbms/src/Storages/StorageDistributed.h | 21 ++++++--- 7 files changed, 92 insertions(+), 51 deletions(-) diff --git a/dbms/src/Common/ProfileEvents.cpp b/dbms/src/Common/ProfileEvents.cpp index 12dfecf576c..06d1cd59e0b 100644 --- a/dbms/src/Common/ProfileEvents.cpp +++ b/dbms/src/Common/ProfileEvents.cpp @@ -122,6 +122,8 @@ M(DictCacheRequests) \ M(DictCacheLockWriteNs) \ M(DictCacheLockReadNs) \ + \ + M(DistributedSyncInsertionTimeoutExceeded) \ namespace ProfileEvents diff --git a/dbms/src/Storages/Distributed/DirectoryMonitor.cpp b/dbms/src/Storages/Distributed/DirectoryMonitor.cpp index 4732e0659b2..07bed4a6cf4 100644 --- a/dbms/src/Storages/Distributed/DirectoryMonitor.cpp +++ b/dbms/src/Storages/Distributed/DirectoryMonitor.cpp @@ -86,8 +86,8 @@ namespace } -StorageDistributedDirectoryMonitor::StorageDistributedDirectoryMonitor(StorageDistributed & storage, const std::string & name) - : storage(storage), pool{createPool(name)}, path{storage.path + name + '/'} +StorageDistributedDirectoryMonitor::StorageDistributedDirectoryMonitor(StorageDistributed & storage, const std::string & name, ConnectionPoolPtr pool) + : storage(storage), pool{pool}, path{storage.path + name + '/'} , current_batch_file_path{path + "current_batch.txt"} , default_sleep_time{storage.context.getSettingsRef().distributed_directory_monitor_sleep_time_ms.totalMilliseconds()} , sleep_time{default_sleep_time} @@ -150,11 +150,11 @@ void StorageDistributedDirectoryMonitor::run() } -ConnectionPoolPtr StorageDistributedDirectoryMonitor::createPool(const std::string & name) +ConnectionPoolPtr StorageDistributedDirectoryMonitor::createPool(const std::string & name, const StorageDistributed & storage) { - const auto pool_factory = [this, &name] (const std::string & host, const UInt16 port, - const std::string & user, const std::string & password, - const std::string & default_database) + const auto pool_factory = [&storage, &name] (const std::string & host, const UInt16 port, + const std::string & user, const std::string & password, + const std::string & default_database) { return std::make_shared( 1, host, port, default_database, diff --git a/dbms/src/Storages/Distributed/DirectoryMonitor.h b/dbms/src/Storages/Distributed/DirectoryMonitor.h index 80f6f6ad16d..0b556fdbbfd 100644 --- a/dbms/src/Storages/Distributed/DirectoryMonitor.h +++ b/dbms/src/Storages/Distributed/DirectoryMonitor.h @@ -16,14 +16,13 @@ namespace DB class StorageDistributedDirectoryMonitor { public: - StorageDistributedDirectoryMonitor(StorageDistributed & storage, const std::string & name); + StorageDistributedDirectoryMonitor(StorageDistributed & storage, const std::string & name, ConnectionPoolPtr pool); ~StorageDistributedDirectoryMonitor(); - const ConnectionPoolPtr & getPool() const { return pool; } + static ConnectionPoolPtr createPool(const std::string & name, const StorageDistributed & storage); private: void run(); - ConnectionPoolPtr createPool(const std::string & name); bool findFiles(); void processFile(const std::string & file_path); void processFilesWithBatching(const std::map & files); diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index e3ce6cf689a..3d6200c0620 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,6 +33,10 @@ namespace CurrentMetrics extern const Metric DistributedSend; } +namespace ProfileEvents +{ + extern const Event DistributedSyncInsertionTimeoutExceeded; +} namespace DB { @@ -41,9 +48,7 @@ namespace ErrorCodes DistributedBlockOutputStream::DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_) - : storage(storage), query_ast(query_ast), cluster(cluster_), insert_sync(insert_sync_), insert_timeout(insert_timeout_), - deadline(std::chrono::system_clock::now() + std::chrono::seconds(insert_timeout)), - log(&Poco::Logger::get("DistributedBlockOutputStream")) + : storage(storage), query_ast(query_ast), cluster(cluster_), insert_sync(insert_sync_), insert_timeout(insert_timeout_) { } @@ -132,8 +137,9 @@ void DistributedBlockOutputStream::writeImpl(const Block & block, const size_t s else { std::atomic timeout_exceeded(false); - auto result = std::async(std::launch::async, &DistributedBlockOutputStream::writeToShardDirect, - this, std::cref(block), std::cref(shard_info.dir_names), std::ref(timeout_exceeded)); + auto launch = insert_timeout ? std::launch::async : std::launch::deferred; + auto result = std::async(launch, &DistributedBlockOutputStream::writeToShardSync, this, std::cref(block), + std::cref(shard_info.dir_names), shard_id, std::ref(timeout_exceeded)); if (insert_timeout && result.wait_until(deadline) == std::future_status::timeout) timeout_exceeded = true; result.get(); @@ -156,19 +162,34 @@ void DistributedBlockOutputStream::writeToLocal(const Block & block, const size_ } -void DistributedBlockOutputStream::writeToShardDirect(const Block & block, const std::vector & dir_names, std::atomic & timeout_exceeded) +void DistributedBlockOutputStream::writeToShardSync(const Block & block, const std::vector & dir_names, + size_t shard_id, const std::atomic & timeout_exceeded) { + auto & blocks_inserted = this->blocks_inserted; + auto writeNodeDescription = [shard_id, & blocks_inserted](WriteBufferFromString & out, const Connection & connection) + { + out << " (While insertion to " << connection.getDescription() << " shard " << shard_id; + out << " Inserted blocks: " << blocks_inserted << ")"; + }; + const auto & query_string = queryToString(query_ast); for (const auto & dir_name : dir_names) { - auto & monitor = storage.requireDirectoryMonitor(dir_name); - auto & pool = monitor.getPool(); + auto pool = storage.requireConnectionPool(dir_name); auto connection = pool->get(); CurrentMetrics::Increment metric_increment{CurrentMetrics::DistributedSend}; if (timeout_exceeded) - throw Exception("Timeout exceeded. Inserted blocks: " + std::to_string(blocks_inserted), ErrorCodes::TIMEOUT_EXCEEDED); + { + ProfileEvents::increment(ProfileEvents::DistributedSyncInsertionTimeoutExceeded); + + String message; + WriteBufferFromString out(message); + out << "Timeout exceeded."; + writeNodeDescription(out, *connection); + throw Exception(message, ErrorCodes::TIMEOUT_EXCEEDED); + } try { @@ -180,11 +201,10 @@ void DistributedBlockOutputStream::writeToShardDirect(const Block & block, const } catch (Exception & exception) { - std::string message = "\nWhile insertion to "; - message += connection->getDescription(); - message += " Inserted blocks: " + std::to_string(blocks_inserted); + String message; + WriteBufferFromString out(message); + writeNodeDescription(out, *connection); exception.addMessage(message); - LOG_ERROR(log, message); exception.rethrow(); } } diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h index 82cfcc09f76..469134afdea 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h @@ -19,7 +19,8 @@ class StorageDistributed; class Cluster; using ClusterPtr = std::shared_ptr; -/** The write is asynchronous - the data is first written to the local filesystem, and then sent to the remote servers. +/** If insert_sync_ is true, the write is synchronous. Uses insert_timeout_ if it is not zero. + * Otherwise, the write is asynchronous - the data is first written to the local filesystem, and then sent to the remote servers. * If the Distributed table uses more than one shard, then in order to support the write, * when creating the table, an additional parameter must be specified for ENGINE - the sharding key. * Sharding key is an arbitrary expression from the columns. For example, rand() or UserID. @@ -30,11 +31,11 @@ using ClusterPtr = std::shared_ptr; class DistributedBlockOutputStream : public IBlockOutputStream { public: - DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_ = 0); + DistributedBlockOutputStream(StorageDistributed & storage, const ASTPtr & query_ast, const ClusterPtr & cluster_, bool insert_sync_, UInt64 insert_timeout_); void write(const Block & block) override; - void writePrefix() override { deadline = std::chrono::system_clock::now() + std::chrono::seconds(insert_timeout); } + void writePrefix() override { deadline = std::chrono::steady_clock::now() + std::chrono::seconds(insert_timeout); } private: IColumn::Selector createSelector(Block block); @@ -47,18 +48,18 @@ private: void writeToShard(const Block & block, const std::vector & dir_names); - void writeToShardDirect(const Block & block, const std::vector & dir_names, std::atomic & timeout_exceeded); + /// Performs synchronous insertion to remote nodes. If timeout_exceeded flag was set, throws. + void writeToShardSync(const Block & block, const std::vector & dir_names, + size_t shard_id, const std::atomic & timeout_exceeded); private: StorageDistributed & storage; ASTPtr query_ast; ClusterPtr cluster; - bool insert_sync = true; - UInt64 insert_timeout = 1; + bool insert_sync; + UInt64 insert_timeout; size_t blocks_inserted = 0; - std::chrono::system_clock::time_point deadline; - - Poco::Logger * log; + std::chrono::steady_clock::time_point deadline; }; } diff --git a/dbms/src/Storages/StorageDistributed.cpp b/dbms/src/Storages/StorageDistributed.cpp index a3a891bad8c..160d50e304b 100644 --- a/dbms/src/Storages/StorageDistributed.cpp +++ b/dbms/src/Storages/StorageDistributed.cpp @@ -273,7 +273,7 @@ void StorageDistributed::startup() void StorageDistributed::shutdown() { - directory_monitors.clear(); + cluster_nodes_data.clear(); } @@ -455,13 +455,6 @@ bool StorageDistributed::hasColumn(const String & column_name) const return VirtualColumnFactory::hasColumn(column_name) || IStorage::hasColumn(column_name); } - -StorageDistributedDirectoryMonitor & StorageDistributed::createDirectoryMonitor(const std::string & name) -{ - return *(directory_monitors.emplace(name, std::make_unique(*this, name)).first->second); -} - - void StorageDistributed::createDirectoryMonitors() { if (path.empty()) @@ -473,16 +466,20 @@ void StorageDistributed::createDirectoryMonitors() boost::filesystem::directory_iterator end; for (auto it = begin; it != end; ++it) if (it->status().type() == boost::filesystem::directory_file) - createDirectoryMonitor(it->path().filename().string()); + requireDirectoryMonitor(it->path().filename().string()); } -StorageDistributedDirectoryMonitor & StorageDistributed::requireDirectoryMonitor(const std::string & name) +void StorageDistributed::requireDirectoryMonitor(const std::string & name) { - auto it = directory_monitors.find(name); - if (it == directory_monitors.end()) - return createDirectoryMonitor(name); - return *it->second; + cluster_nodes_data[name].requireDirectoryMonitor(name, *this); +} + +ConnectionPoolPtr StorageDistributed::requireConnectionPool(const std::string & name) +{ + auto & node_data = cluster_nodes_data[name]; + node_data.requireConnectionPool(name, *this); + return node_data.conneciton_pool; } size_t StorageDistributed::getShardCount() const @@ -496,4 +493,17 @@ ClusterPtr StorageDistributed::getCluster() const return (owned_cluster) ? owned_cluster : context.getCluster(cluster_name); } +void StorageDistributed::ClusterNodeData::requireConnectionPool(const std::string & name, const StorageDistributed & storage) +{ + if (!conneciton_pool) + conneciton_pool = StorageDistributedDirectoryMonitor::createPool(name, storage); +} + +void StorageDistributed::ClusterNodeData::requireDirectoryMonitor(const std::string & name, StorageDistributed & storage) +{ + requireConnectionPool(name, storage); + if (!directory_monitor) + directory_monitor = std::make_unique(storage, name, conneciton_pool); +} + } diff --git a/dbms/src/Storages/StorageDistributed.h b/dbms/src/Storages/StorageDistributed.h index 09bec125048..de79c4ed1da 100644 --- a/dbms/src/Storages/StorageDistributed.h +++ b/dbms/src/Storages/StorageDistributed.h @@ -116,13 +116,12 @@ private: const ASTPtr & sharding_key_ = nullptr, const String & data_path_ = String{}); - - /// create directory monitor thread by subdirectory name - StorageDistributedDirectoryMonitor & createDirectoryMonitor(const std::string & name); /// create directory monitors for each existing subdirectory void createDirectoryMonitors(); - /// ensure directory monitor creation and return it - StorageDistributedDirectoryMonitor & requireDirectoryMonitor(const std::string & name); + /// ensure directory monitor thread by subdirectory name creation + void requireDirectoryMonitor(const std::string & name); + /// ensure connection pool creation and return it + ConnectionPoolPtr requireConnectionPool(const std::string & name); ClusterPtr getCluster() const; @@ -146,7 +145,17 @@ private: String sharding_key_column_name; String path; /// Can be empty if data_path_ is empty. In this case, a directory for the data to be sent is not created. - std::unordered_map> directory_monitors; + struct ClusterNodeData + { + std::unique_ptr directory_monitor; + ConnectionPoolPtr conneciton_pool; + + /// Creates connection_pool if not exists. + void requireConnectionPool(const std::string & name, const StorageDistributed & storage); + /// Creates directory_monitor if not exists. + void requireDirectoryMonitor(const std::string & name, StorageDistributed & storage); + }; + std::unordered_map cluster_nodes_data; /// Used for global monotonic ordering of files to send. SimpleIncrement file_names_increment; From 1f6229d279e3b48d3bdffc0f6676868251ee2faa Mon Sep 17 00:00:00 2001 From: BayoNet Date: Mon, 31 Jul 2017 11:31:30 +0300 Subject: [PATCH 005/281] External dictionaries topic is restructured and updated. --- docs/ru/dicts/external_dicts.rst | 343 +--------------- docs/ru/dicts/external_dicts_dict.rst | 35 ++ docs/ru/dicts/external_dicts_dict_layout.rst | 250 +++++++++++ .../ru/dicts/external_dicts_dict_lifetime.rst | 38 ++ docs/ru/dicts/external_dicts_dict_sources.rst | 388 ++++++++++++++++++ .../dicts/external_dicts_dict_structure.rst | 125 ++++++ docs/ru/dicts/index.rst | 4 +- docs/ru/formats/index.rst | 2 + docs/ru/functions/ext_dict_functions.rst | 4 +- docs/ru/functions/other_functions.rst | 2 + .../operations/server_settings/settings.rst | 14 +- 11 files changed, 877 insertions(+), 328 deletions(-) create mode 100644 docs/ru/dicts/external_dicts_dict.rst create mode 100644 docs/ru/dicts/external_dicts_dict_layout.rst create mode 100644 docs/ru/dicts/external_dicts_dict_lifetime.rst create mode 100644 docs/ru/dicts/external_dicts_dict_sources.rst create mode 100644 docs/ru/dicts/external_dicts_dict_structure.rst diff --git a/docs/ru/dicts/external_dicts.rst b/docs/ru/dicts/external_dicts.rst index 4001eeff87f..00374b5a91e 100644 --- a/docs/ru/dicts/external_dicts.rst +++ b/docs/ru/dicts/external_dicts.rst @@ -1,345 +1,44 @@ .. _dicts-external_dicts: +*************** Внешние словари -=============== +*************** -Существует возможность подключать свои собственные словари из различных источников данных. -Источником данных для словаря может быть файл на локальной файловой системе, сервер ClickHouse, сервер MySQL, MongoDB или любой ODBC источник. -Словарь может полностью храниться в оперативке и периодически обновляться, или быть частично закэшированным в оперативке и динамически подгружать отсутствующие значения. +Существует возможность подключать собственные словари из различных источников данных. Источником данных для словаря может быть локальный текстовый/исполняемый файл, HTTP(s) ресурс или другая СУБД. Подробнее смотрите в разделе ":ref:`dicts-external_dicts_dict_sources`". -Конфигурация внешних словарей находится в отдельном файле или файлах, указанных в конфигурационном параметре :ref:`dictionaries_config `. -Этот параметр содержит абсолютный или относительный путь к файлу с конфигурацией словарей. Относительный путь - относительно директории с конфигурационным файлом сервера. Путь может содержать wildcard-ы \* и ? - тогда рассматриваются все подходящие файлы. Пример: ``dictionaries/*.xml``. +ClickHouse может полностью или частично хранить словари в оперативной памяти, периодически обновлять их и динамически подгружать отсутствующие значения. -Конфигурация словарей, а также множество файлов с конфигурацией, может обновляться без перезапуска сервера. Сервер проверяет обновления каждые 5 секунд. То есть, словари могут подключаться динамически. +Конфигурация внешних словарей находится в одном или нескольких файлах. Путь к конфигурации указывается в параметре :ref:`server_settings-dictionaries_config`. -Создание словарей может производиться при старте сервера или при первом использовании. Это определяется конфигурационном параметром :ref:`dictionaries_lazy_load ` (в основном конфигурационном файле сервера). Параметр не обязателен, по умолчанию - ``true``. Если true, то каждый словарь создаётся при первом использовании; если словарь не удалось создать - вызов функции, использующей словарь, кидает исключение. Если ``false``, то все словари создаются при старте сервера, и в случае ошибки, сервер завершает работу. +Периодически ClickHouse обновляет конфигурацию словарей и словари. Т.о. словари можно подгружать динамически. + +Словари могут загружаться при старте сервера или при первом использовании, в зависимости от настройки :ref:`server_settings-dictionaries_lazy_load`. Конфигурационный файл словарей имеет вид: .. code-block:: xml - Не обязательный элемент с любым содержимым; полностью игнорируется. + Необязательный элемент с любым содержимым. Полностью игнорируется. - - - os - - - - - - - - /opt/dictionaries/os.tsv - - TabSeparated - - - - - - - + + - - - - cat /opt/dictionaries/os.tsv - - TabSeparated - - - - - http://[::1]/os.tsv - - TabSeparated - - - - - - - 300 - 360 - - - - - - - - - - - - - - - - Id - - - - - Name - - String - - - - - - - ParentID - UInt64 - 0 - - true - - true - + ... - - - expr - UInt64 - rand64() - 0 - - + + -Идентификатор (ключевой атрибут) словаря должен быть числом, помещающимся в UInt64. -Также есть возможность задавать произвольные составные ключи (см. раздел "Словари с составными ключами"). Замечание: составной ключ может состоять и из одного элемента, что даёт возможность использовать в качестве ключа, например, строку. +В одном файле можно :ref:`сконфигурировать ` произвольное количество словарей. Формат файла сохраняется даже если словарь один (т.е. `` ``). +Смотрите также ":ref:`ext_dict_functions`" . -Существует шесть способов размещения словаря в памяти. +.. attention:: Вы можете преобразовать значения по небольшому словарю, описав его в запросе ``SELECT`` (см. функцию ":ref:`other_functions-transform`"). Эта функциональность не связана с внешними словарями. -flat ------ -В виде плоских массивов. Самый эффективный способ. Он подходит, если все ключи меньше 500 000. Если при создании словаря обнаружен ключ больше, то кидается исключение и словарь не создаётся. Словарь загружается в оперативку целиком. Словарь использует количество оперативки, пропорциональное максимальному значению ключа. Ввиду ограничения на 500 000, потребление оперативки вряд ли может быть большим. -Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. - -hashed ------- -В виде хэш-таблиц. Слегка менее эффективный способ. Словарь тоже загружается в оперативку целиком, и может содержать произвольное количество элементов с произвольными идентификаторами. На практике, имеет смысл использовать до десятков миллионов элементов, пока хватает оперативки. -Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. - -cache ------ -Наименее эффективный способ. Подходит, если словарь не помещается в оперативку. Представляет собой кэш из фиксированного количества ячеек, в которых могут быть расположены часто используемые данные. Поддерживается источник MySQL, ClickHouse, executable, http; источник-файл не поддерживается. При поиске в словаре, сначала просматривается кэш. На каждый блок данных, все не найденные в кэше ключи (или устаревшие ключи) собираются в пачку, и с этой пачкой делается запрос к источнику вида SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...). Затем полученные данные записываются в кэш. - -range_hashed ------------- -В таблице прописаны какие-то данные для диапазонов дат, для каждого ключа. Дать возможность доставать эти данные для заданного ключа, для заданной даты. - - -Пример: таблица содержит скидки для каждого рекламодателя в виде: - - +------------------+-----------------------------+------------+----------+ - | id рекламодателя | дата начала действия скидки | дата конца | величина | - +==================+=============================+============+==========+ - | 123 | 2015-01-01 | 2015-01-15 | 0.15 | - +------------------+-----------------------------+------------+----------+ - | 123 | 2015-01-16 | 2015-01-31 | 0.25 | - +------------------+-----------------------------+------------+----------+ - | 456 | 2015-01-01 | 2015-01-15 | 0.05 | - +------------------+-----------------------------+------------+----------+ - -Добавляем ``layout = range_hashed``. -При использовании такого layout, в structure должны быть элементы ``range_min``, ``range_max``. - -Пример: - -.. code-block:: xml - - - - Id - - - first - - - last - - ... - -Эти столбцы должны иметь тип Date. Другие типы пока не поддерживаем. -Столбцы обозначают закрытый диапазон дат. - -Для работы с такими словарями, функции dictGetT должны принимать ещё один аргумент - дату: - -``dictGetT('dict_name', 'attr_name', id, date)`` - -Функция достаёт значение для данного id и для диапазона дат, в который входит переданная дата. Если не найден id или для найденного id не найден диапазон, то возвращается значение по умолчанию для словаря. - -Если есть перекрывающиеся диапазоны, то можно использовать любой подходящий. - -Если граница диапазона является NULL или является некорректной датой (1900-01-01, 2039-01-01), то диапазон следует считать открытым. Диапазон может быть открытым с обеих сторон. - -В оперативке данные представлены в виде хэш-таблицы со значением в виде упорядоченного массива диапазонов и соответствующих им значений. - -Пример словаря по диапазонам: - -.. code-block:: xml - - - - xxx - - - xxx - 3306 - xxx - - xxx - 1 - - dicts - xxx
-
- - - 300 - 360 - - - - - - - Abcdef - - - StartDate - - - EndDate - - - XXXType - String - - - -
-
- -complex_key_hashed ------------------- - -Для использования с составными ключами. Аналогичен hashed. - -complex_key_cache ------------------ - -Для использования с составными ключами. Аналогичен cache. - -Примечания ----------- - -Рекомендуется использовать способ ``flat``, если возможно, или ``hashed``, ``complex_key_hashed``. Скорость работы словарей с таким размещением в памяти является безупречной. - -Способы ``cache`` и ``complex_key_cache`` следует использовать лишь если это неизбежно. Скорость работы кэша очень сильно зависит от правильности настройки и сценария использования. Словарь типа cache нормально работает лишь при достаточно больших hit rate-ах (рекомендуется 99% и выше). Посмотреть средний hit rate можно в таблице system.dictionaries. Укажите достаточно большой размер кэша. Количество ячеек следует подобрать экспериментальным путём - выставить некоторое значение, с помощью запроса добиться полной заполненности кэша, посмотреть на потребление оперативки (эта информация находится в таблице system.dictionaries); затем пропорционально увеличить количество ячеек так, чтобы расходовалось разумное количество оперативки. В качестве источника для кэша рекомендуется MySQL, MongoDB, так как ClickHouse плохо обрабатывает запросы со случайными чтениями. - -Во всех случаях, производительность будет выше, если вызывать функцию для работы со словарём после ``GROUP BY``, или если доставаемый атрибут помечен как инъективный. Для cache словарей, производительность будет лучше, если вызывать функцию после LIMIT-а - для этого можно использовать подзапрос с LIMIT-ом, и снаружи вызывать функцию со словарём. - -Атрибут называется инъективным, если разным ключам соответствуют разные значения атрибута. Тогда при использовании в ``GROUP BY`` функции, достающей значение атрибута по ключу, эта функция автоматически выносится из GROUP BY. - -При обновлении словарей из файла, сначала проверяется время модификации файла, и загрузка производится только если файл изменился. -При обновлении из MySQL, для flat и hashed словарей, сначала делается запрос ``SHOW TABLE STATUS`` и смотрится время обновления таблицы. И если оно не NULL, то оно сравнивается с запомненным временем. Это работает для MyISAM таблиц, а для InnoDB таблиц время обновления неизвестно, поэтому загрузка из InnoDB делается при каждом обновлении. - -Для cache-словарей может быть задано время устаревания (``lifetime``) данных в кэше. Если от загрузки данных в ячейке прошло больше времени, чем lifetime, то значение не используется, и будет запрошено заново при следующей необходимости его использовать. - -Если словарь не удалось ни разу загрузить, то при попытке его использования, будет брошено исключение. -Если при запросе к источнику cached словаря возникла ошибка, то будет брошено исключение. -Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы - во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей. - -Список внешних словарей и их статус можно посмотреть в таблице ``system.dictionaries``. - -Для использования внешних словарей, смотрите раздел "Функции для работы с внешними словарями". - -Обратите внимание, что вы можете преобразовать значения по небольшому словарю, указав всё содержимое словаря прямо в запросе SELECT - смотрите раздел "Функция transform". Эта функциональность никак не связана с внешними словарями. - -Словари с составными ключами ----------------------------- - -В качестве ключа может выступать кортеж (tuple) из полей произвольных типов. Параметр layout в этом случае должен быть равен complex_key_hashed или complex_key_cache. - -Структура ключа задаётся не в элементе ````, а в элементе ````. Поля ключа задаются в том же формате, что и атрибуты словаря. Пример: - -.. code-block:: xml - - - - - field1 - String - - - field2 - UInt32 - - ... - - ... - - -При использовании такого словаря, в функции dictGet* в качестве ключа передаётся Tuple со значениями полей. Пример: ``dictGetString('dict_name', 'attr_name', tuple('field1', 123))``. +.. toctree:: + :glob: + + external_dicts_dict* diff --git a/docs/ru/dicts/external_dicts_dict.rst b/docs/ru/dicts/external_dicts_dict.rst new file mode 100644 index 00000000000..b400261f0e5 --- /dev/null +++ b/docs/ru/dicts/external_dicts_dict.rst @@ -0,0 +1,35 @@ +.. _dicts-external_dicts_dict: + +************************** +Настройка внешнего словаря +************************** + +Конфигурация словаря имеет следующую структуру: + +.. code-block:: xml + + + dict_name + + + + + + + + + + + + + + + + + + +* name - Идентификатор, под которым словарь будет доступен для использования. Используйте символы ``[a-zA-Z0-9_\-]``. +* :ref:`source ` - Источник словаря. +* :ref:`layout ` - Размещение словаря в памяти. +* :ref:`structure ` - Ключ словаря. +* :ref:`lifetime ` - Периодичность обновления словарей. diff --git a/docs/ru/dicts/external_dicts_dict_layout.rst b/docs/ru/dicts/external_dicts_dict_layout.rst new file mode 100644 index 00000000000..4ee4cc6fe05 --- /dev/null +++ b/docs/ru/dicts/external_dicts_dict_layout.rst @@ -0,0 +1,250 @@ +.. _dicts-external_dicts_dict_layout: + +************************** +Хранение словарей в памяти +************************** + +Словари можно размещать в памяти :ref:`множеством способов `. + +Рекомендуем :ref:`dicts-external_dicts_dict_layout-flat`, :ref:`dicts-external_dicts_dict_layout-hashed` и :ref:`dicts-external_dicts_dict_layout-complex_key_hashed`. Скорость обработки словарей при этом максимальна. + +Размещение с кэшированием не рекомендуется использовать из-за потенциально низкой производительности и сложностей в подборе оптимальных параметров. Читайте об этом подробнее в разделе ":ref:`dicts-external_dicts_dict_layout-cache`". + +Повысить производительнось словарей можно следующими способами: + +* Вызывать функцию для работы со словарём после ``GROUP BY``. +* Помечать извлекаемые атрибуты как инъективные. Атрибут называется инъективным, если разным ключам соответствуют разные значения атрибута. Тогда при использовании в ``GROUP BY`` функции, достающей значение атрибута по ключу, эта функция автоматически выносится из ``GROUP BY``. + +ClickHouse периодически обновляет словари. Сначала проверяется время модификации файла/таблицы, затем, если файл/таблица обновились, обновляется словарь. Если словарь хранится в таблице типа MyISAM, то время модификации проверяется запросом ``SHOW TABLE STATUS``. Для таблиц InnoDB нельзя получить время модификации, поэтому словарь обновляется каждый раз. + +Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы - во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей. + +При ошибках работы со словарями ClickHouse генерирует исключения. Например, в следующих ситуациях: + +* При обращении к словарю, который не удалось загрузить. +* При ошибке запроса к ``cached``-словарю. + + +Список внешних словарей и их статус можно посмотреть в таблице ``system.dictionaries``. + +Общий вид конфигурации: + +.. code-block:: xml + + + + ... + + + + + + ... + + + + +.. _dicts-external_dicts_dict_layout-manner: + +Способы размещения словарей в памяти +==================================== + +* :ref:`dicts-external_dicts_dict_layout-flat` +* :ref:`dicts-external_dicts_dict_layout-hashed` +* :ref:`dicts-external_dicts_dict_layout-cache` +* :ref:`dicts-external_dicts_dict_layout-range_hashed` +* :ref:`dicts-external_dicts_dict_layout-complex_key_hashed` +* :ref:`dicts-external_dicts_dict_layout-complex_key_cache` + + +.. _dicts-external_dicts_dict_layout-flat: + +flat +---- + +Словарь полностью хранится в оперативной памяти в виде плоских массивов. Объем памяти, занимаемой словарем? пропорционален размеру самого большого (по размеру) ключа. + +Ключ словаря имеет тип ``UInt64`` и его величина ограничена 500 000. Если при создании словаря обнаружен ключ больше, то ClickHouse бросает исключение и не создает словарь. + +Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. + +Это метод обеспечивает максимальную производительность среди всех доступных способов размещения словаря. + +Пример конфигурации: + +.. code-block:: xml + + + + + + +.. _dicts-external_dicts_dict_layout-hashed: + +hashed +------ + +Словарь полностью хранится в оперативной памяти в виде хэш-таблиц. Словарь может содержать произвольное количество элементов с произвольными идентификаторами. На практике, количество ключей может достигать десятков миллионов элементов. + +Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком. + +Пример конфигурации: + +.. code-block:: xml + + + + + + +.. _dicts-external_dicts_dict_layout-complex_key_hashed: + +complex_key_hashed +------------------ + +Тип размещения предназначен для использования с составными :ref:`ключами `. Аналогичен hashed. + +Пример конфигурации: + +.. code-block:: xml + + + + + + +.. _dicts-external_dicts_dict_layout-range_hashed: + +range_hashed +------------ + +Словарь хранится в оперативной памяти в виде хэш-таблицы с упорядоченным массивом диапазонов и соответствующих им значений. + +Этот способ размещения работает также как и hashed и позволяет дополнительно к ключу использовать дипазоны по дате/времени, если они указаны в словаре. + +Пример: таблица содержит скидки для каждого рекламодателя в виде: + + +------------------+-----------------------------+------------+----------+ + | id рекламодателя | дата начала действия скидки | дата конца | величина | + +==================+=============================+============+==========+ + | 123 | 2015-01-01 | 2015-01-15 | 0.15 | + +------------------+-----------------------------+------------+----------+ + | 123 | 2015-01-16 | 2015-01-31 | 0.25 | + +------------------+-----------------------------+------------+----------+ + | 456 | 2015-01-01 | 2015-01-15 | 0.05 | + +------------------+-----------------------------+------------+----------+ + +Столбцы с датами в словаре должны иметь тип ``Date``. + +Чтобы использовать выборку по диапазонам дат, необходимо в :ref:`structure ` определить элементы ``range_min``, ``range_max``. + +Пример: + +.. code-block:: xml + + + + Id + + + first + + + last + + ... + + + +Для работы с такими словарями в функцию ``dictGetT`` необходимо передавать дополнительный аргумент - дату: :: + + dictGetT('dict_name', 'attr_name', id, date) + +Функция возвращает значение для заданных ``id`` и диапазона дат, в который входит переданная дата. + +Особенности алгоритма: + +* Если не найден ``id`` или для найденного ``id`` не найден диапазон, то возвращается значение по умолчанию для словаря. +* Если есть перекрывающиеся диапазоны, то можно использовать любой подходящий. +* Если граница диапазона ``NULL`` или некорректная дата (1900-01-01, 2039-01-01), то диапазон считается открытым. Диапазон может быть открытым с обеих сторон. + + +Пример конфигурации: + +.. code-block:: xml + + + + + ... + + + + + + + + Abcdef + + + StartDate + + + EndDate + + + XXXType + String + + + + + + + + +.. _dicts-external_dicts_dict_layout-cache: + +cache +----- + +Словарь хранится в кэше, состоящем из фиксированного количества ячеек. Ячейки содержат часто используемые элементы. + +При поиске в словаре сначала просматривается кэш. На каждый блок данных, все не найденные в кэше или устаревшие ключи запрашиваются у источника с помощью ``SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)``. Затем, полученные данные записываются в кэш. + +Для cache-словарей может быть задано время устаревания (:ref:`lifetime `) данных в кэше. Если от загрузки данных в ячейке прошло больше времени, чем ``lifetime``, то значение не используется, и будет запрошено заново при следующей необходимости его использовать. + +Это наименее эффективный из всех способов размещения словарей. Скорость работы кэша очень сильно зависит от правильности настройки и сценария использования. Словарь типа cache показывает высокую производительность лишь при достаточно больших hit rate-ах (рекомендуется 99% и выше). Посмотреть средний hit rate можно в таблице ``system.dictionaries``. + +Чтобы увеличить производительность кэша, используйте подзапрос с ``LIMIT``, а снаружи вызывайте функцию со словарём. + +Поддерживаются :ref:`источники `: MySQL, ClickHouse, executable, HTTP. + +Пример настройки: + +.. code-block:: xml + + + + + 1000000000 + + + +Укажите достаточно большой размер кэша. Количество ячеек следует подобрать экспериментальным путём: + +1. Выставить некоторое значение. +2. Запросами добиться полной заполненности кэша. +3. Оценить потребление оперативной памяти с помощью таблицы ``system.dictionaries``. +4. Увеличивать/уменьшать количество ячеек до получения требуемого расхода оперативной памяти. + +.. warning:: Не используйте в качестве источника ClickHouse, поскольку он медленно обрабатывает запросы со случайным чтением. + + +.. _dicts-external_dicts_dict_layout-complex_key_cache: + +complex_key_cache +----------------- + +Тип размещения предназначен для использования с составными :ref:`ключами `. Аналогичен ``cache``. + diff --git a/docs/ru/dicts/external_dicts_dict_lifetime.rst b/docs/ru/dicts/external_dicts_dict_lifetime.rst new file mode 100644 index 00000000000..d3de506b800 --- /dev/null +++ b/docs/ru/dicts/external_dicts_dict_lifetime.rst @@ -0,0 +1,38 @@ +.. _dicts-external_dicts_dict_lifetime: + +******************* +Обновление словарей +******************* + +ClickHouse периодически обновляет словари. Интервал обновления для полностью загружаемых словарей и интервал инвалидации для кэшируемых словарей определяется в теге ```` в секундах. + +Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы, во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей. + +Пример настройки: + +.. code-block:: xml + + + ... + 300 + ... + + + +Настройка ``0`` запрещает обновление словарей. + + +Можно задать интервал, внутри которого ClickHouse равномерно-случайно выберет время для обновления. Это необходимо для распределения нагрузки на источник словаря при обновлении на большом количестве серверов. + +Пример настройки: + +.. code-block:: xml + + + ... + + 300 + 360 + + ... + diff --git a/docs/ru/dicts/external_dicts_dict_sources.rst b/docs/ru/dicts/external_dicts_dict_sources.rst new file mode 100644 index 00000000000..035287b1a52 --- /dev/null +++ b/docs/ru/dicts/external_dicts_dict_sources.rst @@ -0,0 +1,388 @@ +.. _dicts-external_dicts_dict_sources: + +************************** +Источники внешних словарей +************************** + +Внешний словарь можно подключить из множества источников. + +Общий вид конфигурации: + +.. code-block:: xml + + + + ... + + + + + + ... + + ... + + +Источник настраивается в разделе ``source``. + +Типы источников (``source_type``): + + * :ref:`dicts-external_dicts_dict_sources-local_file` + * :ref:`dicts-external_dicts_dict_sources-executable` + * :ref:`dicts-external_dicts_dict_sources-http` + * :ref:`dicts-external_dicts_dict_sources-odbc` + * СУБД: + + * :ref:`dicts-external_dicts_dict_sources-mysql` + * :ref:`dicts-external_dicts_dict_sources-clickhouse` + * :ref:`dicts-external_dicts_dict_sources-mongodb` + + +.. _dicts-external_dicts_dict_sources-local_file: + +Локальный файл +============== + +Пример настройки: + +.. code-block:: xml + + + + /opt/dictionaries/os.tsv + TabSeparated + + + +Поля настройки: + +* ``path`` - Абсолютный путь к файлу. +* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`". + + +.. _dicts-external_dicts_dict_sources-executable: + +Исполняемый файл +================ + +Работа с исполняемым файлом зависит от :ref:`размещения словаря в памяти `. Если тип размещения словаря ``cache`` и ``complex_key_cache``, то ClickHouse запрашивает необходимые ключи, отправляя запрос в ``STDIN`` исполняемого файла. + +Пример настройки: + +.. code-block:: xml + + + + cat /opt/dictionaries/os.tsv + TabSeparated + + + +Поля настройки: + +* ``command`` - Абсолютный путь к исполняемому файлу или имя файла (если каталог программы прописан в ``PATH``). +* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`". + + +.. _dicts-external_dicts_dict_sources-http: + +HTTP(s) +======= + +Работа с HTTP(s) сервером зависит от :ref:`размещения словаря в памяти `. Если тип размещения словаря ``cache`` и ``complex_key_cache``, то ClickHouse запрашивает необходимые ключи, отправляя запрос методом ``POST``. + +Пример настройки: + +.. code-block:: xml + + + + http://[::1]/os.tsv + TabSeparated + + + +Чтобы ClickHouse смог обратиться к HTTPS-ресурсу, необходимо прописать :ref:`настройки openSSL ` в конфигурации сервера. + +Поля настройки: + +* ``url`` - URL источника. +* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`". + + +.. _dicts-external_dicts_dict_sources-odbc: + +ODBC +==== + +Этим способом можно подключить любую базу данных, имеющую ODBC драйвер. + +Пример настройки: + +.. code-block:: xml + + + DatabaseName + TableName
+ DSN=some_parameters +
+ +Поля настройки: + +* ``db`` - Имя базы данных. Не указывать, если имя базы задано в параметрах ````. +* ``table`` - Имя таблицы. +* ``connection_string`` - Строка соединения. + + +Пример подключения PostgreSQL +----------------------------- + +ОС Ubuntu. + +Установка unixODBC и ODBC-драйвера для PostgreSQL: :: + + sudo apt-get install -y unixodbc odbcinst odbc-postgresql + + +Настройка ``/etc/odbc.ini`` (или ``~/.odbc.ini``): :: + + [DEFAULT] + Driver = myconnection + + [myconnection] + Description = PostgreSQL connection to my_db + Driver = PostgreSQL Unicode + Database = my_db + Servername = 127.0.0.1 + UserName = username + Password = password + Port = 5432 + Protocol = 9.3 + ReadOnly = No + RowVersioning = No + ShowSystemTables = No + ConnSettings = + + +Конфигурация словаря в ClickHouse: + +.. code-block:: xml + + + table_name + + + + + DSN=myconnection + postgresql_table
+
+ + + 300 + 360 + + + + + + + id + + + some_column + UInt64 + 0 + + +
+ +Может понадобиться в ``odbc.ini`` указать полный путь до библиотеки с драйвером ``DRIVER=/usr/local/lib/psqlodbcw.so``. + +Пример подключения MS SQL Server +-------------------------------- + +ОС Ubuntu. + +Установка драйвера: :: + + sudo apt-get install tdsodbc freetds-bin sqsh + +Настройка драйвера: :: + + $ cat /etc/freetds/freetds.conf + ... + + [MSSQL] + host = 192.168.56.101 + port = 1433 + tds version = 7.0 + client charset = UTF-8 + + $ cat /etc/odbcinst.ini + ... + + [FreeTDS] + Description = FreeTDS + Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so + Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so + FileUsage = 1 + UsageCount = 5 + + $ cat ~/.odbc.ini + ... + + [MSSQL] + Description = FreeTDS + Driver = FreeTDS + Servername = MSSQL + Database = test + UID = test + PWD = test + Port = 1433 + + +Настройка словаря в ClickHouse: + +.. code-block:: xml + + + + test + + + dict
+ DSN=MSSQL;UID=test;PWD=test +
+ + + + 300 + 360 + + + + + + + + + k + + + s + String + + + +
+
+ + + +СУБД +==== + +.. _dicts-external_dicts_dict_sources-mysql: + +MySQL +----- + +Пример настройки: + +.. code-block:: xml + + + + 3306 + clickhouse + qwerty + + example01-1 + 1 + + + example01-2 + 1 + + conv_main + counters
+ id=10 +
+ + + +Поля настройки: + +* ``port`` - порт сервера MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ````). +* ``user`` - имя пользователя MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ````). +* ``password`` - пароль пользователя MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ````). +* ``replica`` - блок конфигурации реплики. Блоков может быть несколько. + + * ``replica/host`` - хост MySQL. + * ``replica/priority`` - приоритет реплики. При попытке соединения ClickHouse обходит реплики в соответствии с приоритетом. Чем меньше цифра, тем выше приоритет. +* ``db`` - имя базы данных. +* ``table`` - имя таблицы. +* ``where`` - условие выбора. Может отсутствовать. + +.. _dicts-external_dicts_dict_sources-clickhouse: + +ClickHouse +---------- + +Пример настройки: + +.. code-block:: xml + + + + example01-01-1 + 9000 + default + + default + ids
+ id=10 +
+ + +Поля настройки: + +* ``host`` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа :ref:`Distributed ` и прописать её в дальнейших настройках. +* ``port`` - порт сервера ClickHouse. +* ``user`` - имя пользователя ClickHouse. +* ``password`` - пароль пользователя ClickHouse. +* ``db`` - имя базы данных. +* ``table`` - имя таблицы. +* ``where`` - условие выбора. Может отсутствовать. + + +.. _dicts-external_dicts_dict_sources-mongodb: + +MongoDB +------- + +Пример настройки: + +.. code-block:: xml + + + + localhost + 27017 + + + test + dictionary_source + + + + +Поля настройки: + +* ``host`` - хост MongoDB. +* ``port`` - порт сервера MongoDB. +* ``user`` - имя пользователя MongoDB. +* ``password`` - пароль пользователя MongoDB. +* ``db`` - имя базы данных. +* ``collection`` - имя коллекции. diff --git a/docs/ru/dicts/external_dicts_dict_structure.rst b/docs/ru/dicts/external_dicts_dict_structure.rst new file mode 100644 index 00000000000..ec0ae0be370 --- /dev/null +++ b/docs/ru/dicts/external_dicts_dict_structure.rst @@ -0,0 +1,125 @@ +.. _dicts-external_dicts_dict_structure: + +******************* +Ключ и поля словаря +******************* + +Секция ```` описывает ключ словаря и поля, доступные для запросов. + + +Общий вид структуры: + +.. code-block:: xml + + + + + Id + + + + + + + ... + + + + +В структуре описываются столбцы: + +* ```` - :ref:`ключевой столбец `. +* ```` - :ref:`столбец данных `. Столбцов может быть много. + +.. _dicts-external_dicts_dict_structure-key: + +Ключ +==== + +ClickHouse поддерживает следующие виды ключей: + +* Числовой ключ. Формат UInt64. Описывается в теге ````. +* Составной ключ. Набор значений разного типа. Описывается в теге ````. + +Структура может содержать либо ```` либо ````. + + +.. attention:: Ключ не надо дополнительно описывать в атрибутах. + +Числовой ключ +-------------- + +Формат: ``UInt64``. + +Пример конфигурации: + +.. code-block:: xml + + + Id + + + +Поля конфигурации: + +* name - имя столбца с ключами. + + +Составной ключ +--------------- + +Ключем может быть кортеж (``tuple``) из полей произвольных типов. :ref:`layout ` в этом случае должен быть ``complex_key_hashed`` или ``complex_key_cache``. + +.. tip:: Cоставной ключ может состоять и из одного элемента, что даёт возможность использовать в качестве ключа, например, строку. + +Структура ключа задаётся в элементе ````. Поля ключа задаются в том же формате, что и :ref:`атрибуты ` словаря. Пример: + +.. code-block:: xml + + + + + field1 + String + + + field2 + UInt32 + + ... + + ... + + +При запросе в функции ``dictGet*`` в качестве ключа передаётся кортеж. Пример: ``dictGetString('dict_name', 'attr_name', tuple('string for field1', num_for_field2))``. + + +.. _dicts-external_dicts_dict_structure-attributes: + +Атрибуты +======== + +Пример конфигурации: + +.. code-block:: xml + + + ... + + Name + Type + + rand64() + true + true + + + +Поля конфигурации: + +* ``name`` - Имя столбца. +* ``type`` - Тип столбца. Задает способ интерпретации данных в источнике. Например, в случае MySQL, в таблице-источнике поле может быть ``TEXT``, ``VARCHAR``, ``BLOB``, но загружено может быть как ``String``. +* ``null_value`` - Значение по умолчанию для несуществующего элемента. В примере - пустая строка. +* ``expression`` - Атрибут может быть выражением. Тег не обязательный. +* ``hierarchical`` - Поддержка иерархии. Отображение в идентификатор родителя. По умолчанию, ``false``. +* ``injective`` - Признак инъективности отображения ``id -> attribute``. Если ``true``, то можно оптимизировать ``GROUP BY``. По умолчанию, ``false``. diff --git a/docs/ru/dicts/index.rst b/docs/ru/dicts/index.rst index a8ad75e9cd2..8cd65b643e7 100644 --- a/docs/ru/dicts/index.rst +++ b/docs/ru/dicts/index.rst @@ -7,6 +7,6 @@ Существуют встроенные и подключаемые (внешние) словари. .. toctree:: - :glob: - * + external_dicts + internal_dicts diff --git a/docs/ru/formats/index.rst b/docs/ru/formats/index.rst index 6db2890830f..b7510f79d3b 100644 --- a/docs/ru/formats/index.rst +++ b/docs/ru/formats/index.rst @@ -1,3 +1,5 @@ +.. _formats: + Форматы ======= diff --git a/docs/ru/functions/ext_dict_functions.rst b/docs/ru/functions/ext_dict_functions.rst index 0e27687efe3..963c670c5af 100644 --- a/docs/ru/functions/ext_dict_functions.rst +++ b/docs/ru/functions/ext_dict_functions.rst @@ -1,6 +1,8 @@ +.. _ext_dict_functions: + Функции для работы с внешними словарями --------------------------------------- -Подробнее смотрите в разделе "Внешние словари". +Информация о подключении и настройке внешних словарей смотрите в разделе :ref:`dicts-external_dicts`. dictGetUInt8, dictGetUInt16, dictGetUInt32, dictGetUInt64 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ru/functions/other_functions.rst b/docs/ru/functions/other_functions.rst index 32a9c0a3ed3..b9b284e4293 100644 --- a/docs/ru/functions/other_functions.rst +++ b/docs/ru/functions/other_functions.rst @@ -108,6 +108,8 @@ bar │ 23 │ 400397 │ █████████████▎ │ └────┴────────┴────────────────────┘ +.. _other_functions-transform: + transform ~~~~~~~~~ Преобразовать значение согласно явно указанному отображению одних элементов на другие. diff --git a/docs/ru/operations/server_settings/settings.rst b/docs/ru/operations/server_settings/settings.rst index c99054a18fa..9d7370e895a 100644 --- a/docs/ru/operations/server_settings/settings.rst +++ b/docs/ru/operations/server_settings/settings.rst @@ -98,9 +98,13 @@ default_profile dictionaries_config ------------------- -Конфигурация внешних словарей. +Путь к конфигурации внешних словарей. -Смотрите раздел :ref:`dicts-external_dicts`. +Путь: + * Указывается абсолютным или относительно конфигурационного файла сервера. + * Может содержать wildcard-ы \* и ?. + +Про внешние словари читайте в разделе :ref:`dicts-external_dicts`. **Пример** @@ -116,7 +120,11 @@ dictionaries_lazy_load Отложенная загрузка словарей. -С установленным параметром словари подгружаются не при запуске сервера, а при первом обращении. +Если ``true``, то каждый словарь создаётся при первом использовании. Если словарь не удалось создать, то вызов функции, использующей словарь, сгенерирует исключение. + +Если ``false``, то все словари создаются при старте сервера, и в случае ошибки сервер завершает работу. + +По умолчанию - ``true``. **Пример** From 0d876de370e72b24e2ceca411b7c58ed94973f40 Mon Sep 17 00:00:00 2001 From: BayoNet Date: Mon, 31 Jul 2017 12:17:48 +0300 Subject: [PATCH 006/281] Default `make html` language changed to russian. --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 95802e63d01..67c6263a5cd 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -15,7 +15,7 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = $(SPHINXOPTS) en +ALLSPHINXOPTS = $(SPHINXOPTS) ru # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ru From a0cc54457e9e0f5d82fe01592d3c6cb17b9b3d63 Mon Sep 17 00:00:00 2001 From: Pawel Rog Date: Fri, 28 Jul 2017 16:14:07 +0200 Subject: [PATCH 007/281] Added compression NONE --- dbms/src/IO/CompressedReadBufferBase.cpp | 12 +++++++++-- dbms/src/IO/CompressedStream.h | 4 +++- dbms/src/IO/CompressedWriteBuffer.cpp | 20 +++++++++++++++++++ dbms/src/Storages/CompressionMethodSelector.h | 2 ++ dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- .../Storages/MergeTree/MergeTreeDataPart.cpp | 2 +- .../MergeTree/MergeTreeDataWriter.cpp | 2 +- utils/compressor/main.cpp | 4 ++++ 8 files changed, 42 insertions(+), 6 deletions(-) diff --git a/dbms/src/IO/CompressedReadBufferBase.cpp b/dbms/src/IO/CompressedReadBufferBase.cpp index 77b7907e403..487c4b6d77d 100644 --- a/dbms/src/IO/CompressedReadBufferBase.cpp +++ b/dbms/src/IO/CompressedReadBufferBase.cpp @@ -2,6 +2,7 @@ #include +#include #include #ifdef USE_QUICKLZ @@ -57,7 +58,11 @@ size_t CompressedReadBufferBase::readCompressedData(size_t & size_decompressed, size_t & size_compressed = size_compressed_without_checksum; - if (method < 0x80) + if (method == static_cast (CompressionMethodByte::NONE)) { + size_compressed = unalignedLoad(&own_compressed_buffer[1]); + size_decompressed = unalignedLoad(&own_compressed_buffer[5]); + } + else if (method < 0x80) { #ifdef USE_QUICKLZ size_compressed = qlz_size_compressed(&own_compressed_buffer[0]); @@ -108,7 +113,10 @@ void CompressedReadBufferBase::decompress(char * to, size_t size_decompressed, s UInt8 method = compressed_buffer[0]; /// See CompressedWriteBuffer.h - if (method < 0x80) + if (method == static_cast (CompressionMethodByte::NONE)) { + memcpy(to, &compressed_buffer[COMPRESSED_BLOCK_HEADER_SIZE], size_decompressed); + } + else if (method < 0x80) { #ifdef USE_QUICKLZ if (!qlz_state) diff --git a/dbms/src/IO/CompressedStream.h b/dbms/src/IO/CompressedStream.h index 45b7a0b308c..585a6cb34ad 100644 --- a/dbms/src/IO/CompressedStream.h +++ b/dbms/src/IO/CompressedStream.h @@ -20,6 +20,7 @@ enum class CompressionMethod LZ4 = 1, LZ4HC = 2, /// The format is the same as for LZ4. The difference is only in compression. ZSTD = 3, /// Experimental algorithm: https://github.com/Cyan4973/zstd + NONE = 4, /// No compression }; /** The compressed block format is as follows: @@ -53,7 +54,8 @@ enum class CompressionMethod enum class CompressionMethodByte : uint8_t { - LZ4 = 0x82, + NONE = 0x02, + LZ4 = 0x82, ZSTD = 0x90, }; diff --git a/dbms/src/IO/CompressedWriteBuffer.cpp b/dbms/src/IO/CompressedWriteBuffer.cpp index eb00b400196..429cf825d0d 100644 --- a/dbms/src/IO/CompressedWriteBuffer.cpp +++ b/dbms/src/IO/CompressedWriteBuffer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,25 @@ void CompressedWriteBuffer::nextImpl() compressed_buffer_ptr = &compressed_buffer[0]; break; } + case CompressionMethod::NONE: + { + static constexpr size_t header_size = 1 + sizeof (UInt32) + sizeof (UInt32); + + compressed_size = header_size + uncompressed_size; + UInt32 uncompressed_size_32 = uncompressed_size; + UInt32 compressed_size_32 = compressed_size; + + compressed_buffer.resize(compressed_size); + + compressed_buffer[0] = static_cast (CompressionMethodByte::NONE); + + unalignedStore(&compressed_buffer[1], compressed_size_32); + unalignedStore(&compressed_buffer[5], uncompressed_size_32); + memcpy(&compressed_buffer[9], working_buffer.begin(), uncompressed_size); + + compressed_buffer_ptr = &compressed_buffer[0]; + break; + } default: throw Exception("Unknown compression method", ErrorCodes::UNKNOWN_COMPRESSION_METHOD); } diff --git a/dbms/src/Storages/CompressionMethodSelector.h b/dbms/src/Storages/CompressionMethodSelector.h index 5113a662b16..c762bae1513 100644 --- a/dbms/src/Storages/CompressionMethodSelector.h +++ b/dbms/src/Storages/CompressionMethodSelector.h @@ -51,6 +51,8 @@ private: method = CompressionMethod::LZ4; else if (name == "zstd") method = CompressionMethod::ZSTD; + else if (name == "none") + method = CompressionMethod::NONE; else throw Exception("Unknown compression method " + name, ErrorCodes::UNKNOWN_COMPRESSION_METHOD); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index af1b8256e7f..71001947913 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1027,7 +1027,7 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( false, nullptr, "", false, 0, DBMS_DEFAULT_BUFFER_SIZE, false); ExpressionBlockInputStream in(part_in, expression); - MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, CompressionMethod::LZ4, false); + MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, CompressionMethod::NONE, false); in.readPrefix(); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 1baebb13c86..863cd209632 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -200,7 +200,7 @@ void MergeTreeDataPartChecksums::write(WriteBuffer & to) const { writeString("checksums format version: 4\n", to); - CompressedWriteBuffer out{to, CompressionMethod::LZ4, 1 << 16}; + CompressedWriteBuffer out{to, CompressionMethod::NONE, 1 << 16}; writeVarUInt(files.size(), out); for (const auto & it : files) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index c548ee560ee..f2b1b2228cc 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -138,7 +138,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa } NamesAndTypesList columns = data.getColumnsList().filter(block.getColumnsList().getNames()); - MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, CompressionMethod::LZ4); + MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, CompressionMethod::NONE); out.writePrefix(); out.writeWithPermutation(block, perm_ptr); diff --git a/utils/compressor/main.cpp b/utils/compressor/main.cpp index e244561ebec..18263741d64 100644 --- a/utils/compressor/main.cpp +++ b/utils/compressor/main.cpp @@ -59,6 +59,7 @@ int main(int argc, char ** argv) ("qlz", "use QuickLZ (level 1) instead of LZ4") #endif ("zstd", "use ZSTD instead of LZ4") + ("none", "use no compression instead of LZ4") ("stat", "print block statistics of compressed data") ; @@ -85,6 +86,7 @@ int main(int argc, char ** argv) bool use_lz4hc = options.count("hc"); bool use_zstd = options.count("zstd"); bool stat_mode = options.count("stat"); + bool use_none = options.count("none"); unsigned block_size = options["block-size"].as(); DB::CompressionMethod method = DB::CompressionMethod::LZ4; @@ -95,6 +97,8 @@ int main(int argc, char ** argv) method = DB::CompressionMethod::LZ4HC; else if (use_zstd) method = DB::CompressionMethod::ZSTD; + else if (use_none) + method = DB::CompressionMethod::NONE; DB::ReadBufferFromFileDescriptor rb(STDIN_FILENO); DB::WriteBufferFromFileDescriptor wb(STDOUT_FILENO); From e1ab721d3db6fe6887e20052651dd444328e2c22 Mon Sep 17 00:00:00 2001 From: Pawel Rog Date: Mon, 31 Jul 2017 13:05:49 +0200 Subject: [PATCH 008/281] Use compression method from configs --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 5 ++++- dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp | 6 +++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 71001947913..8b2c006c642 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1026,8 +1026,11 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( *this, part, DEFAULT_MERGE_BLOCK_SIZE, 0, expression->getRequiredColumns(), ranges, false, nullptr, "", false, 0, DBMS_DEFAULT_BUFFER_SIZE, false); + auto compression_method = this->context.chooseCompressionMethod( + this->getTotalActiveSizeInBytes(), + static_cast (this->getTotalCompressedSize()) / this->getTotalActiveSizeInBytes()); ExpressionBlockInputStream in(part_in, expression); - MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, CompressionMethod::NONE, false); + MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, compression_method, false); in.readPrefix(); out.writePrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 863cd209632..1baebb13c86 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -200,7 +200,7 @@ void MergeTreeDataPartChecksums::write(WriteBuffer & to) const { writeString("checksums format version: 4\n", to); - CompressedWriteBuffer out{to, CompressionMethod::NONE, 1 << 16}; + CompressedWriteBuffer out{to, CompressionMethod::LZ4, 1 << 16}; writeVarUInt(files.size(), out); for (const auto & it : files) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index f2b1b2228cc..62b50062252 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -137,8 +137,12 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa ProfileEvents::increment(ProfileEvents::MergeTreeDataWriterBlocksAlreadySorted); } + auto compression_method = data.context.chooseCompressionMethod( + data.getTotalActiveSizeInBytes(), + static_cast (data.getTotalCompressedSize()) / data.getTotalActiveSizeInBytes()); + NamesAndTypesList columns = data.getColumnsList().filter(block.getColumnsList().getNames()); - MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, CompressionMethod::NONE); + MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_method); out.writePrefix(); out.writeWithPermutation(block, perm_ptr); From 3d2ec763ed650ceccb75641fbb1aaca98b89db50 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 31 Jul 2017 20:40:56 +0300 Subject: [PATCH 009/281] Update CompressedReadBufferBase.cpp --- dbms/src/IO/CompressedReadBufferBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/IO/CompressedReadBufferBase.cpp b/dbms/src/IO/CompressedReadBufferBase.cpp index 346b844e0dc..33208f95175 100644 --- a/dbms/src/IO/CompressedReadBufferBase.cpp +++ b/dbms/src/IO/CompressedReadBufferBase.cpp @@ -59,7 +59,7 @@ size_t CompressedReadBufferBase::readCompressedData(size_t & size_decompressed, size_compressed = unalignedLoad(&own_compressed_buffer[1]); size_decompressed = unalignedLoad(&own_compressed_buffer[5]); } - else if (method == static_cast (CompressionMethodByte::NONE)) + else if (method == static_cast(CompressionMethodByte::NONE)) { size_compressed = unalignedLoad(&own_compressed_buffer[1]); size_decompressed = unalignedLoad(&own_compressed_buffer[5]); From 50244880ccf2028a734c26e614fcf80dda967e8b Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 31 Jul 2017 20:42:23 +0300 Subject: [PATCH 010/281] Update CompressedReadBufferBase.cpp --- dbms/src/IO/CompressedReadBufferBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/IO/CompressedReadBufferBase.cpp b/dbms/src/IO/CompressedReadBufferBase.cpp index 33208f95175..abcfc35702b 100644 --- a/dbms/src/IO/CompressedReadBufferBase.cpp +++ b/dbms/src/IO/CompressedReadBufferBase.cpp @@ -115,7 +115,7 @@ void CompressedReadBufferBase::decompress(char * to, size_t size_decompressed, s if (ZSTD_isError(res)) throw Exception("Cannot ZSTD_decompress: " + std::string(ZSTD_getErrorName(res)), ErrorCodes::CANNOT_DECOMPRESS); } - else if (method == static_cast (CompressionMethodByte::NONE)) + else if (method == static_cast(CompressionMethodByte::NONE)) { memcpy(to, &compressed_buffer[COMPRESSED_BLOCK_HEADER_SIZE], size_decompressed); } From fdb7e080bed2ddd0f1a092c37843e4cd0d1947ec Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 31 Jul 2017 20:43:33 +0300 Subject: [PATCH 011/281] Update CompressedWriteBuffer.cpp --- dbms/src/IO/CompressedWriteBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/IO/CompressedWriteBuffer.cpp b/dbms/src/IO/CompressedWriteBuffer.cpp index 93eee532754..4575278b12c 100644 --- a/dbms/src/IO/CompressedWriteBuffer.cpp +++ b/dbms/src/IO/CompressedWriteBuffer.cpp @@ -109,7 +109,7 @@ void CompressedWriteBuffer::nextImpl() compressed_buffer.resize(compressed_size); - compressed_buffer[0] = static_cast (CompressionMethodByte::NONE); + compressed_buffer[0] = static_cast(CompressionMethodByte::NONE); unalignedStore(&compressed_buffer[1], compressed_size_32); unalignedStore(&compressed_buffer[5], uncompressed_size_32); From 4877aa394c30932114dc370759096f8bd1d85d87 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 31 Jul 2017 20:44:41 +0300 Subject: [PATCH 012/281] Update MergeTreeData.cpp --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 5dbf55236ed..0c22298dd1d 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1032,7 +1032,7 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( auto compression_method = this->context.chooseCompressionMethod( this->getTotalActiveSizeInBytes(), - static_cast (this->getTotalCompressedSize()) / this->getTotalActiveSizeInBytes()); + static_cast(this->getTotalCompressedSize()) / this->getTotalActiveSizeInBytes()); ExpressionBlockInputStream in(part_in, expression); MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, compression_method, false); in.readPrefix(); From d174ebc5c902f14634271963ba62a71de9369f54 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Mon, 31 Jul 2017 20:44:58 +0300 Subject: [PATCH 013/281] Update MergeTreeDataWriter.cpp --- dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index 2ae318468c2..2b3d869967e 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -148,7 +148,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa auto compression_method = data.context.chooseCompressionMethod( data.getTotalActiveSizeInBytes(), - static_cast (data.getTotalCompressedSize()) / data.getTotalActiveSizeInBytes()); + static_cast(data.getTotalCompressedSize()) / data.getTotalActiveSizeInBytes()); NamesAndTypesList columns = data.getColumnsList().filter(block.getColumnsList().getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_method); From 6578fb264563fce36081928860cd3edeb52651ce Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 00:39:24 +0300 Subject: [PATCH 014/281] Fixed error [#CLICKHOUSE-3191]. --- dbms/src/Columns/ColumnAggregateFunction.cpp | 9 +- dbms/src/Columns/ColumnConst.cpp | 14 +- dbms/src/Common/Exception.cpp | 9 +- dbms/src/Common/FileChecker.cpp | 23 +- dbms/src/Common/formatReadable.cpp | 15 +- dbms/src/Common/tests/hash_table.cpp | 27 +- dbms/src/Common/tests/small_table.cpp | 27 +- dbms/src/Core/Block.cpp | 38 +- dbms/src/Core/ColumnWithTypeAndName.cpp | 25 +- dbms/src/Core/Field.cpp | 2 - dbms/src/Core/FieldVisitors.cpp | 53 ++- dbms/src/Core/NamesAndTypes.cpp | 10 +- dbms/src/Core/SortDescription.cpp | 13 +- dbms/src/Core/tests/string_ref_hash.cpp | 1 - dbms/src/DataStreams/CSVRowInputStream.cpp | 11 +- dbms/src/DataStreams/JSONRowOutputStream.cpp | 10 +- .../DataStreams/PrettyBlockOutputStream.cpp | 1 + dbms/src/DataStreams/TSKVRowOutputStream.cpp | 12 +- .../TabSeparatedRowInputStream.cpp | 12 +- .../DataTypes/DataTypeAggregateFunction.cpp | 5 +- dbms/src/DataTypes/DataTypeArray.cpp | 10 +- dbms/src/DataTypes/DataTypeEnum.cpp | 34 +- dbms/src/DataTypes/DataTypeNested.cpp | 6 +- dbms/src/Databases/DatabaseCloud.cpp | 27 +- .../src/Dictionaries/ExternalQueryBuilder.cpp | 384 +++++++++--------- .../Dictionaries/MySQLDictionarySource.cpp | 11 +- dbms/src/Functions/Conditional/ArgsInfo.cpp | 8 +- .../Functions/Conditional/getArrayType.cpp | 8 +- dbms/src/Functions/FunctionsConversion.cpp | 29 +- dbms/src/Functions/FunctionsFormatting.h | 1 - dbms/src/IO/ReadHelpers.cpp | 38 +- .../IO/WriteBufferFromHTTPServerResponse.cpp | 9 +- dbms/src/IO/WriteBufferFromString.h | 19 + dbms/src/IO/WriteHelpers.h | 11 +- .../gtest_cascade_and_memory_write_buffer.cpp | 1 - dbms/src/IO/tests/parse_int_perf.cpp | 5 - dbms/src/Interpreters/Compiler.cpp | 11 +- dbms/src/Interpreters/DDLWorker.cpp | 17 +- .../Interpreters/InterpreterCreateQuery.cpp | 1 - dbms/src/Interpreters/InterserverIOHandler.h | 6 +- dbms/src/Parsers/ASTFunction.cpp | 6 +- dbms/src/Parsers/IAST.cpp | 11 +- dbms/src/Parsers/parseQuery.cpp | 49 +-- dbms/src/Server/Client.cpp | 1 - dbms/src/Server/HTTPHandler.cpp | 1 - dbms/src/Server/LocalServer.cpp | 6 +- dbms/src/Storages/ColumnsDescription.cpp | 5 +- .../Storages/MergeTree/ActiveDataPartSet.cpp | 30 +- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 24 +- .../Storages/MergeTree/MergeTreeDataPart.cpp | 9 +- .../MergeTree/ReplicatedMergeTreeAddress.h | 9 +- .../MergeTree/ReplicatedMergeTreeLogEntry.cpp | 10 +- .../ReplicatedMergeTreeQuorumEntry.h | 9 +- dbms/src/Storages/MergeTree/ReshardingJob.cpp | 6 +- .../Storages/MergeTree/ReshardingWorker.cpp | 65 ++- .../Storages/StorageReplicatedMergeTree.cpp | 5 +- 56 files changed, 516 insertions(+), 683 deletions(-) diff --git a/dbms/src/Columns/ColumnAggregateFunction.cpp b/dbms/src/Columns/ColumnAggregateFunction.cpp index b54d68eefb1..57a83a1fda8 100644 --- a/dbms/src/Columns/ColumnAggregateFunction.cpp +++ b/dbms/src/Columns/ColumnAggregateFunction.cpp @@ -165,12 +165,9 @@ ColumnPtr ColumnAggregateFunction::permute(const Permutation & perm, size_t limi /// Is required to support operations with Set void ColumnAggregateFunction::updateHashWithValue(size_t n, SipHash & hash) const { - String buf; - { - WriteBufferFromString wbuf(buf); - func->serialize(getData()[n], wbuf); - } - hash.update(buf.c_str(), buf.size()); + WriteBufferFromOwnString wbuf; + func->serialize(getData()[n], wbuf); + hash.update(wbuf.str().c_str(), wbuf.str().size()); } /// NOTE: Highly overestimates size of a column if it was produced in AggregatingBlockInputStream (it contains size of other columns) diff --git a/dbms/src/Columns/ColumnConst.cpp b/dbms/src/Columns/ColumnConst.cpp index caa05fd759c..a28dcd5b956 100644 --- a/dbms/src/Columns/ColumnConst.cpp +++ b/dbms/src/Columns/ColumnConst.cpp @@ -33,16 +33,12 @@ ColumnPtr ColumnConst::convertToFullColumn() const String ColumnConst::dump() const { - String res; - WriteBufferFromString out(res); + WriteBufferFromOwnString out; + out << "ColumnConst, size: " << s << ", nested column: " << data->getName() << ", nested size: " << data->size(); + if (data->size()) + out << ", value: " << applyVisitor(FieldVisitorDump(), (*data)[0]); - { - out << "ColumnConst, size: " << s << ", nested column: " << data->getName() << ", nested size: " << data->size(); - if (data->size()) - out << ", value: " << applyVisitor(FieldVisitorDump(), (*data)[0]); - } - - return res; + return out.str(); } } diff --git a/dbms/src/Common/Exception.cpp b/dbms/src/Common/Exception.cpp index 6301e2b9b30..afca8873335 100644 --- a/dbms/src/Common/Exception.cpp +++ b/dbms/src/Common/Exception.cpp @@ -231,12 +231,9 @@ std::string getExceptionMessage(std::exception_ptr e, bool with_stacktrace) std::string ExecutionStatus::serializeText() const { - std::string res; - { - WriteBufferFromString wb(res); - wb << code << "\n" << escape << message; - } - return res; + WriteBufferFromOwnString wb; + wb << code << "\n" << escape << message; + return wb.str(); } void ExecutionStatus::deserializeText(const std::string & data) diff --git a/dbms/src/Common/FileChecker.cpp b/dbms/src/Common/FileChecker.cpp index 66e315fd754..e3b1db745ca 100644 --- a/dbms/src/Common/FileChecker.cpp +++ b/dbms/src/Common/FileChecker.cpp @@ -131,21 +131,18 @@ void FileChecker::load(Map & map) const if (!Poco::File(files_info_path).exists()) return; - std::string content; - { - ReadBufferFromFile in(files_info_path); - WriteBufferFromString out(content); + ReadBufferFromFile in(files_info_path); + WriteBufferFromOwnString out; - /// The JSON library does not support whitespace. We delete them. Inefficient. - while (!in.eof()) - { - char c; - readChar(c, in); - if (!isspace(c)) - writeChar(c, out); - } + /// The JSON library does not support whitespace. We delete them. Inefficient. + while (!in.eof()) + { + char c; + readChar(c, in); + if (!isspace(c)) + writeChar(c, out); } - JSON json(content); + JSON json(out.str()); JSON files = json["yandex"]; for (const auto & name_value : files) diff --git a/dbms/src/Common/formatReadable.cpp b/dbms/src/Common/formatReadable.cpp index f78fd9ce9f5..1741197344f 100644 --- a/dbms/src/Common/formatReadable.cpp +++ b/dbms/src/Common/formatReadable.cpp @@ -35,10 +35,9 @@ void formatReadableSizeWithBinarySuffix(double value, DB::WriteBuffer & out, int std::string formatReadableSizeWithBinarySuffix(double value, int precision) { - std::string res; - DB::WriteBufferFromString out(res); + DB::WriteBufferFromOwnString out; formatReadableSizeWithBinarySuffix(value, out, precision); - return res; + return out.str(); } @@ -50,10 +49,9 @@ void formatReadableSizeWithDecimalSuffix(double value, DB::WriteBuffer & out, in std::string formatReadableSizeWithDecimalSuffix(double value, int precision) { - std::string res; - DB::WriteBufferFromString out(res); + DB::WriteBufferFromOwnString out; formatReadableSizeWithDecimalSuffix(value, out, precision); - return res; + return out.str(); } @@ -65,8 +63,7 @@ void formatReadableQuantity(double value, DB::WriteBuffer & out, int precision) std::string formatReadableQuantity(double value, int precision) { - std::string res; - DB::WriteBufferFromString out(res); + DB::WriteBufferFromOwnString out; formatReadableQuantity(value, out, precision); - return res; + return out.str(); } diff --git a/dbms/src/Common/tests/hash_table.cpp b/dbms/src/Common/tests/hash_table.cpp index f99a9d72ab3..5093b9ebc48 100644 --- a/dbms/src/Common/tests/hash_table.cpp +++ b/dbms/src/Common/tests/hash_table.cpp @@ -29,13 +29,10 @@ int main(int argc, char ** argv) for (auto x : cont) std::cerr << x << std::endl; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.writeText(wb); - } + DB::WriteBufferFromOwnString wb; + cont.writeText(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } { @@ -48,13 +45,10 @@ int main(int argc, char ** argv) for (auto x : cont) std::cerr << x.first << " -> " << x.second << std::endl; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.writeText(wb); - } + DB::WriteBufferFromOwnString wb; + cont.writeText(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } { @@ -63,13 +57,10 @@ int main(int argc, char ** argv) DB::UInt128TrivialHash>; Cont cont; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.write(wb); - } + DB::WriteBufferFromOwnString wb; + cont.write(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } return 0; diff --git a/dbms/src/Common/tests/small_table.cpp b/dbms/src/Common/tests/small_table.cpp index b542f8d60f2..d11570f6d0f 100644 --- a/dbms/src/Common/tests/small_table.cpp +++ b/dbms/src/Common/tests/small_table.cpp @@ -28,13 +28,10 @@ int main(int argc, char ** argv) for (auto x : cont) std::cerr << x << std::endl; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.writeText(wb); - } + DB::WriteBufferFromOwnString wb; + cont.writeText(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } { @@ -47,26 +44,20 @@ int main(int argc, char ** argv) for (auto x : cont) std::cerr << x.first << " -> " << x.second << std::endl; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.writeText(wb); - } + DB::WriteBufferFromOwnString wb; + cont.writeText(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str(); << std::endl; } { using Cont = SmallSet; Cont cont; - std::string dump; - { - DB::WriteBufferFromString wb(dump); - cont.write(wb); - } + DB::WriteBufferFromOwnString wb; + cont.write(wb); - std::cerr << "dump: " << dump << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } return 0; diff --git a/dbms/src/Core/Block.cpp b/dbms/src/Core/Block.cpp index a1ef634905d..31a3bccb7dd 100644 --- a/dbms/src/Core/Block.cpp +++ b/dbms/src/Core/Block.cpp @@ -317,39 +317,33 @@ size_t Block::allocatedBytes() const std::string Block::dumpNames() const { - std::string res; + WriteBufferFromOwnString out; + for (auto it = data.begin(); it != data.end(); ++it) { - WriteBufferFromString out(res); - for (auto it = data.begin(); it != data.end(); ++it) - { - if (it != data.begin()) - out << ", "; - out << it->name; - } + if (it != data.begin()) + out << ", "; + out << it->name; } - return res; + return out.str(); } std::string Block::dumpStructure() const { - std::string res; + WriteBufferFromOwnString out; + for (auto it = data.begin(); it != data.end(); ++it) { - WriteBufferFromString out(res); - for (auto it = data.begin(); it != data.end(); ++it) - { - if (it != data.begin()) - out << ", "; + if (it != data.begin()) + out << ", "; - out << it->name << ' ' << it->type->getName(); + out << it->name << ' ' << it->type->getName(); - if (it->column) - out << ' ' << it->column->getName() << ' ' << it->column->size(); - else - out << " nullptr"; - } + if (it->column) + out << ' ' << it->column->getName() << ' ' << it->column->size(); + else + out << " nullptr"; } - return res; + return out.str(); } diff --git a/dbms/src/Core/ColumnWithTypeAndName.cpp b/dbms/src/Core/ColumnWithTypeAndName.cpp index 9e0f31e43c3..045ba60dbff 100644 --- a/dbms/src/Core/ColumnWithTypeAndName.cpp +++ b/dbms/src/Core/ColumnWithTypeAndName.cpp @@ -29,22 +29,19 @@ bool ColumnWithTypeAndName::operator== (const ColumnWithTypeAndName & other) con String ColumnWithTypeAndName::prettyPrint() const { - String res; + WriteBufferFromOwnString out; + writeString(name, out); + if (type) { - WriteBufferFromString out(res); - writeString(name, out); - if (type) - { - writeChar(' ', out); - writeString(type->getName(), out); - } - if (column) - { - writeChar(' ', out); - writeString(column->getName(), out); - } + writeChar(' ', out); + writeString(type->getName(), out); } - return res; + if (column) + { + writeChar(' ', out); + writeString(column->getName(), out); + } + return out.str(); } } diff --git a/dbms/src/Core/Field.cpp b/dbms/src/Core/Field.cpp index 1e54768d63c..74bc9e389a5 100644 --- a/dbms/src/Core/Field.cpp +++ b/dbms/src/Core/Field.cpp @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include diff --git a/dbms/src/Core/FieldVisitors.cpp b/dbms/src/Core/FieldVisitors.cpp index 47c9ae8cf69..6589b8a76eb 100644 --- a/dbms/src/Core/FieldVisitors.cpp +++ b/dbms/src/Core/FieldVisitors.cpp @@ -15,41 +15,37 @@ namespace DB template static inline String formatQuoted(T x) { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; writeQuoted(x, wb); - return res; + return wb.str(); } template static inline String formatQuotedWithPrefix(T x, const char * prefix) { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; wb.write(prefix, strlen(prefix)); writeQuoted(x, wb); - return res; + return wb.str(); } -String FieldVisitorDump::operator() (const Null & x) const { return "NULL"; } -String FieldVisitorDump::operator() (const UInt64 & x) const { return formatQuotedWithPrefix(x, "UInt64_"); } -String FieldVisitorDump::operator() (const Int64 & x) const { return formatQuotedWithPrefix(x, "Int64_"); } -String FieldVisitorDump::operator() (const Float64 & x) const { return formatQuotedWithPrefix(x, "Float64_"); } +String FieldVisitorDump::operator() (const Null & x) const { return "NULL"; } +String FieldVisitorDump::operator() (const UInt64 & x) const { return formatQuotedWithPrefix(x, "UInt64_"); } +String FieldVisitorDump::operator() (const Int64 & x) const { return formatQuotedWithPrefix(x, "Int64_"); } +String FieldVisitorDump::operator() (const Float64 & x) const { return formatQuotedWithPrefix(x, "Float64_"); } String FieldVisitorDump::operator() (const String & x) const { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; writeQuoted(x, wb); - return res; + return wb.str(); } String FieldVisitorDump::operator() (const Array & x) const { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; wb.write("Array_[", 7); for (auto it = x.begin(); it != x.end(); ++it) @@ -60,14 +56,13 @@ String FieldVisitorDump::operator() (const Array & x) const } writeChar(']', wb); - return res; + return wb.str(); } String FieldVisitorDump::operator() (const Tuple & x_def) const { auto & x = x_def.t; - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; wb.write("Tuple_(", 7); for (auto it = x.begin(); it != x.end(); ++it) @@ -78,7 +73,7 @@ String FieldVisitorDump::operator() (const Tuple & x_def) const } writeChar(')', wb); - return res; + return wb.str(); } @@ -104,17 +99,16 @@ static String formatFloat(const Float64 x) } -String FieldVisitorToString::operator() (const Null & x) const { return "NULL"; } -String FieldVisitorToString::operator() (const UInt64 & x) const { return formatQuoted(x); } -String FieldVisitorToString::operator() (const Int64 & x) const { return formatQuoted(x); } -String FieldVisitorToString::operator() (const Float64 & x) const { return formatFloat(x); } -String FieldVisitorToString::operator() (const String & x) const { return formatQuoted(x); } +String FieldVisitorToString::operator() (const Null & x) const { return "NULL"; } +String FieldVisitorToString::operator() (const UInt64 & x) const { return formatQuoted(x); } +String FieldVisitorToString::operator() (const Int64 & x) const { return formatQuoted(x); } +String FieldVisitorToString::operator() (const Float64 & x) const { return formatFloat(x); } +String FieldVisitorToString::operator() (const String & x) const { return formatQuoted(x); } String FieldVisitorToString::operator() (const Array & x) const { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; writeChar('[', wb); for (Array::const_iterator it = x.begin(); it != x.end(); ++it) @@ -125,14 +119,13 @@ String FieldVisitorToString::operator() (const Array & x) const } writeChar(']', wb); - return res; + return wb.str(); } String FieldVisitorToString::operator() (const Tuple & x_def) const { auto & x = x_def.t; - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; writeChar('(', wb); for (auto it = x.begin(); it != x.end(); ++it) @@ -143,7 +136,7 @@ String FieldVisitorToString::operator() (const Tuple & x_def) const } writeChar(')', wb); - return res; + return wb.str(); } diff --git a/dbms/src/Core/NamesAndTypes.cpp b/dbms/src/Core/NamesAndTypes.cpp index 8a8f1078e57..1baa3fbee25 100644 --- a/dbms/src/Core/NamesAndTypes.cpp +++ b/dbms/src/Core/NamesAndTypes.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -53,12 +54,9 @@ void NamesAndTypesList::writeText(WriteBuffer & buf) const String NamesAndTypesList::toString() const { - String s; - { - WriteBufferFromString out(s); - writeText(out); - } - return s; + WriteBufferFromOwnString out; + writeText(out); + return out.str(); } NamesAndTypesList NamesAndTypesList::parse(const String & s) diff --git a/dbms/src/Core/SortDescription.cpp b/dbms/src/Core/SortDescription.cpp index f8e69cbd96c..2a23679d39e 100644 --- a/dbms/src/Core/SortDescription.cpp +++ b/dbms/src/Core/SortDescription.cpp @@ -10,14 +10,11 @@ namespace DB std::string SortColumnDescription::getID() const { - std::string res; - { - WriteBufferFromString out(res); - out << column_name << ", " << column_number << ", " << direction << ", " << nulls_direction; - if (collator) - out << ", collation locale: " << collator->getLocale(); - } - return res; + WriteBufferFromOwnString out; + out << column_name << ", " << column_number << ", " << direction << ", " << nulls_direction; + if (collator) + out << ", collation locale: " << collator->getLocale(); + return out.str(); } } diff --git a/dbms/src/Core/tests/string_ref_hash.cpp b/dbms/src/Core/tests/string_ref_hash.cpp index cca25bd6996..786d103600a 100644 --- a/dbms/src/Core/tests/string_ref_hash.cpp +++ b/dbms/src/Core/tests/string_ref_hash.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include diff --git a/dbms/src/DataStreams/CSVRowInputStream.cpp b/dbms/src/DataStreams/CSVRowInputStream.cpp index efdfc8a9ca7..ae4397fb3b7 100644 --- a/dbms/src/DataStreams/CSVRowInputStream.cpp +++ b/dbms/src/DataStreams/CSVRowInputStream.cpp @@ -140,8 +140,7 @@ String CSVRowInputStream::getDiagnosticInfo() if (istr.eof()) /// Buffer has gone, cannot extract information about what has been parsed. return {}; - String res; - WriteBufferFromString out(res); + WriteBufferFromOwnString out; Block block = sample.cloneEmpty(); /// It is possible to display detailed diagnostics only if the last and next to last rows are still in the read buffer. @@ -149,7 +148,7 @@ String CSVRowInputStream::getDiagnosticInfo() if (bytes_read_at_start_of_buffer != bytes_read_at_start_of_buffer_on_prev_row) { out << "Could not print diagnostic info because two last rows aren't in buffer (rare case)\n"; - return res; + return out.str(); } size_t max_length_of_column_name = 0; @@ -170,14 +169,14 @@ String CSVRowInputStream::getDiagnosticInfo() out << "\nRow " << (row_num - 1) << ":\n"; if (!parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name)) - return res; + return out.str(); } else { if (!pos_of_current_row) { out << "Could not print diagnostic info because parsing of data hasn't started.\n"; - return res; + return out.str(); } istr.position() = pos_of_current_row; @@ -187,7 +186,7 @@ String CSVRowInputStream::getDiagnosticInfo() parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name); out << "\n"; - return res; + return out.str(); } diff --git a/dbms/src/DataStreams/JSONRowOutputStream.cpp b/dbms/src/DataStreams/JSONRowOutputStream.cpp index 98b5a9eb111..5d2f78e4aa8 100644 --- a/dbms/src/DataStreams/JSONRowOutputStream.cpp +++ b/dbms/src/DataStreams/JSONRowOutputStream.cpp @@ -18,12 +18,10 @@ JSONRowOutputStream::JSONRowOutputStream(WriteBuffer & ostr_, const Block & samp if (!sample_.getByPosition(i).type->isNumeric()) have_non_numeric_columns = true; - String field_name_quoted; - { - WriteBufferFromString out(field_name_quoted); - writeJSONString(fields[i].name, out); - } - fields[i].name = field_name_quoted; + WriteBufferFromOwnString out; + writeJSONString(fields[i].name, out); + + fields[i].name = out.str(); } if (have_non_numeric_columns) diff --git a/dbms/src/DataStreams/PrettyBlockOutputStream.cpp b/dbms/src/DataStreams/PrettyBlockOutputStream.cpp index 20376557b6d..1c75cf227f8 100644 --- a/dbms/src/DataStreams/PrettyBlockOutputStream.cpp +++ b/dbms/src/DataStreams/PrettyBlockOutputStream.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include diff --git a/dbms/src/DataStreams/TSKVRowOutputStream.cpp b/dbms/src/DataStreams/TSKVRowOutputStream.cpp index 43a27d4dddc..87e2b166208 100644 --- a/dbms/src/DataStreams/TSKVRowOutputStream.cpp +++ b/dbms/src/DataStreams/TSKVRowOutputStream.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -13,13 +14,10 @@ TSKVRowOutputStream::TSKVRowOutputStream(WriteBuffer & ostr_, const Block & samp for (auto & field : fields) { - String prepared_field_name; - { - WriteBufferFromString wb(prepared_field_name); - writeAnyEscapedString<'='>(field.name.data(), field.name.data() + field.name.size(), wb); - writeCString("=", wb); - } - field.name = prepared_field_name; + WriteBufferFromOwnString wb; + writeAnyEscapedString<'='>(field.name.data(), field.name.data() + field.name.size(), wb); + writeCString("=", wb); + field.name = wb.str(); } } diff --git a/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp b/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp index 513c9ca2069..fdbed86c550 100644 --- a/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp +++ b/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -109,8 +110,7 @@ String TabSeparatedRowInputStream::getDiagnosticInfo() if (istr.eof()) /// Buffer has gone, cannot extract information about what has been parsed. return {}; - String res; - WriteBufferFromString out(res); + WriteBufferFromOwnString out; Block block = sample.cloneEmpty(); /// It is possible to display detailed diagnostics only if the last and next to last lines are still in the read buffer. @@ -118,7 +118,7 @@ String TabSeparatedRowInputStream::getDiagnosticInfo() if (bytes_read_at_start_of_buffer != bytes_read_at_start_of_buffer_on_prev_row) { out << "Could not print diagnostic info because two last rows aren't in buffer (rare case)\n"; - return res; + return out.str(); } size_t max_length_of_column_name = 0; @@ -139,14 +139,14 @@ String TabSeparatedRowInputStream::getDiagnosticInfo() out << "\nRow " << (row_num - 1) << ":\n"; if (!parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name)) - return res; + return out.str(); } else { if (!pos_of_current_row) { out << "Could not print diagnostic info because parsing of data hasn't started.\n"; - return res; + return out.str(); } istr.position() = pos_of_current_row; @@ -156,7 +156,7 @@ String TabSeparatedRowInputStream::getDiagnosticInfo() parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name); out << "\n"; - return res; + return out.str(); } diff --git a/dbms/src/DataTypes/DataTypeAggregateFunction.cpp b/dbms/src/DataTypes/DataTypeAggregateFunction.cpp index d8c8057b348..5da0fd620a0 100644 --- a/dbms/src/DataTypes/DataTypeAggregateFunction.cpp +++ b/dbms/src/DataTypes/DataTypeAggregateFunction.cpp @@ -146,10 +146,9 @@ void DataTypeAggregateFunction::deserializeBinaryBulk(IColumn & column, ReadBuff static String serializeToString(const AggregateFunctionPtr & function, const IColumn & column, size_t row_num) { - String res; - WriteBufferFromString buffer(res); + WriteBufferFromOwnString buffer; function.get()->serialize(static_cast(column).getData()[row_num], buffer); - return res; + return buffer.str(); } static void deserializeFromString(const AggregateFunctionPtr & function, IColumn & column, const String & s) diff --git a/dbms/src/DataTypes/DataTypeArray.cpp b/dbms/src/DataTypes/DataTypeArray.cpp index 06224e59708..a73f31787be 100644 --- a/dbms/src/DataTypes/DataTypeArray.cpp +++ b/dbms/src/DataTypes/DataTypeArray.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -364,12 +365,9 @@ void DataTypeArray::serializeTextXML(const IColumn & column, size_t row_num, Wri void DataTypeArray::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr) const { /// There is no good way to serialize an array in CSV. Therefore, we serialize it into a string, and then write the resulting string in CSV. - String s; - { - WriteBufferFromString wb(s); - serializeText(column, row_num, wb); - } - writeCSV(s, ostr); + WriteBufferFromOwnString wb; + serializeText(column, row_num, wb); + writeCSV(wb.str(), ostr); } diff --git a/dbms/src/DataTypes/DataTypeEnum.cpp b/dbms/src/DataTypes/DataTypeEnum.cpp index 0dd97254b47..a4a5b5b3924 100644 --- a/dbms/src/DataTypes/DataTypeEnum.cpp +++ b/dbms/src/DataTypes/DataTypeEnum.cpp @@ -36,31 +36,27 @@ const char * DataTypeEnum::getFamilyName() const template std::string DataTypeEnum::generateName(const Values & values) { - std::string name; + WriteBufferFromOwnString out; + writeString(EnumName::value, out); + writeChar('(', out); + + auto first = true; + for (const auto & name_and_value : values) { - WriteBufferFromString out{name}; + if (!first) + writeString(", ", out); - writeString(EnumName::value, out); - writeChar('(', out); + first = false; - auto first = true; - for (const auto & name_and_value : values) - { - if (!first) - writeString(", ", out); - - first = false; - - writeQuotedString(name_and_value.first, out); - writeString(" = ", out); - writeText(name_and_value.second, out); - } - - writeChar(')', out); + writeQuotedString(name_and_value.first, out); + writeString(" = ", out); + writeText(name_and_value.second, out); } - return name; + writeChar(')', out); + + return out.str(); } template diff --git a/dbms/src/DataTypes/DataTypeNested.cpp b/dbms/src/DataTypes/DataTypeNested.cpp index 06320329a3c..bf81432198b 100644 --- a/dbms/src/DataTypes/DataTypeNested.cpp +++ b/dbms/src/DataTypes/DataTypeNested.cpp @@ -56,8 +56,7 @@ std::string DataTypeNested::extractNestedColumnName(const std::string & nested_n std::string DataTypeNested::getName() const { - std::string res; - WriteBufferFromString out(res); + WriteBufferFromOwnString out; writeCString("Nested(", out); @@ -71,8 +70,7 @@ std::string DataTypeNested::getName() const } writeChar(')', out); - - return res; + return out.str(); } diff --git a/dbms/src/Databases/DatabaseCloud.cpp b/dbms/src/Databases/DatabaseCloud.cpp index 4f0351e2ac6..62c7914b0b2 100644 --- a/dbms/src/Databases/DatabaseCloud.cpp +++ b/dbms/src/Databases/DatabaseCloud.cpp @@ -115,12 +115,9 @@ Hash DatabaseCloud::getTableHash(const String & table_name) const String DatabaseCloud::getNameOfNodeWithTables(const String & table_name) const { Hash hash = getTableHash(table_name); - String res; - { - WriteBufferFromString out(res); - writeText(hash.first % TABLE_TO_NODE_DIVISOR, out); - } - return res; + WriteBufferFromOwnString out; + writeText(hash.first % TABLE_TO_NODE_DIVISOR, out); + return out.str(); } @@ -187,12 +184,9 @@ struct TableSet String toString() const { - String res; - { - WriteBufferFromString out(res); - write(out); - } - return res; + WriteBufferFromOwnString out; + write(out); + return out.str(); } void write(WriteBuffer & buf) const @@ -241,12 +235,9 @@ struct LocalTableSet String toString() const { - String res; - { - WriteBufferFromString out(res); - write(out); - } - return res; + WriteBufferFromOwnString out; + write(out); + return out.str(); } void write(WriteBuffer & buf) const diff --git a/dbms/src/Dictionaries/ExternalQueryBuilder.cpp b/dbms/src/Dictionaries/ExternalQueryBuilder.cpp index 3ee27bae44c..862621327fe 100644 --- a/dbms/src/Dictionaries/ExternalQueryBuilder.cpp +++ b/dbms/src/Dictionaries/ExternalQueryBuilder.cpp @@ -49,110 +49,11 @@ void ExternalQueryBuilder::writeQuoted(const std::string & s, WriteBuffer & out) std::string ExternalQueryBuilder::composeLoadAllQuery() const { - std::string query; + WriteBufferFromOwnString out; + writeString("SELECT ", out); + if (dict_struct.id) { - WriteBufferFromString out{query}; - writeString("SELECT ", out); - - if (dict_struct.id) - { - if (!dict_struct.id.value().expression.empty()) - { - writeParenthesisedString(dict_struct.id.value().expression, out); - writeString(" AS ", out); - } - - writeQuoted(dict_struct.id.value().name, out); - - if (dict_struct.range_min && dict_struct.range_max) - { - writeString(", ", out); - - if (!dict_struct.range_min.value().expression.empty()) - { - writeParenthesisedString(dict_struct.range_min.value().expression, out); - writeString(" AS ", out); - } - - writeQuoted(dict_struct.range_min.value().name, out); - - writeString(", ", out); - - if (!dict_struct.range_max.value().expression.empty()) - { - writeParenthesisedString(dict_struct.range_max.value().expression, out); - writeString(" AS ", out); - } - - writeQuoted(dict_struct.range_max.value().name, out); - } - } - else if (dict_struct.key) - { - auto first = true; - for (const auto & key : *dict_struct.key) - { - if (!first) - writeString(", ", out); - - first = false; - - if (!key.expression.empty()) - { - writeParenthesisedString(key.expression, out); - writeString(" AS ", out); - } - - writeQuoted(key.name, out); - } - } - - for (const auto & attr : dict_struct.attributes) - { - writeString(", ", out); - - if (!attr.expression.empty()) - { - writeParenthesisedString(attr.expression, out); - writeString(" AS ", out); - } - - writeQuoted(attr.name, out); - } - - writeString(" FROM ", out); - if (!db.empty()) - { - writeQuoted(db, out); - writeChar('.', out); - } - writeQuoted(table, out); - - if (!where.empty()) - { - writeString(" WHERE ", out); - writeString(where, out); - } - - writeChar(';', out); - } - - return query; -} - - -std::string ExternalQueryBuilder::composeLoadIdsQuery(const std::vector & ids) -{ - if (!dict_struct.id) - throw Exception{"Simple key required for method", ErrorCodes::UNSUPPORTED_METHOD}; - - std::string query; - - { - WriteBufferFromString out{query}; - writeString("SELECT ", out); - if (!dict_struct.id.value().expression.empty()) { writeParenthesisedString(dict_struct.id.value().expression, out); @@ -161,52 +62,143 @@ std::string ExternalQueryBuilder::composeLoadIdsQuery(const std::vector writeQuoted(dict_struct.id.value().name, out); - for (const auto & attr : dict_struct.attributes) + if (dict_struct.range_min && dict_struct.range_max) { writeString(", ", out); - if (!attr.expression.empty()) + if (!dict_struct.range_min.value().expression.empty()) { - writeParenthesisedString(attr.expression, out); + writeParenthesisedString(dict_struct.range_min.value().expression, out); writeString(" AS ", out); } - writeQuoted(attr.name, out); + writeQuoted(dict_struct.range_min.value().name, out); + + writeString(", ", out); + + if (!dict_struct.range_max.value().expression.empty()) + { + writeParenthesisedString(dict_struct.range_max.value().expression, out); + writeString(" AS ", out); + } + + writeQuoted(dict_struct.range_max.value().name, out); } - - writeString(" FROM ", out); - if (!db.empty()) - { - writeQuoted(db, out); - writeChar('.', out); - } - writeQuoted(table, out); - - writeString(" WHERE ", out); - - if (!where.empty()) - { - writeString(where, out); - writeString(" AND ", out); - } - - writeQuoted(dict_struct.id.value().name, out); - writeString(" IN (", out); - + } + else if (dict_struct.key) + { auto first = true; - for (const auto id : ids) + for (const auto & key : *dict_struct.key) { if (!first) writeString(", ", out); first = false; - writeString(DB::toString(id), out); - } - writeString(");", out); + if (!key.expression.empty()) + { + writeParenthesisedString(key.expression, out); + writeString(" AS ", out); + } + + writeQuoted(key.name, out); + } } - return query; + for (const auto & attr : dict_struct.attributes) + { + writeString(", ", out); + + if (!attr.expression.empty()) + { + writeParenthesisedString(attr.expression, out); + writeString(" AS ", out); + } + + writeQuoted(attr.name, out); + } + + writeString(" FROM ", out); + if (!db.empty()) + { + writeQuoted(db, out); + writeChar('.', out); + } + writeQuoted(table, out); + + if (!where.empty()) + { + writeString(" WHERE ", out); + writeString(where, out); + } + + writeChar(';', out); + + return out.str(); +} + + +std::string ExternalQueryBuilder::composeLoadIdsQuery(const std::vector & ids) +{ + if (!dict_struct.id) + throw Exception{"Simple key required for method", ErrorCodes::UNSUPPORTED_METHOD}; + + WriteBufferFromOwnString out; + writeString("SELECT ", out); + + if (!dict_struct.id.value().expression.empty()) + { + writeParenthesisedString(dict_struct.id.value().expression, out); + writeString(" AS ", out); + } + + writeQuoted(dict_struct.id.value().name, out); + + for (const auto & attr : dict_struct.attributes) + { + writeString(", ", out); + + if (!attr.expression.empty()) + { + writeParenthesisedString(attr.expression, out); + writeString(" AS ", out); + } + + writeQuoted(attr.name, out); + } + + writeString(" FROM ", out); + if (!db.empty()) + { + writeQuoted(db, out); + writeChar('.', out); + } + writeQuoted(table, out); + + writeString(" WHERE ", out); + + if (!where.empty()) + { + writeString(where, out); + writeString(" AND ", out); + } + + writeQuoted(dict_struct.id.value().name, out); + writeString(" IN (", out); + + auto first = true; + for (const auto id : ids) + { + if (!first) + writeString(", ", out); + + first = false; + writeString(DB::toString(id), out); + } + + writeString(");", out); + + return out.str(); } @@ -218,85 +210,81 @@ std::string ExternalQueryBuilder::composeLoadKeysQuery( if (!dict_struct.key) throw Exception{"Composite key required for method", ErrorCodes::UNSUPPORTED_METHOD}; - std::string query; + WriteBufferFromOwnString out; + writeString("SELECT ", out); + auto first = true; + for (const auto & key_or_attribute : boost::join(*dict_struct.key, dict_struct.attributes)) { - WriteBufferFromString out{query}; - writeString("SELECT ", out); + if (!first) + writeString(", ", out); - auto first = true; - for (const auto & key_or_attribute : boost::join(*dict_struct.key, dict_struct.attributes)) + first = false; + + if (!key_or_attribute.expression.empty()) + { + writeParenthesisedString(key_or_attribute.expression, out); + writeString(" AS ", out); + } + + writeQuoted(key_or_attribute.name, out); + } + + writeString(" FROM ", out); + if (!db.empty()) + { + writeQuoted(db, out); + writeChar('.', out); + } + writeQuoted(table, out); + + writeString(" WHERE ", out); + + if (!where.empty()) + { + writeString("(", out); + writeString(where, out); + writeString(") AND (", out); + } + + if (method == AND_OR_CHAIN) + { + first = true; + for (const auto row : requested_rows) + { + if (!first) + writeString(" OR ", out); + + first = false; + composeKeyCondition(key_columns, row, out); + } + } + else if (method == IN_WITH_TUPLES) + { + writeString(composeKeyTupleDefinition(), out); + writeString(" IN (", out); + + first = true; + for (const auto row : requested_rows) { if (!first) writeString(", ", out); first = false; - - if (!key_or_attribute.expression.empty()) - { - writeParenthesisedString(key_or_attribute.expression, out); - writeString(" AS ", out); - } - - writeQuoted(key_or_attribute.name, out); + composeKeyTuple(key_columns, row, out); } - writeString(" FROM ", out); - if (!db.empty()) - { - writeQuoted(db, out); - writeChar('.', out); - } - writeQuoted(table, out); - - writeString(" WHERE ", out); - - if (!where.empty()) - { - writeString("(", out); - writeString(where, out); - writeString(") AND (", out); - } - - if (method == AND_OR_CHAIN) - { - first = true; - for (const auto row : requested_rows) - { - if (!first) - writeString(" OR ", out); - - first = false; - composeKeyCondition(key_columns, row, out); - } - } - else if (method == IN_WITH_TUPLES) - { - writeString(composeKeyTupleDefinition(), out); - writeString(" IN (", out); - - first = true; - for (const auto row : requested_rows) - { - if (!first) - writeString(", ", out); - - first = false; - composeKeyTuple(key_columns, row, out); - } - - writeString(")", out); - } - - if (!where.empty()) - { - writeString(")", out); - } - - writeString(";", out); + writeString(")", out); } - return query; + if (!where.empty()) + { + writeString(")", out); + } + + writeString(";", out); + + return out.str(); } diff --git a/dbms/src/Dictionaries/MySQLDictionarySource.cpp b/dbms/src/Dictionaries/MySQLDictionarySource.cpp index 97a323edc96..05290f9b5c6 100644 --- a/dbms/src/Dictionaries/MySQLDictionarySource.cpp +++ b/dbms/src/Dictionaries/MySQLDictionarySource.cpp @@ -1,6 +1,8 @@ +#include #include #include #include + #if USE_MYSQL #include @@ -119,12 +121,9 @@ std::string MySQLDictionarySource::quoteForLike(const std::string s) tmp.push_back(c); } - std::string res; - { - WriteBufferFromString out(res); - writeQuoted(tmp, out); - } - return res; + WriteBufferFromOwnString out; + writeQuoted(tmp, out); + return out.str(); } LocalDateTime MySQLDictionarySource::getLastModification() const diff --git a/dbms/src/Functions/Conditional/ArgsInfo.cpp b/dbms/src/Functions/Conditional/ArgsInfo.cpp index 37f0322322d..780749e756f 100644 --- a/dbms/src/Functions/Conditional/ArgsInfo.cpp +++ b/dbms/src/Functions/Conditional/ArgsInfo.cpp @@ -22,8 +22,7 @@ namespace std::string dumpArgTypes(const DataTypes & args) { - std::string out; - WriteBufferFromString buf{out}; + WriteBufferFromOwnString buf; size_t else_arg = elseArg(args); @@ -40,10 +39,7 @@ std::string dumpArgTypes(const DataTypes & args) writeString("; ", buf); writeString(args[else_arg]->getName(), buf); - - buf.next(); - - return out; + return buf.str(); } /// Forward declarations. diff --git a/dbms/src/Functions/Conditional/getArrayType.cpp b/dbms/src/Functions/Conditional/getArrayType.cpp index 3e18cc7b5a0..c55430af557 100644 --- a/dbms/src/Functions/Conditional/getArrayType.cpp +++ b/dbms/src/Functions/Conditional/getArrayType.cpp @@ -17,8 +17,7 @@ namespace std::string dumpArgTypes(const DataTypes & args) { - std::string out; - WriteBufferFromString buf{out}; + WriteBufferFromOwnString buf; bool is_first = true; for (size_t i = 0; i < args.size(); ++i) @@ -30,10 +29,7 @@ std::string dumpArgTypes(const DataTypes & args) writeString(args[i]->getName(), buf); } - - buf.next(); - - return out; + return buf.str(); } /// Forward declarations. diff --git a/dbms/src/Functions/FunctionsConversion.cpp b/dbms/src/Functions/FunctionsConversion.cpp index ff20db6215f..54fb0ccfd5a 100644 --- a/dbms/src/Functions/FunctionsConversion.cpp +++ b/dbms/src/Functions/FunctionsConversion.cpp @@ -25,26 +25,23 @@ const DateLUTImpl * extractTimeZoneFromFunctionArguments(Block & block, const Co void throwExceptionForIncompletelyParsedValue( ReadBuffer & read_buffer, Block & block, const ColumnNumbers & arguments, size_t result) { - std::string message; - { - const IDataType & to_type = *block.getByPosition(result).type; + const IDataType & to_type = *block.getByPosition(result).type; - WriteBufferFromString message_buf(message); - message_buf << "Cannot parse string " << quote << String(read_buffer.buffer().begin(), read_buffer.buffer().size()) - << " as " << to_type.getName() - << ": syntax error"; + WriteBufferFromOwnString message_buf; + message_buf << "Cannot parse string " << quote << String(read_buffer.buffer().begin(), read_buffer.buffer().size()) + << " as " << to_type.getName() + << ": syntax error"; - if (read_buffer.offset()) - message_buf << " at position " << read_buffer.offset() - << " (parsed just " << quote << String(read_buffer.buffer().begin(), read_buffer.offset()) << ")"; - else - message_buf << " at begin of string"; + if (read_buffer.offset()) + message_buf << " at position " << read_buffer.offset() + << " (parsed just " << quote << String(read_buffer.buffer().begin(), read_buffer.offset()) << ")"; + else + message_buf << " at begin of string"; - if (to_type.behavesAsNumber()) - message_buf << ". Note: there are to" << to_type.getName() << "OrZero function, which returns zero instead of throwing exception."; - } + if (to_type.behavesAsNumber()) + message_buf << ". Note: there are to" << to_type.getName() << "OrZero function, which returns zero instead of throwing exception."; - throw Exception(message, ErrorCodes::CANNOT_PARSE_TEXT); + throw Exception(message_buf.str(), ErrorCodes::CANNOT_PARSE_TEXT); } diff --git a/dbms/src/Functions/FunctionsFormatting.h b/dbms/src/Functions/FunctionsFormatting.h index 147346b3c47..466f1b0ec71 100644 --- a/dbms/src/Functions/FunctionsFormatting.h +++ b/dbms/src/Functions/FunctionsFormatting.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/dbms/src/IO/ReadHelpers.cpp b/dbms/src/IO/ReadHelpers.cpp index f0aed1c356d..507d429acab 100644 --- a/dbms/src/IO/ReadHelpers.cpp +++ b/dbms/src/IO/ReadHelpers.cpp @@ -58,18 +58,15 @@ void parseUUID(const UInt8 * src36, std::reverse_iterator dst16) static void __attribute__((__noinline__)) throwAtAssertionFailed(const char * s, ReadBuffer & buf) { - std::string message; - { - WriteBufferFromString out(message); - out << "Cannot parse input: expected " << escape << s; + WriteBufferFromOwnString out; + out << "Cannot parse input: expected " << escape << s; - if (buf.eof()) - out << " at end of stream."; - else - out << " before: " << escape << String(buf.position(), std::min(SHOW_CHARS_ON_SYNTAX_ERROR, buf.buffer().end() - buf.position())); - } + if (buf.eof()) + out << " at end of stream."; + else + out << " before: " << escape << String(buf.position(), std::min(SHOW_CHARS_ON_SYNTAX_ERROR, buf.buffer().end() - buf.position())); - throw Exception(message, ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED); + throw Exception(out.str(), ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED); } @@ -753,28 +750,25 @@ void readException(Exception & e, ReadBuffer & buf, const String & additional_me readBinary(stack_trace, buf); readBinary(has_nested, buf); - std::string new_message; - { - WriteBufferFromString out(new_message); + WriteBufferFromOwnString out; - if (!additional_message.empty()) - out << additional_message << ". "; + if (!additional_message.empty()) + out << additional_message << ". "; - if (name != "DB::Exception") - out << name << ". "; + if (name != "DB::Exception") + out << name << ". "; - out << message - << ". Stack trace:\n\n" << stack_trace; - } + out << message + << ". Stack trace:\n\n" << stack_trace; if (has_nested) { Exception nested; readException(nested, buf); - e = Exception(new_message, nested, code); + e = Exception(out.str(), nested, code); } else - e = Exception(new_message, code); + e = Exception(out.str(), code); } void readAndThrowException(ReadBuffer & buf, const String & additional_message) diff --git a/dbms/src/IO/WriteBufferFromHTTPServerResponse.cpp b/dbms/src/IO/WriteBufferFromHTTPServerResponse.cpp index 25351ff1a95..105d3787075 100644 --- a/dbms/src/IO/WriteBufferFromHTTPServerResponse.cpp +++ b/dbms/src/IO/WriteBufferFromHTTPServerResponse.cpp @@ -144,14 +144,11 @@ void WriteBufferFromHTTPServerResponse::onProgress(const Progress & progress) /// Send all common headers before our special progress headers. startSendHeaders(); - std::string progress_string; - { - WriteBufferFromString progress_string_writer(progress_string); - accumulated_progress.writeJSON(progress_string_writer); - } + WriteBufferFromOwnString progress_string_writer; + accumulated_progress.writeJSON(progress_string_writer); #if POCO_CLICKHOUSE_PATCH - *response_header_ostr << "X-ClickHouse-Progress: " << progress_string << "\r\n" << std::flush; + *response_header_ostr << "X-ClickHouse-Progress: " << progress_string_writer.str() << "\r\n" << std::flush; #endif } } diff --git a/dbms/src/IO/WriteBufferFromString.h b/dbms/src/IO/WriteBufferFromString.h index ec50571d2d3..9303a5b817f 100644 --- a/dbms/src/IO/WriteBufferFromString.h +++ b/dbms/src/IO/WriteBufferFromString.h @@ -6,6 +6,7 @@ #define WRITE_BUFFER_FROM_STRING_INITIAL_SIZE_IF_EMPTY 32 + namespace DB { @@ -25,6 +26,7 @@ private: working_buffer = internal_buffer; } +protected: void finish() { s.resize(count()); @@ -47,4 +49,21 @@ public: } }; + +/// Creates the string by itself and allows to get it. +class WriteBufferFromOwnString : public WriteBufferFromString +{ +private: + std::string s; + +public: + WriteBufferFromOwnString() : WriteBufferFromString(s) {} + + std::string & str() + { + finish(); + return s; + } +}; + } diff --git a/dbms/src/IO/WriteHelpers.h b/dbms/src/IO/WriteHelpers.h index 295817302a6..64801cd896a 100644 --- a/dbms/src/IO/WriteHelpers.h +++ b/dbms/src/IO/WriteHelpers.h @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include namespace DB @@ -754,12 +754,9 @@ void writeException(const Exception & e, WriteBuffer & buf); template inline String toString(const T & x) { - String res; - { - WriteBufferFromString buf(res); - writeText(x, buf); - } - return res; + WriteBufferFromOwnString buf; + writeText(x, buf); + return buf.str(); } } diff --git a/dbms/src/IO/tests/gtest_cascade_and_memory_write_buffer.cpp b/dbms/src/IO/tests/gtest_cascade_and_memory_write_buffer.cpp index 6132831800c..67f76450255 100644 --- a/dbms/src/IO/tests/gtest_cascade_and_memory_write_buffer.cpp +++ b/dbms/src/IO/tests/gtest_cascade_and_memory_write_buffer.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/dbms/src/IO/tests/parse_int_perf.cpp b/dbms/src/IO/tests/parse_int_perf.cpp index 7f75309def6..c21c08987a5 100644 --- a/dbms/src/IO/tests/parse_int_perf.cpp +++ b/dbms/src/IO/tests/parse_int_perf.cpp @@ -1144,11 +1144,6 @@ UInt64 rdtsc() int main(int argc, char ** argv) { -/* std::string s(' ', 20); - DB::WriteBufferFromString wb(s); - DB::Faster::writeIntText(DB::parse(argv[1]), wb); - std::cerr << s << std::endl;*/ - try { using T = UInt8; diff --git a/dbms/src/Interpreters/Compiler.cpp b/dbms/src/Interpreters/Compiler.cpp index 37e1910a146..8ca50c4de72 100644 --- a/dbms/src/Interpreters/Compiler.cpp +++ b/dbms/src/Interpreters/Compiler.cpp @@ -67,14 +67,9 @@ static Compiler::HashedKey getHash(const std::string & key) /// Without .so extension. static std::string hashedKeyToFileName(Compiler::HashedKey hashed_key) { - std::string file_name; - - { - WriteBufferFromString out(file_name); - out << hashed_key.low << '_' << hashed_key.high; - } - - return file_name; + WriteBufferFromOwnString out; + out << hashed_key.low << '_' << hashed_key.high; + return out.str(); } diff --git a/dbms/src/Interpreters/DDLWorker.cpp b/dbms/src/Interpreters/DDLWorker.cpp index cb457d3b659..1dc88d8192c 100644 --- a/dbms/src/Interpreters/DDLWorker.cpp +++ b/dbms/src/Interpreters/DDLWorker.cpp @@ -64,18 +64,15 @@ struct DDLLogEntry String toString() { - String res; - { - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; - auto version = CURRENT_VERSION; - wb << "version: " << version << "\n"; - wb << "query: " << escape << query << "\n"; - wb << "hosts: " << hosts << "\n"; - wb << "initiator: " << initiator << "\n"; - } + auto version = CURRENT_VERSION; + wb << "version: " << version << "\n"; + wb << "query: " << escape << query << "\n"; + wb << "hosts: " << hosts << "\n"; + wb << "initiator: " << initiator << "\n"; - return res; + return wb.str(); } void parse(const String & data) diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 6ea6e6600b2..b17ba8dd66f 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -5,7 +5,6 @@ #include -#include #include #include diff --git a/dbms/src/Interpreters/InterserverIOHandler.h b/dbms/src/Interpreters/InterserverIOHandler.h index 29717951253..d899ded4de7 100644 --- a/dbms/src/Interpreters/InterserverIOHandler.h +++ b/dbms/src/Interpreters/InterserverIOHandler.h @@ -45,13 +45,11 @@ public: /// Serializes the location. std::string toString() const { - std::string serialized_location; - WriteBufferFromString buf(serialized_location); + WriteBufferFromOwnString buf; writeBinary(name, buf); writeBinary(host, buf); writeBinary(port, buf); - buf.next(); - return serialized_location; + return buf.str(); } public: diff --git a/dbms/src/Parsers/ASTFunction.cpp b/dbms/src/Parsers/ASTFunction.cpp index 416eccbcb0b..dc3605bd94c 100644 --- a/dbms/src/Parsers/ASTFunction.cpp +++ b/dbms/src/Parsers/ASTFunction.cpp @@ -10,8 +10,7 @@ namespace DB String ASTFunction::getColumnName() const { - String res; - WriteBufferFromString wb(res); + WriteBufferFromOwnString wb; writeString(name, wb); if (parameters) @@ -34,8 +33,7 @@ String ASTFunction::getColumnName() const writeString((*it)->getColumnName(), wb); } writeChar(')', wb); - - return res; + return wb.str(); } /** Get the text that identifies this element. */ diff --git a/dbms/src/Parsers/IAST.cpp b/dbms/src/Parsers/IAST.cpp index 90758a1a96c..b951affd648 100644 --- a/dbms/src/Parsers/IAST.cpp +++ b/dbms/src/Parsers/IAST.cpp @@ -24,7 +24,7 @@ const char * IAST::hilite_alias = "\033[0;32m"; const char * IAST::hilite_none = "\033[0m"; -/// Quota the identifier with backquotes, if required. +/// Quote the identifier with backquotes, if required. String backQuoteIfNeed(const String & x) { String res(x.size(), '\0'); @@ -63,12 +63,9 @@ size_t IAST::checkSize(size_t max_size) const String IAST::getTreeID() const { - String res; - { - WriteBufferFromString out(res); - getTreeIDImpl(out); - } - return res; + WriteBufferFromOwnString out; + getTreeIDImpl(out); + return out.str(); } diff --git a/dbms/src/Parsers/parseQuery.cpp b/dbms/src/Parsers/parseQuery.cpp index 54a66f2c79c..93bc39f75c3 100644 --- a/dbms/src/Parsers/parseQuery.cpp +++ b/dbms/src/Parsers/parseQuery.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -156,18 +157,14 @@ std::string getSyntaxErrorMessage( bool hilite, const std::string & query_description) { - String message; + WriteBufferFromOwnString out; + writeCommonErrorMessage(out, begin, end, last_token, query_description); + writeQueryAroundTheError(out, begin, end, hilite, &last_token, 1); - { - WriteBufferFromString out(message); - writeCommonErrorMessage(out, begin, end, last_token, query_description); - writeQueryAroundTheError(out, begin, end, hilite, &last_token, 1); + if (!expected.variants.empty()) + out << "Expected " << expected; - if (!expected.variants.empty()) - out << "Expected " << expected; - } - - return message; + return out.str(); } @@ -178,17 +175,13 @@ std::string getLexicalErrorMessage( bool hilite, const std::string & query_description) { - String message; + WriteBufferFromOwnString out; + writeCommonErrorMessage(out, begin, end, last_token, query_description); + writeQueryAroundTheError(out, begin, end, hilite, &last_token, 1); - { - WriteBufferFromString out(message); - writeCommonErrorMessage(out, begin, end, last_token, query_description); - writeQueryAroundTheError(out, begin, end, hilite, &last_token, 1); + out << getErrorTokenDescription(last_token.type); - out << getErrorTokenDescription(last_token.type); - } - - return message; + return out.str(); } @@ -199,19 +192,15 @@ std::string getUnmatchedParenthesesErrorMessage( bool hilite, const std::string & query_description) { - String message; + WriteBufferFromOwnString out; + writeCommonErrorMessage(out, begin, end, unmatched_parens[0], query_description); + writeQueryAroundTheError(out, begin, end, hilite, unmatched_parens.data(), unmatched_parens.size()); - { - WriteBufferFromString out(message); - writeCommonErrorMessage(out, begin, end, unmatched_parens[0], query_description); - writeQueryAroundTheError(out, begin, end, hilite, unmatched_parens.data(), unmatched_parens.size()); + out << "Unmatched parentheses: "; + for (const Token & paren : unmatched_parens) + out << *paren.begin; - out << "Unmatched parentheses: "; - for (const Token & paren : unmatched_parens) - out << *paren.begin; - } - - return message; + return out.str(); } } diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 05dd03a202f..8ef9241550d 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/dbms/src/Server/HTTPHandler.cpp b/dbms/src/Server/HTTPHandler.cpp index 1e027176015..1babb58a743 100644 --- a/dbms/src/Server/HTTPHandler.cpp +++ b/dbms/src/Server/HTTPHandler.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/dbms/src/Server/LocalServer.cpp b/dbms/src/Server/LocalServer.cpp index a7616d4d865..17bc099921c 100644 --- a/dbms/src/Server/LocalServer.cpp +++ b/dbms/src/Server/LocalServer.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -352,10 +353,9 @@ catch (const Exception & e) inline String getQuotedString(const String & s) { - String res; - WriteBufferFromString buf(res); + WriteBufferFromOwnString buf; writeQuotedString(s, buf); - return res; + return buf.str(); } diff --git a/dbms/src/Storages/ColumnsDescription.cpp b/dbms/src/Storages/ColumnsDescription.cpp index c586d13e32f..c0bfabea727 100644 --- a/dbms/src/Storages/ColumnsDescription.cpp +++ b/dbms/src/Storages/ColumnsDescription.cpp @@ -23,8 +23,7 @@ namespace ErrorCodes template String ColumnsDescription::toString() const { - String s; - WriteBufferFromString buf{s}; + WriteBufferFromOwnString buf; writeString("columns format version: 1\n", buf); writeText(columns.size() + materialized.size() + alias.size(), buf); @@ -58,7 +57,7 @@ String ColumnsDescription::toString() const write_columns(materialized); write_columns(alias); - return s; + return buf.str(); } diff --git a/dbms/src/Storages/MergeTree/ActiveDataPartSet.cpp b/dbms/src/Storages/MergeTree/ActiveDataPartSet.cpp index e62731de771..106fabba78b 100644 --- a/dbms/src/Storages/MergeTree/ActiveDataPartSet.cpp +++ b/dbms/src/Storages/MergeTree/ActiveDataPartSet.cpp @@ -120,25 +120,23 @@ String ActiveDataPartSet::getPartName(DayNum_t left_date, DayNum_t right_date, I const auto & date_lut = DateLUT::instance(); /// Directory name for the part has form: `YYYYMMDD_YYYYMMDD_N_N_L`. - String res; - { - unsigned left_date_id = date_lut.toNumYYYYMMDD(left_date); - unsigned right_date_id = date_lut.toNumYYYYMMDD(right_date); - WriteBufferFromString wb(res); + unsigned left_date_id = date_lut.toNumYYYYMMDD(left_date); + unsigned right_date_id = date_lut.toNumYYYYMMDD(right_date); - writeIntText(left_date_id, wb); - writeChar('_', wb); - writeIntText(right_date_id, wb); - writeChar('_', wb); - writeIntText(left_id, wb); - writeChar('_', wb); - writeIntText(right_id, wb); - writeChar('_', wb); - writeIntText(level, wb); - } + WriteBufferFromOwnString wb; - return res; + writeIntText(left_date_id, wb); + writeChar('_', wb); + writeIntText(right_date_id, wb); + writeChar('_', wb); + writeIntText(left_id, wb); + writeChar('_', wb); + writeIntText(right_id, wb); + writeChar('_', wb); + writeIntText(level, wb); + + return wb.str(); } diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 4bda89fe020..f90004fca5c 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -879,21 +880,18 @@ void MergeTreeData::createConvertExpression(const DataPartPtr & part, const Name if (part && !out_rename_map.empty()) { - std::string message; + WriteBufferFromOwnString out; + out << "Will rename "; + bool first = true; + for (const auto & from_to : out_rename_map) { - WriteBufferFromString out(message); - out << "Will rename "; - bool first = true; - for (const auto & from_to : out_rename_map) - { - if (!first) - out << ", "; - first = false; - out << from_to.first << " to " << from_to.second; - } - out << " in part " << part->name; + if (!first) + out << ", "; + first = false; + out << from_to.first << " to " << from_to.second; } - LOG_DEBUG(log, message); + out << " in part " << part->name; + LOG_DEBUG(log, out.str()); } } diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp index 4eac19e2a48..9e7585ed8be 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataPart.cpp @@ -256,12 +256,9 @@ void MergeTreeDataPartChecksums::summaryDataChecksum(SipHash & hash) const String MergeTreeDataPartChecksums::toString() const { - String s; - { - WriteBufferFromString out(s); - write(out); - } - return s; + WriteBufferFromOwnString out; + write(out); + return out.str(); } MergeTreeDataPartChecksums MergeTreeDataPartChecksums::parse(const String & s) diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAddress.h b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAddress.h index e1447b33f39..325b2dc617b 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAddress.h +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeAddress.h @@ -46,12 +46,9 @@ struct ReplicatedMergeTreeAddress String toString() const { - String res; - { - WriteBufferFromString out(res); - writeText(out); - } - return res; + WriteBufferFromOwnString out; + writeText(out); + return out.str(); } void fromString(const String & str) diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.cpp index 94687df0dd2..fb1a5b4ed86 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace DB @@ -133,12 +134,9 @@ void ReplicatedMergeTreeLogEntryData::readText(ReadBuffer & in) String ReplicatedMergeTreeLogEntryData::toString() const { - String s; - { - WriteBufferFromString out(s); - writeText(out); - } - return s; + WriteBufferFromOwnString out; + writeText(out); + return out.str(); } ReplicatedMergeTreeLogEntry::Ptr ReplicatedMergeTreeLogEntry::parse(const String & s, const zkutil::Stat & stat) diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQuorumEntry.h b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQuorumEntry.h index d1cdba5ac9d..c44f0b78f84 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQuorumEntry.h +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQuorumEntry.h @@ -61,12 +61,9 @@ struct ReplicatedMergeTreeQuorumEntry String toString() const { - String res; - { - WriteBufferFromString out(res); - writeText(out); - } - return res; + WriteBufferFromOwnString out; + writeText(out); + return out.str(); } void fromString(const String & str) diff --git a/dbms/src/Storages/MergeTree/ReshardingJob.cpp b/dbms/src/Storages/MergeTree/ReshardingJob.cpp index ebf570c5696..2e2f718d68b 100644 --- a/dbms/src/Storages/MergeTree/ReshardingJob.cpp +++ b/dbms/src/Storages/MergeTree/ReshardingJob.cpp @@ -72,8 +72,7 @@ ReshardingJob::operator bool() const std::string ReshardingJob::toString() const { - std::string serialized_job; - WriteBufferFromString buf{serialized_job}; + WriteBufferFromOwnString buf; writeBinary(database_name, buf); writeBinary(table_name, buf); @@ -89,9 +88,8 @@ std::string ReshardingJob::toString() const writeBinary(path.first, buf); writeVarUInt(path.second, buf); } - buf.next(); - return serialized_job; + return buf.str(); } bool ReshardingJob::isCoordinated() const diff --git a/dbms/src/Storages/MergeTree/ReshardingWorker.cpp b/dbms/src/Storages/MergeTree/ReshardingWorker.cpp index df3dbadde90..6ef968975c7 100644 --- a/dbms/src/Storages/MergeTree/ReshardingWorker.cpp +++ b/dbms/src/Storages/MergeTree/ReshardingWorker.cpp @@ -801,8 +801,7 @@ void ReshardingWorker::storeTargetShardsInfo() zookeeper->tryRemove(getLocalJobPath() + "/shards"); - std::string out; - WriteBufferFromString buf{out}; + WriteBufferFromOwnString buf; size_t entries_count = 0; for (const auto & entry : per_shard_data_parts) @@ -830,9 +829,7 @@ void ReshardingWorker::storeTargetShardsInfo() writeBinary(hash, buf); } - buf.next(); - - (void) zookeeper->create(getLocalJobPath() + "/shards", out, + zookeeper->create(getLocalJobPath() + "/shards", buf.str(), zkutil::CreateMode::Persistent); } @@ -2111,45 +2108,36 @@ std::string ReshardingWorker::dumpCoordinatorState(const std::string & coordinat auto current_host = getFQDNOrHostName(); - try + WriteBufferFromOwnString buf; + + writeString("Coordinator dump: ", buf); + writeString("ID: {", buf); + writeString(coordinator_id + "}; ", buf); + + auto zookeeper = context.getZooKeeper(); + + Status status(zookeeper->get(getCoordinatorPath(coordinator_id) + "/status")); + + if (status.getCode() != STATUS_OK) { - WriteBufferFromString buf{out}; + writeString("Global status: {", buf); + writeString(status.getMessage() + "}; ", buf); + } - writeString("Coordinator dump: ", buf); - writeString("ID: {", buf); - writeString(coordinator_id + "}; ", buf); - - auto zookeeper = context.getZooKeeper(); - - Status status(zookeeper->get(getCoordinatorPath(coordinator_id) + "/status")); + auto hosts = zookeeper->getChildren(getCoordinatorPath(coordinator_id) + "/status"); + for (const auto & host : hosts) + { + Status status(zookeeper->get(getCoordinatorPath(coordinator_id) + "/status/" + host)); if (status.getCode() != STATUS_OK) { - writeString("Global status: {", buf); + writeString("NODE ", buf); + writeString(((host == current_host) ? "localhost" : host) + ": {", buf); writeString(status.getMessage() + "}; ", buf); } - - auto hosts = zookeeper->getChildren(getCoordinatorPath(coordinator_id) + "/status"); - for (const auto & host : hosts) - { - Status status(zookeeper->get(getCoordinatorPath(coordinator_id) + "/status/" + host)); - - if (status.getCode() != STATUS_OK) - { - writeString("NODE ", buf); - writeString(((host == current_host) ? "localhost" : host) + ": {", buf); - writeString(status.getMessage() + "}; ", buf); - } - } - - buf.next(); - } - catch (...) - { - tryLogCurrentException(__PRETTY_FUNCTION__); } - return out; + return buf.str(); } /// Compute the hash function from the checksum files of a given part. @@ -2716,8 +2704,7 @@ void ReshardingWorker::LogRecord::writeBack() std::string ReshardingWorker::LogRecord::toString() { - std::string out; - WriteBufferFromString buf{out}; + WriteBufferFromOwnString buf; writeVarUInt(static_cast(operation), buf); writeVarUInt(static_cast(state), buf); @@ -2732,9 +2719,7 @@ std::string ReshardingWorker::LogRecord::toString() writeBinary(entry.second, buf); } - buf.next(); - - return out; + return buf.str(); } } diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index 5aa1866c272..c320db083cd 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -395,10 +395,9 @@ namespace String toString() const { - String res; - WriteBufferFromString out(res); + WriteBufferFromOwnString out; write(out); - return res; + return out.str(); } void check(ReadBuffer & in) const From f8a761fbd9b728567a977838ba217a6e6d4ea79c Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 00:44:57 +0300 Subject: [PATCH 015/281] Fixed error [#CLICKHOUSE-3191]. --- dbms/src/Common/tests/small_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Common/tests/small_table.cpp b/dbms/src/Common/tests/small_table.cpp index d11570f6d0f..825047bf53f 100644 --- a/dbms/src/Common/tests/small_table.cpp +++ b/dbms/src/Common/tests/small_table.cpp @@ -47,7 +47,7 @@ int main(int argc, char ** argv) DB::WriteBufferFromOwnString wb; cont.writeText(wb); - std::cerr << "dump: " << wb.str(); << std::endl; + std::cerr << "dump: " << wb.str() << std::endl; } { From 844990db2784637bf5d6f42245ad3c28833145d8 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 00:50:21 +0300 Subject: [PATCH 016/281] Fixed build with gcc-7.1 [#CLICKHOUSE-2]. --- dbms/src/Common/tests/lru_cache.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbms/src/Common/tests/lru_cache.cpp b/dbms/src/Common/tests/lru_cache.cpp index a3d58c4fa6b..dea6bb6e14a 100644 --- a/dbms/src/Common/tests/lru_cache.cpp +++ b/dbms/src/Common/tests/lru_cache.cpp @@ -5,6 +5,8 @@ #include #include #include +#include + namespace { From a6cb383c4f53aa342e74c7e28e09be5ced863f73 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 04:25:03 +0300 Subject: [PATCH 017/281] Fixed build with gcc-7.1 [#CLICKHOUSE-2]. --- dbms/src/Core/NamesAndTypes.h | 4 ++++ dbms/src/DataStreams/tests/glue_streams.cpp | 4 ++-- dbms/src/Functions/FunctionsMath.h | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dbms/src/Core/NamesAndTypes.h b/dbms/src/Core/NamesAndTypes.h index 86c0b17b66c..e8b9bf258ad 100644 --- a/dbms/src/Core/NamesAndTypes.h +++ b/dbms/src/Core/NamesAndTypes.h @@ -38,6 +38,10 @@ class NamesAndTypesList : public std::list public: using std::list::list; + /// Without this constructor, gcc 7.1.0 get confused. + template + NamesAndTypesList(Iterator begin, Iterator end) : std::list(begin, end) {} + void readText(ReadBuffer & buf); void writeText(WriteBuffer & buf) const; diff --git a/dbms/src/DataStreams/tests/glue_streams.cpp b/dbms/src/DataStreams/tests/glue_streams.cpp index e2ebe2c1e37..78205b9c0ce 100644 --- a/dbms/src/DataStreams/tests/glue_streams.cpp +++ b/dbms/src/DataStreams/tests/glue_streams.cpp @@ -52,13 +52,13 @@ try " GROUP BY SearchPhrase" " ORDER BY count() DESC" " LIMIT 10", - context, QueryProcessingStage::Complete); + context, false, QueryProcessingStage::Complete); BlockIO io2 = executeQuery( "SELECT count()" " FROM hits" " WHERE SearchPhrase != ''", - context, QueryProcessingStage::Complete); + context, false, QueryProcessingStage::Complete); WriteBufferFromFileDescriptor wb(STDOUT_FILENO); diff --git a/dbms/src/Functions/FunctionsMath.h b/dbms/src/Functions/FunctionsMath.h index 7fda2a03fa4..fea7266e379 100644 --- a/dbms/src/Functions/FunctionsMath.h +++ b/dbms/src/Functions/FunctionsMath.h @@ -165,7 +165,7 @@ private: }; -template +template struct UnaryFunctionPlain { static constexpr auto name = Name::name; @@ -180,7 +180,7 @@ struct UnaryFunctionPlain #if USE_VECTORCLASS -template +template struct UnaryFunctionVectorized { static constexpr auto name = Name::name; @@ -437,7 +437,7 @@ private: }; -template +template struct BinaryFunctionPlain { static constexpr auto name = Name::name; @@ -452,7 +452,7 @@ struct BinaryFunctionPlain #if USE_VECTORCLASS -template +template struct BinaryFunctionVectorized { static constexpr auto name = Name::name; From 9a546b54142fc7b91fb3787cddfe1895f15933f4 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 04:58:18 +0300 Subject: [PATCH 018/281] Fixed build with gcc 6 [#CLICKHOUSE-2]. --- dbms/src/Core/NamesAndTypes.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dbms/src/Core/NamesAndTypes.h b/dbms/src/Core/NamesAndTypes.h index e8b9bf258ad..32387a889b1 100644 --- a/dbms/src/Core/NamesAndTypes.h +++ b/dbms/src/Core/NamesAndTypes.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -36,12 +37,14 @@ using NamesAndTypes = std::vector; class NamesAndTypesList : public std::list { public: - using std::list::list; + NamesAndTypesList() {} + + NamesAndTypesList(std::initializer_list init) : std::list(init) {} - /// Without this constructor, gcc 7.1.0 get confused. template NamesAndTypesList(Iterator begin, Iterator end) : std::list(begin, end) {} + void readText(ReadBuffer & buf); void writeText(WriteBuffer & buf) const; From 9f799820d9e62c73792cf4907d0b6a7640e3d752 Mon Sep 17 00:00:00 2001 From: Pawel Rog Date: Tue, 1 Aug 2017 10:12:15 +0200 Subject: [PATCH 019/281] Applied changes requested by Alexey --- dbms/src/IO/CompressedReadBufferBase.cpp | 9 +++------ dbms/src/Storages/MergeTree/MergeTreeData.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/dbms/src/IO/CompressedReadBufferBase.cpp b/dbms/src/IO/CompressedReadBufferBase.cpp index abcfc35702b..55c5b94f13d 100644 --- a/dbms/src/IO/CompressedReadBufferBase.cpp +++ b/dbms/src/IO/CompressedReadBufferBase.cpp @@ -54,12 +54,9 @@ size_t CompressedReadBufferBase::readCompressedData(size_t & size_decompressed, size_t & size_compressed = size_compressed_without_checksum; - if (method == static_cast(CompressionMethodByte::LZ4) || method == static_cast(CompressionMethodByte::ZSTD)) - { - size_compressed = unalignedLoad(&own_compressed_buffer[1]); - size_decompressed = unalignedLoad(&own_compressed_buffer[5]); - } - else if (method == static_cast(CompressionMethodByte::NONE)) + if (method == static_cast(CompressionMethodByte::LZ4) || + method == static_cast(CompressionMethodByte::ZSTD) || + method == static_cast(CompressionMethodByte::NONE)) { size_compressed = unalignedLoad(&own_compressed_buffer[1]); size_decompressed = unalignedLoad(&own_compressed_buffer[5]); diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 0c22298dd1d..70e763c9dd3 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1032,7 +1032,7 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( auto compression_method = this->context.chooseCompressionMethod( this->getTotalActiveSizeInBytes(), - static_cast(this->getTotalCompressedSize()) / this->getTotalActiveSizeInBytes()); + static_cast(this->getTotalActiveSizeInBytes()) / this->getTotalCompressedSize()); ExpressionBlockInputStream in(part_in, expression); MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, compression_method, false); in.readPrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index 2b3d869967e..67de3bcf30e 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -148,7 +148,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa auto compression_method = data.context.chooseCompressionMethod( data.getTotalActiveSizeInBytes(), - static_cast(data.getTotalCompressedSize()) / data.getTotalActiveSizeInBytes()); + static_cast(data.getTotalActiveSizeInBytes()) / data.getTotalCompressedSize()); NamesAndTypesList columns = data.getColumnsList().filter(block.getColumnsList().getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_method); From db984d92a8eeb4ca862d037d96462159d02e5461 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 1 Aug 2017 16:31:38 +0300 Subject: [PATCH 020/281] Fix crash on start --- dbms/src/IO/WriteBufferFromString.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dbms/src/IO/WriteBufferFromString.h b/dbms/src/IO/WriteBufferFromString.h index 9303a5b817f..4f9748c1740 100644 --- a/dbms/src/IO/WriteBufferFromString.h +++ b/dbms/src/IO/WriteBufferFromString.h @@ -50,19 +50,22 @@ public: }; +class StringHolder { +protected: + std::string ss; +}; + /// Creates the string by itself and allows to get it. -class WriteBufferFromOwnString : public WriteBufferFromString +class WriteBufferFromOwnString : public StringHolder, public WriteBufferFromString { -private: - std::string s; public: - WriteBufferFromOwnString() : WriteBufferFromString(s) {} + WriteBufferFromOwnString() : WriteBufferFromString(ss) {} std::string & str() { finish(); - return s; + return ss; } }; From fd5ac57b8e45387945e8c38ce2dba6fb62422a0c Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 17:33:38 +0300 Subject: [PATCH 021/281] Addition to prev. revision [#CLICKHOUSE-2]. --- dbms/src/IO/WriteBufferFromString.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dbms/src/IO/WriteBufferFromString.h b/dbms/src/IO/WriteBufferFromString.h index 4f9748c1740..9545562669f 100644 --- a/dbms/src/IO/WriteBufferFromString.h +++ b/dbms/src/IO/WriteBufferFromString.h @@ -50,22 +50,27 @@ public: }; -class StringHolder { -protected: - std::string ss; -}; +namespace detail +{ + /// For correct order of initialization. + class StringHolder + { + protected: + std::string value; + }; +} /// Creates the string by itself and allows to get it. -class WriteBufferFromOwnString : public StringHolder, public WriteBufferFromString +class WriteBufferFromOwnString : public detail::StringHolder, public WriteBufferFromString { public: - WriteBufferFromOwnString() : WriteBufferFromString(ss) {} + WriteBufferFromOwnString() : WriteBufferFromString(value) {} std::string & str() { finish(); - return ss; + return value; } }; From 34ac4fa3b83e4772319509559ded03c1c19977f6 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 17:34:06 +0300 Subject: [PATCH 022/281] Added metric with revision number for better monitoring of deployment [#CLICKHOUSE-2]. --- dbms/src/Common/CurrentMetrics.cpp | 1 + dbms/src/Server/Server.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dbms/src/Common/CurrentMetrics.cpp b/dbms/src/Common/CurrentMetrics.cpp index 5f23ded3e1b..f664acd7ca3 100644 --- a/dbms/src/Common/CurrentMetrics.cpp +++ b/dbms/src/Common/CurrentMetrics.cpp @@ -34,6 +34,7 @@ M(StorageBufferRows) \ M(StorageBufferBytes) \ M(DictCacheRequests) \ + M(Revision) \ namespace CurrentMetrics diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index 61a45c535ec..ebce924f76d 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,9 +48,15 @@ #include +namespace CurrentMetrics +{ + extern const Metric Revision; +} + namespace DB { -namespace ErrorCodes + + namespace ErrorCodes { extern const int NO_ELEMENTS_IN_CONFIG; extern const int SUPPORT_IS_DISABLED; @@ -221,6 +229,8 @@ int Server::main(const std::vector & args) registerAggregateFunctions(); registerTableFunctions(); + CurrentMetrics::set(CurrentMetrics::Revision, ClickHouseRevision::get()); + /** Context contains all that query execution is dependent: * settings, available functions, data types, aggregate functions, databases... */ From d6a2056851bc89dfbf273537b58bce9b37c01a10 Mon Sep 17 00:00:00 2001 From: Pawel Rog Date: Tue, 1 Aug 2017 16:48:24 +0200 Subject: [PATCH 023/281] Applied changes requested by Alexey --- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 4 ++-- dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index 70e763c9dd3..c9f1bac787b 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -1031,8 +1031,8 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( false, nullptr, "", false, 0, DBMS_DEFAULT_BUFFER_SIZE, false); auto compression_method = this->context.chooseCompressionMethod( - this->getTotalActiveSizeInBytes(), - static_cast(this->getTotalActiveSizeInBytes()) / this->getTotalCompressedSize()); + part->size_in_bytes, + static_cast(part->size_in_bytes) / this->getTotalActiveSizeInBytes()); ExpressionBlockInputStream in(part_in, expression); MergedColumnOnlyOutputStream out(*this, full_path + part->name + '/', true, compression_method, false); in.readPrefix(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index 82076becfbe..e7b9ad90c5f 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -620,8 +620,8 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart merged_stream = std::make_shared(merged_stream, Limits(), 0 /*limit_hint*/, Names()); auto compression_method = data.context.chooseCompressionMethod( - merge_entry->total_size_bytes_compressed, - static_cast(merge_entry->total_size_bytes_compressed) / data.getTotalActiveSizeInBytes()); + merge_entry->total_size_bytes_compressed, + static_cast (merge_entry->total_size_bytes_compressed) / data.getTotalActiveSizeInBytes()); MergedBlockOutputStream to{ data, new_part_tmp_path, merging_columns, compression_method, merged_column_to_size, aio_threshold}; From 8f6c2d4e476fa87d2a21e16ea74a88d0c5ed5c99 Mon Sep 17 00:00:00 2001 From: proller Date: Tue, 1 Aug 2017 16:26:19 +0300 Subject: [PATCH 024/281] Fix .h compile --- .../src/AggregateFunctions/AggregateFunctionQuantileTiming.h | 5 +++++ dbms/src/Functions/FunctionsCoding.h | 1 + 2 files changed, 6 insertions(+) diff --git a/dbms/src/AggregateFunctions/AggregateFunctionQuantileTiming.h b/dbms/src/AggregateFunctions/AggregateFunctionQuantileTiming.h index bcf9273b2c9..9f4bb9eeda2 100644 --- a/dbms/src/AggregateFunctions/AggregateFunctionQuantileTiming.h +++ b/dbms/src/AggregateFunctions/AggregateFunctionQuantileTiming.h @@ -21,6 +21,11 @@ #include +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + namespace DB { diff --git a/dbms/src/Functions/FunctionsCoding.h b/dbms/src/Functions/FunctionsCoding.h index 6ec2a1b269d..33e335219e3 100644 --- a/dbms/src/Functions/FunctionsCoding.h +++ b/dbms/src/Functions/FunctionsCoding.h @@ -32,6 +32,7 @@ namespace DB namespace ErrorCodes { extern const int TOO_LESS_ARGUMENTS_FOR_FUNCTION; + extern const int LOGICAL_ERROR; } From aaff26336df1cedfd4d21f76121e47a27b2344f0 Mon Sep 17 00:00:00 2001 From: felixoid Date: Tue, 1 Aug 2017 18:55:40 +0300 Subject: [PATCH 025/281] remove login mode from su in debian init-script, CLICKHOUSE-3195 --- debian/clickhouse-server.init | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/clickhouse-server.init b/debian/clickhouse-server.init index 7d867db8b46..1eaa433a6c2 100755 --- a/debian/clickhouse-server.init +++ b/debian/clickhouse-server.init @@ -88,7 +88,7 @@ die() check_config() { if [ -x "$BINDIR/$GENERIC_PROGRAM" ]; then - su -l $CLICKHOUSE_USER -s $SHELL -c "$BINDIR/$GENERIC_PROGRAM --extract-from-config --config-file=\"$CLICKHOUSE_CONFIG\" --key=path" >/dev/null || die "Configuration file ${CLICKHOUSE_CONFIG} doesn't parse successfully. Won't restart server. You may use forcerestart if you are sure."; + su -s $SHELL ${CLICKHOUSE_USER} -c "$BINDIR/$GENERIC_PROGRAM --extract-from-config --config-file=\"$CLICKHOUSE_CONFIG\" --key=path" >/dev/null || die "Configuration file ${CLICKHOUSE_CONFIG} doesn't parse successfully. Won't restart server. You may use forcerestart if you are sure."; fi } @@ -96,7 +96,7 @@ check_config() initdb() { if [ -x "$BINDIR/$GENERIC_PROGRAM" ]; then - CLICKHOUSE_DATADIR_FROM_CONFIG=$(su -l $CLICKHOUSE_USER -s $SHELL -c "$BINDIR/$GENERIC_PROGRAM --extract-from-config --config-file=\"$CLICKHOUSE_CONFIG\" --key=path") + CLICKHOUSE_DATADIR_FROM_CONFIG=$(su -s $SHELL ${CLICKHOUSE_USER} -c "$BINDIR/$GENERIC_PROGRAM --extract-from-config --config-file=\"$CLICKHOUSE_CONFIG\" --key=path") if [ "(" "$?" -ne "0" ")" -o "(" -z "${CLICKHOUSE_DATADIR_FROM_CONFIG}" ")" ]; then die "Cannot obtain value of path from config file: ${CLICKHOUSE_CONFIG}"; fi @@ -167,7 +167,7 @@ start() rm -f $CLICKHOUSE_PIDFILE # Lock should not be held while running child process, so we release the lock. Note: obviously, there is race condition. # But clickhouse-server has protection from simultaneous runs with same data directory. - su -l $CLICKHOUSE_USER -s $SHELL -c "flock -u 9; exec -a \"$PROGRAM\" \"$BINDIR/$PROGRAM\" --daemon --pid-file=\"$CLICKHOUSE_PIDFILE\" --config-file=\"$CLICKHOUSE_CONFIG\"" + su -s $SHELL ${CLICKHOUSE_USER} -c "flock -u 9; exec -a \"$PROGRAM\" \"$BINDIR/$PROGRAM\" --daemon --pid-file=\"$CLICKHOUSE_PIDFILE\" --config-file=\"$CLICKHOUSE_CONFIG\"" EXIT_STATUS=$? if [ $EXIT_STATUS -ne 0 ]; then break From fd9b8c6fbe661205c69dfe010569d65bf7b2c796 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 20:02:41 +0300 Subject: [PATCH 026/281] Fixed error [#METR-25976]. --- dbms/src/DataStreams/CSVRowInputStream.cpp | 6 ++--- .../TabSeparatedRowInputStream.cpp | 24 ++++++++++--------- dbms/src/Parsers/ParserInsertQuery.cpp | 5 +++- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/dbms/src/DataStreams/CSVRowInputStream.cpp b/dbms/src/DataStreams/CSVRowInputStream.cpp index ae4397fb3b7..7521abd690e 100644 --- a/dbms/src/DataStreams/CSVRowInputStream.cpp +++ b/dbms/src/DataStreams/CSVRowInputStream.cpp @@ -115,13 +115,13 @@ void CSVRowInputStream::readPrefix() bool CSVRowInputStream::read(Block & block) { + if (istr.eof()) + return false; + updateDiagnosticInfo(); size_t size = data_types.size(); - if (istr.eof()) - return false; - for (size_t i = 0; i < size; ++i) { skipWhitespacesAndTabs(istr); diff --git a/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp b/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp index fdbed86c550..35bc8ac89a1 100644 --- a/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp +++ b/dbms/src/DataStreams/TabSeparatedRowInputStream.cpp @@ -60,7 +60,7 @@ void TabSeparatedRowInputStream::readPrefix() } - /** Check for a common error case - usage of Windows line feed. +/** Check for a common error case - usage of Windows line feed. */ static void checkForCarriageReturn(ReadBuffer & istr) { @@ -75,13 +75,13 @@ static void checkForCarriageReturn(ReadBuffer & istr) bool TabSeparatedRowInputStream::read(Block & block) { + if (istr.eof()) + return false; + updateDiagnosticInfo(); size_t size = data_types.size(); - if (istr.eof()) - return false; - for (size_t i = 0; i < size; ++i) { data_types[i].get()->deserializeTextEscaped(*block.getByPosition(i).column.get(), istr); @@ -307,15 +307,17 @@ void TabSeparatedRowInputStream::syncAfterError() { skipToUnescapedNextLineOrEOF(istr); } + + void TabSeparatedRowInputStream::updateDiagnosticInfo() - { - ++row_num; +{ + ++row_num; - bytes_read_at_start_of_buffer_on_prev_row = bytes_read_at_start_of_buffer_on_current_row; - bytes_read_at_start_of_buffer_on_current_row = istr.count() - istr.offset(); + bytes_read_at_start_of_buffer_on_prev_row = bytes_read_at_start_of_buffer_on_current_row; + bytes_read_at_start_of_buffer_on_current_row = istr.count() - istr.offset(); - pos_of_prev_row = pos_of_current_row; - pos_of_current_row = istr.position(); - } + pos_of_prev_row = pos_of_current_row; + pos_of_current_row = istr.position(); +} } diff --git a/dbms/src/Parsers/ParserInsertQuery.cpp b/dbms/src/Parsers/ParserInsertQuery.cpp index 9222c00116f..1bb43d47f3d 100644 --- a/dbms/src/Parsers/ParserInsertQuery.cpp +++ b/dbms/src/Parsers/ParserInsertQuery.cpp @@ -75,6 +75,8 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) } else if (s_format.ignore(pos, expected)) { + auto name_pos = pos; + if (!name_p.parse(pos, format, expected)) return false; @@ -88,7 +90,8 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) "Note that there is no ';' in first line.", ErrorCodes::SYNTAX_ERROR); /// Data starts after the first newline, if there is one, or after all the whitespace characters, otherwise. - data = pos->begin; + + data = name_pos->end; while (data < end && (*data == ' ' || *data == '\t' || *data == '\f')) ++data; From b5913042652d03644a081b06ac7eabd188bda311 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Tue, 1 Aug 2017 20:14:45 +0300 Subject: [PATCH 027/281] Auto version update to [54266] --- dbms/cmake/version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index f7e5f0a1e65..07461982e61 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54265-testing) -set(VERSION_REVISION 54265) +set(VERSION_DESCRIBE v1.1.54266-testing) +set(VERSION_REVISION 54266) # end of autochange set (VERSION_MAJOR 1) From 35ff7ab9f2943e215e9f7d63767eb9a4d8dc5221 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Aug 2017 20:26:36 +0300 Subject: [PATCH 028/281] Added test [#METR-25976]. --- .../0_stateless/00485_http_insert_format.reference | 6 ++++++ .../0_stateless/00485_http_insert_format.sh | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00485_http_insert_format.reference create mode 100755 dbms/tests/queries/0_stateless/00485_http_insert_format.sh diff --git a/dbms/tests/queries/0_stateless/00485_http_insert_format.reference b/dbms/tests/queries/0_stateless/00485_http_insert_format.reference new file mode 100644 index 00000000000..08737b88a9d --- /dev/null +++ b/dbms/tests/queries/0_stateless/00485_http_insert_format.reference @@ -0,0 +1,6 @@ +{"s":"","x":"ABC"} +{"s":"","x":"DEF"} +{"s":"","x":"JKL"} +{"s":"","x":"MNO"} +{"s":"hello","x":"GHI"} +{"s":"hello","x":"PQR"} diff --git a/dbms/tests/queries/0_stateless/00485_http_insert_format.sh b/dbms/tests/queries/0_stateless/00485_http_insert_format.sh new file mode 100755 index 00000000000..1ff3702e435 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00485_http_insert_format.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +clickhouse-client --query="DROP TABLE IF EXISTS test.format" +clickhouse-client --query="CREATE TABLE test.format (s String, x FixedString(3)) ENGINE = Memory" + +echo -ne '\tABC\n' | curl -sS "http://localhost:8123/?query=INSERT+INTO+test.format+FORMAT+TabSeparated" --data-binary @- +echo -ne 'INSERT INTO test.format FORMAT TabSeparated\n\tDEF\n' | curl -sS "http://localhost:8123/" --data-binary @- +echo -ne 'INSERT INTO test.format FORMAT TabSeparated hello\tGHI\n' | curl -sS "http://localhost:8123/" --data-binary @- +echo -ne 'INSERT INTO test.format FORMAT TabSeparated\r\n\tJKL\n' | curl -sS "http://localhost:8123/" --data-binary @- +echo -ne 'INSERT INTO test.format FORMAT TabSeparated \t\r\n\tMNO\n' | curl -sS "http://localhost:8123/" --data-binary @- +echo -ne 'INSERT INTO test.format FORMAT TabSeparated\t\t\thello\tPQR\n' | curl -sS "http://localhost:8123/" --data-binary @- + +clickhouse-client --query="SELECT * FROM test.format ORDER BY s, x FORMAT JSONEachRow" +clickhouse-client --query="DROP TABLE test.format" From 2ae6f1ebdb9007c8664a0bc25f04405e17fe7011 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Tue, 1 Aug 2017 23:07:16 +0300 Subject: [PATCH 029/281] Update MergeTreeDataWriter.cpp --- dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index 67de3bcf30e..dff3d22f168 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -146,9 +146,9 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa ProfileEvents::increment(ProfileEvents::MergeTreeDataWriterBlocksAlreadySorted); } - auto compression_method = data.context.chooseCompressionMethod( - data.getTotalActiveSizeInBytes(), - static_cast(data.getTotalActiveSizeInBytes()) / data.getTotalCompressedSize()); + /// This effectively chooses minimal compression method: + /// either default lz4 or compression method with zero thresholds on absolute and relative part size. + auto compression_method = data.context.chooseCompressionMethod(0, 0); NamesAndTypesList columns = data.getColumnsList().filter(block.getColumnsList().getNames()); MergedBlockOutputStream out(data, new_data_part->getFullPath(), columns, compression_method); From afc4b1bef28cfeb48334a70463b4f7349c0cfd55 Mon Sep 17 00:00:00 2001 From: robot-metrika-test Date: Wed, 2 Aug 2017 17:13:14 +0300 Subject: [PATCH 030/281] Auto version update to [54267] --- dbms/cmake/version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbms/cmake/version.cmake b/dbms/cmake/version.cmake index 07461982e61..9b572b85bae 100644 --- a/dbms/cmake/version.cmake +++ b/dbms/cmake/version.cmake @@ -1,6 +1,6 @@ # This strings autochanged from release_lib.sh: -set(VERSION_DESCRIBE v1.1.54266-testing) -set(VERSION_REVISION 54266) +set(VERSION_DESCRIBE v1.1.54267-testing) +set(VERSION_REVISION 54267) # end of autochange set (VERSION_MAJOR 1) From 003d2a94788351b08d757645285505a4b693b339 Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Thu, 3 Aug 2017 03:21:50 +0300 Subject: [PATCH 031/281] Add comprehensive exception message for ZooKeeper::multi(). [#CLICKHOUSE-2] --- dbms/src/Common/ZooKeeper/ZooKeeper.cpp | 15 +++++- .../src/Common/ZooKeeper/tests/CMakeLists.txt | 3 ++ .../tests/zkutil_test_multi_exception.cpp | 49 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 dbms/src/Common/ZooKeeper/tests/zkutil_test_multi_exception.cpp diff --git a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp index c1fcb86a86f..11bf5cc45bd 100644 --- a/dbms/src/Common/ZooKeeper/ZooKeeper.cpp +++ b/dbms/src/Common/ZooKeeper/ZooKeeper.cpp @@ -568,7 +568,20 @@ int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_) OpResultsPtr ZooKeeper::multi(const Ops & ops) { OpResultsPtr results; - check(tryMulti(ops, &results)); + int code = tryMulti(ops, &results); + if (code != ZOK) + { + if (results && results->size() == ops.size()) + { + for (size_t i = 0; i < ops.size(); ++i) + { + if (results->at(i).err == code) + throw KeeperException("multi() failed at op #" + std::to_string(i) + ", " + ops[i]->describe(), code); + } + } + + throw KeeperException(code); + } return results; } diff --git a/dbms/src/Common/ZooKeeper/tests/CMakeLists.txt b/dbms/src/Common/ZooKeeper/tests/CMakeLists.txt index 82da63e8ab3..93409ca6f53 100644 --- a/dbms/src/Common/ZooKeeper/tests/CMakeLists.txt +++ b/dbms/src/Common/ZooKeeper/tests/CMakeLists.txt @@ -15,3 +15,6 @@ target_link_libraries(zkutil_zookeeper_holder dbms) add_executable (zk_many_watches_reconnect zk_many_watches_reconnect.cpp) target_link_libraries (zk_many_watches_reconnect dbms) + +add_executable (zkutil_test_multi_exception zkutil_test_multi_exception.cpp) +target_link_libraries (zkutil_test_multi_exception dbms) diff --git a/dbms/src/Common/ZooKeeper/tests/zkutil_test_multi_exception.cpp b/dbms/src/Common/ZooKeeper/tests/zkutil_test_multi_exception.cpp new file mode 100644 index 00000000000..bcf5d6614fd --- /dev/null +++ b/dbms/src/Common/ZooKeeper/tests/zkutil_test_multi_exception.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +using namespace DB; + +int main() +{ + auto zookeeper = std::make_unique("localhost:2181"); + + try + { + auto acl = zookeeper->getDefaultACL(); + zkutil::Ops ops; + + zookeeper->tryRemoveRecursive("/clickhouse_test_zkutil_multi"); + + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + zookeeper->multi(ops); + + ops.clear(); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/c", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Remove("/clickhouse_test_zkutil_multi/c", -1)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "BadBoy", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/b", "_", acl, zkutil::CreateMode::Persistent)); + ops.emplace_back(new zkutil::Op::Create("/clickhouse_test_zkutil_multi/a", "_", acl, zkutil::CreateMode::Persistent)); + + zookeeper->multi(ops); + } + catch (...) + { + zookeeper->tryRemoveRecursive("/clickhouse_test_zkutil_multi"); + + String msg = getCurrentExceptionMessage(false); + + if (msg.find("/clickhouse_test_zkutil_multi/a") == std::string::npos || msg.find("#2") == std::string::npos) + { + std::cerr << "Wrong: " << msg; + return -1; + } + + std::cout << "Ok: " << msg; + return 0; + } + + std::cerr << "Unexpected"; + return -1; +} From d6833a0d5569a9dbd4d1cdf67d95015712f13cb6 Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 3 Aug 2017 15:44:39 +0300 Subject: [PATCH 032/281] Cmake: remove global include_directories (#1055) * Fix .h compile * Cmake: remove global include_directories * boost include hide * fix cctz * add \n --- cmake/find_boost.cmake | 4 -- contrib/libboost/CMakeLists.txt | 5 ++ contrib/libbtrie/CMakeLists.txt | 4 +- contrib/libcctz/CMakeLists.txt | 13 ++-- contrib/libcityhash/CMakeLists.txt | 5 +- contrib/libfarmhash/CMakeLists.txt | 4 +- contrib/liblz4/CMakeLists.txt | 3 +- contrib/libmetrohash/CMakeLists.txt | 4 +- contrib/libre2/CMakeLists.txt | 6 +- contrib/libtcmalloc/CMakeLists.txt | 73 ++++++++++---------- contrib/libunwind/CMakeLists.txt | 10 ++- contrib/libzookeeper/CMakeLists.txt | 17 ++--- dbms/cmake/find_vectorclass.cmake | 13 ++-- dbms/src/Functions/CMakeLists.txt | 4 ++ dbms/tests/CMakeLists.txt | 2 +- libs/libcommon/CMakeLists.txt | 4 +- libs/libcommon/cmake/find_cctz.cmake | 2 - libs/libcommon/cmake/find_gperftools.cmake | 4 -- libs/libcommon/cmake/find_jemalloc.cmake | 3 +- libs/libdaemon/CMakeLists.txt | 8 +-- libs/libdaemon/cmake/find_unwind.cmake | 2 - libs/libmysqlxx/CMakeLists.txt | 4 +- libs/libmysqlxx/cmake/find_mysqlclient.cmake | 1 - libs/libmysqlxx/src/tests/CMakeLists.txt | 1 - libs/libpocoext/CMakeLists.txt | 6 +- utils/corrector_utf8/CMakeLists.txt | 1 - utils/iotest/CMakeLists.txt | 2 - 27 files changed, 100 insertions(+), 105 deletions(-) diff --git a/cmake/find_boost.cmake b/cmake/find_boost.cmake index 12dc9ec809c..a7f72d8c68e 100644 --- a/cmake/find_boost.cmake +++ b/cmake/find_boost.cmake @@ -16,9 +16,6 @@ if (NOT USE_INTERNAL_BOOST_LIBRARY) set (Boost_SYSTEM_LIBRARY "") endif () - if (Boost_INCLUDE_DIRS) - include_directories (${Boost_INCLUDE_DIRS}) - endif () endif () if (NOT Boost_SYSTEM_LIBRARY) @@ -28,7 +25,6 @@ if (NOT Boost_SYSTEM_LIBRARY) set (Boost_SYSTEM_LIBRARY boost_system_internal) set (Boost_FILESYSTEM_LIBRARY boost_filesystem_internal) set (Boost_INCLUDE_DIRS "${ClickHouse_SOURCE_DIR}/contrib/libboost/boost_1_62_0/") - include_directories (BEFORE ${Boost_INCLUDE_DIRS}) endif () message (STATUS "Using Boost: ${Boost_INCLUDE_DIRS} : ${Boost_PROGRAM_OPTIONS_LIBRARY},${Boost_SYSTEM_LIBRARY},${Boost_FILESYSTEM_LIBRARY}") diff --git a/contrib/libboost/CMakeLists.txt b/contrib/libboost/CMakeLists.txt index 45f01045b31..8c630ee1dba 100644 --- a/contrib/libboost/CMakeLists.txt +++ b/contrib/libboost/CMakeLists.txt @@ -48,3 +48,8 @@ boost_1_62_0/libs/test/src/unit_test_monitor.cpp boost_1_62_0/libs/test/src/unit_test_parameters.cpp boost_1_62_0/libs/test/src/xml_log_formatter.cpp boost_1_62_0/libs/test/src/xml_report_formatter.cpp) + +target_include_directories (boost_program_options_internal BEFORE PUBLIC ${Boost_INCLUDE_DIRS}) +target_include_directories (boost_filesystem_internal BEFORE PUBLIC ${Boost_INCLUDE_DIRS}) +target_include_directories (boost_system_internal BEFORE PUBLIC ${Boost_INCLUDE_DIRS}) +target_include_directories (boost_test_internal BEFORE PUBLIC ${Boost_INCLUDE_DIRS}) diff --git a/contrib/libbtrie/CMakeLists.txt b/contrib/libbtrie/CMakeLists.txt index 8d91eb1c316..7423fc57bea 100644 --- a/contrib/libbtrie/CMakeLists.txt +++ b/contrib/libbtrie/CMakeLists.txt @@ -1,6 +1,6 @@ -include_directories (BEFORE include) - add_library (btrie src/btrie.c include/btrie.h ) + +target_include_directories (btrie PUBLIC include) diff --git a/contrib/libcctz/CMakeLists.txt b/contrib/libcctz/CMakeLists.txt index 14767e6c7f7..e87a7da4c44 100644 --- a/contrib/libcctz/CMakeLists.txt +++ b/contrib/libcctz/CMakeLists.txt @@ -1,9 +1,3 @@ -include_directories (include) - -if (CMAKE_SYSTEM MATCHES "FreeBSD") - # yes, need linux, because bsd check inside linux in time_zone_libc.cc:24 - add_definitions (-D__USE_BSD -Dlinux -D_XOPEN_SOURCE=600) -endif () add_library(cctz src/time_zone_libc.cc @@ -24,3 +18,10 @@ add_library(cctz include/time_zone.h include/civil_time_detail.h include/civil_time.h) + +if (CMAKE_SYSTEM MATCHES "FreeBSD") + # yes, need linux, because bsd check inside linux in time_zone_libc.cc:24 + target_compile_definitions (cctz PRIVATE __USE_BSD linux _XOPEN_SOURCE=600) +endif () + +target_include_directories (cctz PUBLIC include) diff --git a/contrib/libcityhash/CMakeLists.txt b/contrib/libcityhash/CMakeLists.txt index 3bc7fe8a041..8c3716d8526 100644 --- a/contrib/libcityhash/CMakeLists.txt +++ b/contrib/libcityhash/CMakeLists.txt @@ -1,8 +1,9 @@ -include_directories (include src) - add_library(cityhash src/city.cc include/citycrc.h include/city.h src/config.h) + +target_include_directories (cityhash PUBLIC include) +target_include_directories (cityhash PRIVATE src) diff --git a/contrib/libfarmhash/CMakeLists.txt b/contrib/libfarmhash/CMakeLists.txt index 170fb17ac53..7781028094d 100644 --- a/contrib/libfarmhash/CMakeLists.txt +++ b/contrib/libfarmhash/CMakeLists.txt @@ -1,5 +1,5 @@ -include_directories (${CMAKE_CURRENT_BINARY_DIR}) - add_library(farmhash farmhash.cc farmhash.h) + +target_include_directories (farmhash PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/contrib/liblz4/CMakeLists.txt b/contrib/liblz4/CMakeLists.txt index 033b923e8e3..98f13476887 100644 --- a/contrib/liblz4/CMakeLists.txt +++ b/contrib/liblz4/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (BEFORE include) - add_library (lz4 src/lz4.c src/lz4hc.c @@ -8,3 +6,4 @@ add_library (lz4 include/lz4/lz4hc.h include/lz4/lz4opt.h) +target_include_directories(lz4 PUBLIC include) diff --git a/contrib/libmetrohash/CMakeLists.txt b/contrib/libmetrohash/CMakeLists.txt index f9a2d147e22..6947b92e054 100644 --- a/contrib/libmetrohash/CMakeLists.txt +++ b/contrib/libmetrohash/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (${CMAKE_CURRENT_BINARY_DIR}) - if (HAVE_SSE42) # Not used. Pretty easy to port. set (SOURCES_SSE42_ONLY src/metrohash128crc.cpp) endif () @@ -11,3 +9,5 @@ add_library(metrohash src/metrohash64.cpp src/metrohash128.cpp ${SOURCES_SSE42_ONLY}) + +target_include_directories(metrohash PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/contrib/libre2/CMakeLists.txt b/contrib/libre2/CMakeLists.txt index c76162fa371..111c60f3f49 100644 --- a/contrib/libre2/CMakeLists.txt +++ b/contrib/libre2/CMakeLists.txt @@ -34,14 +34,12 @@ set (re2_sources # re2 changes its state during matching of regular expression, e.g. creates temporary DFA. # It uses RWLock to process the same regular expression object from different threads. # In order to avoid redundant locks in some cases, we use not thread-safe version of the library (re2_st). -add_definitions (-DNDEBUG) - -include_directories (BEFORE .) add_library (re2 ${re2_sources}) add_library (re2_st ${re2_sources}) -set_target_properties (re2_st PROPERTIES COMPILE_DEFINITIONS "NO_THREADS;re2=re2_st") +target_compile_definitions (re2 PRIVATE NDEBUG) +target_compile_definitions (re2_st PRIVATE NDEBUG NO_THREADS re2=re2_st) file (MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/re2_st) foreach (FILENAME filtered_re2.h re2.h set.h stringpiece.h variadic_function.h) diff --git a/contrib/libtcmalloc/CMakeLists.txt b/contrib/libtcmalloc/CMakeLists.txt index d07ed17a0b2..57b7cd9c553 100644 --- a/contrib/libtcmalloc/CMakeLists.txt +++ b/contrib/libtcmalloc/CMakeLists.txt @@ -1,39 +1,5 @@ -add_definitions( - -DNO_TCMALLOC_SAMPLES - -DNDEBUG - -DNO_FRAME_POINTER - -Wwrite-strings - -Wno-sign-compare - -Wno-unused-result - -Wno-deprecated-declarations - -Wno-unused-function - -Wno-unused-private-field - -fno-builtin-malloc - -fno-builtin-free - -fno-builtin-realloc - -fno-builtin-calloc - -fno-builtin-cfree - -fno-builtin-memalign - -fno-builtin-posix_memalign - -fno-builtin-valloc - -fno-builtin-pvalloc -) -if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.9) - add_definitions( -Wno-dynamic-exception-spec ) -endif() - -if(CMAKE_SYSTEM MATCHES "FreeBSD" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - add_definitions(-Wno-unused-but-set-variable) -endif() - -if(CMAKE_SYSTEM MATCHES "FreeBSD") - add_definitions(-D_GNU_SOURCE) -endif() - -include_directories (include src) - -message(STATUS "Building: tcmalloc_minimal_internal") +message (STATUS "Building: tcmalloc_minimal_internal") add_library (tcmalloc_minimal_internal ./src/malloc_hook.cc @@ -71,3 +37,40 @@ add_library (tcmalloc_minimal_internal ./src/raw_printer.cc ./src/memory_region_map.cc ) + +target_compile_options (tcmalloc_minimal_internal PUBLIC + -DNO_TCMALLOC_SAMPLES + -DNDEBUG + -DNO_FRAME_POINTER + -Wwrite-strings + -Wno-sign-compare + -Wno-unused-result + -Wno-deprecated-declarations + -Wno-unused-function + -Wno-unused-private-field + -fno-builtin-malloc + -fno-builtin-free + -fno-builtin-realloc + -fno-builtin-calloc + -fno-builtin-cfree + -fno-builtin-memalign + -fno-builtin-posix_memalign + -fno-builtin-valloc + -fno-builtin-pvalloc +) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.9) + target_compile_options(tcmalloc_minimal_internal PUBLIC -Wno-dynamic-exception-spec ) +endif () + +if (CMAKE_SYSTEM MATCHES "FreeBSD" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(tcmalloc_minimal_internal PUBLIC -Wno-unused-but-set-variable) +endif () + +if (CMAKE_SYSTEM MATCHES "FreeBSD") + target_compile_definitions(tcmalloc_minimal_internal PUBLIC _GNU_SOURCE) +endif () + +target_include_directories (tcmalloc_minimal_internal PUBLIC include) +target_include_directories (tcmalloc_minimal_internal PRIVATE src) + diff --git a/contrib/libunwind/CMakeLists.txt b/contrib/libunwind/CMakeLists.txt index 69f67c52a39..1a1b1e79bc3 100644 --- a/contrib/libunwind/CMakeLists.txt +++ b/contrib/libunwind/CMakeLists.txt @@ -1,6 +1,3 @@ -add_definitions(-DHAVE_CONFIG_H=1 -D_XOPEN_SOURCE -D_GNU_SOURCE -Wno-visibility -Wno-header-guard) - -include_directories(include include/tdep src) enable_language(ASM) @@ -55,3 +52,10 @@ src/elf64.c src/os-linux.c src/x86_64/Los-linux.c ) + +target_compile_definitions (unwind PRIVATE HAVE_CONFIG_H=1 _XOPEN_SOURCE _GNU_SOURCE) +target_compile_options (unwind PRIVATE -Wno-visibility -Wno-header-guard) + +target_include_directories (unwind PUBLIC include) +target_include_directories (unwind PRIVATE include/tdep) +target_include_directories (unwind PRIVATE src) diff --git a/contrib/libzookeeper/CMakeLists.txt b/contrib/libzookeeper/CMakeLists.txt index db13694527b..1d9eb050c9c 100644 --- a/contrib/libzookeeper/CMakeLists.txt +++ b/contrib/libzookeeper/CMakeLists.txt @@ -1,8 +1,3 @@ -add_definitions(-DHAVE_CONFIG_H -DTHREADED) - -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - add_definitions(-Wno-unused-but-set-variable) -endif() add_library (zookeeper_mt src/zookeeper.c @@ -15,8 +10,14 @@ src/hashtable/hashtable.c src/hashtable/hashtable_itr.c ) +target_compile_definitions (zookeeper_mt PRIVATE HAVE_CONFIG_H THREADED) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options (zookeeper_mt PRIVATE -Wno-unused-but-set-variable) +endif() + target_include_directories (zookeeper_mt - PRIVATE include/zookeeper - PRIVATE src - INTERFACE include + PRIVATE include/zookeeper + PRIVATE src + INTERFACE include ) diff --git a/dbms/cmake/find_vectorclass.cmake b/dbms/cmake/find_vectorclass.cmake index c94bb4640e3..021929a4090 100644 --- a/dbms/cmake/find_vectorclass.cmake +++ b/dbms/cmake/find_vectorclass.cmake @@ -3,14 +3,13 @@ option (ENABLE_VECTORCLASS "Faster math functions with vectorclass lib" OFF) if (ENABLE_VECTORCLASS) -set (VECTORCLASS_INCLUDE_PATHS "${ClickHouse_SOURCE_DIR}/contrib/vectorclass" CACHE STRING "Path of vectorclass library") -find_path (VECTORCLASS_INCLUDE_DIR NAMES vectorf128.h PATHS ${VECTORCLASS_INCLUDE_PATHS}) + set (VECTORCLASS_INCLUDE_PATHS "${ClickHouse_SOURCE_DIR}/contrib/vectorclass" CACHE STRING "Path of vectorclass library") + find_path (VECTORCLASS_INCLUDE_DIR NAMES vectorf128.h PATHS ${VECTORCLASS_INCLUDE_PATHS}) -if (VECTORCLASS_INCLUDE_DIR) - set (USE_VECTORCLASS 1) - include_directories (BEFORE ${VECTORCLASS_INCLUDE_DIR}) -endif () + if (VECTORCLASS_INCLUDE_DIR) + set (USE_VECTORCLASS 1) + endif () -message (STATUS "Using vectorclass=${ENABLE_VECTORCLASS}: ${VECTORCLASS_INCLUDE_DIR}") + message (STATUS "Using vectorclass=${USE_VECTORCLASS}: ${VECTORCLASS_INCLUDE_DIR}") endif () diff --git a/dbms/src/Functions/CMakeLists.txt b/dbms/src/Functions/CMakeLists.txt index 36017fd0d18..d92e2a4603f 100644 --- a/dbms/src/Functions/CMakeLists.txt +++ b/dbms/src/Functions/CMakeLists.txt @@ -68,6 +68,10 @@ target_include_directories (clickhouse_functions BEFORE PUBLIC ${ClickHouse_SOUR target_include_directories (clickhouse_functions BEFORE PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/libmetrohash/src) target_include_directories (clickhouse_functions BEFORE PUBLIC ${CITYHASH_INCLUDE_DIR}) +if (USE_VECTORCLASS) + target_include_directories (clickhouse_functions BEFORE PUBLIC ${VECTORCLASS_INCLUDE_DIR}) +endif () + if (ENABLE_TESTS) add_subdirectory (tests) endif () diff --git a/dbms/tests/CMakeLists.txt b/dbms/tests/CMakeLists.txt index 7ec702449f2..3eff0f02cc9 100644 --- a/dbms/tests/CMakeLists.txt +++ b/dbms/tests/CMakeLists.txt @@ -11,7 +11,7 @@ endif () # Google Test from sources add_subdirectory(${ClickHouse_SOURCE_DIR}/contrib/googletest ${CMAKE_CURRENT_BINARY_DIR}/googletest) # avoid problems with -target_compile_definitions (gtest INTERFACE -DGTEST_HAS_POSIX_RE=0) +target_compile_definitions (gtest INTERFACE GTEST_HAS_POSIX_RE=0) target_include_directories (gtest INTERFACE ${ClickHouse_SOURCE_DIR}/contrib/googletest/include) diff --git a/libs/libcommon/CMakeLists.txt b/libs/libcommon/CMakeLists.txt index 534d728e49b..0c50a44089d 100644 --- a/libs/libcommon/CMakeLists.txt +++ b/libs/libcommon/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (include) - if (APPLE) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND NOT "${CMAKE_SYSTEM_VERSION}" VERSION_LESS "16.1.0") set (APPLE_SIERRA_OR_NEWER 1) @@ -80,7 +78,7 @@ find_package (Threads) target_include_directories (common BEFORE PRIVATE ${CCTZ_INCLUDE_DIR}) target_include_directories (common BEFORE PUBLIC ${CITYHASH_INCLUDE_DIR}) -target_include_directories (common BEFORE PUBLIC ${COMMON_INCLUDE_DIR}) +target_include_directories (common PUBLIC ${COMMON_INCLUDE_DIR}) target_link_libraries ( common diff --git a/libs/libcommon/cmake/find_cctz.cmake b/libs/libcommon/cmake/find_cctz.cmake index 807cb9eb56c..a8a4d99521d 100644 --- a/libs/libcommon/cmake/find_cctz.cmake +++ b/libs/libcommon/cmake/find_cctz.cmake @@ -6,11 +6,9 @@ if (NOT USE_INTERNAL_CCTZ_LIBRARY) endif () if (CCTZ_LIBRARY AND CCTZ_INCLUDE_DIR) - #include_directories (${CCTZ_INCLUDE_DIR}) else () set (USE_INTERNAL_CCTZ_LIBRARY 1) set (CCTZ_INCLUDE_DIR "${ClickHouse_SOURCE_DIR}/contrib/libcctz/include") - #include_directories (BEFORE ${CCTZ_INCLUDE_DIR}) set (CCTZ_LIBRARY cctz) endif () diff --git a/libs/libcommon/cmake/find_gperftools.cmake b/libs/libcommon/cmake/find_gperftools.cmake index 052755c9d51..ff95e2a480a 100644 --- a/libs/libcommon/cmake/find_gperftools.cmake +++ b/libs/libcommon/cmake/find_gperftools.cmake @@ -10,16 +10,12 @@ if (ENABLE_LIBTCMALLOC) #contrib/libtcmalloc doesnt build debug version, try find in system if (DEBUG_LIBTCMALLOC OR NOT USE_INTERNAL_GPERFTOOLS_LIBRARY) find_package (Gperftools) - if (GPERFTOOLS_FOUND) - include_directories (${GPERFTOOLS_INCLUDE_DIR}) - endif () endif () if (NOT (GPERFTOOLS_FOUND AND GPERFTOOLS_INCLUDE_DIR AND GPERFTOOLS_TCMALLOC_MINIMAL)) set (USE_INTERNAL_GPERFTOOLS_LIBRARY 1) set (GPERFTOOLS_INCLUDE_DIR "${ClickHouse_SOURCE_DIR}/contrib/libtcmalloc/include") set (GPERFTOOLS_TCMALLOC_MINIMAL tcmalloc_minimal_internal) - include_directories (BEFORE ${GPERFTOOLS_INCLUDE_DIR}) endif () set (USE_TCMALLOC 1) diff --git a/libs/libcommon/cmake/find_jemalloc.cmake b/libs/libcommon/cmake/find_jemalloc.cmake index bac53073be9..f8fb20fe9b6 100644 --- a/libs/libcommon/cmake/find_jemalloc.cmake +++ b/libs/libcommon/cmake/find_jemalloc.cmake @@ -1,10 +1,9 @@ option (ENABLE_JEMALLOC "Set to TRUE to use jemalloc instead of tcmalloc" OFF) if (ENABLE_JEMALLOC) - find_package(JeMalloc) + find_package (JeMalloc) if (JEMALLOC_INCLUDE_DIR AND JEMALLOC_LIBRARIES) - include_directories (${JEMALLOC_INCLUDE_DIR}) set (USE_JEMALLOC 1) if (USE_TCMALLOC) message (WARNING "Disabling tcmalloc") diff --git a/libs/libdaemon/CMakeLists.txt b/libs/libdaemon/CMakeLists.txt index e20a99a78cc..6a2fde64588 100644 --- a/libs/libdaemon/CMakeLists.txt +++ b/libs/libdaemon/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (include) - add_library (daemon src/BaseDaemon.cpp src/GraphiteWriter.cpp @@ -11,10 +9,12 @@ add_library (daemon ) if (USE_UNWIND) + target_compile_definitions (daemon PRIVATE USE_UNWIND=1) target_include_directories (daemon BEFORE PRIVATE ${UNWIND_INCLUDE_DIR}) - add_definitions(-DUSE_UNWIND=1) target_link_libraries (daemon ${UNWIND_LIBRARY}) endif () -target_link_libraries (daemon dbms) +target_include_directories (daemon PUBLIC include) target_include_directories (daemon PRIVATE ${ClickHouse_SOURCE_DIR}/libs/libpocoext/include) + +target_link_libraries (daemon dbms) diff --git a/libs/libdaemon/cmake/find_unwind.cmake b/libs/libdaemon/cmake/find_unwind.cmake index 007240ad88b..0c55715b60c 100644 --- a/libs/libdaemon/cmake/find_unwind.cmake +++ b/libs/libdaemon/cmake/find_unwind.cmake @@ -33,12 +33,10 @@ if (NOT USE_INTERNAL_UNWIND_LIBRARY) endif () if (UNWIND_LIBRARY AND UNWIND_INCLUDE_DIR) - #include_directories (${UNWIND_INCLUDE_DIR}) set (USE_UNWIND 1) elseif (CMAKE_SYSTEM MATCHES "Linux" AND NOT ARM) set (USE_INTERNAL_UNWIND_LIBRARY 1) set (UNWIND_INCLUDE_DIR "${ClickHouse_SOURCE_DIR}/contrib/libunwind/include") - #include_directories (BEFORE ${UNWIND_INCLUDE_DIR}) set (UNWIND_LIBRARY unwind) set (USE_UNWIND 1) endif () diff --git a/libs/libmysqlxx/CMakeLists.txt b/libs/libmysqlxx/CMakeLists.txt index f3455f780e1..df732d24d02 100644 --- a/libs/libmysqlxx/CMakeLists.txt +++ b/libs/libmysqlxx/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (include) -include_directories (${ClickHouse_SOURCE_DIR}/libs/libcommon/include) add_library (mysqlxx src/Connection.cpp @@ -30,6 +28,8 @@ add_library (mysqlxx include/mysqlxx/Value.h ) +target_include_directories (mysqlxx PUBLIC include) + set(PLATFORM_LIBS ${CMAKE_DL_LIBS}) if (USE_STATIC_LIBRARIES AND STATIC_MYSQLCLIENT_LIB) diff --git a/libs/libmysqlxx/cmake/find_mysqlclient.cmake b/libs/libmysqlxx/cmake/find_mysqlclient.cmake index b98852919f6..ae77349e444 100644 --- a/libs/libmysqlxx/cmake/find_mysqlclient.cmake +++ b/libs/libmysqlxx/cmake/find_mysqlclient.cmake @@ -29,7 +29,6 @@ if (ENABLE_MYSQL) if (MYSQL_INCLUDE_DIR AND (STATIC_MYSQLCLIENT_LIB OR MYSQLCLIENT_LIB)) set (MYSQL_FOUND 1) - include_directories (${MYSQL_INCLUDE_DIR}) endif () if (MYSQL_FOUND) diff --git a/libs/libmysqlxx/src/tests/CMakeLists.txt b/libs/libmysqlxx/src/tests/CMakeLists.txt index fa419a666da..86fadceb885 100644 --- a/libs/libmysqlxx/src/tests/CMakeLists.txt +++ b/libs/libmysqlxx/src/tests/CMakeLists.txt @@ -1,4 +1,3 @@ -include_directories (${CMAKE_CURRENT_BINARY_DIR}) add_executable (mysqlxx_test mysqlxx_test.cpp) add_executable (failover failover.cpp) diff --git a/libs/libpocoext/CMakeLists.txt b/libs/libpocoext/CMakeLists.txt index 5800bfcc5b6..18eaaabf67d 100644 --- a/libs/libpocoext/CMakeLists.txt +++ b/libs/libpocoext/CMakeLists.txt @@ -1,6 +1,3 @@ -include_directories (include) -include_directories (${ClickHouse_SOURCE_DIR}/libs/libcommon/include) - add_library (pocoext src/LevelFilterChannel.cpp src/ThreadNumber.cpp @@ -8,4 +5,7 @@ add_library (pocoext include/Poco/Ext/LevelFilterChannel.h include/Poco/Ext/ThreadNumber.h) +target_include_directories (pocoext PUBLIC include PRIVATE ${COMMON_INCLUDE_DIR}) + + target_link_libraries(pocoext ${Poco_Util_LIBRARY} ${Poco_Net_LIBRARY} ${Poco_XML_LIBRARY} ${Poco_Foundation_LIBRARY}) diff --git a/utils/corrector_utf8/CMakeLists.txt b/utils/corrector_utf8/CMakeLists.txt index a48433c5804..db5cfc4964b 100644 --- a/utils/corrector_utf8/CMakeLists.txt +++ b/utils/corrector_utf8/CMakeLists.txt @@ -1,4 +1,3 @@ -include_directories (${ClickHouse_SOURCE_DIR}/dbms/src) add_executable(corrector_utf8 corrector_utf8.cpp) diff --git a/utils/iotest/CMakeLists.txt b/utils/iotest/CMakeLists.txt index 9c1bb50cb2c..f4f916b3f7f 100644 --- a/utils/iotest/CMakeLists.txt +++ b/utils/iotest/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories (${ClickHouse_SOURCE_DIR}/dbms/src) -include_directories (${ClickHouse_SOURCE_DIR}/libs/libcommon/include) add_executable (iotest iotest.cpp ${SRCS}) target_link_libraries (iotest dbms) From 0c15b2c6fc74a02708fb4dd1bb2e7d4b7a09f539 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 1 Aug 2017 16:04:48 +0300 Subject: [PATCH 033/281] fixed number of rows to read from first granula in mergetree --- .../MergeTreeBaseBlockInputStream.cpp | 25 +++++++++++++++---- .../MergeTree/MergeTreeRangeReader.cpp | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/dbms/src/Storages/MergeTree/MergeTreeBaseBlockInputStream.cpp b/dbms/src/Storages/MergeTree/MergeTreeBaseBlockInputStream.cpp index b798f59b4db..ad288f0be5c 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeBaseBlockInputStream.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeBaseBlockInputStream.cpp @@ -13,6 +13,7 @@ namespace DB namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER; + extern const int LOGICAL_ERROR; } @@ -208,7 +209,9 @@ Block MergeTreeBaseBlockInputStream::readFromPart() if (!res) { if (!pre_range_reader) + { task->current_range_reader = std::experimental::nullopt; + } return res; } @@ -297,7 +300,7 @@ Block MergeTreeBaseBlockInputStream::readFromPart() if (!task->current_range_reader) { if (next_range_idx == ranges_to_read.size()) - throw Exception("Nothing to read"); + throw Exception("Not enough ranges to read after prewhere.", ErrorCodes::LOGICAL_ERROR); const auto & range = ranges_to_read[next_range_idx++]; task->current_range_reader = reader->readRange(range.begin, range.end); } @@ -307,7 +310,7 @@ Block MergeTreeBaseBlockInputStream::readFromPart() /// Now we need to read the same number of rows as in prewhere. size_t rows_to_read = next_range_idx == ranges_to_read.size() - ? rows_was_read_in_last_range : task->current_range_reader->unreadRows(); + ? rows_was_read_in_last_range : (task->current_range_reader->unreadRows() - number_of_rows_to_skip); auto readRows = [&]() { @@ -352,8 +355,18 @@ Block MergeTreeBaseBlockInputStream::readFromPart() if (will_read_until_mark) { /// Can skip the rest of granule with false prewhere conditon right now. - current_range_rows_read += range_reader.skipToNextMark() - number_of_rows_to_skip; - number_of_rows_to_skip = 0; + do + { + size_t rows_was_skipped = range_reader.skipToNextMark(); + if (number_of_rows_to_skip < rows_was_skipped) + { + current_range_rows_read += rows_was_skipped - number_of_rows_to_skip; + number_of_rows_to_skip = 0; + } + else + number_of_rows_to_skip -= rows_was_skipped; + } + while (number_of_rows_to_skip); } else { @@ -364,7 +377,6 @@ Block MergeTreeBaseBlockInputStream::readFromPart() pre_filter_begin_pos = limit; } - pre_filter_pos = limit; } @@ -405,6 +417,7 @@ Block MergeTreeBaseBlockInputStream::readFromPart() /// Replace column with condition value from PREWHERE to a constant. if (!task->remove_prewhere_column) res.getByName(prewhere_column).column = DataTypeUInt8().createConstColumn(rows, UInt64(1)); + } else throw Exception{ @@ -445,7 +458,9 @@ Block MergeTreeBaseBlockInputStream::readFromPart() task->current_range_reader = std::experimental::nullopt; if (res && task->size_predictor) + { task->size_predictor->update(res); + } space_left -= rows_was_read; } diff --git a/dbms/src/Storages/MergeTree/MergeTreeRangeReader.cpp b/dbms/src/Storages/MergeTree/MergeTreeRangeReader.cpp index 7b795074716..93dcd0ef370 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeRangeReader.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeRangeReader.cpp @@ -15,6 +15,8 @@ size_t MergeTreeRangeReader::skipToNextMark() auto unread_rows_in_current_part = unreadRowsInCurrentGranule(); continue_reading = false; ++current_mark; + if (current_mark == last_mark) + is_reading_finished = true; read_rows_after_current_mark = 0; return unread_rows_in_current_part; } From 83cd2a40e4209b6f7cba7b2a67d8ecc5ea770758 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 1 Aug 2017 20:52:05 +0300 Subject: [PATCH 034/281] added test --- .../00484_preferred_max_column_in_block_size_bytes.sql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dbms/tests/queries/0_stateless/00484_preferred_max_column_in_block_size_bytes.sql b/dbms/tests/queries/0_stateless/00484_preferred_max_column_in_block_size_bytes.sql index 4c4b89cd2fe..6ab513feac1 100644 --- a/dbms/tests/queries/0_stateless/00484_preferred_max_column_in_block_size_bytes.sql +++ b/dbms/tests/queries/0_stateless/00484_preferred_max_column_in_block_size_bytes.sql @@ -12,3 +12,9 @@ set preferred_max_column_in_block_size_bytes = 2097152; select max(blockSize()), min(blockSize()), any(ignore(*)) from test.tab; set preferred_max_column_in_block_size_bytes = 4194304; select max(blockSize()), min(blockSize()), any(ignore(*)) from test.tab; + +drop table if exists test.tab; +create table test.tab (date Date, x UInt64, s FixedString(128)) engine = MergeTree(date, (date, x), 32); +insert into test.tab select today(), number, toFixedString('', 128) from system.numbers limit 47; +set preferred_max_column_in_block_size_bytes = 1152; +select blockSize(), * from test.tab where x = 1 or x > 36 format Null; From 23263a1acc45cd95fdf8669eb009469711d8402e Mon Sep 17 00:00:00 2001 From: proller Date: Thu, 3 Aug 2017 16:23:41 +0300 Subject: [PATCH 035/281] Fix apple build --- libs/libcommon/CMakeLists.txt | 1 + libs/libcommon/src/tests/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/libcommon/CMakeLists.txt b/libs/libcommon/CMakeLists.txt index 0c50a44089d..c2aa28b2a9d 100644 --- a/libs/libcommon/CMakeLists.txt +++ b/libs/libcommon/CMakeLists.txt @@ -14,6 +14,7 @@ if (APPLE) src/apple_rt.cpp include/common/apple_rt.h ) + target_include_directories (apple_rt PUBLIC ${COMMON_INCLUDE_DIR}) endif () add_library (common diff --git a/libs/libcommon/src/tests/CMakeLists.txt b/libs/libcommon/src/tests/CMakeLists.txt index b092cb2694e..65a1d0bc77e 100644 --- a/libs/libcommon/src/tests/CMakeLists.txt +++ b/libs/libcommon/src/tests/CMakeLists.txt @@ -1,7 +1,5 @@ include (${ClickHouse_SOURCE_DIR}/cmake/add_check.cmake) -include_directories (${CMAKE_CURRENT_BINARY_DIR}) - add_executable (date_lut_init date_lut_init.cpp) add_executable (date_lut2 date_lut2.cpp) add_executable (date_lut3 date_lut3.cpp) From 63ec81e2e3dc9ded591dd895827b173fe57af660 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 3 Aug 2017 20:42:31 +0300 Subject: [PATCH 036/281] added threadpool for sync insertion into distributed --- .../DistributedBlockOutputStream.cpp | 114 +++++++++++++++++- .../DistributedBlockOutputStream.h | 20 ++- 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp index 3d6200c0620..919cf062205 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.cpp @@ -21,12 +21,15 @@ #include #include #include +#include #include #include #include #include +#include +#include namespace CurrentMetrics { @@ -52,8 +55,27 @@ DistributedBlockOutputStream::DistributedBlockOutputStream(StorageDistributed & { } +DistributedBlockOutputStream::writePrefix() +{ + deadline = std::chrono::steady_clock::now() + std::chrono::seconds(insert_timeout); + remote_jobs_count = 0; + if (storage.getShardingKeyExpr()) + { + const auto & shards_info = cluster->getShardsInfo(); + for (const auto & shard_info : shards_info) + remote_jobs_count += shard_info.dir_names.size(); + } +} void DistributedBlockOutputStream::write(const Block & block) +{ + if (insert_sync) + writeSync(block); + else + writeAsync(block); +} + +void DistributedBlockOutputStream::writeAsync(const Block & block) { if (storage.getShardingKeyExpr() && (cluster->getShardsInfo().size() > 1)) return writeSplit(block); @@ -62,6 +84,85 @@ void DistributedBlockOutputStream::write(const Block & block) ++blocks_inserted; } +ThreadPool::Job createWritingJob(std::vector & done_jobs, std::atomic & finished_jobs_count, + std::condition_variable & cond_var, const Block & block, size_t job_id, + const Cluster::ShardInfo & shard_info, size_t replica_id) +{ + auto memory_tracker = current_memory_tracker; + return [this, memory_tracker, & done_jobs, & finished_jobs_count, & cond_var, & block, + size_t job_id, const Cluster::ShardInfo & shard_info, size_t replica_id]() + { + if (!current_memory_tracker) + { + current_memory_tracker = memory_tracker; + setThreadName("DistributedBlockOutputStreamProc"); + } + try + { + this->writeToShardSync(block, shard_info, replica_id); + ++finished_jobs_count; + done_jobs[job_id] = true; + cond_var.notify_one(); + } + catch (...) + { + ++finished_jobs_count; + cond_var.notify_one(); + throw; + } + }; +} + +void DistributedBlockOutputStream::writeToLocal(const Blocks & blocks) +{ + const Cluster::ShardInfo & shard_info = cluster->getShardsInfo(); + for (size_t shard_id: ext::range(0, shards_info.size())) + { + const auto & shard_info = shards_info[shard_id]; + if (shard_info.getLocalNodeCount() > 0) + writeToLocal(blocks[shard_id], shard_info.getLocalNodeCount()); + } +} + + +std::string getCurrentStateDescription(const std::vector & done_jobs) +{ +} + +void DistributedBlockOutputStream::writeSync(const Block & block) +{ + if (!pool) + pool = ThreadPool(remote_jobs_count); + + std::vector done_jobs(remote_jobs_count, false); + std::atomic finished_jobs_count = 0; + std::mutex mutex; + std::condition_variable cond_var; + + const Cluster::ShardInfo & shard_info = cluster->getShardsInfo(); + Blocks blocks = shard_info.size() > 1 ? splitBlocks(block) : Blocks({block}); + + size_t job_id = 0; + for (size_t shard_id: ext::range(0, blocks.size())) + for (size_t replica_id : ext::range(0, shards_info[shard_id].dir_names.size())) + pool->schledule(createWritingJob(jobs_done, finished_jobs_count, cond_var, + blocks[shard_id], job_id++, shards_info[shard_id], replica_id)); + try + writeToLocal(blocks); + catch(Exception & exception) + { + try + pool->wait(); + catch(Exception & exception) + { + + throw; + } + throw; + } + + ++blocks_inserted; +} IColumn::Selector DistributedBlockOutputStream::createSelector(Block block) { @@ -89,7 +190,7 @@ IColumn::Selector DistributedBlockOutputStream::createSelector(Block block) } -void DistributedBlockOutputStream::writeSplit(const Block & block) +Blocks DistributedBlockOutputStream::splitBlocks(const Block & block) { const auto num_cols = block.columns(); /// cache column pointers for later reuse @@ -115,6 +216,15 @@ void DistributedBlockOutputStream::writeSplit(const Block & block) splitted_blocks[shard_idx].getByPosition(col_idx_in_block).column = std::move(splitted_columns[shard_idx]); } + return splitted_blocks; +} + + +void DistributedBlockOutputStream::writeSplit(const Block & block) +{ + Blocks splitted_blocks = splitBlocks(block); + const size_t num_shards = splitted_blocks.size(); + for (size_t shard_idx = 0; shard_idx < num_shards; ++shard_idx) if (splitted_blocks[shard_idx].rows()) writeImpl(splitted_blocks[shard_idx], shard_idx); @@ -185,7 +295,7 @@ void DistributedBlockOutputStream::writeToShardSync(const Block & block, const s ProfileEvents::increment(ProfileEvents::DistributedSyncInsertionTimeoutExceeded); String message; - WriteBufferFromString out(message); + ut(message); out << "Timeout exceeded."; writeNodeDescription(out, *connection); throw Exception(message, ErrorCodes::TIMEOUT_EXCEEDED); diff --git a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h index 469134afdea..cc3acef1c97 100644 --- a/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h +++ b/dbms/src/Storages/Distributed/DistributedBlockOutputStream.h @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include namespace Poco { @@ -35,11 +37,25 @@ public: void write(const Block & block) override; - void writePrefix() override { deadline = std::chrono::steady_clock::now() + std::chrono::seconds(insert_timeout); } + void writePrefix() override; private: + void writeAsync(const Block & block); + + void writeSync(const Block & block); + + ThreadPool::Job createWritingJob(std::vector & done_jobs, std::atomic & finished_jobs_count, + std::condition_variable & cond_var, const Block & block, size_t job_id, + const Cluster::ShardInfo & shard_info, size_t replica_id); + + void writeToLocal(const Blocks & blocks); + + std::string getCurrentStateDescription(const std::vector & done_jobs); + IColumn::Selector createSelector(Block block); + Blocks splitBlock(const Block & block); + void writeSplit(const Block & block); void writeImpl(const Block & block, const size_t shard_id = 0); @@ -60,6 +76,8 @@ private: UInt64 insert_timeout; size_t blocks_inserted = 0; std::chrono::steady_clock::time_point deadline; + size_t remote_jobs_count; + std::experimental::optional pool; }; } From 10c14cfccb7a8c595b8d154d9e7d3f34e376114e Mon Sep 17 00:00:00 2001 From: Vitaliy Lyudvichenko Date: Fri, 4 Aug 2017 17:00:26 +0300 Subject: [PATCH 037/281] Small code enhancements according to clang-tidy. [#CLICKHOUSE-2931] --- dbms/src/Common/PoolWithFailoverBase.h | 2 +- .../tests/zkutil_expiration_test.cpp | 2 +- .../IProfilingBlockInputStream.cpp | 2 +- dbms/src/Interpreters/executeQuery.cpp | 6 ++-- dbms/src/Server/Client.cpp | 2 +- .../Storages/MergeTree/DataPartsExchange.cpp | 2 +- dbms/src/Storages/MergeTree/MergeTreeData.cpp | 28 +++++++++---------- .../MergeTree/MergeTreeDataMerger.cpp | 6 ++-- .../MergeTree/MergeTreeDataWriter.cpp | 2 +- .../ReplicatedMergeTreeBlockOutputStream.cpp | 2 +- .../ReplicatedMergeTreePartCheckThread.cpp | 2 +- .../MergeTree/ReplicatedMergeTreeQueue.cpp | 6 ++-- .../ReplicatedMergeTreeRestartingThread.cpp | 2 +- .../MergeTree/ShardedPartitionUploader.cpp | 2 +- dbms/src/Storages/StorageBuffer.cpp | 4 +-- dbms/src/Storages/StorageMergeTree.cpp | 2 +- .../Storages/StorageReplicatedMergeTree.cpp | 10 +++---- dbms/src/Storages/StorageTrivialBuffer.cpp | 4 +-- libs/libcommon/include/common/logger_useful.h | 16 +++++------ 19 files changed, 51 insertions(+), 51 deletions(-) diff --git a/dbms/src/Common/PoolWithFailoverBase.h b/dbms/src/Common/PoolWithFailoverBase.h index 34d74f50354..0478bece49c 100644 --- a/dbms/src/Common/PoolWithFailoverBase.h +++ b/dbms/src/Common/PoolWithFailoverBase.h @@ -350,7 +350,7 @@ PoolWithFailoverBase::updatePoolStates() for (auto & state : shared_pool_states) state.randomize(); - time_t current_time = time(0); + time_t current_time = time(nullptr); if (last_error_decrease_time) { diff --git a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp index b612e60172c..4ee2b147447 100644 --- a/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp +++ b/dbms/src/Common/ZooKeeper/tests/zkutil_expiration_test.cpp @@ -27,7 +27,7 @@ int main(int argc, char ** argv) std::cerr << "Please run `./nozk.sh && sleep 40s && ./yeszk.sh`" << std::endl; - time_t time0 = time(0); + time_t time0 = time(nullptr); while (true) { diff --git a/dbms/src/DataStreams/IProfilingBlockInputStream.cpp b/dbms/src/DataStreams/IProfilingBlockInputStream.cpp index 01490e895c7..2c3e6603bf1 100644 --- a/dbms/src/DataStreams/IProfilingBlockInputStream.cpp +++ b/dbms/src/DataStreams/IProfilingBlockInputStream.cpp @@ -203,7 +203,7 @@ void IProfilingBlockInputStream::checkQuota(Block & block) case LIMITS_CURRENT: { - time_t current_time = time(0); + time_t current_time = time(nullptr); double total_elapsed = info.total_stopwatch.elapsedSeconds(); quota->checkAndAddResultRowsBytes(current_time, block.rows(), block.bytes()); diff --git a/dbms/src/Interpreters/executeQuery.cpp b/dbms/src/Interpreters/executeQuery.cpp index 9ea3a2e85da..782d73974cc 100644 --- a/dbms/src/Interpreters/executeQuery.cpp +++ b/dbms/src/Interpreters/executeQuery.cpp @@ -128,7 +128,7 @@ static std::tuple executeQueryImpl( QueryProcessingStage::Enum stage) { ProfileEvents::increment(ProfileEvents::Query); - time_t current_time = time(0); + time_t current_time = time(nullptr); const Settings & settings = context.getSettingsRef(); @@ -253,7 +253,7 @@ static std::tuple executeQueryImpl( elem.type = QueryLogElement::QUERY_FINISH; - elem.event_time = time(0); + elem.event_time = time(nullptr); elem.query_duration_ms = elapsed_seconds * 1000; elem.read_rows = process_list_elem->progress_in.rows; @@ -305,7 +305,7 @@ static std::tuple executeQueryImpl( elem.type = QueryLogElement::EXCEPTION_WHILE_PROCESSING; - elem.event_time = time(0); + elem.event_time = time(nullptr); elem.query_duration_ms = 1000 * (elem.event_time - elem.query_start_time); elem.exception = getCurrentExceptionMessage(false); diff --git a/dbms/src/Server/Client.cpp b/dbms/src/Server/Client.cpp index 8ef9241550d..11839e96090 100644 --- a/dbms/src/Server/Client.cpp +++ b/dbms/src/Server/Client.cpp @@ -249,7 +249,7 @@ private: /// Should we celebrate a bit? bool isNewYearMode() { - time_t current_time = time(0); + time_t current_time = time(nullptr); /// It's bad to be intrusive. if (current_time % 3 != 0) diff --git a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp index 380583369fe..a9164a36214 100644 --- a/dbms/src/Storages/MergeTree/DataPartsExchange.cpp +++ b/dbms/src/Storages/MergeTree/DataPartsExchange.cpp @@ -265,7 +265,7 @@ MergeTreeData::MutableDataPartPtr Fetcher::fetchPartImpl( assertEOF(in); ActiveDataPartSet::parsePartName(part_name, *new_data_part); - new_data_part->modification_time = time(0); + new_data_part->modification_time = time(nullptr); new_data_part->loadColumns(true); new_data_part->loadChecksums(true); new_data_part->loadIndex(); diff --git a/dbms/src/Storages/MergeTree/MergeTreeData.cpp b/dbms/src/Storages/MergeTree/MergeTreeData.cpp index ad649119111..6efe3336dbe 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeData.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeData.cpp @@ -483,7 +483,7 @@ void MergeTreeData::clearOldTemporaryDirectories(ssize_t custom_directories_life if (!lock.try_lock()) return; - time_t current_time = time(0); + time_t current_time = time(nullptr); ssize_t deadline = (custom_directories_lifetime_seconds >= 0) ? current_time - custom_directories_lifetime_seconds : current_time - settings.temporary_directories_lifetime; @@ -522,12 +522,12 @@ MergeTreeData::DataPartsVector MergeTreeData::grabOldParts() if (!lock.try_lock()) return res; - time_t now = time(0); + time_t now = time(nullptr); { - std::lock_guard lock(all_data_parts_mutex); + std::lock_guard lock_all_parts(all_data_parts_mutex); - for (DataParts::iterator it = all_data_parts.begin(); it != all_data_parts.end();) + for (auto it = all_data_parts.begin(); it != all_data_parts.end();) { if (it->unique() && /// After this ref_count cannot increase. (*it)->remove_time < now && @@ -1047,7 +1047,7 @@ MergeTreeData::AlterDataPartTransactionPtr MergeTreeData::alterDataPart( DataPart::Checksums new_checksums = part->checksums; for (auto it : transaction->rename_map) { - if (it.second == "") + if (it.second.empty()) new_checksums.files.erase(it.first); else new_checksums.files[it.second] = add_checksums.files[it.first]; @@ -1110,7 +1110,7 @@ void MergeTreeData::AlterDataPartTransaction::commit() Poco::File{path + it.first}.renameTo(path + it.second); } - DataPart & mutable_part = const_cast(*data_part); + auto & mutable_part = const_cast(*data_part); mutable_part.checksums = new_checksums; mutable_part.columns = new_columns; @@ -1231,7 +1231,7 @@ MergeTreeData::DataPartsVector MergeTreeData::renameTempPartAndReplace( /// Parts contained in the part are consecutive in data_parts, intersecting the insertion place /// for the part itself. - DataParts::iterator it = data_parts.lower_bound(part); + auto it = data_parts.lower_bound(part); /// Go to the left. while (it != data_parts.begin()) { @@ -1244,7 +1244,7 @@ MergeTreeData::DataPartsVector MergeTreeData::renameTempPartAndReplace( break; } replaced.push_back(*it); - (*it)->remove_time = time(0); + (*it)->remove_time = time(nullptr); removePartContributionToColumnSizes(*it); data_parts.erase(it++); /// Yes, ++, not --. } @@ -1259,7 +1259,7 @@ MergeTreeData::DataPartsVector MergeTreeData::renameTempPartAndReplace( break; } replaced.push_back(*it); - (*it)->remove_time = time(0); + (*it)->remove_time = time(nullptr); removePartContributionToColumnSizes(*it); data_parts.erase(it++); } @@ -1267,7 +1267,7 @@ MergeTreeData::DataPartsVector MergeTreeData::renameTempPartAndReplace( if (obsolete) { LOG_WARNING(log, "Obsolete part " << part->name << " added"); - part->remove_time = time(0); + part->remove_time = time(nullptr); } else { @@ -1488,7 +1488,7 @@ MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(const String & std::lock_guard lock(data_parts_mutex); /// The part can be covered only by the previous or the next one in data_parts. - DataParts::iterator it = data_parts.lower_bound(tmp_part); + auto it = data_parts.lower_bound(tmp_part); if (it != data_parts.end()) { @@ -1514,7 +1514,7 @@ MergeTreeData::DataPartPtr MergeTreeData::getPartIfExists(const String & part_na ActiveDataPartSet::parsePartName(part_name, *tmp_part); std::lock_guard lock(all_data_parts_mutex); - DataParts::iterator it = all_data_parts.lower_bound(tmp_part); + auto it = all_data_parts.lower_bound(tmp_part); if (it != all_data_parts.end() && (*it)->name == part_name) return *it; @@ -1527,8 +1527,8 @@ MergeTreeData::DataPartPtr MergeTreeData::getShardedPartIfExists(const String & if (part_from_shard->name == part_name) return part_from_shard; - else - return nullptr; + + return nullptr; } MergeTreeData::MutableDataPartPtr MergeTreeData::loadPartAndFixMetadata(const String & relative_path) diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp index e7b9ad90c5f..aeff72dbab7 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataMerger.cpp @@ -262,7 +262,7 @@ bool MergeTreeDataMerger::selectAllPartsToMergeWithinPartition( /// Enough disk space to cover the new merge with a margin. if (available_disk_space <= sum_bytes * DISK_USAGE_COEFFICIENT_TO_SELECT) { - time_t now = time(0); + time_t now = time(nullptr); if (now - disk_space_warning_time > 3600) { disk_space_warning_time = now; @@ -758,7 +758,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataMerger::mergePartsToTemporaryPart throw Exception("Empty part after merge", ErrorCodes::LOGICAL_ERROR); new_data_part->size = to.marksCount(); - new_data_part->modification_time = time(0); + new_data_part->modification_time = time(nullptr); new_data_part->size_in_bytes = MergeTreeData::DataPart::calcTotalSize(new_part_tmp_path); new_data_part->is_sharded = false; @@ -1080,7 +1080,7 @@ MergeTreeData::PerShardDataParts MergeTreeDataMerger::reshardPartition( data_part->checksums = output_stream->writeSuffixAndGetChecksums(); data_part->index.swap(output_stream->getIndex()); data_part->size = output_stream->marksCount(); - data_part->modification_time = time(0); + data_part->modification_time = time(nullptr); data_part->size_in_bytes = MergeTreeData::DataPart::calcTotalSize(output_stream->getPartPath()); data_part->is_sharded = true; data_part->shard_no = shard_no; diff --git a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp index dff3d22f168..0817e4a8e71 100644 --- a/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/dbms/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -163,7 +163,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithDa new_data_part->right = temp_index; new_data_part->level = 0; new_data_part->size = part_size; - new_data_part->modification_time = time(0); + new_data_part->modification_time = time(nullptr); new_data_part->month = min_month; new_data_part->columns = columns; new_data_part->checksums = checksums; diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp index 173a1443c96..94c6579d7a2 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeBlockOutputStream.cpp @@ -182,7 +182,7 @@ void ReplicatedMergeTreeBlockOutputStream::commitPart(zkutil::ZooKeeperPtr & zoo StorageReplicatedMergeTree::LogEntry log_entry; log_entry.type = StorageReplicatedMergeTree::LogEntry::GET_PART; - log_entry.create_time = time(0); + log_entry.create_time = time(nullptr); log_entry.source_replica = storage.replica_name; log_entry.new_part_name = part_name; log_entry.quorum = quorum; diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreePartCheckThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreePartCheckThread.cpp index 6958cb7cd69..d377c50f00b 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreePartCheckThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreePartCheckThread.cpp @@ -305,7 +305,7 @@ void ReplicatedMergeTreePartCheckThread::run() { try { - time_t current_time = time(0); + time_t current_time = time(nullptr); /// Take part from the queue for verification. PartsToCheckQueue::iterator selected = parts_queue.end(); /// end from std::list is not get invalidated diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp index 721d5dad046..3e8d3c0c887 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeQueue.cpp @@ -341,7 +341,7 @@ bool ReplicatedMergeTreeQueue::pullLogsToQueue(zkutil::ZooKeeperPtr zookeeper, z insertUnlocked(copied_entries[i]); } - last_queue_update = time(0); + last_queue_update = time(nullptr); } catch (...) { @@ -644,7 +644,7 @@ ReplicatedMergeTreeQueue::CurrentlyExecuting::CurrentlyExecuting(ReplicatedMerge { entry->currently_executing = true; ++entry->num_tries; - entry->last_attempt_time = time(0); + entry->last_attempt_time = time(nullptr); if (!queue.future_parts.insert(entry->new_part_name).second) throw Exception("Tagging already tagged future part " + entry->new_part_name + ". This is a bug.", ErrorCodes::LOGICAL_ERROR); @@ -708,7 +708,7 @@ ReplicatedMergeTreeQueue::SelectedEntry ReplicatedMergeTreeQueue::selectEntryToP else { ++(*it)->num_postponed; - (*it)->last_postpone_time = time(0); + (*it)->last_postpone_time = time(nullptr); } } diff --git a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp index 2f6ac26726f..db05fd937b9 100644 --- a/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp +++ b/dbms/src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp @@ -112,7 +112,7 @@ void ReplicatedMergeTreeRestartingThread::run() first_time = false; } - time_t current_time = time(0); + time_t current_time = time(nullptr); if (current_time >= prev_time_of_check_delay + static_cast(storage.data.settings.check_delay_period)) { /// Find out lag of replicas. diff --git a/dbms/src/Storages/MergeTree/ShardedPartitionUploader.cpp b/dbms/src/Storages/MergeTree/ShardedPartitionUploader.cpp index 55b48108278..175b261fafa 100644 --- a/dbms/src/Storages/MergeTree/ShardedPartitionUploader.cpp +++ b/dbms/src/Storages/MergeTree/ShardedPartitionUploader.cpp @@ -105,7 +105,7 @@ void Service::processQuery(const Poco::Net::HTMLForm & params, ReadBuffer & body assertEOF(body); ActiveDataPartSet::parsePartName(part_name, *data_part); - data_part->modification_time = time(0); + data_part->modification_time = time(nullptr); data_part->loadColumns(true); data_part->loadChecksums(true); data_part->loadIndex(); diff --git a/dbms/src/Storages/StorageBuffer.cpp b/dbms/src/Storages/StorageBuffer.cpp index 9298bca5b12..3b531e90fb8 100644 --- a/dbms/src/Storages/StorageBuffer.cpp +++ b/dbms/src/Storages/StorageBuffer.cpp @@ -296,7 +296,7 @@ private: void insertIntoBuffer(const Block & block, StorageBuffer::Buffer & buffer, std::unique_lock && lock) { - time_t current_time = time(0); + time_t current_time = time(nullptr); /// Sort the columns in the block. This is necessary to make it easier to concatenate the blocks later. Block sorted_block = block.sortColumns(); @@ -434,7 +434,7 @@ void StorageBuffer::flushAllBuffers(const bool check_thresholds) void StorageBuffer::flushBuffer(Buffer & buffer, bool check_thresholds) { Block block_to_write; - time_t current_time = time(0); + time_t current_time = time(nullptr); size_t rows = 0; size_t bytes = 0; diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index c9962f894a2..bc1ad69b13a 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -343,7 +343,7 @@ bool StorageMergeTree::merge( if (auto part_log = context.getPartLog(database_name, table_name)) { PartLogElement elem; - elem.event_time = time(0); + elem.event_time = time(nullptr); elem.merged_from.reserve(merging_tagger->parts.size()); for (const auto & part : merging_tagger->parts) diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index c320db083cd..ea3532893e4 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -1120,7 +1120,7 @@ bool StorageReplicatedMergeTree::executeLogEntry(const LogEntry & entry) if (auto part_log = context.getPartLog(database_name, table_name)) { PartLogElement elem; - elem.event_time = time(0); + elem.event_time = time(nullptr); elem.merged_from.reserve(parts.size()); for (const auto & part : parts) @@ -1843,7 +1843,7 @@ bool StorageReplicatedMergeTree::createLogEntryToMergeParts( entry.source_replica = replica_name; entry.new_part_name = merged_name; entry.deduplicate = deduplicate; - entry.create_time = time(0); + entry.create_time = time(nullptr); for (const auto & part : parts) entry.parts_to_merge.push_back(part->name); @@ -2147,7 +2147,7 @@ bool StorageReplicatedMergeTree::fetchPart(const String & part_name, const Strin if (auto part_log = context.getPartLog(database_name, table_name)) { PartLogElement elem; - elem.event_time = time(0); + elem.event_time = time(nullptr); elem.event_type = PartLogElement::DOWNLOAD_PART; elem.size_in_bytes = part->size_in_bytes; elem.duration_ms = stopwatch.elapsed() / 10000000; @@ -2650,7 +2650,7 @@ void StorageReplicatedMergeTree::clearColumnInPartition( entry.type = LogEntry::CLEAR_COLUMN; entry.new_part_name = fake_part_name; entry.column_name = column_name.safeGet(); - entry.create_time = time(0); + entry.create_time = time(nullptr); String log_znode_path = getZooKeeper()->create(zookeeper_path + "/log/log-", entry.toString(), zkutil::CreateMode::PersistentSequential); entry.znode_name = log_znode_path.substr(log_znode_path.find_last_of('/') + 1); @@ -2700,7 +2700,7 @@ void StorageReplicatedMergeTree::dropPartition(const ASTPtr & query, const Field entry.source_replica = replica_name; entry.new_part_name = fake_part_name; entry.detach = detach; - entry.create_time = time(0); + entry.create_time = time(nullptr); String log_znode_path = getZooKeeper()->create(zookeeper_path + "/log/log-", entry.toString(), zkutil::CreateMode::PersistentSequential); entry.znode_name = log_znode_path.substr(log_znode_path.find_last_of('/') + 1); diff --git a/dbms/src/Storages/StorageTrivialBuffer.cpp b/dbms/src/Storages/StorageTrivialBuffer.cpp index ee403aa62d6..bccde1673ad 100644 --- a/dbms/src/Storages/StorageTrivialBuffer.cpp +++ b/dbms/src/Storages/StorageTrivialBuffer.cpp @@ -191,7 +191,7 @@ void StorageTrivialBuffer::addBlock(const Block & block, DeduplicationController void StorageTrivialBuffer::flush(bool check_thresholds, bool is_called_from_background) { Block block_to_write; - time_t current_time = time(0); + time_t current_time = time(nullptr); time_t time_passed = 0; @@ -316,7 +316,7 @@ public: } } - time_t current_time = time(0); + time_t current_time = time(nullptr); if (buffer.checkThresholds(current_time, rows, bytes)) { /** We'll try to flush the buffer if thresholds are overdrafted. diff --git a/libs/libcommon/include/common/logger_useful.h b/libs/libcommon/include/common/logger_useful.h index c21eca30fda..7ecd6f3bcd2 100644 --- a/libs/libcommon/include/common/logger_useful.h +++ b/libs/libcommon/include/common/logger_useful.h @@ -17,46 +17,46 @@ using Poco::Logger; if ((logger)->trace()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->trace(oss_internal_rare.str());}} while(0) + (logger)->trace(oss_internal_rare.str());}} while(false) #define LOG_DEBUG(logger, message) do { \ if ((logger)->debug()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->debug(oss_internal_rare.str());}} while(0) + (logger)->debug(oss_internal_rare.str());}} while(false) #define LOG_INFO(logger, message) do { \ if ((logger)->information()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->information(oss_internal_rare.str());}} while(0) + (logger)->information(oss_internal_rare.str());}} while(false) #define LOG_NOTICE(logger, message) do { \ if ((logger)->notice()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->notice(oss_internal_rare.str());}} while(0) + (logger)->notice(oss_internal_rare.str());}} while(false) #define LOG_WARNING(logger, message) do { \ if ((logger)->warning()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->warning(oss_internal_rare.str());}} while(0) + (logger)->warning(oss_internal_rare.str());}} while(false) #define LOG_ERROR(logger, message) do { \ if ((logger)->error()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->error(oss_internal_rare.str());}} while(0) + (logger)->error(oss_internal_rare.str());}} while(false) #define LOG_CRITICAL(logger, message) do { \ if ((logger)->critical()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->critical(oss_internal_rare.str());}} while(0) + (logger)->critical(oss_internal_rare.str());}} while(false) #define LOG_FATAL(logger, message) do { \ if ((logger)->fatal()) {\ std::stringstream oss_internal_rare; \ oss_internal_rare << message; \ - (logger)->fatal(oss_internal_rare.str());}} while(0) + (logger)->fatal(oss_internal_rare.str());}} while(false) From 515a0f061f9aa4f0f34af70af013ffcd719f68c8 Mon Sep 17 00:00:00 2001 From: Ivan Blinkov Date: Fri, 4 Aug 2017 17:52:08 +0300 Subject: [PATCH 038/281] Work in progress on CLICKHOUSE-2720 & CLICKHOUSE-3067 (#1046) * update presentations * CLICKHOUSE-2936: redirect from clickhouse.yandex.ru and clickhouse.yandex.com * update submodule * lost files * CLICKHOUSE-2981: prefer sphinx docs over original reference * CLICKHOUSE-2981: docs styles more similar to main website + add flags to switch language links * update presentations * Less confusing directory structure (docs -> doc/reference/) * Minify sphinx docs too * Website release script: fail fast + pass docker hash on deploy * Do not underline links in docs * shorter * cleanup docker images * tune nginx config * CLICKHOUSE-3043: get rid of habrastorage links * Lost translation * CLICKHOUSE-2936: temporary client-side redirect * behaves weird in test * put redirect back * CLICKHOUSE-3047: copy docs txts to public too * move to proper file * remove old pages to avoid confusion * Remove reference redirect warning for now * Refresh README.md * Yellow buttons in docs * Use svg flags instead of unicode ones in docs * fix test website instance * Put flags to separate files * wrong flag * Copy Yandex.Metrica introduction from main page to docs * Yet another home page structure change, couple new blocks (CLICKHOUSE-3045) * Update Contacts section * CLICKHOUSE-2849: more detailed legal information * CLICKHOUSE-2978 preparation - split by files * More changes in Contacts block * Tune texts on index page * update presentations * One more benchmark * Add usage sections to index page, adapted from slides * Get the roadmap started, based on slides from last ClickHouse Meetup * CLICKHOUSE-2977: some rendering tuning * Get rid of excessive section in the end of getting started * Make headers linkable * CLICKHOUSE-2981: links to editing reference - https://github.com/yandex/ClickHouse/issues/849 * CLICKHOUSE-2981: fix mobile styles in docs * Ban crawling of duplicating docs * Open some external links in new tab * Ban old docs too * Lots of trivial fixes in english docs * Lots of trivial fixes in russian docs * Remove getting started copies in markdown * Add Yandex.Webmaster * Fix some sphinx warnings * More warnings fixed in english docs * More sphinx warnings fixed * Add code-block:: text * More code-block:: text * These headers look not that well * Better switch between documentation languages * merge use_case.rst into ya_metrika_task.rst * Edit the agg_functions.rst texts * Add lost empty lines * Lost blank lines * Add new logo sizes * update presentations * Next step in migrating to new documentation * Fix all warnings in en reference * Fix all warnings in ru reference * Re-arrange existing reference * Move operation tips to main reference * Fix typos noticed by milovidov@ * Get rid of zookeeper.md * Looks like duplicate of tutorial.html * Fix some mess with html tags in tutorial * No idea why nobody noticed this before, but it was completely not clear whet to get the data * Match code block styling between main and tutorial pages (in favor of the latter) * Get rid of some copypaste in tutorial * Normalize header styles * Move example_datasets to sphinx * Move presentations submodule to website * Move and update README.md * No point in duplicating articles from habrahabr here * Move development-related docs as is for now * doc/reference/ -> docs/ (to match the URL on website) * Adapt links to match the previous commit * Adapt development docs to rst (still lacks translation and strikethrough support) * clean on release * blacklist presentations in gulp * strikethrough support in sphinx * just copy development folder for now * fix weird introduction in style article * Style guide translation (WIP) * Finish style guide translation to English * gulp clean separately * Update year in LICENSE * Initial CONTRIBUTING.md * Fix remaining links to old docs in tutorial * Some tutorial fixes * Typo * Another typo * Update list of authors from yandex-team accoding to git log * Fix diff with master * couple fixes in en what_is_clickhouse.rst * Try different link to blog in Russian * Swap words * Slightly larger line height * CLICKHOUSE-3089: disable hyphenation in docs * update presentations * Fix copying of txt files * update submodule * CLICKHOUSE-3108: fix overflow issues in mobile version * Less weird tutorial header in mobile version * CLICKHOUSE-3073: skip sourcemaps by default * CLICKHOUSE-3067: rename item in docs navigation * fix list markup * CLICKHOUSE-3067: some documentation style tuning * CLICKHOUSE-3067: less laggy single page documentation --- docs/Makefile | 4 +- docs/_singlehtml_templates/navigation.html | 10 ---- docs/_static/custom.css | 55 ++++++++++++++++++++-- docs/_templates/layout.html | 10 +++- docs/_templates/navigation.html | 8 ++++ docs/_templates/page.html | 6 +++ docs/_templates/search.html | 50 ++++++++++++++++++++ docs/_templates/searchbox.html | 11 +++++ docs/en/conf.py | 9 +++- docs/en/query_language/queries.rst | 1 + docs/ru/conf.py | 9 +++- docs/ru/query_language/queries.rst | 1 + website/gulpfile.js | 8 +++- website/index.css | 32 ++++++++++--- website/tutorial.html | 2 +- 15 files changed, 185 insertions(+), 31 deletions(-) delete mode 100644 docs/_singlehtml_templates/navigation.html create mode 100644 docs/_templates/navigation.html create mode 100644 docs/_templates/page.html create mode 100644 docs/_templates/search.html create mode 100644 docs/_templates/searchbox.html diff --git a/docs/Makefile b/docs/Makefile index 95802e63d01..285b71a53b6 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -24,8 +24,8 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ru default: $(SPHINXBUILD) -b html $(SPHINXOPTS) ru $(BUILDDIR)/docs/ru $(SPHINXBUILD) -b html $(SPHINXOPTS) en $(BUILDDIR)/docs/en - SPHINX_TEMPLATES=../_singlehtml_templates $(SPHINXBUILD) -b singlehtml $(SPHINXOPTS) ru $(BUILDDIR)/docs/ru/single - SPHINX_TEMPLATES=../_singlehtml_templates $(SPHINXBUILD) -b singlehtml $(SPHINXOPTS) en $(BUILDDIR)/docs/en/single + $(SPHINXBUILD) -b singlehtml $(SPHINXOPTS) ru $(BUILDDIR)/docs/ru/single + $(SPHINXBUILD) -b singlehtml $(SPHINXOPTS) en $(BUILDDIR)/docs/en/single help: @echo "Please use \`make ' where is one of" diff --git a/docs/_singlehtml_templates/navigation.html b/docs/_singlehtml_templates/navigation.html deleted file mode 100644 index f98fc4161f7..00000000000 --- a/docs/_singlehtml_templates/navigation.html +++ /dev/null @@ -1,10 +0,0 @@ -

{{ _('Navigation') }}

-{{ toctree(includehidden=theme_sidebar_includehidden, collapse=False) }} -{% if theme_extra_nav_links %} -
-
    - {% for text, uri in theme_extra_nav_links.items() %} -
  • {{ text }}
  • - {% endfor %} -
-{% endif %} diff --git a/docs/_static/custom.css b/docs/_static/custom.css index e9e25250dcd..11b6c05856a 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,23 +1,65 @@ -div.document, div.footer { +div.document { + margin: 20px auto 0 auto; +} +div.document, +div.footer { width: 1240px; } div.sphinxsidebarwrapper { padding: 2px 10px; } -div.body dd, div.body li, div.body p { +div.body p { line-height: 1.6em; } -div.body blockquote, div.body dd, div.body li, div.body p { +div.body dd, +div.body li { + line-height: 1.2em; + margin-bottom: 0.4em; +} +div.body blockquote, +div.body dd, +div.body li, +div.body p { -moz-hyphens: none; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none; } +input { + padding: 2px; +} +div.sphinxsidebar #searchbox input[type="text"] { + width: 190px; +} +div.sphinxsidebar #searchbox input[type="submit"], +#search-form input[type="submit"] { + padding: 4px 8px; +} +#searchbox, #extra-nav-links { + margin: 20px 0; +} +ol ol ul, +ol ul ul, +ul ol ul, +ul ul ul, +ul ul, +ol ul, +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points +{ + list-style-type: disc; +} +blockquote { + line-height: 1.4em; + border-left: 4px solid #ccc; + margin: 0; + padding: 0 0 0 20px; +} div.sphinxsidebarwrapper p.logo { float: left; text-align: left; - margin: -4px 4px 0 0; + margin: -2px 6px 0 0; } div.sphinxsidebar a { @@ -26,7 +68,10 @@ div.sphinxsidebar a { } pre { - padding: 4px; + padding: 6px; +} +code { + padding: 2px; } input { diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 0decfc367b1..a79653125d5 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -72,7 +72,7 @@ clickmap:true, trackLinks:true, accurateTrackBounce:true, - webvisor:true + webvisor: {% if builder != "singlehtml" %}true{% else %}false{% endif %} }); } catch(e) { } }); @@ -93,5 +93,11 @@
- +{% if builder == "singlehtml" %} + +{% endif %} {%- endblock %} diff --git a/docs/_templates/navigation.html b/docs/_templates/navigation.html new file mode 100644 index 00000000000..6a2deb8eb57 --- /dev/null +++ b/docs/_templates/navigation.html @@ -0,0 +1,8 @@ +{% if theme_extra_nav_links %} + +{% endif %} +{{ toctree(includehidden=theme_sidebar_includehidden, collapse=builder != "singlehtml") }} diff --git a/docs/_templates/page.html b/docs/_templates/page.html new file mode 100644 index 00000000000..ca1d158efa7 --- /dev/null +++ b/docs/_templates/page.html @@ -0,0 +1,6 @@ +{%- extends "layout.html" %} +{% block body %} +{% if builder != "singlehtml" %} +{{ body }} +{% endif %} +{% endblock %} diff --git a/docs/_templates/search.html b/docs/_templates/search.html new file mode 100644 index 00000000000..458afd627bc --- /dev/null +++ b/docs/_templates/search.html @@ -0,0 +1,50 @@ +{%- extends "layout.html" %} +{% set title = _('Search') %} +{% set script_files = script_files + ['_static/searchtools.js'] %} +{% block extrahead %} + + {# this is used when loading the search index using $.ajax fails, + such as on Chrome for documents on localhost #} + + {{ super() }} +{% endblock %} +{% block body %} +

{{ _('Search') }}

+
+ +

+ {% trans %}Please activate JavaScript to enable the search + functionality.{% endtrans %} +

+
+

+ {% trans %}From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list.{% endtrans %} +

+
+ + + +
+ {% if search_performed %} +

{{ _('Search Results') }}

+ {% if not search_results %} +

{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}

+ {% endif %} + {% endif %} +
+ {% if search_results %} +
    + {% for href, caption, context in search_results %} +
  • {{ caption }} +
    {{ context|e }}
    +
  • + {% endfor %} +
+ {% endif %} +
+{% endblock %} diff --git a/docs/_templates/searchbox.html b/docs/_templates/searchbox.html new file mode 100644 index 00000000000..ec3564f6960 --- /dev/null +++ b/docs/_templates/searchbox.html @@ -0,0 +1,11 @@ +{%- if pagename != "search" and builder != "singlehtml" %} + + +{%- endif %} diff --git a/docs/en/conf.py b/docs/en/conf.py index 5750d284d24..c58139ce779 100644 --- a/docs/en/conf.py +++ b/docs/en/conf.py @@ -128,7 +128,7 @@ html_theme_options = { ('Switch to Russian ', '#ru'), ('Single page documentation', '/docs/en/single/'), ('Website home', '/'), - ('ClickHouse repository', 'https://github.com/yandex/ClickHouse'), + ('Source code', 'https://github.com/yandex/ClickHouse'), ('Edit this page', '#edit'), ]) } @@ -174,9 +174,9 @@ html_static_path = ['../_static'] html_sidebars = { '**': [ 'about.html', + 'searchbox.html', 'navigation.html', 'relations.html', - 'searchbox.html', ] } @@ -292,5 +292,10 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False +def add_filters(app): + import json + app.builder.templates.environment.filters[str('escapejs')] = lambda x: json.dumps(unicode(x)) + def setup(app): app.add_javascript('custom.js') + app.connect(str('builder-inited'), add_filters) diff --git a/docs/en/query_language/queries.rst b/docs/en/query_language/queries.rst index 25d526358f0..17896c5f6fa 100644 --- a/docs/en/query_language/queries.rst +++ b/docs/en/query_language/queries.rst @@ -373,6 +373,7 @@ As an alternative, you can manually copy data from the ``/var/lib/clickhouse/dat ``ALTER TABLE ... FREEZE PARTITION`` only copies data, not table metadata. To make a backup of table metadata, copy the file ``/var/lib/clickhouse/metadata/database/table.sql`` To restore from a backup: + * Use the CREATE query to create the table if it doesn't exist. The query can be taken from an .sql file (replace ATTACH in it with CREATE). * Copy data from the ``data/database/table/`` directory inside the backup to the ``/var/lib/clickhouse/data/database/table/detached/`` directory. * Run ``ALTER TABLE ... ATTACH PARTITION YYYYMM``queries where ``YYYYMM`` is the month, for every month. diff --git a/docs/ru/conf.py b/docs/ru/conf.py index 97e513a29af..ec57feedd43 100644 --- a/docs/ru/conf.py +++ b/docs/ru/conf.py @@ -128,7 +128,7 @@ html_theme_options = { ('Switch to English ', '#en'), ('Документация на одной странице', '/docs/ru/single/'), ('Главная страница сайта', '/'), - ('Репозиторий ClickHouse', 'https://github.com/yandex/ClickHouse'), + ('Исходный код', 'https://github.com/yandex/ClickHouse'), ('Редактировать страницу', '#edit'), ]) } @@ -174,9 +174,9 @@ html_static_path = ['../_static'] html_sidebars = { '**': [ 'about.html', + 'searchbox.html', 'navigation.html', 'relations.html', - 'searchbox.html', ] } @@ -292,5 +292,10 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False +def add_filters(app): + import json + app.builder.templates.environment.filters[str('escapejs')] = lambda x: json.dumps(unicode(x)) + def setup(app): app.add_javascript('custom.js') + app.connect(str('builder-inited'), add_filters) diff --git a/docs/ru/query_language/queries.rst b/docs/ru/query_language/queries.rst index 90fbbf45d22..7a54620765a 100644 --- a/docs/ru/query_language/queries.rst +++ b/docs/ru/query_language/queries.rst @@ -379,6 +379,7 @@ ALTER ``ALTER TABLE ... FREEZE PARTITION`` копирует только данные, но не метаданные таблицы. Чтобы сделать бэкап метаданных таблицы, скопируйте файл ``/var/lib/clickhouse/metadata/database/table.sql`` Для восстановления из бэкапа: + * создайте таблицу, если её нет, с помощью запроса CREATE. Запрос можно взять из .sql файла (замените в нём ``ATTACH`` на ``CREATE``); * скопируйте данные из директории data/database/table/ внутри бэкапа в директорию ``/var/lib/clickhouse/data/database/table/detached/`` * выполните запросы ``ALTER TABLE ... ATTACH PARTITION YYYYMM``, где ``YYYYMM`` - месяц, для каждого месяца. diff --git a/website/gulpfile.js b/website/gulpfile.js index d46a6ed76f0..a47e286e433 100644 --- a/website/gulpfile.js +++ b/website/gulpfile.js @@ -82,7 +82,7 @@ gulp.task('htmls', ['docs', 'docstxt'], function () { .pipe(gulp.dest(outputDir)) }); -gulp.task('scripts', ['docs'], function () { +gulp.task('sourcemaps', ['docs'], function () { return gulp.src(paths.scripts) .pipe(sourcemaps.init()) .pipe(uglify()) @@ -90,6 +90,12 @@ gulp.task('scripts', ['docs'], function () { .pipe(gulp.dest(outputDir)) }); +gulp.task('scripts', ['docs'], function () { + return gulp.src(paths.scripts) + .pipe(uglify()) + .pipe(gulp.dest(outputDir)) +}); + gulp.task('styles', ['docs'], function () { return gulp.src(paths.styles) .pipe(cleanCss({inline: ['none']})) diff --git a/website/index.css b/website/index.css index 859acab3b9a..bd419701f44 100644 --- a/website/index.css +++ b/website/index.css @@ -244,12 +244,6 @@ a:hover, a:active { color: #ededed; } -#ubuntu-install { - overflow: auto; - overflow-y: hidden; - -ms-overflow-y: hidden; -} - #footer { text-align: right; padding: 8px 0 0 0; @@ -266,6 +260,7 @@ pre { border-left: 5px solid #ffdb4d; padding: 5px 10px; background-color: #fff8e8; + overflow: scroll; } ul { @@ -287,6 +282,10 @@ ul.dashed > li:before { text-indent: 1em; } +img { + width: 100%; +} + .warranty { margin-top: 6em; font-size: 50%; @@ -306,6 +305,13 @@ ul.dashed > li:before { border-bottom: 1px solid #08f; } +#tutorial_logo { + float: left; + margin-right: -100%; + margin-top: 34px; + margin-left: 3px; +} + #tutorial_title { font: normal 100px 'Yandex Sans Display Web', Arial, sans-serif; margin-top: 25px; @@ -460,4 +466,18 @@ ul.dashed > li:before { width: 100%; float: none; } + + #tutorial_logo, #tutorial_title, #tutorial_subtitle { + float: none; + text-align: left; + margin: 10px 0; + padding: 0; + } + + #tutorial_title { + font-size: 75px; + } + + + } diff --git a/website/tutorial.html b/website/tutorial.html index b75c0ffe5c9..a9ce64bc355 100644 --- a/website/tutorial.html +++ b/website/tutorial.html @@ -17,7 +17,7 @@
-
+