mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-29 02:52:13 +00:00
Merge pull request #570 from f1yegor/translate/comments
translate comments
This commit is contained in:
commit
e5c45ebff8
@ -10,9 +10,9 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Не агрегатная функция, а адаптер агрегатных функций,
|
||||
* который любую агрегатную функцию agg(x) делает агрегатной функцией вида aggArray(x).
|
||||
* Адаптированная агрегатная функция вычисляет вложенную агрегатную функцию для каждого элемента массива.
|
||||
/** Not an aggregate function, but an adapter of aggregate functions,
|
||||
* which any aggregate function `agg(x)` makes an aggregate function of the form `aggArray(x)`.
|
||||
* The adapted aggregate function calculates nested aggregate function for each element of the array.
|
||||
*/
|
||||
class AggregateFunctionArray final : public IAggregateFunction
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ struct AggregateFunctionAvgData
|
||||
};
|
||||
|
||||
|
||||
/// Считает арифметическое среднее значение чисел.
|
||||
/// Calculates arithmetic mean of numbers.
|
||||
template <typename T>
|
||||
class AggregateFunctionAvg final : public IUnaryAggregateFunction<AggregateFunctionAvgData<typename NearestFieldType<T>::Type>, AggregateFunctionAvg<T> >
|
||||
{
|
||||
|
@ -23,11 +23,11 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/// Частный случай - реализация для числовых типов.
|
||||
/// A particular case is an implementation for numeric types.
|
||||
template <typename T>
|
||||
struct AggregateFunctionGroupArrayDataNumeric
|
||||
{
|
||||
/// Сразу будет выделена память на несколько элементов так, чтобы состояние занимало 64 байта.
|
||||
/// Memory is allocated to several elements immediately so that the state occupies 64 bytes.
|
||||
static constexpr size_t bytes_in_arena = 64 - sizeof(PODArray<T>);
|
||||
|
||||
using Array = PODArray<T, bytes_in_arena, AllocatorWithStackMemory<Allocator<false>, bytes_in_arena>>;
|
||||
@ -100,14 +100,14 @@ public:
|
||||
|
||||
|
||||
|
||||
/// Общий случай (неэффективно). NOTE Можно ещё реализовать частный случай для строк.
|
||||
/// General case (ineffective). NOTE You can also implement a special case for strings.
|
||||
struct AggregateFunctionGroupArrayDataGeneric
|
||||
{
|
||||
Array value; /// TODO Добавить MemoryTracker
|
||||
Array value; /// TODO Add MemoryTracker
|
||||
};
|
||||
|
||||
|
||||
/// Складывает все значения в массив, общий случай. Реализовано неэффективно.
|
||||
/// Puts all values to an array, general case. Implemented inefficiently.
|
||||
class AggregateFunctionGroupArrayGeneric final
|
||||
: public IUnaryAggregateFunction<AggregateFunctionGroupArrayDataGeneric, AggregateFunctionGroupArrayGeneric>
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace DB
|
||||
template <typename T>
|
||||
struct AggregateFunctionGroupUniqArrayData
|
||||
{
|
||||
/// При создании, хэш-таблица должна быть небольшой.
|
||||
/// When creating, the hash table must be small.
|
||||
using Set = HashSet<
|
||||
T,
|
||||
DefaultHash<T>,
|
||||
@ -35,7 +35,7 @@ struct AggregateFunctionGroupUniqArrayData
|
||||
};
|
||||
|
||||
|
||||
/// Складывает все значения в хэш-множество. Возвращает массив уникальных значений. Реализована для числовых типов.
|
||||
/// Puts all values to the hash set. Returns an array of unique values. Implemented for numeric types.
|
||||
template <typename T>
|
||||
class AggregateFunctionGroupUniqArray
|
||||
: public IUnaryAggregateFunction<AggregateFunctionGroupUniqArrayData<T>, AggregateFunctionGroupUniqArray<T>>
|
||||
|
@ -8,11 +8,11 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Не агрегатная функция, а адаптер агрегатных функций,
|
||||
* который любую агрегатную функцию agg(x) делает агрегатной функцией вида aggIf(x, cond).
|
||||
* Адаптированная агрегатная функция принимает два аргумента - значение и условие,
|
||||
* и вычисляет вложенную агрегатную функцию для значений при выполненном условии.
|
||||
* Например, avgIf(x, cond) вычисляет среднее x при условии cond.
|
||||
/** Not an aggregate function, but an adapter of aggregate functions,
|
||||
* which any aggregate function `agg(x)` makes an aggregate function of the form `aggIf(x, cond)`.
|
||||
* The adapted aggregate function takes two arguments - a value and a condition,
|
||||
* and calculates the nested aggregate function for the values when the condition is satisfied.
|
||||
* For example, avgIf(x, cond) calculates the average x if `cond`.
|
||||
*/
|
||||
class AggregateFunctionIf final : public IAggregateFunction
|
||||
{
|
||||
|
@ -9,10 +9,10 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Не агрегатная функция, а адаптер агрегатных функций,
|
||||
* Агрегатные функции с суффиксом Merge принимают в качестве аргумента DataTypeAggregateFunction
|
||||
* (состояние агрегатной функции, полученное ранее с помощью применения агрегатной функции с суффиксом State)
|
||||
* и объединяют их при агрегации.
|
||||
/** Not an aggregate function, but an adapter of aggregate functions,
|
||||
* Aggregate functions with the `Merge` suffix accept `DataTypeAggregateFunction` as an argument
|
||||
* (state of the aggregate function obtained earlier using the aggregate function with the `State` suffix)
|
||||
* and combine them with aggregation.
|
||||
*/
|
||||
|
||||
class AggregateFunctionMerge final : public IAggregateFunction
|
||||
|
@ -22,14 +22,14 @@ template <typename ArgumentFieldType>
|
||||
struct AggregateFunctionQuantileData
|
||||
{
|
||||
using Sample = ReservoirSampler<ArgumentFieldType, ReservoirSamplerOnEmpty::RETURN_NAN_OR_ZERO>;
|
||||
Sample sample; /// TODO Добавить MemoryTracker
|
||||
Sample sample; /// TODO Add MemoryTracker
|
||||
};
|
||||
|
||||
|
||||
/** Приближённо вычисляет квантиль.
|
||||
* В качестве типа аргумента может быть только числовой тип (в том числе, дата и дата-с-временем).
|
||||
* Если returns_float = true, то типом результата будет Float64, иначе - тип результата совпадает с типом аргумента.
|
||||
* Для дат и дат-с-временем returns_float следует задавать равным false.
|
||||
/** Approximately calculates the quantile.
|
||||
* The argument type can only be a numeric type (including date and date-time).
|
||||
* If returns_float = true, the result type is Float64, otherwise - the result type is the same as the argument type.
|
||||
* For dates and date-time, returns_float should be set to false.
|
||||
*/
|
||||
template <typename ArgumentFieldType, bool returns_float = true>
|
||||
class AggregateFunctionQuantile final
|
||||
@ -90,7 +90,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Sample может отсортироваться при получении квантиля, но в этом контексте можно не считать это нарушением константности.
|
||||
/// `Sample` can be sorted when a quantile is received, but in this context, you can not think of this as a violation of constancy.
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
if (returns_float)
|
||||
@ -101,9 +101,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но позволяет вычислить сразу несколько квантилей.
|
||||
* Для этого, принимает в качестве параметров несколько уровней. Пример: quantiles(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Возвращает массив результатов.
|
||||
/** The same, but allows you to calculate several quantiles at once.
|
||||
* For this, takes as parameters several levels. Example: quantiles(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Returns an array of results.
|
||||
*/
|
||||
template <typename ArgumentFieldType, bool returns_float = true>
|
||||
class AggregateFunctionQuantiles final
|
||||
@ -167,7 +167,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Sample может отсортироваться при получении квантиля, но в этом контексте можно не считать это нарушением константности.
|
||||
/// `Sample` can be sorted when a quantile is received, but in this context, you can not think of this as a violation of constancy.
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
|
@ -22,14 +22,14 @@ template <typename ArgumentFieldType>
|
||||
struct AggregateFunctionQuantileDeterministicData
|
||||
{
|
||||
using Sample = ReservoirSamplerDeterministic<ArgumentFieldType, ReservoirSamplerDeterministicOnEmpty::RETURN_NAN_OR_ZERO>;
|
||||
Sample sample; /// TODO Добавить MemoryTracker
|
||||
Sample sample; /// TODO Add MemoryTracker
|
||||
};
|
||||
|
||||
|
||||
/** Приближённо вычисляет квантиль.
|
||||
* В качестве типа аргумента может быть только числовой тип (в том числе, дата и дата-с-временем).
|
||||
* Если returns_float = true, то типом результата будет Float64, иначе - тип результата совпадает с типом аргумента.
|
||||
* Для дат и дат-с-временем returns_float следует задавать равным false.
|
||||
/** Approximately calculates the quantile.
|
||||
* The argument type can only be a numeric type (including date and date-time).
|
||||
* If returns_float = true, the result type is Float64, otherwise - the result type is the same as the argument type.
|
||||
* For dates and date-time, returns_float should be set to false.
|
||||
*/
|
||||
template <typename ArgumentFieldType, bool returns_float = true>
|
||||
class AggregateFunctionQuantileDeterministic final
|
||||
@ -97,7 +97,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Sample может отсортироваться при получении квантиля, но в этом контексте можно не считать это нарушением константности.
|
||||
/// `Sample` can be sorted when a quantile is received, but in this context, you can not think of this as a violation of constancy.
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
if (returns_float)
|
||||
@ -108,9 +108,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но позволяет вычислить сразу несколько квантилей.
|
||||
* Для этого, принимает в качестве параметров несколько уровней. Пример: quantiles(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Возвращает массив результатов.
|
||||
/** The same, but allows you to calculate several quantiles at once.
|
||||
* To do this, takes several levels as parameters. Example: quantiles(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Returns an array of results.
|
||||
*/
|
||||
template <typename ArgumentFieldType, bool returns_float = true>
|
||||
class AggregateFunctionQuantilesDeterministic final
|
||||
@ -181,7 +181,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Sample может отсортироваться при получении квантиля, но в этом контексте можно не считать это нарушением константности.
|
||||
/// `Sample` can be sorted when a quantile is received, but in this context, you can not think of this as a violation of constancy.
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
|
@ -18,14 +18,14 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** В качестве состояния используется массив, в который складываются все значения.
|
||||
* NOTE Если различных значений мало, то это не оптимально.
|
||||
* Для 8 и 16-битных значений возможно, было бы лучше использовать lookup-таблицу.
|
||||
/** The state is an array, into which all values are added.
|
||||
* NOTE If there are few different values then this is not optimal.
|
||||
* For 8 and 16-bit values it might be better to use a lookup table.
|
||||
*/
|
||||
template <typename T>
|
||||
struct AggregateFunctionQuantileExactData
|
||||
{
|
||||
/// Сразу будет выделена память на несколько элементов так, чтобы состояние занимало 64 байта.
|
||||
/// The memory will be allocated to several elements at once, so that the state occupies 64 bytes.
|
||||
static constexpr size_t bytes_in_arena = 64 - sizeof(PODArray<T>);
|
||||
|
||||
using Array = PODArray<T, bytes_in_arena, AllocatorWithStackMemory<Allocator<false>, bytes_in_arena>>;
|
||||
@ -33,9 +33,9 @@ struct AggregateFunctionQuantileExactData
|
||||
};
|
||||
|
||||
|
||||
/** Точно вычисляет квантиль.
|
||||
* В качестве типа аргумента может быть только числовой тип (в том числе, дата и дата-с-временем).
|
||||
* Тип результата совпадает с типом аргумента.
|
||||
/** Exactly calculates the quantile.
|
||||
* The argument type can only be a numeric type (including date and date-time).
|
||||
* The result type is the same as the argument type.
|
||||
*/
|
||||
template <typename T>
|
||||
class AggregateFunctionQuantileExact final
|
||||
@ -99,7 +99,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Сортировка массива не будет считаться нарушением константности.
|
||||
/// Sorting an array will not be considered a violation of constancy.
|
||||
auto & array = const_cast<typename AggregateFunctionQuantileExactData<T>::Array &>(this->data(place).array);
|
||||
|
||||
T quantile = T();
|
||||
@ -110,7 +110,7 @@ public:
|
||||
? level * array.size()
|
||||
: (array.size() - 1);
|
||||
|
||||
std::nth_element(array.begin(), array.begin() + n, array.end()); /// NOTE Можно придумать алгоритм radix-select.
|
||||
std::nth_element(array.begin(), array.begin() + n, array.end()); /// NOTE You can think of the radix-select algorithm.
|
||||
|
||||
quantile = array[n];
|
||||
}
|
||||
@ -120,9 +120,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но позволяет вычислить сразу несколько квантилей.
|
||||
* Для этого, принимает в качестве параметров несколько уровней. Пример: quantilesExact(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Возвращает массив результатов.
|
||||
/** The same, but allows you to calculate several quantiles at once.
|
||||
* To do this, takes several levels as parameters. Example: quantilesExact(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Returns an array of results.
|
||||
*/
|
||||
template <typename T>
|
||||
class AggregateFunctionQuantilesExact final
|
||||
@ -181,7 +181,7 @@ public:
|
||||
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
/// Сортировка массива не будет считаться нарушением константности.
|
||||
/// Sorting an array will not be considered a violation of constancy.
|
||||
auto & array = const_cast<typename AggregateFunctionQuantileExactData<T>::Array &>(this->data(place).array);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
|
@ -15,7 +15,7 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** В качестве состояния используется хэш-таблица вида: значение -> сколько раз встретилось.
|
||||
/** The state is a hash table of the form: value -> how many times it happened.
|
||||
*/
|
||||
template <typename T>
|
||||
struct AggregateFunctionQuantileExactWeightedData
|
||||
@ -23,7 +23,7 @@ struct AggregateFunctionQuantileExactWeightedData
|
||||
using Key = T;
|
||||
using Weight = UInt64;
|
||||
|
||||
/// При создании, хэш-таблица должна быть небольшой.
|
||||
/// When creating, the hash table must be small.
|
||||
using Map = HashMap<
|
||||
Key, Weight,
|
||||
HashCRC32<Key>,
|
||||
@ -35,11 +35,11 @@ struct AggregateFunctionQuantileExactWeightedData
|
||||
};
|
||||
|
||||
|
||||
/** Точно вычисляет квантиль по множеству значений, для каждого из которых задан вес - сколько раз значение встречалось.
|
||||
* Можно рассматривать набор пар value, weight - как набор гистограмм,
|
||||
* в которых value - значение, округлённое до середины столбика, а weight - высота столбика.
|
||||
* В качестве типа аргумента может быть только числовой тип (в том числе, дата и дата-с-временем).
|
||||
* Тип результата совпадает с типом аргумента.
|
||||
/** Exactly calculates a quantile over a set of values, for each of which a weight is given - how many times the value was encountered.
|
||||
* You can consider a set of pairs `values, weight` - as a set of histograms,
|
||||
* where value is the value rounded to the middle of the column, and weight is the height of the column.
|
||||
* The argument type can only be a numeric type (including date and date-time).
|
||||
* The result type is the same as the argument type.
|
||||
*/
|
||||
template <typename ValueType, typename WeightType>
|
||||
class AggregateFunctionQuantileExactWeighted final
|
||||
@ -118,7 +118,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
/// Копируем данные во временный массив, чтобы получить нужный по порядку элемент.
|
||||
/// Copy the data to a temporary array to get the element you need in order.
|
||||
using Pair = typename AggregateFunctionQuantileExactWeightedData<ValueType>::Map::value_type;
|
||||
std::unique_ptr<Pair[]> array_holder(new Pair[size]);
|
||||
Pair * array = array_holder.get();
|
||||
@ -157,9 +157,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но позволяет вычислить сразу несколько квантилей.
|
||||
* Для этого, принимает в качестве параметров несколько уровней. Пример: quantilesExactWeighted(0.5, 0.8, 0.9, 0.95)(ConnectTiming, Weight).
|
||||
* Возвращает массив результатов.
|
||||
/** Same, but allows you to calculate several quantiles at once.
|
||||
* For this, takes as parameters several levels. Example: quantilesExactWeighted(0.5, 0.8, 0.9, 0.95)(ConnectTiming, Weight).
|
||||
* Returns an array of results.
|
||||
*/
|
||||
template <typename ValueType, typename WeightType>
|
||||
class AggregateFunctionQuantilesExactWeighted final
|
||||
@ -248,7 +248,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
/// Копируем данные во временный массив, чтобы получить нужный по порядку элемент.
|
||||
/// Copy the data to a temporary array to get the element you need in order.
|
||||
using Pair = typename AggregateFunctionQuantileExactWeightedData<ValueType>::Map::value_type;
|
||||
std::unique_ptr<Pair[]> array_holder(new Pair[size]);
|
||||
Pair * array = array_holder.get();
|
||||
|
@ -25,16 +25,16 @@ namespace ErrorCodes
|
||||
}
|
||||
}
|
||||
|
||||
/** Алгоритм реализовал Алексей Борзенков https://███████████.yandex-team.ru/snaury
|
||||
* Ему принадлежит авторство кода и половины комментариев в данном namespace,
|
||||
* за исключением слияния, сериализации и сортировки, а также выбора типов и других изменений.
|
||||
* Мы благодарим Алексея Борзенкова за написание изначального кода.
|
||||
/** The algorithm was implemented by Alexei Borzenkov https: //███████████.yandex-team.ru/snaury
|
||||
* He owns the authorship of the code and half the comments in this namespace,
|
||||
* except for merging, serialization, and sorting, as well as selecting types and other changes.
|
||||
* We thank Alexei Borzenkov for writing the original code.
|
||||
*/
|
||||
namespace tdigest
|
||||
{
|
||||
|
||||
/**
|
||||
* Центроид хранит вес точек вокруг их среднего значения
|
||||
* The centroid stores the weight of points around their mean value
|
||||
*/
|
||||
template <typename Value, typename Count>
|
||||
struct Centroid
|
||||
@ -63,13 +63,12 @@ struct Centroid
|
||||
};
|
||||
|
||||
|
||||
/** :param epsilon: значение \delta из статьи - погрешность в районе
|
||||
* квантиля 0.5 (по-умолчанию 0.01, т.е. 1%)
|
||||
* :param max_unmerged: при накоплении кол-ва новых точек сверх этого
|
||||
* значения запускается компрессия центроидов
|
||||
* (по-умолчанию 2048, чем выше значение - тем
|
||||
* больше требуется памяти, но повышается
|
||||
* амортизация времени выполнения)
|
||||
/** :param epsilon: value \delta from the article - error in the range
|
||||
* quantile 0.5 (default is 0.01, i.e. 1%)
|
||||
* :param max_unmerged: when accumulating count of new points beyond this
|
||||
* value centroid compression is triggered
|
||||
* (default is 2048, the higher the value - the
|
||||
* more memory is required, but amortization of execution time increases)
|
||||
*/
|
||||
template <typename Value>
|
||||
struct Params
|
||||
@ -79,17 +78,17 @@ struct Params
|
||||
};
|
||||
|
||||
|
||||
/** Реализация алгоритма t-digest (https://github.com/tdunning/t-digest).
|
||||
* Этот вариант очень похож на MergingDigest на java, однако решение об
|
||||
* объединении принимается на основе оригинального условия из статьи
|
||||
* (через ограничение на размер, используя апроксимацию квантиля каждого
|
||||
* центроида, а не расстояние на кривой положения их границ). MergingDigest
|
||||
* на java даёт значительно меньше центроидов, чем данный вариант, что
|
||||
* негативно влияет на точность при том же факторе компрессии, но даёт
|
||||
* гарантии размера. Сам автор на предложение об этом варианте сказал, что
|
||||
* размер дайжеста растёт как O(log(n)), в то время как вариант на java
|
||||
* не зависит от предполагаемого кол-ва точек. Кроме того вариант на java
|
||||
* использует asin, чем немного замедляет алгоритм.
|
||||
/** Implementation of t-digest algorithm (https://github.com/tdunning/t-digest).
|
||||
* This option is very similar to MergingDigest on java, however the decision about
|
||||
* the union is accepted based on the original condition from the article
|
||||
* (via a size constraint, using the approximation of the quantile of each
|
||||
* centroid, not the distance on the curve of the position of their boundaries). MergingDigest
|
||||
* on java gives significantly fewer centroids than this variant, that
|
||||
* negatively affects accuracy with the same compression factor, but gives
|
||||
* size guarantees. The author himself on the proposal for this variant said that
|
||||
* the size of the digest grows like O(log(n)), while the version on java
|
||||
* does not depend on the expected number of points. Also an variant on java
|
||||
* uses asin, which slows down the algorithm a bit.
|
||||
*/
|
||||
template <typename Value, typename CentroidCount, typename TotalCount>
|
||||
class MergingDigest
|
||||
@ -97,7 +96,7 @@ class MergingDigest
|
||||
using Params = tdigest::Params<Value>;
|
||||
using Centroid = tdigest::Centroid<Value, CentroidCount>;
|
||||
|
||||
/// Сразу будет выделена память на несколько элементов так, чтобы состояние занимало 64 байта.
|
||||
/// The memory will be allocated to several elements at once, so that the state occupies 64 bytes.
|
||||
static constexpr size_t bytes_in_arena = 64 - sizeof(DB::PODArray<Centroid>) - sizeof(TotalCount) - sizeof(uint32_t);
|
||||
|
||||
using Summary = DB::PODArray<Centroid, bytes_in_arena / sizeof(Centroid), AllocatorWithStackMemory<Allocator<false>, bytes_in_arena>>;
|
||||
@ -106,7 +105,7 @@ class MergingDigest
|
||||
TotalCount count = 0;
|
||||
uint32_t unmerged = 0;
|
||||
|
||||
/** Линейная интерполяция в точке x на прямой (x1, y1)..(x2, y2)
|
||||
/** Linear interpolation at the point x on the line (x1, y1)..(x2, y2)
|
||||
*/
|
||||
static Value interpolate(Value x, Value x1, Value y1, Value x2, Value y2)
|
||||
{
|
||||
@ -126,19 +125,19 @@ class MergingDigest
|
||||
using Transform = RadixSortFloatTransform<KeyBits>;
|
||||
using Allocator = RadixSortMallocAllocator;
|
||||
|
||||
/// Функция получения ключа из элемента массива.
|
||||
/// The function to get the key from an array element.
|
||||
static Key & extractKey(Element & elem) { return elem.mean; }
|
||||
};
|
||||
|
||||
public:
|
||||
/** Добавляет к дайджесту изменение x с весом cnt (по-умолчанию 1)
|
||||
/** Adds to the digest a change in `x` with a weight of `cnt` (default 1)
|
||||
*/
|
||||
void add(const Params & params, Value x, CentroidCount cnt = 1)
|
||||
{
|
||||
add(params, Centroid(x, cnt));
|
||||
}
|
||||
|
||||
/** Добавляет к дайджесту центроид c
|
||||
/** Adds a centroid `c` to the digest
|
||||
*/
|
||||
void add(const Params & params, const Centroid & c)
|
||||
{
|
||||
@ -149,9 +148,9 @@ public:
|
||||
compress(params);
|
||||
}
|
||||
|
||||
/** Выполняет компрессию накопленных центроидов
|
||||
* При объединении сохраняется инвариант на максимальный размер каждого
|
||||
* центроида, не превышающий 4 q (1 - q) \delta N.
|
||||
/** Performs compression of accumulated centroids
|
||||
* When merging, the invariant is retained to the maximum size of each
|
||||
* centroid that does not exceed `4 q (1 - q) \ delta N`.
|
||||
*/
|
||||
void compress(const Params & params)
|
||||
{
|
||||
@ -161,7 +160,7 @@ public:
|
||||
|
||||
if (summary.size() > 3)
|
||||
{
|
||||
/// Пара подряд идущих столбиков гистограммы.
|
||||
/// A pair of consecutive bars of the histogram.
|
||||
auto l = summary.begin();
|
||||
auto r = std::next(l);
|
||||
|
||||
@ -170,11 +169,11 @@ public:
|
||||
{
|
||||
// we use quantile which gives us the smallest error
|
||||
|
||||
/// Отношение части гистограммы до l, включая половинку l ко всей гистограмме. То есть, какого уровня квантиль в позиции l.
|
||||
/// The ratio of the part of the histogram to l, including the half l to the entire histogram. That is, what level quantile in position l.
|
||||
Value ql = (sum + l->count * 0.5) / count;
|
||||
Value err = ql * (1 - ql);
|
||||
|
||||
/// Отношение части гистограммы до l, включая l и половинку r ко всей гистограмме. То есть, какого уровня квантиль в позиции r.
|
||||
/// The ratio of the portion of the histogram to l, including l and half r to the entire histogram. That is, what level is the quantile in position r.
|
||||
Value qr = (sum + l->count + r->count * 0.5) / count;
|
||||
Value err2 = qr * (1 - qr);
|
||||
|
||||
@ -183,15 +182,15 @@ public:
|
||||
|
||||
Value k = 4 * count * err * params.epsilon;
|
||||
|
||||
/** Отношение веса склеенной пары столбиков ко всем значениям не больше,
|
||||
* чем epsilon умножить на некий квадратичный коэффициент, который в медиане равен 1 (4 * 1/2 * 1/2),
|
||||
* а по краям убывает и примерно равен расстоянию до края * 4.
|
||||
/** The ratio of the weight of the glued column pair to all values is not greater,
|
||||
* than epsilon multiply by a certain quadratic coefficient, which in the median is 1 (4 * 1/2 * 1/2),
|
||||
* and at the edges decreases and is approximately equal to the distance to the edge * 4.
|
||||
*/
|
||||
|
||||
if (l->count + r->count <= k)
|
||||
{
|
||||
// it is possible to merge left and right
|
||||
/// Левый столбик "съедает" правый.
|
||||
/// The left column "eats" the right.
|
||||
*l += *r;
|
||||
}
|
||||
else
|
||||
@ -200,14 +199,14 @@ public:
|
||||
sum += l->count;
|
||||
++l;
|
||||
|
||||
/// Пропускаем все "съеденные" ранее значения.
|
||||
/// We skip all the values "eaten" earlier.
|
||||
if (l != r)
|
||||
*l = *r;
|
||||
}
|
||||
++r;
|
||||
}
|
||||
|
||||
/// По окончании цикла, все значения правее l были "съедены".
|
||||
/// At the end of the loop, all values to the right of l were "eaten".
|
||||
summary.resize(l - summary.begin() + 1);
|
||||
}
|
||||
|
||||
@ -215,8 +214,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/** Вычисляет квантиль q [0, 1] на основе дайджеста
|
||||
* Для пустого дайджеста возвращает NaN.
|
||||
/** Calculates the quantile q [0, 1] based on the digest.
|
||||
* For an empty digest returns NaN.
|
||||
*/
|
||||
Value getQuantile(const Params & params, Value q)
|
||||
{
|
||||
@ -248,10 +247,10 @@ public:
|
||||
return summary.back().mean;
|
||||
}
|
||||
|
||||
/** Получить несколько квантилей (size штук).
|
||||
* levels - массив уровней нужных квантилей. Они идут в произвольном порядке.
|
||||
* levels_permutation - массив-перестановка уровней. На i-ой позиции будет лежать индекс i-го по возрастанию уровня в массиве levels.
|
||||
* result - массив, куда сложить результаты, в порядке levels,
|
||||
/** Get multiple quantiles (`size` pieces).
|
||||
* levels - an array of levels of the desired quantiles. They are in a random order.
|
||||
* levels_permutation - array-permutation levels. The i-th position will be the index of the i-th ascending level in the `levels` array.
|
||||
* result - the array where the results are added, in order of `levels`,
|
||||
*/
|
||||
template <typename ResultType>
|
||||
void getManyQuantiles(const Params & params, const Value * levels, const size_t * levels_permutation, size_t size, ResultType * result)
|
||||
@ -303,7 +302,7 @@ public:
|
||||
result[levels_permutation[result_num]] = rest_of_results;
|
||||
}
|
||||
|
||||
/** Объединить с другим состоянием.
|
||||
/** Combine with another state.
|
||||
*/
|
||||
void merge(const Params & params, const MergingDigest & other)
|
||||
{
|
||||
@ -311,7 +310,7 @@ public:
|
||||
add(params, c);
|
||||
}
|
||||
|
||||
/** Записать в поток.
|
||||
/** Write to the stream.
|
||||
*/
|
||||
void write(const Params & params, DB::WriteBuffer & buf)
|
||||
{
|
||||
@ -320,7 +319,7 @@ public:
|
||||
buf.write(reinterpret_cast<const char *>(&summary[0]), summary.size() * sizeof(summary[0]));
|
||||
}
|
||||
|
||||
/** Прочитать из потока.
|
||||
/** Read from the stream.
|
||||
*/
|
||||
void read(const Params & params, DB::ReadBuffer & buf)
|
||||
{
|
||||
|
@ -23,21 +23,21 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Вычисляет квантиль для времени в миллисекундах, меньшего 30 сек.
|
||||
* Если значение больше 30 сек, то значение приравнивается к 30 сек.
|
||||
/** Calculates quantile for time in milliseconds, less than 30 seconds.
|
||||
* If the value is greater than 30 seconds, the value is set to 30 seconds.
|
||||
*
|
||||
* Если всего значений не больше примерно 5670, то вычисление точное.
|
||||
* If total values is not greater than about 5670, then the calculation is accurate.
|
||||
*
|
||||
* Иначе:
|
||||
* Если время меньше 1024 мс., то вычисление точное.
|
||||
* Иначе вычисление идёт с округлением до числа, кратного 16 мс.
|
||||
* Otherwise
|
||||
* If time less that 1024 ms, than calculation is accurate.
|
||||
* Otherwise, the computation is rounded to a multiple of 16 ms.
|
||||
*
|
||||
* Используется три разные структуры данных:
|
||||
* - плоский массив (всех встреченных значений) фиксированной длины, выделяемый inplace, размер 64 байта; хранит 0..31 значений;
|
||||
* - плоский массив (всех встреченных значений), выделяемый отдельно, увеличивающейся длины;
|
||||
* - гистограмма (то есть, отображение значение -> количество), состоящая из двух частей:
|
||||
* -- для значений от 0 до 1023 - с шагом 1;
|
||||
* -- для значений от 1024 до 30000 - с шагом 16;
|
||||
* Three different data structures are used:
|
||||
* - flat array (of all met values) of fixed length, allocated inplace, size 64 bytes; Stores 0..31 values;
|
||||
* - flat array (of all values encountered), allocated separately, increasing length;
|
||||
* - a histogram (that is, value -> number), consisting of two parts
|
||||
* -- for values from 0 to 1023 - in increments of 1;
|
||||
* -- for values from 1024 to 30,000 - in increments of 16;
|
||||
*/
|
||||
|
||||
#define TINY_MAX_ELEMS 31
|
||||
@ -45,20 +45,20 @@ namespace DB
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/** Вспомогательная структура для оптимизации в случае маленького количества значений
|
||||
* - плоский массив фиксированного размера "на стеке", в который кладутся все встреченные значения подряд.
|
||||
* Размер - 64 байта. Должна быть POD-типом (используется в union).
|
||||
/** Helper structure for optimization in the case of a small number of values
|
||||
* - flat array of a fixed size "on the stack" in which all encountered values placed in succession.
|
||||
* Size - 64 bytes. Must be a POD-type (used in union).
|
||||
*/
|
||||
struct QuantileTimingTiny
|
||||
{
|
||||
mutable UInt16 elems[TINY_MAX_ELEMS]; /// mutable потому что сортировка массива не считается изменением состояния.
|
||||
/// Важно, чтобы count был в конце структуры, так как начало структуры будет впоследствии перезатёрто другими объектами.
|
||||
/// Вы должны сами инициализировать его нулём.
|
||||
/// Почему? Поле count переиспользуется и в тех случаях, когда в union-е лежат другие структуры
|
||||
/// (размер которых не дотягивает до этого поля.)
|
||||
mutable UInt16 elems[TINY_MAX_ELEMS]; /// mutable because array sorting is not considered a state change.
|
||||
/// It's important that `count` be at the end of the structure, since the beginning of the structure will be subsequently rewritten by other objects.
|
||||
/// You must initialize it by zero itself.
|
||||
/// Why? `count` field is reused even in cases where the union contains other structures
|
||||
/// (the size of which falls short of this field.)
|
||||
UInt16 count;
|
||||
|
||||
/// Можно использовать только пока count < TINY_MAX_ELEMS.
|
||||
/// Can only be used while `count < TINY_MAX_ELEMS`.
|
||||
void insert(UInt64 x)
|
||||
{
|
||||
if (unlikely(x > BIG_THRESHOLD))
|
||||
@ -68,7 +68,7 @@ namespace detail
|
||||
++count;
|
||||
}
|
||||
|
||||
/// Можно использовать только пока count + rhs.count <= TINY_MAX_ELEMS.
|
||||
/// Can only be used while `count + rhs.count <= TINY_MAX_ELEMS`.
|
||||
void merge(const QuantileTimingTiny & rhs)
|
||||
{
|
||||
for (size_t i = 0; i < rhs.count; ++i)
|
||||
@ -90,7 +90,7 @@ namespace detail
|
||||
buf.readStrict(reinterpret_cast<char *>(elems), count * sizeof(elems[0]));
|
||||
}
|
||||
|
||||
/** Эту функцию обязательно нужно позвать перед get-функциями. */
|
||||
/** This function must be called before get-functions. */
|
||||
void prepare() const
|
||||
{
|
||||
std::sort(elems, elems + count);
|
||||
@ -116,7 +116,7 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
/// То же самое, но в случае пустого состояния возвращается NaN.
|
||||
/// The same, but in the case of an empty state NaN is returned.
|
||||
float getFloat(double level) const
|
||||
{
|
||||
return count
|
||||
@ -135,14 +135,14 @@ namespace detail
|
||||
};
|
||||
|
||||
|
||||
/** Вспомогательная структура для оптимизации в случае среднего количества значений
|
||||
* - плоский массив, выделенный отдельно, в который кладутся все встреченные значения подряд.
|
||||
/** Auxiliary structure for optimization in case of average number of values
|
||||
* - a flat array, allocated separately, into which all found values are put in succession.
|
||||
*/
|
||||
struct QuantileTimingMedium
|
||||
{
|
||||
/// sizeof - 24 байта.
|
||||
/// sizeof - 24 bytes.
|
||||
using Array = PODArray<UInt16, 128>;
|
||||
mutable Array elems; /// mutable потому что сортировка массива не считается изменением состояния.
|
||||
mutable Array elems; /// mutable because array sorting is not considered a state change.
|
||||
|
||||
QuantileTimingMedium() {}
|
||||
QuantileTimingMedium(const UInt16 * begin, const UInt16 * end) : elems(begin, end) {}
|
||||
@ -184,7 +184,7 @@ namespace detail
|
||||
? level * elems.size()
|
||||
: (elems.size() - 1);
|
||||
|
||||
/// Сортировка массива не будет считаться нарушением константности.
|
||||
/// Sorting an array will not be considered a violation of constancy.
|
||||
auto & array = const_cast<Array &>(elems);
|
||||
std::nth_element(array.begin(), array.begin() + n, array.end());
|
||||
quantile = array[n];
|
||||
@ -214,7 +214,7 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
/// То же самое, но в случае пустого состояния возвращается NaN.
|
||||
/// Same, but in the case of an empty state, NaN is returned.
|
||||
float getFloat(double level) const
|
||||
{
|
||||
return !elems.empty()
|
||||
@ -240,30 +240,30 @@ namespace detail
|
||||
#define SIZE_OF_LARGE_WITHOUT_COUNT ((SMALL_THRESHOLD + BIG_SIZE) * sizeof(UInt64))
|
||||
|
||||
|
||||
/** Для большого количества значений. Размер около 22 680 байт.
|
||||
/** For a large number of values. The size is about 22 680 bytes.
|
||||
*/
|
||||
class QuantileTimingLarge
|
||||
{
|
||||
private:
|
||||
/// Общее число значений.
|
||||
/// Total number of values.
|
||||
UInt64 count;
|
||||
/// Использование UInt64 весьма расточительно.
|
||||
/// Но UInt32 точно не хватает, а изобретать 6-байтные значения слишком сложно.
|
||||
/// Use of UInt64 is very wasteful.
|
||||
/// But UInt32 is definitely not enough, and it's too hard to invent 6-byte values.
|
||||
|
||||
/// Число значений для каждого значения меньше small_threshold.
|
||||
/// Number of values for each value is smaller than `small_threshold`.
|
||||
UInt64 count_small[SMALL_THRESHOLD];
|
||||
|
||||
/// Число значений для каждого значения от small_threshold до big_threshold, округлённого до big_precision.
|
||||
/// The number of values for each value from `small_threshold` to `big_threshold`, rounded to `big_precision`.
|
||||
UInt64 count_big[BIG_SIZE];
|
||||
|
||||
/// Получить значение квантиля по индексу в массиве count_big.
|
||||
/// Get value of quantile by index in array `count_big`.
|
||||
static inline UInt16 indexInBigToValue(size_t i)
|
||||
{
|
||||
return (i * BIG_PRECISION) + SMALL_THRESHOLD
|
||||
+ (intHash32<0>(i) % BIG_PRECISION - (BIG_PRECISION / 2)); /// Небольшая рандомизация, чтобы не было заметно, что все значения чётные.
|
||||
+ (intHash32<0>(i) % BIG_PRECISION - (BIG_PRECISION / 2)); /// A small randomization so that it is not noticeable that all the values are even.
|
||||
}
|
||||
|
||||
/// Позволяет перебрать значения гистограммы, пропуская нули.
|
||||
/// Lets you scroll through the histogram values, skipping zeros.
|
||||
class Iterator
|
||||
{
|
||||
private:
|
||||
@ -340,12 +340,12 @@ namespace detail
|
||||
|
||||
if (count * 2 > SMALL_THRESHOLD + BIG_SIZE)
|
||||
{
|
||||
/// Простая сериализация для сильно заполненного случая.
|
||||
/// Simple serialization for a heavily dense case.
|
||||
buf.write(reinterpret_cast<const char *>(this) + sizeof(count), SIZE_OF_LARGE_WITHOUT_COUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Более компактная сериализация для разреженного случая.
|
||||
/// More compact serialization for a sparse case.
|
||||
|
||||
for (size_t i = 0; i < SMALL_THRESHOLD; ++i)
|
||||
{
|
||||
@ -365,7 +365,7 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
/// Символизирует конец данных.
|
||||
/// Symbolizes end of data.
|
||||
writeBinary(UInt16(BIG_THRESHOLD), buf);
|
||||
}
|
||||
}
|
||||
@ -399,7 +399,7 @@ namespace detail
|
||||
}
|
||||
|
||||
|
||||
/// Получить значение квантиля уровня level. Уровень должен быть от 0 до 1.
|
||||
/// Get the value of the `level` quantile. The level must be between 0 and 1.
|
||||
UInt16 get(double level) const
|
||||
{
|
||||
UInt64 pos = std::ceil(count * level);
|
||||
@ -420,8 +420,8 @@ namespace detail
|
||||
return it.isValid() ? it.key() : BIG_THRESHOLD;
|
||||
}
|
||||
|
||||
/// Получить значения size квантилей уровней levels. Записать size результатов начиная с адреса result.
|
||||
/// indices - массив индексов levels такой, что соответствующие элементы будут идти в порядке по возрастанию.
|
||||
/// Get the `size` values of `levels` quantiles. Write `size` results starting with `result` address.
|
||||
/// indices - an array of index levels such that the corresponding elements will go in ascending order.
|
||||
template <typename ResultType>
|
||||
void getMany(const double * levels, const size_t * indices, size_t size, ResultType * result) const
|
||||
{
|
||||
@ -458,7 +458,7 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
/// То же самое, но в случае пустого состояния возвращается NaN.
|
||||
/// The same, but in the case of an empty state, NaN is returned.
|
||||
float getFloat(double level) const
|
||||
{
|
||||
return count
|
||||
@ -478,8 +478,8 @@ namespace detail
|
||||
}
|
||||
|
||||
|
||||
/** sizeof - 64 байта.
|
||||
* Если их не хватает - выделяет дополнительно до 20 КБ памяти.
|
||||
/** sizeof - 64 bytes.
|
||||
* If there are not enough of them - allocates up to 20 KB of memory in addition.
|
||||
*/
|
||||
class QuantileTiming : private boost::noncopyable
|
||||
{
|
||||
@ -519,7 +519,7 @@ private:
|
||||
if (current_memory_tracker)
|
||||
current_memory_tracker->alloc(sizeof(detail::QuantileTimingLarge));
|
||||
|
||||
/// На время копирования данных из medium, устанавливать значение large ещё нельзя (иначе оно перезатрёт часть данных).
|
||||
/// While the data is copied from medium, it is not possible to set `large` value (otherwise it will overwrite some data).
|
||||
detail::QuantileTimingLarge * tmp_large = new detail::QuantileTimingLarge;
|
||||
|
||||
for (const auto & elem : medium.elems)
|
||||
@ -535,7 +535,7 @@ private:
|
||||
if (current_memory_tracker)
|
||||
current_memory_tracker->alloc(sizeof(detail::QuantileTimingLarge));
|
||||
|
||||
/// На время копирования данных из medium, устанавливать значение large ещё нельзя (иначе оно перезатрёт часть данных).
|
||||
/// While the data is copied from `medium` it is not possible to set `large` value (otherwise it will overwrite some data).
|
||||
detail::QuantileTimingLarge * tmp_large = new detail::QuantileTimingLarge;
|
||||
|
||||
for (size_t i = 0; i < tiny.count; ++i)
|
||||
@ -601,7 +601,7 @@ public:
|
||||
|
||||
void insertWeighted(UInt64 x, size_t weight)
|
||||
{
|
||||
/// NOTE: Первое условие - для того, чтобы избежать переполнения.
|
||||
/// NOTE: First condition is to avoid overflow.
|
||||
if (weight < TINY_MAX_ELEMS && tiny.count + weight <= TINY_MAX_ELEMS)
|
||||
{
|
||||
for (size_t i = 0; i < weight; ++i)
|
||||
@ -610,13 +610,13 @@ public:
|
||||
else
|
||||
{
|
||||
if (unlikely(tiny.count <= TINY_MAX_ELEMS))
|
||||
tinyToLarge(); /// Для weighted варианта medium не используем - предположительно, нецелесообразно.
|
||||
tinyToLarge(); /// For the weighted variant we do not use `medium` - presumably, it is impractical.
|
||||
|
||||
large->insertWeighted(x, weight);
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE Слишком сложный код.
|
||||
/// NOTE Too complicated.
|
||||
void merge(const QuantileTiming & rhs)
|
||||
{
|
||||
if (tiny.count + rhs.tiny.count <= TINY_MAX_ELEMS)
|
||||
@ -628,7 +628,7 @@ public:
|
||||
auto kind = which();
|
||||
auto rhs_kind = rhs.which();
|
||||
|
||||
/// Если то, с чем сливаем, имеет бОльшую структуру данных, то приводим текущую структуру к такой же.
|
||||
/// If one with which we merge has a larger data structure, then we bring the current structure to the same one.
|
||||
if (kind == Kind::Tiny && rhs_kind == Kind::Medium)
|
||||
{
|
||||
tinyToMedium();
|
||||
@ -644,7 +644,7 @@ public:
|
||||
mediumToLarge();
|
||||
kind = Kind::Large;
|
||||
}
|
||||
/// Случай, когда два состояния маленькие, но при их слиянии, они превратятся в средние.
|
||||
/// Case when two states are small, but when merged, they will turn into average.
|
||||
else if (kind == Kind::Tiny && rhs_kind == Kind::Tiny)
|
||||
{
|
||||
tinyToMedium();
|
||||
@ -676,8 +676,8 @@ public:
|
||||
else
|
||||
throw Exception("Logical error in QuantileTiming::merge function: not all cases are covered", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
/// Для детерминированности, мы должны всегда переводить в large при достижении условия на размер
|
||||
/// - независимо от порядка мерджей.
|
||||
/// For determinism, we should always convert to `large` when size condition is reached
|
||||
/// - regardless of merge order.
|
||||
if (kind == Kind::Medium && unlikely(mediumIsWorthToConvertToLarge()))
|
||||
{
|
||||
mediumToLarge();
|
||||
@ -698,7 +698,7 @@ public:
|
||||
large->serialize(buf);
|
||||
}
|
||||
|
||||
/// Вызывается для пустого объекта.
|
||||
/// Called for an empty object.
|
||||
void deserialize(ReadBuffer & buf)
|
||||
{
|
||||
Kind kind;
|
||||
@ -720,7 +720,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Получить значение квантиля уровня level. Уровень должен быть от 0 до 1.
|
||||
/// Get the value of the `level` quantile. The level must be between 0 and 1.
|
||||
UInt16 get(double level) const
|
||||
{
|
||||
Kind kind = which();
|
||||
@ -740,7 +740,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Получить значения size квантилей уровней levels. Записать size результатов начиная с адреса result.
|
||||
/// Get the size values of the quantiles of the `levels` levels. Record `size` results starting with `result` address.
|
||||
template <typename ResultType>
|
||||
void getMany(const double * levels, const size_t * levels_permutation, size_t size, ResultType * result) const
|
||||
{
|
||||
@ -761,7 +761,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// То же самое, но в случае пустого состояния возвращается NaN.
|
||||
/// The same, but in the case of an empty state, NaN is returned.
|
||||
float getFloat(double level) const
|
||||
{
|
||||
return tiny.count
|
||||
@ -842,7 +842,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но с двумя аргументами. Второй аргумент - "вес" (целое число) - сколько раз учитывать значение.
|
||||
/** Same, but with two arguments. The second argument is "weight" (integer) - how many times to consider the value.
|
||||
*/
|
||||
template <typename ArgumentFieldType, typename WeightFieldType>
|
||||
class AggregateFunctionQuantileTimingWeighted final
|
||||
@ -902,9 +902,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** То же самое, но позволяет вычислить сразу несколько квантилей.
|
||||
* Для этого, принимает в качестве параметров несколько уровней. Пример: quantilesTiming(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Возвращает массив результатов.
|
||||
/** Same, but allows you to calculate several quantiles at once.
|
||||
* To do this, takes several levels as parameters. Example: quantilesTiming(0.5, 0.8, 0.9, 0.95)(ConnectTiming).
|
||||
* Returns an array of results.
|
||||
*/
|
||||
template <typename ArgumentFieldType>
|
||||
class AggregateFunctionQuantilesTiming final : public IUnaryAggregateFunction<QuantileTiming, AggregateFunctionQuantilesTiming<ArgumentFieldType> >
|
||||
|
@ -9,9 +9,9 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Не агрегатная функция, а адаптер агрегатных функций,
|
||||
* Агрегатные функции с суффиксом State отличаются от соответствующих тем, что их состояния не финализируются.
|
||||
* Возвращаемый тип - DataTypeAggregateFunction.
|
||||
/** Not an aggregate function, but an adapter of aggregate functions,
|
||||
* Aggregate functions with the `State` suffix differ from the corresponding ones in that their states are not finalized.
|
||||
* Return type - DataTypeAggregateFunction.
|
||||
*/
|
||||
|
||||
class AggregateFunctionState final : public IAggregateFunction
|
||||
@ -97,7 +97,7 @@ public:
|
||||
static_cast<ColumnAggregateFunction &>(to).getData().push_back(const_cast<AggregateDataPtr>(place));
|
||||
}
|
||||
|
||||
/// Аггрегатная функция или состояние аггрегатной функции.
|
||||
/// Aggregate function or aggregate function state.
|
||||
bool isState() const override { return true; }
|
||||
|
||||
bool allocatesMemoryInArena() const override
|
||||
|
@ -20,7 +20,7 @@ struct AggregateFunctionSumData
|
||||
};
|
||||
|
||||
|
||||
/// Считает сумму чисел.
|
||||
/// Counts the sum of the numbers.
|
||||
template <typename T>
|
||||
class AggregateFunctionSum final : public IUnaryAggregateFunction<AggregateFunctionSumData<typename NearestFieldType<T>::Type>, AggregateFunctionSum<T> >
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ struct AggregateFunctionUniqUniquesHashSetData
|
||||
static String getName() { return "uniq"; }
|
||||
};
|
||||
|
||||
/// Для функции, принимающей несколько аргументов. Такая функция сама заранее их хэширует, поэтому здесь используется TrivialHash.
|
||||
/// For a function that takes multiple arguments. Such a function pre-hashes them in advance, so TrivialHash is used here.
|
||||
struct AggregateFunctionUniqUniquesHashSetDataForVariadic
|
||||
{
|
||||
using Set = UniquesHashSet<TrivialHash>;
|
||||
@ -84,7 +84,7 @@ struct AggregateFunctionUniqExactData
|
||||
{
|
||||
using Key = T;
|
||||
|
||||
/// При создании, хэш-таблица должна быть небольшой.
|
||||
/// When creating, the hash table must be small.
|
||||
typedef HashSet<
|
||||
Key,
|
||||
HashCRC32<Key>,
|
||||
@ -97,13 +97,13 @@ struct AggregateFunctionUniqExactData
|
||||
static String getName() { return "uniqExact"; }
|
||||
};
|
||||
|
||||
/// Для строк будем класть в хэш-таблицу значения SipHash-а (128 бит).
|
||||
/// For rows, we put the SipHash values (128 bits) into the hash table.
|
||||
template <>
|
||||
struct AggregateFunctionUniqExactData<String>
|
||||
{
|
||||
using Key = UInt128;
|
||||
|
||||
/// При создании, хэш-таблица должна быть небольшой.
|
||||
/// When creating, the hash table must be small.
|
||||
typedef HashSet<
|
||||
Key,
|
||||
UInt128TrivialHash,
|
||||
@ -154,9 +154,9 @@ struct BaseUniqCombinedData<String, mode>
|
||||
Set set;
|
||||
};
|
||||
|
||||
/// Агрегатные функции uniqCombinedRaw, uniqCombinedLinearCounting, и uniqCombinedBiasCorrected
|
||||
/// предназначены для разработки новых версий функции uniqCombined.
|
||||
/// Пользователи должны использовать только uniqCombined.
|
||||
/// Aggregate functions uniqCombinedRaw, uniqCombinedLinearCounting, and uniqCombinedBiasCorrected
|
||||
/// are intended for development of new versions of the uniqCombined function.
|
||||
/// Users should only use uniqCombined.
|
||||
|
||||
template <typename T>
|
||||
struct AggregateFunctionUniqCombinedRawData
|
||||
@ -189,7 +189,7 @@ struct AggregateFunctionUniqCombinedData
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/** Хэш-функция для uniq.
|
||||
/** Hash function for uniq.
|
||||
*/
|
||||
template <typename T> struct AggregateFunctionUniqTraits
|
||||
{
|
||||
@ -216,7 +216,7 @@ template <> struct AggregateFunctionUniqTraits<Float64>
|
||||
}
|
||||
};
|
||||
|
||||
/** Хэш-функция для uniqCombined.
|
||||
/** Hash function for uniqCombined.
|
||||
*/
|
||||
template <typename T> struct AggregateFunctionUniqCombinedTraits
|
||||
{
|
||||
@ -243,8 +243,8 @@ template <> struct AggregateFunctionUniqCombinedTraits<Float64>
|
||||
}
|
||||
};
|
||||
|
||||
/** Структура для делегации работы по добавлению одного элемента в агрегатные функции uniq.
|
||||
* Используется для частичной специализации для добавления строк.
|
||||
/** The structure for the delegation work to add one element to the `uniq` aggregate functions.
|
||||
* Used for partial specialization to add strings.
|
||||
*/
|
||||
template <typename T, typename Data, typename Enable = void>
|
||||
struct OneAdder;
|
||||
@ -324,7 +324,7 @@ struct OneAdder<T, Data, typename std::enable_if<
|
||||
}
|
||||
|
||||
|
||||
/// Приближённо или точно вычисляет количество различных значений.
|
||||
/// Calculates the number of different values approximately or exactly.
|
||||
template <typename T, typename Data>
|
||||
class AggregateFunctionUniq final : public IUnaryAggregateFunction<Data, AggregateFunctionUniq<T, Data> >
|
||||
{
|
||||
@ -367,9 +367,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** Для нескольких аргументов. Для вычисления, хэширует их.
|
||||
* Можно передать несколько аргументов как есть; также можно передать один аргумент - кортеж.
|
||||
* Но (для возможности эффективной реализации), нельзя передать несколько аргументов, среди которых есть кортежи.
|
||||
/** For multiple arguments. To compute, hashes them.
|
||||
* You can pass multiple arguments as is; You can also pass one argument - a tuple.
|
||||
* But (for the possibility of effective implementation), you can not pass several arguments, among which there are tuples.
|
||||
*/
|
||||
template <typename Data, bool argument_is_tuple>
|
||||
class AggregateFunctionUniqVariadic final : public IAggregateFunctionHelper<Data>
|
||||
|
@ -11,25 +11,24 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Считает количество уникальных значений до не более чем указанного в параметре.
|
||||
/** Counts the number of unique values up to no more than specified in the parameter.
|
||||
*
|
||||
* Пример: uniqUpTo(3)(UserID)
|
||||
* - посчитает количество уникальных посетителей, вернёт 1, 2, 3 или 4, если их >= 4.
|
||||
* Example: uniqUpTo(3)(UserID)
|
||||
* - will count the number of unique visitors, return 1, 2, 3 or 4 if visitors > = 4.
|
||||
*
|
||||
* Для строк используется некриптографическая хэш-функция, за счёт чего рассчёт может быть немного неточным.
|
||||
* For strings, a non-cryptographic hash function is used, due to which the calculation may be a bit inaccurate.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct __attribute__((__packed__)) AggregateFunctionUniqUpToData
|
||||
{
|
||||
/** Если count == threshold + 1 - это значит, что "переполнилось" (значений больше threshold).
|
||||
* В этом случае (например, после вызова функции merge), массив data не обязательно содержит инициализированные значения
|
||||
* - пример: объединяем состояние, в котором мало значений, с другим состоянием, которое переполнилось;
|
||||
* тогда выставляем count в threshold + 1, а значения из другого состояния не копируем.
|
||||
*/
|
||||
/** If count == threshold + 1 - this means that it is "overflowed" (values greater than threshold).
|
||||
* In this case (for example, after calling the merge function), the `data` array does not necessarily contain the initialized values
|
||||
* - example: combine a state in which there are few values, with another state that has overflowed;
|
||||
* then set count to `threshold + 1`, and values from another state are not copied.
|
||||
*/
|
||||
UInt8 count = 0;
|
||||
|
||||
/// Данные идут после конца структуры. При вставке, делается линейный поиск.
|
||||
T data[0];
|
||||
|
||||
|
||||
@ -38,23 +37,23 @@ struct __attribute__((__packed__)) AggregateFunctionUniqUpToData
|
||||
return count;
|
||||
}
|
||||
|
||||
/// threshold - для скольки элементов есть место в data.
|
||||
/// threshold - for how many elements there is room in a `data`.
|
||||
void insert(T x, UInt8 threshold)
|
||||
{
|
||||
/// Состояние уже переполнено - ничего делать не нужно.
|
||||
/// The state is already full - nothing needs to be done.
|
||||
if (count > threshold)
|
||||
return;
|
||||
|
||||
/// Линейный поиск совпадающего элемента.
|
||||
/// Linear search for the matching element.
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (data[i] == x)
|
||||
return;
|
||||
|
||||
/// Не нашли совпадающий элемент. Если есть место ещё для одного элемента - вставляем его.
|
||||
/// Did not find the matching element. If there is room for one more element, insert it.
|
||||
if (count < threshold)
|
||||
data[count] = x;
|
||||
|
||||
/// После увеличения count, состояние может оказаться переполненным.
|
||||
/// After increasing count, the state may be overflowed.
|
||||
++count;
|
||||
}
|
||||
|
||||
@ -65,7 +64,7 @@ struct __attribute__((__packed__)) AggregateFunctionUniqUpToData
|
||||
|
||||
if (rhs.count > threshold)
|
||||
{
|
||||
/// Если rhs переполнено, то выставляем у текущего состояния count тоже переполненным.
|
||||
/// If `rhs` is overflowed, then set `count` too also overflowed for the current state.
|
||||
count = rhs.count;
|
||||
return;
|
||||
}
|
||||
@ -78,7 +77,7 @@ struct __attribute__((__packed__)) AggregateFunctionUniqUpToData
|
||||
{
|
||||
writeBinary(count, wb);
|
||||
|
||||
/// Пишем значения, только если состояние не переполнено. Иначе они не нужны, а важен только факт того, что состояние переполнено.
|
||||
/// Write values only if the state is not overflowed. Otherwise, they are not needed, and only the fact that the state is overflowed is important.
|
||||
if (count <= threshold)
|
||||
wb.write(reinterpret_cast<const char *>(&data[0]), count * sizeof(data[0]));
|
||||
}
|
||||
@ -99,13 +98,13 @@ struct __attribute__((__packed__)) AggregateFunctionUniqUpToData
|
||||
};
|
||||
|
||||
|
||||
/// Для строк, запоминаются их хэши.
|
||||
/// For strings, their hashes are remembered.
|
||||
template <>
|
||||
struct AggregateFunctionUniqUpToData<String> : AggregateFunctionUniqUpToData<UInt64>
|
||||
{
|
||||
void addImpl(const IColumn & column, size_t row_num, UInt8 threshold)
|
||||
{
|
||||
/// Имейте ввиду, что вычисление приближённое.
|
||||
/// Keep in mind that calculations are approximate.
|
||||
StringRef value = column.getDataAt(row_num);
|
||||
insert(CityHash64(value.data, value.size), threshold);
|
||||
}
|
||||
@ -118,7 +117,7 @@ template <typename T>
|
||||
class AggregateFunctionUniqUpTo final : public IUnaryAggregateFunction<AggregateFunctionUniqUpToData<T>, AggregateFunctionUniqUpTo<T> >
|
||||
{
|
||||
private:
|
||||
UInt8 threshold = 5; /// Значение по-умолчанию, если параметр не указан.
|
||||
UInt8 threshold = 5; /// Default value if the parameter is not specified.
|
||||
|
||||
public:
|
||||
size_t sizeOfData() const override
|
||||
@ -178,16 +177,16 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** Для нескольких аргументов. Для вычисления, хэширует их.
|
||||
* Можно передать несколько аргументов как есть; также можно передать один аргумент - кортеж.
|
||||
* Но (для возможности эффективной реализации), нельзя передать несколько аргументов, среди которых есть кортежи.
|
||||
/** For multiple arguments. To compute, hashes them.
|
||||
* You can pass multiple arguments as is; You can also pass one argument - a tuple.
|
||||
* But (for the possibility of effective implementation), you can not pass several arguments, among which there are tuples.
|
||||
*/
|
||||
template <bool argument_is_tuple>
|
||||
class AggregateFunctionUniqUpToVariadic final : public IAggregateFunctionHelper<AggregateFunctionUniqUpToData<UInt64>>
|
||||
{
|
||||
private:
|
||||
size_t num_args = 0;
|
||||
UInt8 threshold = 5; /// Значение по-умолчанию, если параметр не указан.
|
||||
UInt8 threshold = 5; /// Default value if the parameter is not specified.
|
||||
|
||||
public:
|
||||
size_t sizeOfData() const override
|
||||
|
@ -8,18 +8,18 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/// Возможные значения параметров шаблонов см. в AggregateFunctionsMinMaxAny.h
|
||||
/// For possible values for template parameters, see AggregateFunctionsMinMaxAny.h
|
||||
template <typename ResultData, typename ValueData>
|
||||
struct AggregateFunctionsArgMinMaxData
|
||||
{
|
||||
using ResultData_t = ResultData;
|
||||
using ValueData_t = ValueData;
|
||||
|
||||
ResultData result; // аргумент, при котором достигается минимальное/максимальное значение value.
|
||||
ValueData value; // значение, для которого считается минимум/максимум.
|
||||
ResultData result; // the argument at which the minimum/maximum value is reached.
|
||||
ValueData value; // value for which the minimum/maximum is calculated.
|
||||
};
|
||||
|
||||
/// Возвращает первое попавшееся значение arg для минимального/максимального value. Пример: argMax(arg, value).
|
||||
/// Returns the first arg value found for the minimum/maximum value. Example: argMax(arg, value).
|
||||
template <typename Data>
|
||||
class AggregateFunctionsArgMinMax final : public IBinaryAggregateFunction<Data, AggregateFunctionsArgMinMax<Data>>
|
||||
{
|
||||
|
@ -13,18 +13,18 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Агрегатные функции, запоминающие одно какое-либо переданное значение.
|
||||
* Например, min, max, any, anyLast.
|
||||
/** Aggregate functions that store one of any passed values.
|
||||
* For example: min, max, any, anyLast.
|
||||
*/
|
||||
|
||||
|
||||
/// Для числовых значений.
|
||||
/// For numeric values.
|
||||
template <typename T>
|
||||
struct SingleValueDataFixed
|
||||
{
|
||||
using Self = SingleValueDataFixed<T>;
|
||||
|
||||
bool has_value = false; /// Надо запомнить, было ли передано хотя бы одно значение. Это нужно для AggregateFunctionIf.
|
||||
bool has_value = false; /// You need to remember if at least one value has been passed. This is necessary for AggregateFunctionIf.
|
||||
T value;
|
||||
|
||||
|
||||
@ -164,21 +164,21 @@ struct SingleValueDataFixed
|
||||
};
|
||||
|
||||
|
||||
/** Для строк. Короткие строки хранятся в самой структуре, а длинные выделяются отдельно.
|
||||
* NOTE Могло бы подойти также для массивов чисел.
|
||||
/** For strings. Short lines are stored in the structure itself, and long lines are allocated separately.
|
||||
* NOTE It could also be suitable for arrays of numbers.
|
||||
*/
|
||||
struct __attribute__((__packed__, __aligned__(1))) SingleValueDataString
|
||||
{
|
||||
using Self = SingleValueDataString;
|
||||
|
||||
Int32 size = -1; /// -1 обозначает, что значения нет.
|
||||
Int32 size = -1; /// -1 indicates that there is no value.
|
||||
|
||||
static constexpr Int32 AUTOMATIC_STORAGE_SIZE = 64;
|
||||
static constexpr Int32 MAX_SMALL_STRING_SIZE = AUTOMATIC_STORAGE_SIZE - sizeof(size);
|
||||
|
||||
union __attribute__((__packed__, __aligned__(1)))
|
||||
{
|
||||
char small_data[MAX_SMALL_STRING_SIZE]; /// Включая завершающий ноль.
|
||||
char small_data[MAX_SMALL_STRING_SIZE]; /// Including the terminating zero.
|
||||
char * __attribute__((__packed__, __aligned__(1))) large_data;
|
||||
};
|
||||
|
||||
@ -396,7 +396,7 @@ static_assert(
|
||||
"Incorrect size of SingleValueDataString struct");
|
||||
|
||||
|
||||
/// Для любых других типов значений.
|
||||
/// For any other value types.
|
||||
struct SingleValueDataGeneric
|
||||
{
|
||||
using Self = SingleValueDataGeneric;
|
||||
@ -561,9 +561,9 @@ struct SingleValueDataGeneric
|
||||
};
|
||||
|
||||
|
||||
/** То, чем отличаются друг от другая агрегатные функции min, max, any, anyLast
|
||||
* (условием, при котором сохранённое значение заменяется на новое,
|
||||
* а также, конечно, именем).
|
||||
/** What is the difference between the aggregate functions min, max, any, anyLast
|
||||
* (the condition that the stored value is replaced by a new one,
|
||||
* as well as, of course, the name).
|
||||
*/
|
||||
|
||||
template <typename Data>
|
||||
|
@ -15,10 +15,10 @@ namespace DB
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Эта функция возвращает true если оба значения велики и сравнимы.
|
||||
/// Она употребляется для вычисления среднего значения путём слияния двух источников.
|
||||
/// Ибо если размеры обоих источников велики и сравнимы, то надо применить особенную
|
||||
/// формулу гарантирующую больше стабильности.
|
||||
/// This function returns true if both values are large and comparable.
|
||||
/// It is used to calculate the mean value by merging two sources.
|
||||
/// It means that if the sizes of both sources are large and comparable, then we must apply a special
|
||||
/// formula guaranteeing more stability.
|
||||
bool areComparable(UInt64 a, UInt64 b)
|
||||
{
|
||||
const Float64 sensitivity = 0.001;
|
||||
@ -33,18 +33,18 @@ bool areComparable(UInt64 a, UInt64 b)
|
||||
|
||||
}
|
||||
|
||||
/** Статистические аггрегатные функции:
|
||||
* varSamp - выборочная дисперсия
|
||||
* stddevSamp - среднее выборочное квадратичное отклонение
|
||||
* varPop - дисперсия
|
||||
* stddevPop - среднее квадратичное отклонение
|
||||
* covarSamp - выборочная ковариация
|
||||
* covarPop - ковариация
|
||||
* corr - корреляция
|
||||
/** Statistical aggregate functions
|
||||
* varSamp - sample variance
|
||||
* stddevSamp - mean sample quadratic deviation
|
||||
* varPop - variance
|
||||
* stddevPop - standard deviation
|
||||
* covarSamp - selective covariance
|
||||
* covarPop - covariance
|
||||
* corr - correlation
|
||||
*/
|
||||
|
||||
/** Параллельный и инкрементальный алгоритм для вычисления дисперсии.
|
||||
* Источник: "Updating formulae and a pairwise algorithm for computing sample variances"
|
||||
/** Parallel and incremental algorithm for calculating variance.
|
||||
* Source: "Updating formulae and a pairwise algorithm for computing sample variances"
|
||||
* (Chan et al., Stanford University, 12.1979)
|
||||
*/
|
||||
template<typename T, typename Op>
|
||||
@ -107,7 +107,7 @@ private:
|
||||
Float64 m2 = 0.0;
|
||||
};
|
||||
|
||||
/** Основной код для реализации функций varSamp, stddevSamp, varPop, stddevPop.
|
||||
/** The main code for the implementation of varSamp, stddevSamp, varPop, stddevPop.
|
||||
*/
|
||||
template<typename T, typename Op>
|
||||
class AggregateFunctionVariance final
|
||||
@ -158,7 +158,7 @@ public:
|
||||
namespace
|
||||
{
|
||||
|
||||
/** Реализации функции varSamp.
|
||||
/** Implementing the varSamp function.
|
||||
*/
|
||||
struct VarSampImpl
|
||||
{
|
||||
@ -173,7 +173,7 @@ struct VarSampImpl
|
||||
}
|
||||
};
|
||||
|
||||
/** Реализация функции stddevSamp.
|
||||
/** Implementing the stddevSamp function.
|
||||
*/
|
||||
struct StdDevSampImpl
|
||||
{
|
||||
@ -185,7 +185,7 @@ struct StdDevSampImpl
|
||||
}
|
||||
};
|
||||
|
||||
/** Реализация функции varPop.
|
||||
/** Implementing the varPop function.
|
||||
*/
|
||||
struct VarPopImpl
|
||||
{
|
||||
@ -202,7 +202,7 @@ struct VarPopImpl
|
||||
}
|
||||
};
|
||||
|
||||
/** Реализация функции stddevPop.
|
||||
/** Implementing the stddevPop function.
|
||||
*/
|
||||
struct StdDevPopImpl
|
||||
{
|
||||
@ -216,8 +216,8 @@ struct StdDevPopImpl
|
||||
|
||||
}
|
||||
|
||||
/** Если флаг compute_marginal_moments установлен, этот класс предоставялет наследнику
|
||||
* CovarianceData поддержку маргинальных моментов для вычисления корреляции.
|
||||
/** If `compute_marginal_moments` flag is set this class provides the heir
|
||||
* CovarianceData support of marginal moments for calculating the correlation.
|
||||
*/
|
||||
template<bool compute_marginal_moments>
|
||||
class BaseCovarianceData
|
||||
@ -262,8 +262,8 @@ protected:
|
||||
Float64 right_m2 = 0.0;
|
||||
};
|
||||
|
||||
/** Параллельный и инкрементальный алгоритм для вычисления ковариации.
|
||||
* Источник: "Numerically Stable, Single-Pass, Parallel Statistics Algorithms"
|
||||
/** Parallel and incremental algorithm for calculating covariance.
|
||||
* Source: "Numerically Stable, Single-Pass, Parallel Statistics Algorithms"
|
||||
* (J. Bennett et al., Sandia National Laboratories,
|
||||
* 2009 IEEE International Conference on Cluster Computing)
|
||||
*/
|
||||
@ -292,7 +292,7 @@ public:
|
||||
right_mean += right_delta / count;
|
||||
co_moment += (left_val - left_mean) * (right_val - old_right_mean);
|
||||
|
||||
/// Обновить маргинальные моменты, если они есть.
|
||||
/// Update the marginal moments, if any.
|
||||
if (compute_marginal_moments)
|
||||
{
|
||||
Float64 left_incr = left_delta * (left_val - left_mean);
|
||||
@ -325,7 +325,7 @@ public:
|
||||
co_moment += source.co_moment + left_delta * right_delta * factor;
|
||||
count = total_count;
|
||||
|
||||
/// Обновить маргинальные моменты, если они есть.
|
||||
/// Update the marginal moments, if any.
|
||||
if (compute_marginal_moments)
|
||||
{
|
||||
Float64 left_incr = left_delta * left_delta * factor;
|
||||
@ -426,7 +426,7 @@ public:
|
||||
namespace
|
||||
{
|
||||
|
||||
/** Реализация функции covarSamp.
|
||||
/** Implementing the covarSamp function.
|
||||
*/
|
||||
struct CovarSampImpl
|
||||
{
|
||||
@ -441,7 +441,7 @@ struct CovarSampImpl
|
||||
}
|
||||
};
|
||||
|
||||
/** Реализация функции covarPop.
|
||||
/** Implementing the covarPop function.
|
||||
*/
|
||||
struct CovarPopImpl
|
||||
{
|
||||
@ -458,7 +458,7 @@ struct CovarPopImpl
|
||||
}
|
||||
};
|
||||
|
||||
/** Реализация функции corr.
|
||||
/** `corr` function implementation.
|
||||
*/
|
||||
struct CorrImpl
|
||||
{
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Создать агрегатную функцию с числовым типом в параметре шаблона, в зависимости от типа аргумента.
|
||||
/** Create an aggregate function with a numeric type in the template parameter, depending on the type of the argument.
|
||||
*/
|
||||
template <template <typename> class AggregateFunctionTemplate>
|
||||
static IAggregateFunction * createWithNumericType(const IDataType & argument_type)
|
||||
@ -73,7 +73,7 @@ static IAggregateFunction * createWithNumericType(const IDataType & argument_typ
|
||||
}
|
||||
|
||||
|
||||
/** Для шаблона с двумя аргументами.
|
||||
/** For template with two arguments.
|
||||
*/
|
||||
template <typename FirstType, template <typename, typename> class AggregateFunctionTemplate>
|
||||
static IAggregateFunction * createWithTwoNumericTypesSecond(const IDataType & second_type)
|
||||
|
@ -23,28 +23,28 @@ using AggregateDataPtr = char *;
|
||||
using ConstAggregateDataPtr = const char *;
|
||||
|
||||
|
||||
/** Интерфейс для агрегатных функций.
|
||||
* Экземпляры классов с этим интерфейсом не содержат самих данных для агрегации,
|
||||
* а содержат лишь метаданные (описание) агрегатной функции,
|
||||
* а также методы для создания, удаления и работы с данными.
|
||||
* Данные, получающиеся во время агрегации (промежуточные состояния вычислений), хранятся в других объектах
|
||||
* (которые могут быть созданы в каком-нибудь пуле),
|
||||
* а IAggregateFunction - внешний интерфейс для манипулирования ими.
|
||||
/** Aggregate functions interface.
|
||||
* Instances of classes with this interface do not contain the data itself for aggregation,
|
||||
* but contain only metadata (description) of the aggregate function,
|
||||
* as well as methods for creating, deleting and working with data.
|
||||
* The data resulting from the aggregation (intermediate computing states) is stored in other objects
|
||||
* (which can be created in some pool),
|
||||
* and IAggregateFunction is the external interface for manipulating them.
|
||||
*/
|
||||
class IAggregateFunction
|
||||
{
|
||||
public:
|
||||
/// Получить основное имя функции.
|
||||
/// Get main function name.
|
||||
virtual String getName() const = 0;
|
||||
|
||||
/** Указать типы аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
|
||||
* Необходимо вызывать перед остальными вызовами.
|
||||
/** Specify the types of arguments. If the function does not apply to these arguments throw an exception.
|
||||
* You must call before other calls.
|
||||
*/
|
||||
virtual void setArguments(const DataTypes & arguments) = 0;
|
||||
|
||||
/** Указать параметры - для параметрических агрегатных функций.
|
||||
* Если параметры не предусмотрены или переданные параметры недопустимы - кинуть исключение.
|
||||
* Если параметры есть - необходимо вызывать перед остальными вызовами, иначе - не вызывать.
|
||||
/** Specify parameters for parametric aggregate functions.
|
||||
* If no parameters are provided, or the passed parameters are not valid, throw an exception.
|
||||
* If there are parameters - it is necessary to call before other calls, otherwise - do not call.
|
||||
*/
|
||||
virtual void setParameters(const Array & params)
|
||||
{
|
||||
@ -52,29 +52,29 @@ public:
|
||||
ErrorCodes::AGGREGATE_FUNCTION_DOESNT_ALLOW_PARAMETERS);
|
||||
}
|
||||
|
||||
/// Получить тип результата.
|
||||
/// Get the result type.
|
||||
virtual DataTypePtr getReturnType() const = 0;
|
||||
|
||||
virtual ~IAggregateFunction() {};
|
||||
|
||||
|
||||
/** Функции по работе с данными. */
|
||||
/** Data functions. */
|
||||
|
||||
/** Создать пустые данные для агрегации с помощью placement new в заданном месте.
|
||||
* Вы должны будете уничтожить их с помощью метода destroy.
|
||||
/** Create empty data for aggregation with `placement new` at the specified location.
|
||||
* You will have to destroy them using the `destroy` method.
|
||||
*/
|
||||
virtual void create(AggregateDataPtr place) const = 0;
|
||||
|
||||
/// Уничтожить данные для агрегации.
|
||||
/// Delete data for aggregation.
|
||||
virtual void destroy(AggregateDataPtr place) const noexcept = 0;
|
||||
|
||||
/// Уничтожать данные не обязательно.
|
||||
/// It is not necessary to delete data.
|
||||
virtual bool hasTrivialDestructor() const = 0;
|
||||
|
||||
/// Получить sizeof структуры с данными.
|
||||
/// Get `sizeof` of structure with data.
|
||||
virtual size_t sizeOfData() const = 0;
|
||||
|
||||
/// Как должна быть выровнена структура с данными. NOTE: Сейчас не используется (структуры с состоянием агрегации кладутся без выравнивания).
|
||||
/// How the data structure should be aligned. NOTE: Currently not used (structures with aggregation state are put without alignment).
|
||||
virtual size_t alignOfData() const = 0;
|
||||
|
||||
/** Adds a value into aggregation data on which place points to.
|
||||
@ -102,24 +102,24 @@ public:
|
||||
/// Inserts results into a column.
|
||||
virtual void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const = 0;
|
||||
|
||||
/** Возвращает true для агрегатных функций типа -State.
|
||||
* Они выполняются как другие агрегатные функции, но не финализируются (возвращают состояние агрегации, которое может быть объединено с другим).
|
||||
/** Returns true for aggregate functions of type -State.
|
||||
* They are executed as other aggregate functions, but not finalized (return an aggregation state that can be combined with another).
|
||||
*/
|
||||
virtual bool isState() const { return false; }
|
||||
|
||||
|
||||
/** Внутренний цикл, использующий указатель на функцию, получается лучше, чем использующий виртуальную функцию.
|
||||
* Причина в том, что в случае виртуальных функций, GCC 5.1.2 генерирует код,
|
||||
* который на каждой итерации цикла заново грузит из памяти в регистр адрес функции (значение по смещению в таблице виртуальных функций).
|
||||
* Это даёт падение производительности на простых запросах в районе 12%.
|
||||
* После появления более хороших компиляторов, код можно будет убрать.
|
||||
/** The inner loop that uses the function pointer is better than using the virtual function.
|
||||
* The reason is that in the case of virtual functions GCC 5.1.2 generates code,
|
||||
* which, at each iteration of the loop, reloads the function address (the offset value in the virtual function table) from memory to the register.
|
||||
* This gives a performance drop on simple queries around 12%.
|
||||
* After the appearance of better compilers, the code can be removed.
|
||||
*/
|
||||
using AddFunc = void (*)(const IAggregateFunction *, AggregateDataPtr, const IColumn **, size_t, Arena *);
|
||||
virtual AddFunc getAddressOfAddFunction() const = 0;
|
||||
};
|
||||
|
||||
|
||||
/// Реализует несколько методов. T - тип структуры с данными для агрегации.
|
||||
/// Implements several methods. T - type of structure with data for aggregation.
|
||||
template <typename T>
|
||||
class IAggregateFunctionHelper : public IAggregateFunction
|
||||
{
|
||||
@ -150,7 +150,7 @@ public:
|
||||
return sizeof(Data);
|
||||
}
|
||||
|
||||
/// NOTE: Сейчас не используется (структуры с состоянием агрегации кладутся без выравнивания).
|
||||
/// NOTE: Currently not used (structures with aggregation state are put without alignment).
|
||||
size_t alignOfData() const override
|
||||
{
|
||||
return __alignof__(Data);
|
||||
|
@ -14,22 +14,22 @@ namespace ErrorCodes
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
/** Параметры разных функций quantilesSomething.
|
||||
* - список уровней квантилей.
|
||||
* Также необходимо вычислить массив индексов уровней, идущих по возрастанию.
|
||||
/** Parameters of different functions quantiles*.
|
||||
* - list of levels of quantiles.
|
||||
* It is also necessary to calculate an array of indices of levels that go in ascending order.
|
||||
*
|
||||
* Пример: quantiles(0.5, 0.99, 0.95)(x).
|
||||
* Example: quantiles(0.5, 0.99, 0.95)(x).
|
||||
* levels: 0.5, 0.99, 0.95
|
||||
* levels_permutation: 0, 2, 1
|
||||
*/
|
||||
template <typename T> /// float или double
|
||||
template <typename T> /// float or double
|
||||
struct QuantileLevels
|
||||
{
|
||||
using Levels = std::vector<T>;
|
||||
using Permutation = std::vector<size_t>;
|
||||
|
||||
Levels levels;
|
||||
Permutation permutation; /// Индекс i-го по величине уровня в массиве levels.
|
||||
Permutation permutation; /// Index of the i-th level in `levels`.
|
||||
|
||||
size_t size() const { return levels.size(); }
|
||||
|
||||
|
@ -13,14 +13,14 @@
|
||||
#include <boost/random.hpp>
|
||||
|
||||
|
||||
/// Реализация алгоритма Reservoir Sampling. Инкрементально выбирает из добавленных объектов случайное подмножество размера sample_count.
|
||||
/// Умеет приближенно получать квантили.
|
||||
/// Вызов quantile занимает O(sample_count log sample_count), если после предыдущего вызова quantile был хотя бы один вызов insert. Иначе, O(1).
|
||||
/// То есть, имеет смысл сначала добавлять, потом получать квантили, не добавляя.
|
||||
/// Implementing the Reservoir Sampling algorithm. Incrementally selects from the added objects a random subset of the sample_count size.
|
||||
/// Can approximately get quantiles.
|
||||
/// Call `quantile` takes O(sample_count log sample_count), if after the previous call `quantile` there was at least one call `insert`. Otherwise O(1).
|
||||
/// That is, it makes sense to first add, then get quantiles without adding.
|
||||
|
||||
const size_t DEFAULT_SAMPLE_COUNT = 8192;
|
||||
|
||||
/// Что делать, если нет ни одного значения - кинуть исключение, или вернуть 0 или NaN в случае double?
|
||||
/// What if there is not a single value - throw an exception, or return 0 or NaN in the case of double?
|
||||
namespace ReservoirSamplerOnEmpty
|
||||
{
|
||||
enum Enum
|
||||
@ -99,8 +99,8 @@ public:
|
||||
return samples[int_index];
|
||||
}
|
||||
|
||||
/** Если T не числовой тип, использование этого метода вызывает ошибку компиляции,
|
||||
* но использование класса ошибки не вызывает. SFINAE.
|
||||
/** If T is not a numeric type, using this method causes a compilation error,
|
||||
* but use of error class does not. SFINAE.
|
||||
*/
|
||||
double quantileInterpolated(double level)
|
||||
{
|
||||
@ -111,7 +111,7 @@ public:
|
||||
|
||||
double index = std::max(0., std::min(samples.size() - 1., level * (samples.size() - 1)));
|
||||
|
||||
/// Чтобы получить значение по дробному индексу линейно интерполируем между соседними значениями.
|
||||
/// To get the value of a fractional index, we linearly interpolate between neighboring values.
|
||||
size_t left_index = static_cast<size_t>(index);
|
||||
size_t right_index = left_index + 1;
|
||||
if (right_index == samples.size())
|
||||
@ -189,7 +189,7 @@ private:
|
||||
friend void qdigest_test(int normal_size, UInt64 value_limit, const std::vector<UInt64> & values, int queries_count, bool verbose);
|
||||
friend void rs_perf_test();
|
||||
|
||||
/// Будем выделять немного памяти на стеке - чтобы избежать аллокаций, когда есть много объектов с маленьким количеством элементов.
|
||||
/// We allocate a little memory on the stack - to avoid allocations when there are many objects with a small number of elements.
|
||||
static constexpr size_t bytes_on_stack = 64;
|
||||
using Array = DB::PODArray<T, bytes_on_stack / sizeof(T), AllocatorWithStackMemory<Allocator<false>, bytes_on_stack>>;
|
||||
|
||||
@ -202,7 +202,7 @@ private:
|
||||
|
||||
UInt64 genRandom(size_t lim)
|
||||
{
|
||||
/// При большом количестве значений будем генерировать случайные числа в несколько раз медленнее.
|
||||
/// With a large number of values, we will generate random numbers several times slower.
|
||||
if (lim <= static_cast<UInt64>(rng.max()))
|
||||
return static_cast<UInt32>(rng()) % static_cast<UInt32>(lim);
|
||||
else
|
||||
|
@ -15,10 +15,10 @@
|
||||
#include <boost/random.hpp>
|
||||
|
||||
|
||||
/// Реализация алгоритма Reservoir Sampling. Инкрементально выбирает из добавленных объектов случайное подмножество размера sample_count.
|
||||
/// Умеет приближенно получать квантили.
|
||||
/// Вызов quantile занимает O(sample_count log sample_count), если после предыдущего вызова quantile был хотя бы один вызов insert. Иначе, O(1).
|
||||
/// То есть, имеет смысл сначала добавлять, потом получать квантили, не добавляя.
|
||||
/// Implementation of Reservoir Sampling algorithm. Incrementally selects from the added objects a random subset of the `sample_count` size.
|
||||
/// Can approximately get quantiles.
|
||||
/// The `quantile` call takes O(sample_count log sample_count), if after the previous call `quantile` there was at least one call to insert. Otherwise, O(1).
|
||||
/// That is, it makes sense to first add, then get quantiles without adding.
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -36,7 +36,7 @@ const size_t DEFAULT_SAMPLE_COUNT = 8192;
|
||||
const auto MAX_SKIP_DEGREE = sizeof(UInt32) * 8;
|
||||
}
|
||||
|
||||
/// Что делать, если нет ни одного значения - кинуть исключение, или вернуть 0 или NaN в случае double?
|
||||
/// What if there is not a single value - throw an exception, or return 0 or NaN in the case of double?
|
||||
enum class ReservoirSamplerDeterministicOnEmpty
|
||||
{
|
||||
THROW,
|
||||
@ -94,9 +94,9 @@ public:
|
||||
return samples[int_index].first;
|
||||
}
|
||||
|
||||
/** Если T не числовой тип, использование этого метода вызывает ошибку компиляции,
|
||||
* но использование класса ошибки не вызывает. SFINAE.
|
||||
* Не SFINAE. Функции члены шаблонов типов просто не проверяются, пока не используются.
|
||||
/** If T is not a numeric type, using this method causes a compilation error,
|
||||
* but use of error class does not cause. SFINAE.
|
||||
* Not SFINAE. Functions members of type templates are simply not checked until they are used.
|
||||
*/
|
||||
double quantileInterpolated(double level)
|
||||
{
|
||||
@ -107,7 +107,7 @@ public:
|
||||
|
||||
const double index = std::max(0., std::min(samples.size() - 1., level * (samples.size() - 1)));
|
||||
|
||||
/// Чтобы получить значение по дробному индексу линейно интерполируем между соседними значениями.
|
||||
/// To get a value from a fractional index, we linearly interpolate between adjacent values.
|
||||
size_t left_index = static_cast<size_t>(index);
|
||||
size_t right_index = left_index + 1;
|
||||
if (right_index == samples.size())
|
||||
@ -160,7 +160,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/// Будем выделять немного памяти на стеке - чтобы избежать аллокаций, когда есть много объектов с маленьким количеством элементов.
|
||||
/// We allocate some memory on the stack to avoid allocations when there are many objects with a small number of elements.
|
||||
static constexpr size_t bytes_on_stack = 64;
|
||||
using Element = std::pair<T, UInt32>;
|
||||
using Array = DB::PODArray<Element, bytes_on_stack / sizeof(Element), AllocatorWithStackMemory<Allocator<false>, bytes_on_stack>>;
|
||||
|
@ -5,34 +5,34 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Данные для HyperLogLogBiasEstimator в функции uniqCombined.
|
||||
* Схема разработки следующая:
|
||||
* 1. Собрать ClickHouse.
|
||||
* 2. Запустить скрипт src/dbms/scripts/gen-bias-data.py, который возвращает один массив для getRawEstimates()
|
||||
* и другой массив для getBiases().
|
||||
* 3. Обновить массивы raw_estimates и biases. Также обновить размер массивов в InterpolatedData.
|
||||
* 4. Собрать ClickHouse.
|
||||
* 5. Запустить скрипт src/dbms/scripts/linear-counting-threshold.py, который создаёт 3 файла:
|
||||
* - raw_graph.txt (1-й столбец: настоящее количество уникальных значений;
|
||||
* 2-й столбец: относительная погрешность в случае HyperLogLog без применения каких-либо поправок)
|
||||
* - linear_counting_graph.txt (1-й столбец: настоящее количество уникальных значений;
|
||||
* 2-й столбец: относительная погрешность в случае HyperLogLog с применением LinearCounting)
|
||||
* - bias_corrected_graph.txt (1-й столбец: настоящее количество уникальных значений;
|
||||
* 2-й столбец: относительная погрешность в случае HyperLogLog с применением поправок из алгортима HyperLogLog++)
|
||||
* 6. Сгенерить график с gnuplot на основе этих данных.
|
||||
* 7. Определить минимальное количество уникальных значений, при котором лучше исправить погрешность
|
||||
* с помощью её оценки (т.е. по алгоритму HyperLogLog++), чем применить алгоритм LinearCounting.
|
||||
* 7. Соответственно обновить константу в функции getThreshold()
|
||||
* 8. Собрать ClickHouse.
|
||||
*/
|
||||
/** Data for HyperLogLogBiasEstimator in the uniqCombined function.
|
||||
* The development plan is as follows:
|
||||
* 1. Assemble ClickHouse.
|
||||
* 2. Run the script src/dbms/scripts/gen-bias-data.py, which returns one array for getRawEstimates()
|
||||
* and another array for getBiases().
|
||||
* 3. Update `raw_estimates` and `biases` arrays. Also update the size of arrays in InterpolatedData.
|
||||
* 4. Assemble ClickHouse.
|
||||
* 5. Run the script src/dbms/scripts/linear-counting-threshold.py, which creates 3 files:
|
||||
* - raw_graph.txt (1st column: the present number of unique values;
|
||||
* 2nd column: relative error in the case of HyperLogLog without applying any corrections)
|
||||
* - linear_counting_graph.txt (1st column: the present number of unique values;
|
||||
* 2nd column: relative error in the case of HyperLogLog using LinearCounting)
|
||||
* - bias_corrected_graph.txt (1st column: the present number of unique values;
|
||||
* 2nd column: relative error in the case of HyperLogLog with the use of corrections from the algorithm HyperLogLog++)
|
||||
* 6. Generate a graph with gnuplot based on this data.
|
||||
* 7. Determine the minimum number of unique values at which it is better to correct the error
|
||||
* using its evaluation (ie, using the HyperLogLog++ algorithm) than applying the LinearCounting algorithm.
|
||||
* 7. Accordingly, update the constant in the function getThreshold()
|
||||
* 8. Assemble ClickHouse.
|
||||
*/
|
||||
struct UniqCombinedBiasData
|
||||
{
|
||||
using InterpolatedData = std::array<double, 200>;
|
||||
|
||||
static double getThreshold();
|
||||
/// Оценки количества уникальных значений по алгоритму HyperLogLog без применения каких-либо поправок.
|
||||
/// Estimates of the number of unique values using the HyperLogLog algorithm without applying any corrections.
|
||||
static const InterpolatedData & getRawEstimates();
|
||||
/// Соответствующие оценки погрешности.
|
||||
/// Corresponding error estimates.
|
||||
static const InterpolatedData & getBiases();
|
||||
};
|
||||
|
||||
|
@ -10,17 +10,17 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Хэширует набор аргументов агрегатной функции
|
||||
* для вычисления количества уникальных значений
|
||||
* и добавляет их в множество.
|
||||
/** Hashes a set of arguments to the aggregate function
|
||||
* to calculate the number of unique values
|
||||
* and adds them to the set.
|
||||
*
|
||||
* Четыре варианта (2 x 2):
|
||||
* Four options (2 x 2)
|
||||
*
|
||||
* - для приближённого вычисления, использует некриптографическую 64-битную хэш-функцию;
|
||||
* - для точного вычисления, использует криптографическую 128-битную хэш-функцию;
|
||||
* - for approximate calculation, uses a non-cryptographic 64-bit hash function;
|
||||
* - for an accurate calculation, uses a cryptographic 128-bit hash function;
|
||||
*
|
||||
* - для нескольких аргументов, переданных обычным способом;
|
||||
* - для одного аргумента-кортежа.
|
||||
* - for several arguments passed in the usual way;
|
||||
* - for one argument-tuple.
|
||||
*/
|
||||
|
||||
template <bool exact, bool for_tuple>
|
||||
|
@ -14,54 +14,53 @@
|
||||
#include <DB/Common/HashTable/Hash.h>
|
||||
|
||||
|
||||
/** Приближённый рассчёт чего-угодно, как правило, построен по следующей схеме:
|
||||
* - для рассчёта значения X используется некоторая структура данных;
|
||||
* - в структуру данных добавляются не все значения, а только избранные (согласно некоторому критерию избранности);
|
||||
* - после обработки всех элементов, структура данных находится в некотором состоянии S;
|
||||
* - в качестве приближённого значения X возвращается значание, посчитанное по принципу максимального правдоподобия:
|
||||
* при каком реальном значении X, вероятность нахождения структуры данных в полученном состоянии S максимальна.
|
||||
*/
|
||||
/** Approximate calculation of anything, as a rule, is constructed according to the following scheme:
|
||||
* - some data structure is used to calculate the value of X;
|
||||
* - Not all values are added to the data structure, but only selected ones (according to some selectivity criteria);
|
||||
* - after processing all elements, the data structure is in some state S;
|
||||
* - as an approximate value of X, the value calculated according to the maximum likelihood principle is returned:
|
||||
* at what real value X, the probability of finding the data structure in the obtained state S is maximal.
|
||||
*/
|
||||
|
||||
/** В частности, то, что описано ниже, можно найти по названию BJKST algorithm.
|
||||
*/
|
||||
/** In particular, what is described below can be found by the name of the BJKST algorithm.
|
||||
*/
|
||||
|
||||
/** Очень простое хэш-множество для приближённого подсчёта количества уникальных значений.
|
||||
* Работает так:
|
||||
* - вставлять можно UInt64;
|
||||
* - перед вставкой, сначала вычисляется хэш-функция UInt64 -> UInt32;
|
||||
* - исходное значение не сохраняется (теряется);
|
||||
* - далее все операции производятся с этими хэшами;
|
||||
* - хэш таблица построена по схеме:
|
||||
* - open addressing (один буфер, позиция в буфере вычисляется взятием остатка от деления на его размер);
|
||||
* - linear probing (если в ячейке уже есть значение, то берётся ячейка, следующая за ней и т. д.);
|
||||
* - отсутствующее значение кодируется нулём; чтобы запомнить наличие в множестве нуля, используется отдельная переменная типа bool;
|
||||
* - рост буфера в 2 раза при заполнении более чем на 50%;
|
||||
* - если в множестве больше UNIQUES_HASH_MAX_SIZE элементов, то из множества удаляются все элементы,
|
||||
* не делящиеся на 2, и затем все элементы, которые не делятся на 2, не вставляются в множество;
|
||||
* - если ситуация повторяется, то берутся только элементы делящиеся на 4 и т. п.
|
||||
* - метод size() возвращает приблизительное количество элементов, которые были вставлены в множество;
|
||||
* - есть методы для быстрого чтения и записи в бинарный и текстовый вид.
|
||||
*/
|
||||
/** Very simple hash-set for approximate number of unique values.
|
||||
* Works like this:
|
||||
* - you can insert UInt64;
|
||||
* - before insertion, first the hash function UInt64 -> UInt32 is calculated;
|
||||
* - the original value is not saved (lost);
|
||||
* - further all operations are made with these hashes;
|
||||
* - hash table is constructed according to the scheme:
|
||||
* - open addressing (one buffer, position in buffer is calculated by taking remainder of division by its size);
|
||||
* - linear probing (if the cell already has a value, then the cell following it is taken, etc.);
|
||||
* - the missing value is zero-encoded; to remember presence of zero in set, separate variable of type bool is used;
|
||||
* - buffer growth by 2 times when filling more than 50%;
|
||||
* - if the set has more UNIQUES_HASH_MAX_SIZE elements, then all the elements are removed from the set,
|
||||
* not divisible by 2, and then all elements that do not divide by 2 are not inserted into the set;
|
||||
* - if the situation repeats, then only elements dividing by 4, etc., are taken.
|
||||
* - the size() method returns an approximate number of elements that have been inserted into the set;
|
||||
* - there are methods for quick reading and writing in binary and text form.
|
||||
*/
|
||||
|
||||
|
||||
/// Максимальная степень размера буфера перед тем, как значения будут выкидываться
|
||||
/// The maximum degree of buffer size before the values are discarded
|
||||
#define UNIQUES_HASH_MAX_SIZE_DEGREE 17
|
||||
|
||||
/// Максимальное количество элементов перед тем, как значения будут выкидываться
|
||||
/// The maximum number of elements before the values are discarded
|
||||
#define UNIQUES_HASH_MAX_SIZE (1 << (UNIQUES_HASH_MAX_SIZE_DEGREE - 1))
|
||||
|
||||
/** Количество младших бит, использующихся для прореживания. Оставшиеся старшие биты используются для определения позиции в хэш-таблице.
|
||||
* (старшие биты берутся потому что младшие будут постоянными после выкидывания части значений)
|
||||
*/
|
||||
/** The number of least significant bits used for thinning. The remaining high-order bits are used to determine the position in the hash table.
|
||||
* (high-order bits are taken because the younger bits will be constant after dropping some of the values)
|
||||
*/
|
||||
#define UNIQUES_HASH_BITS_FOR_SKIP (32 - UNIQUES_HASH_MAX_SIZE_DEGREE)
|
||||
|
||||
/// Начальная степень размера буфера
|
||||
/// Initial buffer size degree
|
||||
#define UNIQUES_HASH_SET_INITIAL_SIZE_DEGREE 4
|
||||
|
||||
|
||||
/** Эта хэш-функция не самая оптимальная, но состояния UniquesHashSet, посчитанные с ней,
|
||||
* хранятся много где на дисках (в Метраже), поэтому она продолжает использоваться.
|
||||
*/
|
||||
/** This hash function is not the most optimal, but UniquesHashSet states counted with it,
|
||||
* stored in many places on disks (in the Meter), so it continues to be used.
|
||||
*/
|
||||
struct UniquesHashSetDefaultHash
|
||||
{
|
||||
size_t operator() (UInt64 x) const
|
||||
@ -79,15 +78,15 @@ private:
|
||||
using HashValue_t = UInt32;
|
||||
using Allocator = HashTableAllocatorWithStackMemory<(1 << UNIQUES_HASH_SET_INITIAL_SIZE_DEGREE) * sizeof(UInt32)>;
|
||||
|
||||
UInt32 m_size; /// Количество элементов
|
||||
UInt8 size_degree; /// Размер таблицы в виде степени двух
|
||||
UInt8 skip_degree; /// Пропускать элементы не делящиеся на 2 ^ skip_degree
|
||||
bool has_zero; /// Хэш-таблица содержит элемент со значением хэш-функции = 0.
|
||||
UInt32 m_size; /// Number of elements
|
||||
UInt8 size_degree; /// The size of the table as a power of 2
|
||||
UInt8 skip_degree; /// Skip elements not divisible by 2 ^ skip_degree
|
||||
bool has_zero; /// The hash table contains an element with a hash value of 0.
|
||||
|
||||
HashValue_t * buf;
|
||||
|
||||
#ifdef UNIQUES_HASH_SET_COUNT_COLLISIONS
|
||||
/// Для профилирования.
|
||||
/// For profiling.
|
||||
mutable size_t collisions;
|
||||
#endif
|
||||
|
||||
@ -111,7 +110,7 @@ private:
|
||||
inline size_t mask() const { return buf_size() - 1; }
|
||||
inline size_t place(HashValue_t x) const { return (x >> UNIQUES_HASH_BITS_FOR_SKIP) & mask(); }
|
||||
|
||||
/// Значение делится на 2 ^ skip_degree
|
||||
/// The value is divided by 2 ^ skip_degree
|
||||
inline bool good(HashValue_t hash) const
|
||||
{
|
||||
return hash == ((hash >> skip_degree) << skip_degree);
|
||||
@ -122,7 +121,7 @@ private:
|
||||
return Hash()(key);
|
||||
}
|
||||
|
||||
/// Удалить все значения, хэши которых не делятся на 2 ^ skip_degree
|
||||
/// Delete all values whose hashes do not divide by 2 ^ skip_degree
|
||||
void rehash()
|
||||
{
|
||||
for (size_t i = 0; i < buf_size(); ++i)
|
||||
@ -134,9 +133,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/** После удаления элементов, возможно, освободилось место для элементов,
|
||||
* которые были помещены дальше, чем нужно, из-за коллизии.
|
||||
* Надо переместить их.
|
||||
/** After removing the elements, there may have been room for items,
|
||||
* which were placed further than necessary, due to a collision.
|
||||
* You need to move them.
|
||||
*/
|
||||
for (size_t i = 0; i < buf_size(); ++i)
|
||||
{
|
||||
@ -149,7 +148,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/// Увеличить размер буфера в 2 раза или до new_size_degree, если указана ненулевая.
|
||||
/// Increase the size of the buffer 2 times or up to new_size_degree, if it is non-zero.
|
||||
void resize(size_t new_size_degree = 0)
|
||||
{
|
||||
size_t old_size = buf_size();
|
||||
@ -157,21 +156,21 @@ private:
|
||||
if (!new_size_degree)
|
||||
new_size_degree = size_degree + 1;
|
||||
|
||||
/// Расширим пространство.
|
||||
/// Expand the space.
|
||||
buf = reinterpret_cast<HashValue_t *>(Allocator::realloc(buf, old_size * sizeof(buf[0]), (1 << new_size_degree) * sizeof(buf[0])));
|
||||
size_degree = new_size_degree;
|
||||
|
||||
/** Теперь некоторые элементы может потребоваться переместить на новое место.
|
||||
* Элемент может остаться на месте, или переместиться в новое место "справа",
|
||||
* или переместиться левее по цепочке разрешения коллизий, из-за того, что элементы левее него были перемещены в новое место "справа".
|
||||
* Также имеется особый случай:
|
||||
* если элемент должен был быть в конце старого буфера, [ x]
|
||||
* но находится в начале из-за цепочки разрешения коллизий, [o x]
|
||||
* то после ресайза, он сначала снова окажется не на своём месте, [ xo ]
|
||||
* и для того, чтобы перенести его куда надо,
|
||||
* надо будет после переноса всех элементов из старой половинки [ o x ]
|
||||
* обработать ещё хвостик из цепочки разрешения коллизий сразу после неё [ o x ]
|
||||
* Именно для этого написано || buf[i] ниже.
|
||||
/** Now some items may need to be moved to a new location.
|
||||
* The element can stay in place, or move to a new location "on the right",
|
||||
* or move to the left of the collision resolution chain, because the elements to the left of it have been moved to the new "right" location.
|
||||
* There is also a special case
|
||||
* if the element was to be at the end of the old buffer, [ x]
|
||||
* but is at the beginning because of the collision resolution chain, [o x]
|
||||
* then after resizing, it will first be out of place again, [ xo ]
|
||||
* and in order to transfer it to where you need it,
|
||||
* will have to be after transferring all elements from the old half [ o x ]
|
||||
* process another tail from the collision resolution chain immediately after it [ o x ]
|
||||
* This is why || buf[i] below.
|
||||
*/
|
||||
for (size_t i = 0; i < old_size || buf[i]; ++i)
|
||||
{
|
||||
@ -181,7 +180,7 @@ private:
|
||||
|
||||
size_t place_value = place(x);
|
||||
|
||||
/// Элемент на своём месте.
|
||||
/// The element is in its place.
|
||||
if (place_value == i)
|
||||
continue;
|
||||
|
||||
@ -195,7 +194,7 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Элемент остался на своём месте.
|
||||
/// The element remained in its place.
|
||||
if (buf[place_value] == x)
|
||||
continue;
|
||||
|
||||
@ -204,7 +203,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/// Вставить значение.
|
||||
/// Insert a value.
|
||||
void insertImpl(HashValue_t x)
|
||||
{
|
||||
if (x == 0)
|
||||
@ -232,8 +231,8 @@ private:
|
||||
++m_size;
|
||||
}
|
||||
|
||||
/** Вставить в новый буфер значение, которое было в старом буфере.
|
||||
* Используется при увеличении размера буфера, а также при чтении из файла.
|
||||
/** Insert a value into the new buffer that was in the old buffer.
|
||||
* Used when increasing the size of the buffer, as well as when reading from a file.
|
||||
*/
|
||||
void reinsertImpl(HashValue_t x)
|
||||
{
|
||||
@ -251,8 +250,8 @@ private:
|
||||
buf[place_value] = x;
|
||||
}
|
||||
|
||||
/** Если хэш-таблица достаточно заполнена, то сделать resize.
|
||||
* Если элементов слишком много - то выкидывать половину, пока их не станет достаточно мало.
|
||||
/** If the hash table is full enough, then do resize.
|
||||
* If there are too many items, then throw half the pieces until they are small enough.
|
||||
*/
|
||||
void shrinkIfNeed()
|
||||
{
|
||||
@ -330,16 +329,16 @@ public:
|
||||
|
||||
size_t res = m_size * (1 << skip_degree);
|
||||
|
||||
/** Псевдослучайный остаток - для того, чтобы не было видно,
|
||||
* что количество делится на степень двух.
|
||||
/** Pseudo-random remainder - in order to be not visible,
|
||||
* that the number is divided by the power of two.
|
||||
*/
|
||||
res += (intHashCRC32(m_size) & ((1 << skip_degree) - 1));
|
||||
|
||||
/** Коррекция систематической погрешности из-за коллизий при хэшировании в UInt32.
|
||||
* Формула fixed_res(res)
|
||||
* - при каком количестве разных элементов fixed_res,
|
||||
* при их случайном разбрасывании по 2^32 корзинам,
|
||||
* получается в среднем res заполненных корзин.
|
||||
/** Correction of a systematic error due to collisions during hashing in UInt32.
|
||||
* `fixed_res(res)` formula
|
||||
* - with how many different elements of fixed_res,
|
||||
* when randomly scattered across 2^32 baskets,
|
||||
* filled baskets with average of res is obtained.
|
||||
*/
|
||||
size_t p32 = 1ULL << 32;
|
||||
size_t fixed_res = round(p32 * (log(p32) - log(p32 - res)));
|
||||
|
@ -26,9 +26,9 @@ namespace DB
|
||||
|
||||
class ClientInfo;
|
||||
|
||||
/// Поток блоков читающих из таблицы и ее имя
|
||||
/// The stream of blocks reading from the table and its name
|
||||
using ExternalTableData = std::pair<BlockInputStreamPtr, std::string>;
|
||||
/// Вектор пар, описывающих таблицы
|
||||
/// Vector of pairs describing tables
|
||||
using ExternalTablesData = std::vector<ExternalTableData>;
|
||||
|
||||
class Connection;
|
||||
@ -175,8 +175,8 @@ public:
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
/** Заполнить информацию, которая необходима при получении блока для некоторых задач
|
||||
* (пока только для запроса DESCRIBE TABLE с Distributed-таблицами).
|
||||
/** Fill in the information that is needed when getting the block for some tasks
|
||||
* (so far only for a DESCRIBE TABLE query with Distributed tables).
|
||||
*/
|
||||
void fillBlockExtraInfo(BlockExtraInfo & info) const;
|
||||
|
||||
@ -195,7 +195,7 @@ private:
|
||||
*/
|
||||
Poco::Net::SocketAddress resolved_address;
|
||||
|
||||
/// Для сообщений в логе и в эксепшенах.
|
||||
/// For messages in log and in exceptions.
|
||||
String description;
|
||||
void setDescription();
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Интерфейс для пулов соединений.
|
||||
/** Interface for connection pools.
|
||||
*
|
||||
* Использование (на примере обычного ConnectionPool):
|
||||
* Usage (using the usual `ConnectionPool` example)
|
||||
* ConnectionPool pool(...);
|
||||
*
|
||||
* void thread()
|
||||
@ -27,16 +27,16 @@ public:
|
||||
public:
|
||||
virtual ~IConnectionPool() {}
|
||||
|
||||
/** Выделяет соединение для работы. */
|
||||
/** Selects the connection to work. */
|
||||
Entry get(const Settings * settings = nullptr)
|
||||
{
|
||||
return doGet(settings);
|
||||
}
|
||||
|
||||
/** Выделяет до указанного количества соединений для работы.
|
||||
* Соединения предоставляют доступ к разным репликам одного шарда.
|
||||
* Если флаг get_all установлен, все соединения достаются.
|
||||
* Выкидывает исключение, если не удалось выделить ни одного соединения.
|
||||
/** Allocates up to the specified number of connections to work.
|
||||
* Connections provide access to different replicas of one shard.
|
||||
* If `get_all` flag is set, all connections are taken.
|
||||
* Throws an exception if no connections can be selected.
|
||||
*/
|
||||
std::vector<Entry> getMany(const Settings * settings = nullptr,
|
||||
PoolMode pool_mode = PoolMode::GET_MANY)
|
||||
@ -58,7 +58,7 @@ using ConnectionPools = std::vector<ConnectionPoolPtr>;
|
||||
using ConnectionPoolsPtr = std::shared_ptr<ConnectionPools>;
|
||||
|
||||
|
||||
/** Обычный пул соединений, без отказоустойчивости.
|
||||
/** A common connection pool, without fault tolerance.
|
||||
*/
|
||||
class ConnectionPool : public PoolBase<Connection>, public IConnectionPool
|
||||
{
|
||||
@ -106,7 +106,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Создает новый объект для помещения в пул. */
|
||||
/** Creates a new object to put in the pool. */
|
||||
ConnectionPtr allocObject() override
|
||||
{
|
||||
return std::make_shared<Connection>(
|
||||
@ -132,13 +132,13 @@ private:
|
||||
String user;
|
||||
String password;
|
||||
|
||||
/** Адрес может быть заранее отрезолвен и передан в конструктор. Тогда поля host и port имеют смысл только для логгирования.
|
||||
* Иначе адрес резолвится в конструкторе. То есть, DNS балансировка не поддерживается.
|
||||
/** The address can be resolved in advance and passed to the constructor. Then `host` and `port` fields are meaningful only for logging.
|
||||
* Otherwise, address is resolved in constructor. That is, DNS balancing is not supported.
|
||||
*/
|
||||
Poco::Net::SocketAddress resolved_address;
|
||||
|
||||
String client_name;
|
||||
Protocol::Compression::Enum compression; /// Сжимать ли данные при взаимодействии с сервером.
|
||||
Protocol::Compression::Enum compression; /// Whether to compress data when interacting with the server.
|
||||
|
||||
Poco::Timespan connect_timeout;
|
||||
Poco::Timespan receive_timeout;
|
||||
|
@ -22,14 +22,14 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/** Пул соединений с отказоустойчивостью.
|
||||
* Инициализируется несколькими другими IConnectionPool-ами.
|
||||
* При получении соединения, пытается создать или выбрать живое соединение из какого-нибудь пула,
|
||||
* перебирая их в некотором порядке, используя не более указанного количества попыток.
|
||||
* Предпочитаются пулы с меньшим количеством ошибок;
|
||||
* пулы с одинаковым количеством ошибок пробуются в случайном порядке.
|
||||
/** Connection pool with fault tolerance.
|
||||
* Initialized by several other IConnectionPools.
|
||||
* When a connection is received, it tries to create or select a live connection from a pool,
|
||||
* fetch them in some order, using no more than the specified number of attempts.
|
||||
* Pools with fewer errors are preferred;
|
||||
* pools with the same number of errors are tried in random order.
|
||||
*
|
||||
* Замечание: если один из вложенных пулов заблокируется из-за переполнения, то этот пул тоже заблокируется.
|
||||
* Note: if one of the nested pools is blocked due to overflow, then this pool will also be blocked.
|
||||
*/
|
||||
class ConnectionPoolWithFailover : public PoolWithFailoverBase<IConnectionPool>, public IConnectionPool
|
||||
{
|
||||
@ -81,15 +81,15 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
/** Выделяет соединение для работы. */
|
||||
/** Allocates connection to work. */
|
||||
Entry doGet(const Settings * settings) override
|
||||
{
|
||||
applyLoadBalancing(settings);
|
||||
return Base::get(settings);
|
||||
}
|
||||
|
||||
/** Выделяет до указанного количества соединений для работы.
|
||||
* Соединения предоставляют доступ к разным репликам одного шарда.
|
||||
/** Allocates up to the specified number of connections to work.
|
||||
* Connections provide access to different replicas of one shard.
|
||||
*/
|
||||
std::vector<Entry> doGetMany(const Settings * settings, PoolMode pool_mode) override
|
||||
{
|
||||
@ -117,7 +117,7 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<size_t> hostname_differences; /// Расстояния от имени этого хоста до имен хостов пулов.
|
||||
std::vector<size_t> hostname_differences; /// Distances from name of this host to the names of hosts of pools.
|
||||
LoadBalancing default_load_balancing;
|
||||
};
|
||||
|
||||
|
@ -10,39 +10,36 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Для получения данных сразу из нескольких реплик (соединений) из одного или нексольких шардов
|
||||
* в рамках одного потока. В качестве вырожденного случая, может также работать с одним соединением.
|
||||
* Предполагается, что все функции кроме sendCancel всегда выполняются в одном потоке.
|
||||
/** To retrieve data directly from multiple replicas (connections) from one or several shards
|
||||
* within a single thread. As a degenerate case, it can also work with one connection.
|
||||
* It is assumed that all functions except sendCancel are always executed in one thread.
|
||||
*
|
||||
* Интерфейс почти совпадает с Connection.
|
||||
* The interface is almost the same as Connection.
|
||||
*/
|
||||
class MultiplexedConnections final : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Принимает готовое соединение.
|
||||
/// Accepts ready connection.
|
||||
MultiplexedConnections(Connection * connection_, const Settings * settings_, ThrottlerPtr throttler_);
|
||||
|
||||
/** Принимает пул, из которого нужно будет достать одно или несколько соединений.
|
||||
* Если флаг append_extra_info установлен, к каждому полученному блоку прилагается
|
||||
* дополнительная информация.
|
||||
* Если флаг get_all_replicas установлен, достаются все соединения.
|
||||
/** Accepts a pool from which it will be necessary to get one or more connections.
|
||||
* If the append_extra_info flag is set, additional information appended to each received block.
|
||||
* If the get_all_replicas flag is set, all connections are selected.
|
||||
*/
|
||||
MultiplexedConnections(IConnectionPool * pool_, const Settings * settings_, ThrottlerPtr throttler_,
|
||||
bool append_extra_info = false, PoolMode pool_mode_ = PoolMode::GET_MANY);
|
||||
|
||||
/** Принимает пулы, один для каждого шарда, из которих нужно будет достать одно или несколько
|
||||
* соединений.
|
||||
* Если флаг append_extra_info установлен, к каждому полученному блоку прилагается
|
||||
* дополнительная информация.
|
||||
* Если флаг do_broadcast установлен, достаются все соединения.
|
||||
/** Accepts pools, one for each shard, from which one will need to get one or more connections.
|
||||
* If the append_extra_info flag is set, additional information appended to each received block.
|
||||
* If the do_broadcast flag is set, all connections are received.
|
||||
*/
|
||||
MultiplexedConnections(ConnectionPools & pools_, const Settings * settings_, ThrottlerPtr throttler_,
|
||||
bool append_extra_info = false, PoolMode pool_mode_ = PoolMode::GET_MANY);
|
||||
|
||||
/// Отправить на реплики всё содержимое внешних таблиц.
|
||||
/// Send all content of external tables to replicas.
|
||||
void sendExternalTablesData(std::vector<ExternalTablesData> & data);
|
||||
|
||||
/// Отправить запрос на реплики.
|
||||
/// Send request to replicas.
|
||||
void sendQuery(
|
||||
const String & query,
|
||||
const String & query_id = "",
|
||||
@ -50,87 +47,86 @@ public:
|
||||
const ClientInfo * client_info = nullptr,
|
||||
bool with_pending_data = false);
|
||||
|
||||
/// Получить пакет от какой-нибудь реплики.
|
||||
/// Get package from any replica.
|
||||
Connection::Packet receivePacket();
|
||||
|
||||
/// Получить информацию про последний полученный пакет.
|
||||
/// Get information about the last received package.
|
||||
BlockExtraInfo getBlockExtraInfo() const;
|
||||
|
||||
/// Разорвать все действующие соединения.
|
||||
/// Break all active connections.
|
||||
void disconnect();
|
||||
|
||||
/// Отправить на реплики просьбу отменить выполнение запроса
|
||||
/// Send a request to the replica to cancel the request
|
||||
void sendCancel();
|
||||
|
||||
/** На каждой реплике читать и пропускать все пакеты до EndOfStream или Exception.
|
||||
* Возвращает EndOfStream, если не было получено никакого исключения. В противном
|
||||
* случае возвращает последний полученный пакет типа Exception.
|
||||
/** On each replica, read and skip all packets to EndOfStream or Exception.
|
||||
* Returns EndOfStream if no exception has been received. Otherwise
|
||||
* returns the last received packet of type Exception.
|
||||
*/
|
||||
Connection::Packet drain();
|
||||
|
||||
/// Получить адреса реплик в виде строки.
|
||||
/// Get the replica addresses as a string.
|
||||
std::string dumpAddresses() const;
|
||||
|
||||
/// Возвращает количесто реплик.
|
||||
/// Без блокировки, потому что sendCancel() не меняет это количество.
|
||||
/// Returns the number of replicas.
|
||||
/// Without locking, because sendCancel() does not change this number.
|
||||
size_t size() const { return replica_map.size(); }
|
||||
|
||||
/// Проверить, есть ли действительные реплики.
|
||||
/// Без блокировки, потому что sendCancel() не меняет состояние реплик.
|
||||
/// Check if there are any valid replicas.
|
||||
/// Without locking, because sendCancel() does not change the state of the replicas.
|
||||
bool hasActiveConnections() const { return active_connection_total_count > 0; }
|
||||
|
||||
private:
|
||||
/// Соединения 1-го шарда, затем соединения 2-го шарда, и т.д.
|
||||
/// Connections of the 1st shard, then the connections of the 2nd shard, etc.
|
||||
using Connections = std::vector<Connection *>;
|
||||
|
||||
/// Состояние соединений одного шарда.
|
||||
/// The state of the connections of one shard.
|
||||
struct ShardState
|
||||
{
|
||||
/// Количество выделенных соединений, т.е. реплик, для этого шарда.
|
||||
/// The number of connections allocated, i.e. replicas for this shard.
|
||||
size_t allocated_connection_count;
|
||||
/// Текущее количество действительных соединений к репликам этого шарда.
|
||||
/// The current number of valid connections to the replicas of this shard.
|
||||
size_t active_connection_count;
|
||||
};
|
||||
|
||||
/// Описание одной реплики.
|
||||
/// Description of a single replica.
|
||||
struct ReplicaState
|
||||
{
|
||||
/// Индекс соединения.
|
||||
size_t connection_index;
|
||||
/// Владелец этой реплики.
|
||||
/// The owner of this replica.
|
||||
ShardState * shard_state;
|
||||
};
|
||||
|
||||
/// Реплики хэшированные по id сокета.
|
||||
/// Replicas hashed by id of the socket.
|
||||
using ReplicaMap = std::unordered_map<int, ReplicaState>;
|
||||
|
||||
/// Состояние каждого шарда.
|
||||
/// The state of each shard.
|
||||
using ShardStates = std::vector<ShardState>;
|
||||
|
||||
private:
|
||||
void initFromShard(IConnectionPool * pool);
|
||||
|
||||
/// Зарегистрировать шарды.
|
||||
/// Register shards.
|
||||
void registerShards();
|
||||
|
||||
/// Зарегистрировать реплики одного шарда.
|
||||
/// Register replicas of one shard.
|
||||
void registerReplicas(size_t index_begin, size_t index_end, ShardState & shard_state);
|
||||
|
||||
/// Внутренняя версия функции receivePacket без блокировки.
|
||||
/// Interval version of `receivePacket` function without blocking.
|
||||
Connection::Packet receivePacketUnlocked();
|
||||
|
||||
/// Внутренняя версия функции dumpAddresses без блокировки.
|
||||
/// Interval version of `dumpAddresses` function without blocking.
|
||||
std::string dumpAddressesUnlocked() const;
|
||||
|
||||
/// Получить реплику, на которой можно прочитать данные.
|
||||
/// Get a replica where you can read the data.
|
||||
ReplicaMap::iterator getReplicaForReading();
|
||||
|
||||
/** Проверить, есть ли данные, которые можно прочитать на каких-нибудь репликах.
|
||||
* Возвращает одну такую реплику, если она найдётся.
|
||||
/** Check if there are any data that can be read on any of the replicas.
|
||||
* Returns one such replica if it exists.
|
||||
*/
|
||||
ReplicaMap::iterator waitForReadEvent();
|
||||
|
||||
/// Пометить реплику как недействительную.
|
||||
/// Mark the replica as invalid.
|
||||
void invalidateReplica(ReplicaMap::iterator it);
|
||||
|
||||
private:
|
||||
@ -140,29 +136,29 @@ private:
|
||||
ReplicaMap replica_map;
|
||||
ShardStates shard_states;
|
||||
|
||||
/// Если не nullptr, то используется, чтобы ограничить сетевой трафик.
|
||||
/// If not nullptr, then it is used to restrict network traffic.
|
||||
ThrottlerPtr throttler;
|
||||
|
||||
std::vector<ConnectionPool::Entry> pool_entries;
|
||||
|
||||
/// Соединение, c которого был получен последний блок.
|
||||
/// Connection that received last block.
|
||||
Connection * current_connection;
|
||||
/// Информация про последний полученный блок, если поддерживается.
|
||||
/// Information about the last received block, if supported.
|
||||
std::unique_ptr<BlockExtraInfo> block_extra_info;
|
||||
|
||||
/// Текущее количество действительных соединений к репликам.
|
||||
/// The current number of valid connections to replicas.
|
||||
size_t active_connection_total_count = 0;
|
||||
/// Запрос выполняется параллельно на нескольких репликах.
|
||||
/// The query is run in parallel on multiple replicas.
|
||||
bool supports_parallel_execution;
|
||||
/// Отправили запрос
|
||||
/// Send the request
|
||||
bool sent_query = false;
|
||||
/// Отменили запрос
|
||||
/// Cancel request
|
||||
bool cancelled = false;
|
||||
|
||||
PoolMode pool_mode = PoolMode::GET_MANY;
|
||||
|
||||
/// Мьютекс для того, чтобы функция sendCancel могла выполняться безопасно
|
||||
/// в отдельном потоке.
|
||||
/// A mutex for the sendCancel function to execute safely
|
||||
/// in separate thread.
|
||||
mutable std::mutex cancel_mutex;
|
||||
};
|
||||
|
||||
|
@ -23,29 +23,29 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/** Столбец состояний агрегатных функций.
|
||||
* Представлен в виде массива указателей на состояния агрегатных функций (data).
|
||||
* Сами состояния хранятся в одном из пулов (arenas).
|
||||
/** State column of aggregate functions.
|
||||
* Presented as an array of pointers to the states of aggregate functions (data).
|
||||
* The states themselves are stored in one of the pools (arenas).
|
||||
*
|
||||
* Может быть в двух вариантах:
|
||||
* It can be in two variants:
|
||||
*
|
||||
* 1. Владеть своими значениями - то есть, отвечать за их уничтожение.
|
||||
* Столбец состоит из значений, "отданных ему на попечение" после выполнения агрегации (см. Aggregator, функция convertToBlocks),
|
||||
* или из значений, созданных им самим (см. метод insert).
|
||||
* В этом случае, src будет равно nullptr, и столбец будет сам уничтожать (вызывать IAggregateFunction::destroy)
|
||||
* состояния агрегатных функций в деструкторе.
|
||||
* 1. Own its values - that is, be responsible for destroying them.
|
||||
* The column consists of the values "assigned to it" after the aggregation is performed (see Aggregator, convertToBlocks function),
|
||||
* or from values created by itself (see `insert` method).
|
||||
* In this case, `src` will be `nullptr`, and the column itself will be destroyed (call `IAggregateFunction::destroy`)
|
||||
* states of aggregate functions in the destructor.
|
||||
*
|
||||
* 2. Не владеть своими значениями, а использовать значения, взятые из другого столбца ColumnAggregateFunction.
|
||||
* Например, это столбец, полученный перестановкой/фильтрацией или другими преобразованиями из другого столбца.
|
||||
* В этом случае, в src будет shared ptr-ом на столбец-источник. Уничтожением значений будет заниматься этот столбец-источник.
|
||||
* 2. Do not own its values, but use values taken from another ColumnAggregateFunction column.
|
||||
* For example, this is a column obtained by permutation/filtering or other transformations from another column.
|
||||
* In this case, `src` will be `shared ptr` to the source column. Destruction of values will be handled by this source column.
|
||||
*
|
||||
* Это решение несколько ограничено:
|
||||
* - не поддерживается вариант, в котором столбец содержит часть "своих" и часть "чужих" значений;
|
||||
* - не поддерживается вариант наличия нескольких столбцов-источников, что может понадобиться для более оптимального слияния двух столбцов.
|
||||
* This solution is somewhat limited:
|
||||
* - the variant in which the column contains a part of "it's own" and a part of "another's" values is not supported;
|
||||
* - the option of having multiple source columns is not supported, which may be necessary for a more optimal merge of the two columns.
|
||||
*
|
||||
* Эти ограничения можно снять, если добавить массив флагов или даже refcount-ов,
|
||||
* определяющий, какие отдельные значения надо уничтожать, а какие - нет.
|
||||
* Ясно, что этот метод имел бы существенно ненулевую цену.
|
||||
* These restrictions can be removed if you add an array of flags or even refcount,
|
||||
* specifying which individual values should be destroyed and which ones should not.
|
||||
* Clearly, this method would have a substantially non-zero price.
|
||||
*/
|
||||
class ColumnAggregateFunction final : public IColumn, public std::enable_shared_from_this<ColumnAggregateFunction>
|
||||
{
|
||||
@ -281,7 +281,7 @@ public:
|
||||
res[i] = i;
|
||||
}
|
||||
|
||||
/** Более эффективные методы манипуляции */
|
||||
/** More efficient manipulation methods */
|
||||
Container_t & getData()
|
||||
{
|
||||
return data;
|
||||
|
@ -21,17 +21,17 @@ namespace ErrorCodes
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
/** Cтолбeц значений типа массив.
|
||||
* В памяти он представлен, как один столбец вложенного типа, размер которого равен сумме размеров всех массивов,
|
||||
* и как массив смещений в нём, который позволяет достать каждый элемент.
|
||||
/** A column of array values.
|
||||
* In memory, it is represented as one column of a nested type, whose size is equal to the sum of the sizes of all arrays,
|
||||
* and as an array of offsets in it, which allows you to get each element.
|
||||
*/
|
||||
class ColumnArray final : public IColumn
|
||||
{
|
||||
public:
|
||||
/** По индексу i находится смещение до начала i + 1 -го элемента. */
|
||||
/** On the index i there is an offset to the beginning of the i + 1 -th element. */
|
||||
using ColumnOffsets_t = ColumnVector<Offset_t>;
|
||||
|
||||
/** Создать пустой столбец массивов, с типом значений, как в столбце nested_column */
|
||||
/** Create an empty column of arrays with the type of values as in the column `nested_column` */
|
||||
explicit ColumnArray(ColumnPtr nested_column, ColumnPtr offsets_column = nullptr)
|
||||
: data(nested_column), offsets(offsets_column)
|
||||
{
|
||||
@ -106,10 +106,10 @@ public:
|
||||
|
||||
StringRef getDataAt(size_t n) const override
|
||||
{
|
||||
/** Возвращает диапазон памяти, покрывающий все элементы массива.
|
||||
* Работает для массивов значений фиксированной длины.
|
||||
* Для массивов строк и массивов массивов полученный кусок памяти может не взаимно-однозначно соответствовать элементам,
|
||||
* так как содержит лишь уложенные подряд данные, но не смещения.
|
||||
/** Returns the range of memory that covers all elements of the array.
|
||||
* Works for arrays of fixed length values.
|
||||
* For arrays of strings and arrays of arrays, the resulting chunk of memory may not be one-to-one correspondence with the elements,
|
||||
* since it contains only the data laid in succession, but not the offsets.
|
||||
*/
|
||||
|
||||
size_t array_size = sizeAt(n);
|
||||
@ -127,7 +127,7 @@ public:
|
||||
|
||||
void insertData(const char * pos, size_t length) override
|
||||
{
|
||||
/** Аналогично - только для массивов значений фиксированной длины.
|
||||
/** Similarly - only for arrays of fixed length values.
|
||||
*/
|
||||
IColumn * data_ = data.get();
|
||||
if (!data_->isFixed())
|
||||
@ -226,7 +226,7 @@ public:
|
||||
{
|
||||
const ColumnArray & rhs = static_cast<const ColumnArray &>(rhs_);
|
||||
|
||||
/// Не оптимально
|
||||
/// Not optimal
|
||||
size_t lhs_size = sizeAt(n);
|
||||
size_t rhs_size = rhs.sizeAt(m);
|
||||
size_t min_size = std::min(lhs_size, rhs_size);
|
||||
@ -262,7 +262,7 @@ public:
|
||||
void reserve(size_t n) override
|
||||
{
|
||||
getOffsets().reserve(n);
|
||||
getData().reserve(n); /// Средний размер массивов тут никак не учитывается. Или считается, что он не больше единицы.
|
||||
getData().reserve(n); /// The average size of arrays is not taken into account here. Or it is considered to be no more than 1.
|
||||
}
|
||||
|
||||
size_t byteSize() const override
|
||||
@ -285,7 +285,7 @@ public:
|
||||
return offsets1.size() == offsets2.size() && 0 == memcmp(&offsets1[0], &offsets2[0], sizeof(offsets1[0]) * offsets1.size());
|
||||
}
|
||||
|
||||
/** Более эффективные методы манипуляции */
|
||||
/** More efficient methods of manipulation */
|
||||
IColumn & getData() { return *data.get(); }
|
||||
const IColumn & getData() const { return *data.get(); }
|
||||
|
||||
@ -339,28 +339,28 @@ public:
|
||||
|
||||
private:
|
||||
ColumnPtr data;
|
||||
ColumnPtr offsets; /// Смещения могут быть разделяемыми для нескольких столбцов - для реализации вложенных структур данных.
|
||||
ColumnPtr offsets; /// Displacements can be shared across multiple columns - to implement nested data structures.
|
||||
|
||||
size_t ALWAYS_INLINE offsetAt(size_t i) const { return i == 0 ? 0 : getOffsets()[i - 1]; }
|
||||
size_t ALWAYS_INLINE sizeAt(size_t i) const { return i == 0 ? getOffsets()[0] : (getOffsets()[i] - getOffsets()[i - 1]); }
|
||||
|
||||
|
||||
/// Размножить значения, если вложенный столбец - ColumnVector<T>.
|
||||
/// Multiply values if the nested column is ColumnVector<T>.
|
||||
template <typename T>
|
||||
ColumnPtr replicateNumber(const Offsets_t & replicate_offsets) const;
|
||||
|
||||
/// Размножить значения, если вложенный столбец - ColumnString. Код слишком сложный.
|
||||
/// Multiply the values if the nested column is ColumnString. The code is too complicated.
|
||||
ColumnPtr replicateString(const Offsets_t & replicate_offsets) const;
|
||||
|
||||
/** Неконстантные массивы константных значений - довольно редкое явление.
|
||||
* Большинство функций не умеет с ними работать, и не создаёт такие столбцы в качестве результата.
|
||||
* Исключение - функция replicate (см. FunctionsMiscellaneous.h), которая имеет служебное значение для реализации лямбда-функций.
|
||||
* Только ради неё сделана реализация метода replicate для ColumnArray(ColumnConst).
|
||||
/** Non-constant arrays of constant values are quite rare.
|
||||
* Most functions can not work with them, and does not create such columns as a result.
|
||||
* An exception is the function `replicate`(see FunctionsMiscellaneous.h), which has service meaning for the implementation of lambda functions.
|
||||
* Only for its sake is the implementation of the `replicate` method for ColumnArray(ColumnConst).
|
||||
*/
|
||||
ColumnPtr replicateConst(const Offsets_t & replicate_offsets) const;
|
||||
|
||||
|
||||
/// Специализации для функции filter.
|
||||
/// Specializations for the filter function.
|
||||
template <typename T>
|
||||
ColumnPtr filterNumber(const Filter & filt, ssize_t result_size_hint) const;
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace ColumnConstDetails
|
||||
return x == y;
|
||||
}
|
||||
|
||||
/// Проверяет побитовую идентичность элементов, даже если они являются NaN-ами.
|
||||
/// Checks the bitwise identity of elements, even if they are NaNs.
|
||||
template <>
|
||||
inline bool equals(const Float32 & x, const Float32 & y)
|
||||
{
|
||||
@ -68,15 +68,15 @@ namespace ColumnConstDetails
|
||||
}
|
||||
|
||||
|
||||
/** Столбец-константа может содержать внутри себя само значение,
|
||||
* или, в случае массивов, std::shared_ptr от значения-массива,
|
||||
* чтобы избежать проблем производительности при копировании очень больших массивов.
|
||||
/** A constant column can contain the value itself,
|
||||
* or, in the case of arrays, std::shared_ptr from the value-array,
|
||||
* to avoid performance problems when copying very large arrays.
|
||||
*
|
||||
* T - тип значения,
|
||||
* DataHolder - как значение хранится в таблице (либо T, либо std::shared_ptr<T>)
|
||||
* Derived должен реализовать методы getDataFromHolderImpl - получить ссылку на значение из holder-а.
|
||||
* T - the value type,
|
||||
* DataHolder - how the value is stored in a table (either T, or std::shared_ptr<T>)
|
||||
* Derived must implement the `getDataFromHolderImpl` methods - get a reference to the value from the holder.
|
||||
*
|
||||
* Для строк и массивов реализации sizeOfField и byteSize могут быть некорректными.
|
||||
* For rows and arrays `sizeOfField` and `byteSize` implementations may be incorrect.
|
||||
*/
|
||||
template <typename T, typename DataHolder, typename Derived>
|
||||
class ColumnConstBase : public IColumnConst
|
||||
@ -193,7 +193,7 @@ public:
|
||||
int compareAt(size_t n, size_t m, const IColumn & rhs_, int nan_direction_hint) const override
|
||||
{
|
||||
const Derived & rhs = static_cast<const Derived &>(rhs_);
|
||||
return getDataFromHolder() < rhs.getDataFromHolder() /// TODO: правильное сравнение NaN-ов в константных столбцах.
|
||||
return getDataFromHolder() < rhs.getDataFromHolder() /// TODO: correct comparison of NaNs in constant columns.
|
||||
? -1
|
||||
: (data == rhs.data
|
||||
? 0
|
||||
@ -212,7 +212,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** шаблон для столбцов-констант (столбцов одинаковых значений).
|
||||
/** template for columns-constants (columns of the same values).
|
||||
*/
|
||||
template <typename T>
|
||||
class ColumnConst final : public ColumnConstBase<T, T, ColumnConst<T>>
|
||||
@ -224,9 +224,9 @@ private:
|
||||
const T & getDataFromHolderImpl() const { return this->data; }
|
||||
|
||||
public:
|
||||
/// Для ColumnConst<Array> data_type_ должен быть ненулевым.
|
||||
/// Для ColumnConst<Tuple> data_type_ должен быть ненулевым.
|
||||
/// Для ColumnConst<String> data_type_ должен быть ненулевым, если тип данных FixedString.
|
||||
/// For ColumnConst<Array> data_type_ must be not null.
|
||||
/// For ColumnConst<Tuple> data_type_ must be not null.
|
||||
/// For ColumnConst<String> data_type_ must be not null if data type is FixedString.
|
||||
ColumnConst(size_t s_, const T & data_, DataTypePtr data_type_ = DataTypePtr())
|
||||
: ColumnConstBase<T, T, ColumnConst<T>>(s_, data_, data_type_) {}
|
||||
|
||||
@ -235,11 +235,11 @@ public:
|
||||
StringRef getDataAtWithTerminatingZero(size_t n) const override;
|
||||
UInt64 get64(size_t n) const override;
|
||||
|
||||
/** Более эффективные методы манипуляции */
|
||||
/** More efficient methods of manipulation */
|
||||
T & getData() { return this->data; }
|
||||
const T & getData() const { return this->data; }
|
||||
|
||||
/** Преобразование из константы в полноценный столбец */
|
||||
/** Converting from a constant to a full-blown column */
|
||||
ColumnPtr convertToFullColumn() const override;
|
||||
|
||||
void getExtremes(Field & min, Field & max) const override
|
||||
@ -260,7 +260,7 @@ private:
|
||||
const Array & getDataFromHolderImpl() const { return *data; }
|
||||
|
||||
public:
|
||||
/// data_type_ должен быть ненулевым.
|
||||
/// data_type_ must be not null.
|
||||
ColumnConst(size_t s_, const Array & data_, DataTypePtr data_type_)
|
||||
: ColumnConstBase<Array, std::shared_ptr<Array>, ColumnConst<Array>>(s_, std::make_shared<Array>(data_), data_type_) {}
|
||||
|
||||
@ -271,10 +271,10 @@ public:
|
||||
StringRef getDataAtWithTerminatingZero(size_t n) const override;
|
||||
UInt64 get64(size_t n) const override;
|
||||
|
||||
/** Более эффективные методы манипуляции */
|
||||
/** More efficient methods of manipulation */
|
||||
const Array & getData() const { return *data; }
|
||||
|
||||
/** Преобразование из константы в полноценный столбец */
|
||||
/** Converting from a constant to a full-blown column */
|
||||
ColumnPtr convertToFullColumn() const override;
|
||||
|
||||
void getExtremes(Field & min, Field & max) const override
|
||||
@ -295,7 +295,7 @@ private:
|
||||
const Tuple & getDataFromHolderImpl() const { return *data; }
|
||||
|
||||
public:
|
||||
/// data_type_ должен быть ненулевым.
|
||||
/// data_type_ must be not null.
|
||||
ColumnConst(size_t s_, const Tuple & data_, DataTypePtr data_type_)
|
||||
: ColumnConstBase<Tuple, std::shared_ptr<Tuple>, ColumnConst<Tuple>>(s_, std::make_shared<Tuple>(data_), data_type_) {}
|
||||
|
||||
@ -306,10 +306,10 @@ public:
|
||||
StringRef getDataAtWithTerminatingZero(size_t n) const override;
|
||||
UInt64 get64(size_t n) const override;
|
||||
|
||||
/** Более эффективные методы манипуляции */
|
||||
/** More efficient methods of manipulation */
|
||||
const Tuple & getData() const { return *data; }
|
||||
|
||||
/** Преобразование из константы в полноценный столбец */
|
||||
/** Converting from a constant to a full-blown column */
|
||||
ColumnPtr convertToFullColumn() const override;
|
||||
|
||||
/** Create ColumnTuple of constant columns as elements. */
|
||||
@ -363,7 +363,7 @@ template <typename T> UInt64 ColumnConst<T>::get64(size_t n) const
|
||||
throw Exception("Method get64 is not supported for " + this->getName(), ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/// Для элементарных типов.
|
||||
/// For elementary types.
|
||||
template <typename T> StringRef getDataAtImpl(const T & data)
|
||||
{
|
||||
return StringRef(reinterpret_cast<const char *>(&data), sizeof(data));
|
||||
|
@ -9,8 +9,8 @@ namespace DB
|
||||
|
||||
class ExpressionActions;
|
||||
|
||||
/** Столбец, содержащий лямбда-выражение.
|
||||
* Ведёт себя как столбец-константа. Содержит выражение, но не входные или выходные данные.
|
||||
/** A column containing a lambda expression.
|
||||
* Behaves like a constant-column. Contains an expression, but not input or output data.
|
||||
*/
|
||||
class ColumnExpression final : public IColumnDummy
|
||||
{
|
||||
|
@ -22,8 +22,8 @@ namespace ErrorCodes
|
||||
extern const int PARAMETER_OUT_OF_BOUND;
|
||||
}
|
||||
|
||||
/** Cтолбeц значений типа "строка фиксированной длины".
|
||||
* Если вставить строку меньшей длины, то она будет дополнена нулевыми байтами.
|
||||
/** A column of values of "fixed-length string" type.
|
||||
* If you insert a smaller string, it will be padded with zero bytes.
|
||||
*/
|
||||
class ColumnFixedString final : public IColumn
|
||||
{
|
||||
@ -31,16 +31,16 @@ public:
|
||||
using Chars_t = PaddedPODArray<UInt8>;
|
||||
|
||||
private:
|
||||
/// Байты строк, уложенные подряд. Строки хранятся без завершающего нулевого байта.
|
||||
/** NOTE Требуется, чтобы смещение и тип chars в объекте был таким же, как у data в ColumnUInt8.
|
||||
* Это используется в функции packFixed (AggregationCommon.h)
|
||||
/// Bytes of rows, laid in succession. The strings are stored without a trailing zero byte.
|
||||
/** NOTE It is required that the offset and type of chars in the object be the same as that of `data in ColumnUInt8`.
|
||||
* Used in `packFixed` function (AggregationCommon.h)
|
||||
*/
|
||||
Chars_t chars;
|
||||
/// Размер строк.
|
||||
/// The size of the rows.
|
||||
const size_t n;
|
||||
|
||||
public:
|
||||
/** Создать пустой столбец строк фиксированной длины n */
|
||||
/** Create an empty column of strings of fixed-length `n` */
|
||||
ColumnFixedString(size_t n_) : n(n_) {}
|
||||
|
||||
std::string getName() const override { return "ColumnFixedString"; }
|
||||
@ -181,7 +181,7 @@ public:
|
||||
less(const ColumnFixedString & parent_) : parent(parent_) {}
|
||||
bool operator()(size_t lhs, size_t rhs) const
|
||||
{
|
||||
/// TODO: memcmp тормозит.
|
||||
/// TODO: memcmp slows down.
|
||||
int res = memcmp(&parent.chars[lhs * parent.n], &parent.chars[rhs * parent.n], parent.n);
|
||||
return positive ? (res < 0) : (res > 0);
|
||||
}
|
||||
|
@ -10,16 +10,16 @@ class Set;
|
||||
using ConstSetPtr = std::shared_ptr<const Set>;
|
||||
|
||||
|
||||
/** Столбец, содержащий множество значений в секции IN.
|
||||
* Ведёт себя как столбец-константа (так как множество одно, а не своё на каждую строку).
|
||||
* Значение у этого столбца нестандартное, поэтому его невозможно получить через обычный интерфейс.
|
||||
/** A column containing multiple values in the `IN` section.
|
||||
* Behaves like a constant-column (because the set is one, not its own for each line).
|
||||
* This column has a nonstandard value, so it can not be obtained via a normal interface.
|
||||
*/
|
||||
class ColumnSet final : public IColumnDummy
|
||||
{
|
||||
public:
|
||||
ColumnSet(size_t s_, ConstSetPtr data_) : IColumnDummy(s_), data(data_) {}
|
||||
|
||||
/// Столбец не константный. Иначе столбец будет использоваться в вычислениях в ExpressionActions::prepare, когда множество из подзапроса ещё не готово.
|
||||
/// The column is not a constant. Otherwise, the column will be used in calculations in ExpressionActions::prepare, when a set from subquery is not ready yet.
|
||||
bool isConst() const override { return false; }
|
||||
|
||||
std::string getName() const override { return "ColumnSet"; }
|
||||
|
@ -25,7 +25,7 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/** Cтолбeц значений типа "строка".
|
||||
/** A column of values of type `String`.
|
||||
*/
|
||||
class ColumnString final : public IColumn
|
||||
{
|
||||
@ -33,22 +33,22 @@ public:
|
||||
using Chars_t = PaddedPODArray<UInt8>;
|
||||
|
||||
private:
|
||||
/// По индексу i находится смещение до начала i + 1 -го элемента.
|
||||
/// On the index i there is an offset to the beginning of the i + 1 -th element.
|
||||
Offsets_t offsets;
|
||||
|
||||
/// Байты строк, уложенные подряд. Строки хранятся с завершающим нулевым байтом.
|
||||
/// Bytes of rows laid in succession. Strings are stored with the trailing zero byte.
|
||||
Chars_t chars;
|
||||
|
||||
size_t __attribute__((__always_inline__)) offsetAt(size_t i) const { return i == 0 ? 0 : offsets[i - 1]; }
|
||||
|
||||
/// Размер, включая завершающий нулевой байт.
|
||||
/// Size, including the trailing zero byte.
|
||||
size_t __attribute__((__always_inline__)) sizeAt(size_t i) const { return i == 0 ? offsets[0] : (offsets[i] - offsets[i - 1]); }
|
||||
|
||||
template <bool positive>
|
||||
friend struct lessWithCollation;
|
||||
|
||||
public:
|
||||
/** Создать пустой столбец строк */
|
||||
/** Create an empty column of rows */
|
||||
ColumnString() {}
|
||||
|
||||
std::string getName() const override { return "ColumnString"; }
|
||||
@ -347,16 +347,16 @@ public:
|
||||
{
|
||||
const ColumnString & rhs = static_cast<const ColumnString &>(rhs_);
|
||||
|
||||
/** Для производительности, строки сравниваются до первого нулевого байта.
|
||||
* (если нулевой байт в середине строки, то то, что после него - игнорируется)
|
||||
* Замечу, что завершающий нулевой байт всегда есть.
|
||||
/** For performance, the strings are compared to the first zero byte.
|
||||
* (if zero byte is in the middle of the line, then what is after it is ignored)
|
||||
* Note that the terminating zero byte is always present.
|
||||
*/
|
||||
return strcmp(
|
||||
reinterpret_cast<const char *>(&chars[offsetAt(n)]),
|
||||
reinterpret_cast<const char *>(&rhs.chars[rhs.offsetAt(m)]));
|
||||
}
|
||||
|
||||
/// Версия compareAt для locale-sensitive сравнения строк
|
||||
/// Version `compareAt` for locale-sensitive string comparison
|
||||
int compareAtWithCollation(size_t n, size_t m, const IColumn & rhs_, const Collator & collator) const;
|
||||
|
||||
template <bool positive>
|
||||
@ -400,7 +400,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Сортировка с учетом Collation
|
||||
/// Sorting with regard to `Collation`
|
||||
void getPermutationWithCollation(const Collator & collator, bool reverse, size_t limit, Permutation & res) const;
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & replicate_offsets) const override
|
||||
|
@ -27,10 +27,10 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/** Штука для сравнения чисел.
|
||||
* Целые числа сравниваются как обычно.
|
||||
* Числа с плавающей запятой сравниваются так, что NaN-ы всегда оказываются в конце
|
||||
* (если этого не делать, то сортировка не работала бы вообще).
|
||||
/** Stuff for comparing numbers.
|
||||
* Integer values are compared as usual.
|
||||
* Floating-point numbers are compared this way that NaNs always end up at the end
|
||||
* (if you don't do this, the sort would not work at all).
|
||||
*/
|
||||
template <typename T>
|
||||
struct CompareHelper
|
||||
@ -38,11 +38,11 @@ struct CompareHelper
|
||||
static bool less(T a, T b) { return a < b; }
|
||||
static bool greater(T a, T b) { return a > b; }
|
||||
|
||||
/** Сравнивает два числа. Выдаёт число меньше нуля, равное нулю, или больше нуля, если a < b, a == b, a > b, соответственно.
|
||||
* Если одно из значений является NaN, то:
|
||||
* - если nan_direction_hint == -1 - NaN считаются меньше всех чисел;
|
||||
* - если nan_direction_hint == 1 - NaN считаются больше всех чисел;
|
||||
* По-сути: nan_direction_hint == -1 говорит, что сравнение идёт для сортировки по убыванию.
|
||||
/** Compares two numbers. Returns a number less than zero, equal to zero, or greater than zero if a < b, a == b, a > b, respectively.
|
||||
* If one of the values is NaN, then
|
||||
* - if nan_direction_hint == -1 - NaN are considered less than all numbers;
|
||||
* - if nan_direction_hint == 1 - NaN are considered to be larger than all numbers;
|
||||
* Essentially: nan_direction_hint == -1 says that the comparison is for sorting in descending order.
|
||||
*/
|
||||
static int compare(T a, T b, int nan_direction_hint)
|
||||
{
|
||||
@ -89,7 +89,7 @@ template <> struct CompareHelper<Float32> : public FloatCompareHelper<Float32> {
|
||||
template <> struct CompareHelper<Float64> : public FloatCompareHelper<Float64> {};
|
||||
|
||||
|
||||
/** Для реализации функции get64.
|
||||
/** To implement `get64` function.
|
||||
*/
|
||||
template <typename T>
|
||||
inline UInt64 unionCastToUInt64(T x) { return x; }
|
||||
@ -141,7 +141,7 @@ typename std::enable_if<!std::is_floating_point<T>::value, T>::type NaNOrZero()
|
||||
}
|
||||
|
||||
|
||||
/** Шаблон столбцов, которые используют для хранения простой массив.
|
||||
/** A pattern of columns that use a simple array to store.
|
||||
*/
|
||||
template <typename T>
|
||||
class ColumnVector final : public IColumn
|
||||
@ -358,10 +358,10 @@ public:
|
||||
const T * data_pos = &data[0];
|
||||
|
||||
#if __SSE2__
|
||||
/** Чуть более оптимизированная версия.
|
||||
* Исходит из допущения, что часто куски последовательно идущих значений
|
||||
* полностью проходят или полностью не проходят фильтр.
|
||||
* Поэтому, будем оптимистично проверять куски по SIMD_BYTES значений.
|
||||
/** A slightly more optimized version.
|
||||
* Based on the assumption that often pieces of consecutive values
|
||||
* completely pass or do not pass the filter completely.
|
||||
* Therefore, we will optimistically check the parts of `SIMD_BYTES` values.
|
||||
*/
|
||||
|
||||
static constexpr size_t SIMD_BYTES = 16;
|
||||
@ -374,7 +374,7 @@ public:
|
||||
|
||||
if (0 == mask)
|
||||
{
|
||||
/// Ничего не вставляем.
|
||||
/// Nothing is inserted.
|
||||
}
|
||||
else if (0xFFFF == mask)
|
||||
{
|
||||
|
@ -3,16 +3,16 @@
|
||||
#include <DB/Columns/IColumn.h>
|
||||
|
||||
|
||||
/// Общие вспомогательные методы для реализации разных столбцов.
|
||||
/// Common helper methods for implementation of different columns.
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Считает, сколько байт в filt больше нуля.
|
||||
/// Counts how many bytes of `filt` are greater than zero.
|
||||
size_t countBytesInFilter(const IColumn::Filter & filt);
|
||||
|
||||
|
||||
/// Общая реализация функции filter для ColumnArray и ColumnString.
|
||||
/// The general implementation of `filter` function for ColumnArray and ColumnString.
|
||||
template <typename T>
|
||||
void filterArraysImpl(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
|
@ -14,8 +14,8 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/** Базовый класс для столбцов-констант, содержащих значение, не входящее в Field.
|
||||
* Не является полноценым столбцом и используется особым образом.
|
||||
/** Base class for columns-constants that contain a value that is not in the `Field`.
|
||||
* Not a full-fledged column and is used in a special way.
|
||||
*/
|
||||
class IColumnDummy : public IColumn
|
||||
{
|
||||
|
@ -259,7 +259,7 @@ private:
|
||||
{
|
||||
time_t current_time = time(0);
|
||||
|
||||
/// Плохо быть навязчивым.
|
||||
/// It's bad to be intrusive.
|
||||
if (current_time % 3 != 0)
|
||||
return false;
|
||||
|
||||
|
@ -28,7 +28,7 @@ struct Connection
|
||||
session.setKeepAlive(true);
|
||||
session.setKeepAliveTimeout(Poco::Timespan(86400, 0));
|
||||
|
||||
/// TODO Таймаут.
|
||||
/// TODO Timeout.
|
||||
}
|
||||
|
||||
void init(
|
||||
@ -57,7 +57,7 @@ struct Connection
|
||||
|
||||
void init(const std::string & connection_string)
|
||||
{
|
||||
/// connection_string - строка вида DSN=ClickHouse;UID=default;PWD=password
|
||||
/// connection_string - string of the form `DSN=ClickHouse;UID=default;PWD=password`
|
||||
|
||||
const char * pos = connection_string.data();
|
||||
const char * end = pos + connection_string.size();
|
||||
|
@ -5,10 +5,10 @@
|
||||
#include <Poco/Types.h>
|
||||
|
||||
|
||||
/// В формате VarUInt.
|
||||
/// In the format of VarUInt.
|
||||
inline void readSize(Poco::UInt64 & res, std::istream & istr)
|
||||
{
|
||||
static constexpr auto MAX_LENGTH_OF_SIZE = 4; /// Ограничивает размер 256 мегабайтами (2 ^ (7 * 4)).
|
||||
static constexpr auto MAX_LENGTH_OF_SIZE = 4; /// Limits the size to 256 megabytes (2 ^ (7 * 4)).
|
||||
|
||||
res = 0;
|
||||
for (size_t i = 0; i < MAX_LENGTH_OF_SIZE; ++i)
|
||||
|
@ -12,7 +12,7 @@ void ResultSet::init(Statement & statement_)
|
||||
if (in().peek() == EOF)
|
||||
return;
|
||||
|
||||
/// Заголовок: количество столбцов, их имена и типы.
|
||||
/// Title: number of columns, their names and types.
|
||||
Poco::UInt64 num_columns = 0;
|
||||
readSize(num_columns, in());
|
||||
|
||||
@ -33,7 +33,7 @@ void ResultSet::init(Statement & statement_)
|
||||
|
||||
readNextBlock();
|
||||
|
||||
/// Отображаемые размеры столбцов, вычисляются по первому блоку.
|
||||
/// The displayed column sizes are calculated from the first block.
|
||||
for (const auto & row : current_block.data)
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
columns_info[i].display_size = std::max(row.data[i].data.size(), columns_info[i].display_size);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "ResultSet.h"
|
||||
|
||||
|
||||
/// Информация, куда и как складывать значения при чтении.
|
||||
/// Information where and how to add values when reading.
|
||||
struct Binding
|
||||
{
|
||||
SQLSMALLINT target_type;
|
||||
@ -43,7 +43,7 @@ public:
|
||||
request.setKeepAlive(true);
|
||||
request.setChunkedTransferEncoding(true);
|
||||
request.setCredentials("Basic", user_password_base64.str());
|
||||
request.setURI("/?database=" + connection.database + "&default_format=ODBCDriver"); /// TODO Возможность передать настройки. TODO эскейпинг
|
||||
request.setURI("/?database=" + connection.database + "&default_format=ODBCDriver"); /// TODO Ability to transfer settings. TODO escaping
|
||||
|
||||
// if (in && in->peek() != EOF)
|
||||
connection.session.reset();
|
||||
|
@ -139,7 +139,7 @@ SQLFreeStmt(HSTMT statement_handle,
|
||||
case SQL_DROP:
|
||||
return freeHandle<Statement>(statement_handle);
|
||||
|
||||
case SQL_CLOSE: /// Закрыть курсор, проигнорировать оставшиеся результаты. Если курсора нет, то noop.
|
||||
case SQL_CLOSE: /// Close the cursor, ignore the remaining results. If there is no cursor, then noop.
|
||||
statement.reset();
|
||||
|
||||
case SQL_UNBIND:
|
||||
|
@ -22,10 +22,10 @@ SQLGetInfo(HDBC connection_handle,
|
||||
|
||||
LOG("GetInfo with info_type: " << info_type << ", out_value_max_length: " << out_value_max_length);
|
||||
|
||||
/** Как выбираются все эти значения?
|
||||
* В части них приведена правдивая информация о возможностях СУБД.
|
||||
* Но в большинстве случаев, возможности декларируются "про запас", чтобы посмотреть,
|
||||
* какие запросы будет отправлять и что будет делать всякий софт, имея ввиду эти возможности.
|
||||
/** How are all these values selected?
|
||||
* Part of them provides true information about the capabilities of the DBMS.
|
||||
* But in most cases, the possibilities are declared "in reserve" to see,
|
||||
* what requests will be sent and what any software will do, meaning these features.
|
||||
*/
|
||||
|
||||
return doWith<Connection>(connection_handle, [&](Connection & connection)
|
||||
@ -74,7 +74,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
CASE_FALLTHROUGH(SQL_ROW_UPDATES)
|
||||
CASE_STRING(SQL_DESCRIBE_PARAMETER, "N")
|
||||
|
||||
/// UINTEGER одиночные значения
|
||||
/// UINTEGER single values
|
||||
CASE_NUM(SQL_ODBC_INTERFACE_CONFORMANCE, SQLUINTEGER, SQL_OIC_CORE)
|
||||
CASE_NUM(SQL_ASYNC_MODE, SQLUINTEGER, SQL_AM_NONE)
|
||||
CASE_NUM(SQL_ASYNC_NOTIFICATION, SQLUINTEGER, SQL_ASYNC_NOTIFICATION_NOT_CAPABLE)
|
||||
@ -84,7 +84,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
CASE_NUM(SQL_PARAM_ARRAY_SELECTS, SQLUINTEGER, SQL_PAS_NO_SELECT)
|
||||
CASE_NUM(SQL_SQL_CONFORMANCE, SQLUINTEGER, SQL_SC_SQL92_ENTRY)
|
||||
|
||||
/// USMALLINT одиночные значения
|
||||
/// USMALLINT single values
|
||||
CASE_NUM(SQL_GROUP_BY, SQLUSMALLINT, SQL_GB_GROUP_BY_CONTAINS_SELECT)
|
||||
CASE_NUM(SQL_CATALOG_LOCATION, SQLUSMALLINT, SQL_CL_START)
|
||||
CASE_NUM(SQL_FILE_USAGE, SQLUSMALLINT, SQL_FILE_NOT_SUPPORTED)
|
||||
@ -99,7 +99,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
CASE_NUM(SQL_NULL_COLLATION, SQLUSMALLINT, SQL_NC_END)
|
||||
CASE_NUM(SQL_TXN_CAPABLE, SQLUSMALLINT, SQL_TC_NONE)
|
||||
|
||||
/// UINTEGER непустые битмаски
|
||||
/// UINTEGER non-empty bitmasks
|
||||
CASE_NUM(SQL_CATALOG_USAGE, SQLUINTEGER, SQL_CU_DML_STATEMENTS | SQL_CU_TABLE_DEFINITION)
|
||||
CASE_NUM(SQL_AGGREGATE_FUNCTIONS, SQLUINTEGER, SQL_AF_ALL | SQL_AF_AVG | SQL_AF_COUNT | SQL_AF_DISTINCT | SQL_AF_MAX | SQL_AF_MIN | SQL_AF_SUM)
|
||||
CASE_NUM(SQL_ALTER_TABLE, SQLUINTEGER, SQL_AT_ADD_COLUMN_DEFAULT | SQL_AT_ADD_COLUMN_SINGLE | SQL_AT_DROP_COLUMN_DEFAULT | SQL_AT_SET_COLUMN_DEFAULT)
|
||||
@ -197,7 +197,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
|
||||
CASE_NUM(SQL_UNION, SQLUINTEGER, SQL_U_UNION | SQL_U_UNION_ALL)
|
||||
|
||||
/// UINTEGER пустые битмаски
|
||||
/// UINTEGER empty bitmasks
|
||||
CASE_FALLTHROUGH(SQL_ALTER_DOMAIN)
|
||||
CASE_FALLTHROUGH(SQL_BATCH_ROW_COUNT)
|
||||
CASE_FALLTHROUGH(SQL_BATCH_SUPPORT)
|
||||
@ -230,7 +230,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
CASE_FALLTHROUGH(SQL_SQL92_REVOKE)
|
||||
CASE_NUM(SQL_DDL_INDEX, SQLUINTEGER, 0)
|
||||
|
||||
/// Ограничения на максимальное число, USMALLINT.
|
||||
/// Limits on the maximum number, USMALLINT.
|
||||
CASE_FALLTHROUGH(SQL_ACTIVE_ENVIRONMENTS)
|
||||
CASE_FALLTHROUGH(SQL_MAX_COLUMNS_IN_GROUP_BY)
|
||||
CASE_FALLTHROUGH(SQL_MAX_COLUMNS_IN_INDEX)
|
||||
@ -249,7 +249,7 @@ SQLGetInfo(HDBC connection_handle,
|
||||
CASE_FALLTHROUGH(SQL_MAX_TABLE_NAME_LEN)
|
||||
CASE_NUM(SQL_MAX_CATALOG_NAME_LEN, SQLUSMALLINT, 0)
|
||||
|
||||
/// Ограничения на максимальное число, UINTEGER.
|
||||
/// Limitations on the maximum number, UINTEGER.
|
||||
CASE_FALLTHROUGH(SQL_MAX_ROW_SIZE)
|
||||
CASE_FALLTHROUGH(SQL_MAX_STATEMENT_LEN)
|
||||
CASE_FALLTHROUGH(SQL_MAX_BINARY_LITERAL_LEN)
|
||||
|
@ -21,11 +21,11 @@
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/** Функции из ODBC интерфейса не могут напрямую вызывать другие функции.
|
||||
* Потому что будет вызвана не функция из этой библиотеки, а обёртка из driver manager-а,
|
||||
* которая может неправильно работать, будучи вызванной изнутри другой функции.
|
||||
* Неправильно - потому что driver manager оборачивает все handle в свои другие,
|
||||
* которые имеют уже другие адреса.
|
||||
/** Functions from the ODBC interface can not directly call other functions.
|
||||
* Because not a function from this library will be called, but a wrapper from the driver manager,
|
||||
* which can work incorrectly, being called from within another function.
|
||||
* Wrong - because driver manager wraps all handle in its own,
|
||||
* which already have other addresses.
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
@ -532,7 +532,7 @@ impl_SQLGetDiagRec(SQLSMALLINT handle_type, SQLHANDLE handle,
|
||||
if (diagnostic_record->native_error_code == 0)
|
||||
return SQL_NO_DATA;
|
||||
|
||||
/// Пятибуквенный SQLSTATE и завершающий ноль.
|
||||
/// The five-letter SQLSTATE and the trailing zero.
|
||||
if (out_sqlstate)
|
||||
strncpy(reinterpret_cast<char *>(out_sqlstate), diagnostic_record->sql_state.data(), 6);
|
||||
|
||||
@ -798,7 +798,7 @@ SQLBrowseConnect(HDBC connection_handle,
|
||||
}
|
||||
|
||||
|
||||
/// Не реализовано.
|
||||
/// Not implemented.
|
||||
|
||||
|
||||
RETCODE SQL_API
|
||||
@ -832,7 +832,7 @@ SQLGetCursorName(HSTMT StatementHandle,
|
||||
|
||||
|
||||
/*
|
||||
/// Эта функция может быть реализована в driver manager-е.
|
||||
/// This function can be implemented in the driver manager.
|
||||
RETCODE SQL_API
|
||||
SQLGetFunctions(HDBC ConnectionHandle,
|
||||
SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported)
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "StringRef.h"
|
||||
|
||||
|
||||
/** Проверяет handle. Ловит исключения и засовывает их в DiagnosticRecord.
|
||||
/** Checks `handle`. Catches exceptions and puts them into the DiagnosticRecord.
|
||||
*/
|
||||
template <typename Handle, typename F>
|
||||
RETCODE doWith(SQLHANDLE handle_opaque, F && f)
|
||||
@ -29,7 +29,7 @@ RETCODE doWith(SQLHANDLE handle_opaque, F && f)
|
||||
}
|
||||
|
||||
|
||||
/// Парсит строку вида key1=value1;key2=value2... TODO Парсинг значений в фигурных скобках.
|
||||
/// Parse a string of the form `key1=value1;key2=value2` ... TODO Parsing values in curly brackets.
|
||||
static const char * nextKeyValuePair(const char * data, const char * end, StringRef & out_key, StringRef & out_value)
|
||||
{
|
||||
if (data >= end)
|
||||
@ -154,7 +154,7 @@ RETCODE fillOutputNumber(NUM num,
|
||||
}
|
||||
|
||||
|
||||
/// См. для примера info.cpp
|
||||
/// See for example info.cpp
|
||||
|
||||
#define CASE_FALLTHROUGH(NAME) \
|
||||
case NAME: \
|
||||
|
@ -23,7 +23,7 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque
|
||||
|
||||
LOG_TRACE(log, "Request URI: " << request.getURI());
|
||||
|
||||
/// NOTE: Тут можно сделать аутентификацию, если понадобится.
|
||||
/// NOTE: You can do authentication here if you need to.
|
||||
|
||||
String endpoint_name = params.get("endpoint");
|
||||
bool compress = params.get("compress") == "true";
|
||||
@ -50,7 +50,7 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque
|
||||
|
||||
void InterserverIOHTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response)
|
||||
{
|
||||
/// Для того, чтобы работал keep-alive.
|
||||
/// In order to work keep-alive.
|
||||
if (request.getVersion() == Poco::Net::HTTPServerRequest::HTTP_1_1)
|
||||
response.setChunkedTransferEncoding(true);
|
||||
|
||||
|
@ -26,7 +26,7 @@ void ReplicasStatusHandler::handleRequest(Poco::Net::HTTPServerRequest & request
|
||||
{
|
||||
HTMLForm params(request);
|
||||
|
||||
/// Даже в случае, когда отставание небольшое, выводить подробную информацию об отставании.
|
||||
/// Even if lag is small, output detailed information about the lag.
|
||||
bool verbose = params.get("verbose", "") == "1";
|
||||
|
||||
const MergeTreeSettings & settings = context.getMergeTreeSettings();
|
||||
@ -36,7 +36,7 @@ void ReplicasStatusHandler::handleRequest(Poco::Net::HTTPServerRequest & request
|
||||
|
||||
auto databases = context.getDatabases();
|
||||
|
||||
/// Перебираем все реплицируемые таблицы.
|
||||
/// Iterate through all the replicated tables.
|
||||
for (const auto & db : databases)
|
||||
{
|
||||
for (auto iterator = db.second->getIterator(); iterator->isValid(); iterator->next())
|
||||
@ -83,7 +83,7 @@ void ReplicasStatusHandler::handleRequest(Poco::Net::HTTPServerRequest & request
|
||||
|
||||
if (!response.sent())
|
||||
{
|
||||
/// Ещё ничего не отправляли, и даже не знаем, нужно ли сжимать ответ.
|
||||
/// We have not sent anything yet and we don't even know if we need to compress response.
|
||||
response.send() << getCurrentExceptionMessage(false) << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ namespace DB
|
||||
|
||||
class Context;
|
||||
|
||||
/// Отвечает "Ok.\n", если все реплики на этом сервере не слишком сильно отстают. Иначе выводит информацию об отставании.
|
||||
/// Replies "Ok.\n" if all replicas on this server don't lag too much. Otherwise output lag information.
|
||||
class ReplicasStatusHandler : public Poco::Net::HTTPRequestHandler
|
||||
{
|
||||
private:
|
||||
|
@ -23,7 +23,7 @@ namespace DB
|
||||
StatusFile::StatusFile(const std::string & path_)
|
||||
: path(path_)
|
||||
{
|
||||
/// Если файл уже существует. NOTE Незначительный race condition.
|
||||
/// If file already exists. NOTE Minor race condition.
|
||||
if (Poco::File(path).exists())
|
||||
{
|
||||
std::string contents;
|
||||
@ -61,7 +61,7 @@ StatusFile::StatusFile(const std::string & path_)
|
||||
if (0 != lseek(fd, 0, SEEK_SET))
|
||||
throwFromErrno("Cannot lseek " + path);
|
||||
|
||||
/// Записываем в файл информацию о текущем экземпляре сервера.
|
||||
/// Write information about current server instance to the file.
|
||||
{
|
||||
WriteBufferFromFileDescriptor out(fd, 1024);
|
||||
out
|
||||
|
@ -8,7 +8,7 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Обеспечивает, что с одной директорией с данными может одновременно работать не более одного сервера.
|
||||
/** Provides that no more than one server works with one data directory.
|
||||
*/
|
||||
class StatusFile : private boost::noncopyable
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ void TCPHandler::runImpl()
|
||||
{
|
||||
receiveHello();
|
||||
}
|
||||
catch (const Exception & e) /// Типично при неправильном имени пользователя, пароле, адресе.
|
||||
catch (const Exception & e) /// Typical for an incorrect username, password, or address.
|
||||
{
|
||||
if (e.code() == ErrorCodes::CLIENT_HAS_CONNECTED_TO_WRONG_PORT)
|
||||
{
|
||||
@ -85,7 +85,7 @@ void TCPHandler::runImpl()
|
||||
|
||||
try
|
||||
{
|
||||
/// Пытаемся отправить информацию об ошибке клиенту.
|
||||
/// We try to send error information to the client.
|
||||
sendException(e);
|
||||
}
|
||||
catch (...) {}
|
||||
@ -93,7 +93,7 @@ void TCPHandler::runImpl()
|
||||
throw;
|
||||
}
|
||||
|
||||
/// При соединении может быть указана БД по умолчанию.
|
||||
/// When connecting, the default database can be specified.
|
||||
if (!default_database.empty())
|
||||
{
|
||||
if (!connection_context.isDatabaseExist(default_database))
|
||||
@ -114,43 +114,43 @@ void TCPHandler::runImpl()
|
||||
|
||||
while (1)
|
||||
{
|
||||
/// Ждём пакета от клиента. При этом, каждые POLL_INTERVAL сек. проверяем, не требуется ли завершить работу.
|
||||
/// We are waiting for package from client. Thus, every `POLL_INTERVAL` seconds check whether you do not need to complete the work.
|
||||
while (!static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000) && !BaseDaemon::instance().isCancelled())
|
||||
;
|
||||
|
||||
/// Если требуется завершить работу, или клиент отсоединился.
|
||||
/// If you need to quit, or client disconnects.
|
||||
if (BaseDaemon::instance().isCancelled() || in->eof())
|
||||
break;
|
||||
|
||||
Stopwatch watch;
|
||||
state.reset();
|
||||
|
||||
/** Исключение во время выполнения запроса (его надо отдать по сети клиенту).
|
||||
* Клиент сможет его принять, если оно не произошло во время отправки другого пакета и клиент ещё не разорвал соединение.
|
||||
/** An exception during the execution of request (it must be sent over the network to the client).
|
||||
* The client will be able to accept it, if it did not happen while sending another packet and the client has not disconnected yet.
|
||||
*/
|
||||
std::unique_ptr<Exception> exception;
|
||||
|
||||
try
|
||||
{
|
||||
/// Восстанавливаем контекст запроса.
|
||||
/// Restore context of request.
|
||||
query_context = connection_context;
|
||||
|
||||
/** Если Query - обрабатываем. Если Ping или Cancel - возвращаемся в начало.
|
||||
* Могут прийти настройки на отдельный запрос, которые модифицируют query_context.
|
||||
/** If Query - process it. If Ping or Cancel - go back to the beginning.
|
||||
* There may come settings for a separate query that modify `query_context`.
|
||||
*/
|
||||
if (!receivePacket())
|
||||
continue;
|
||||
|
||||
/// Получить блоки временных таблиц
|
||||
/// Get blocks of temporary tables
|
||||
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
||||
readData(global_settings);
|
||||
|
||||
/// Очищаем, так как, получая данные внешних таблиц, мы получили пустой блок.
|
||||
/// А значит, stream помечен как cancelled и читать из него нельзя.
|
||||
/// We are clearing, as we received an empty block from the external table data.
|
||||
/// So, stream is marked as cancelled and can not be read from it.
|
||||
state.block_in.reset();
|
||||
state.maybe_compressed_in.reset(); /// Для более корректного учёта MemoryTracker-ом.
|
||||
state.maybe_compressed_in.reset(); /// For more accurate accounting of MemoryTracker.
|
||||
|
||||
/// Обрабатываем Query
|
||||
/// Processing Query
|
||||
state.io = executeQuery(state.query, query_context, false, state.stage);
|
||||
|
||||
if (state.io.out)
|
||||
@ -159,7 +159,7 @@ void TCPHandler::runImpl()
|
||||
after_check_cancelled.restart();
|
||||
after_send_progress.restart();
|
||||
|
||||
/// Запрос требует приёма данных от клиента?
|
||||
/// Does the request require receive data from client?
|
||||
if (state.need_receive_data_for_insert)
|
||||
processInsertQuery(global_settings);
|
||||
else
|
||||
@ -179,11 +179,11 @@ void TCPHandler::runImpl()
|
||||
}
|
||||
catch (const Poco::Net::NetException & e)
|
||||
{
|
||||
/** Сюда мы можем попадать, если была ошибка в соединении с клиентом,
|
||||
* или в соединении с удалённым сервером, который использовался для обработки запроса.
|
||||
* Здесь не получается отличить эти два случая.
|
||||
* Хотя в одном из них, мы должны отправить эксепшен клиенту, а в другом - не можем.
|
||||
* Будем пытаться отправить эксепшен клиенту в любом случае - см. ниже.
|
||||
/** We can get here if there was an error during connection to the client,
|
||||
* or in connection with a remote server that was used to process the request.
|
||||
* It is not possible to distinguish between these two cases.
|
||||
* Although in one of them, we have to send exception to the client, but in the other - we can not.
|
||||
* We will try to send exception to the client in any case - see below.
|
||||
*/
|
||||
state.io.onException();
|
||||
exception = std::make_unique<Exception>(e.displayText(), ErrorCodes::POCO_EXCEPTION);
|
||||
@ -213,7 +213,7 @@ void TCPHandler::runImpl()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
/** Не удалось отправить информацию об эксепшене клиенту. */
|
||||
/** Could not send exception information to the client. */
|
||||
network_error = true;
|
||||
LOG_WARNING(log, "Client has gone away.");
|
||||
}
|
||||
@ -224,10 +224,10 @@ void TCPHandler::runImpl()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
/** В процессе обработки запроса было исключение, которое мы поймали и, возможно, отправили клиенту.
|
||||
* При уничтожении конвейера выполнения запроса, было второе исключение.
|
||||
* Например, конвейер мог выполняться в нескольких потоках, и в каждом из них могло возникнуть исключение.
|
||||
* Проигнорируем его.
|
||||
/** During the processing of request, there was an exception that we caught and possibly sent to client.
|
||||
* When destroying the request pipeline execution there was a second exception.
|
||||
* For example, a pipeline could run in multiple threads, and an exception could occur in each of them.
|
||||
* Ignore it.
|
||||
*/
|
||||
}
|
||||
|
||||
@ -248,29 +248,29 @@ void TCPHandler::readData(const Settings & global_settings)
|
||||
{
|
||||
Stopwatch watch(CLOCK_MONOTONIC_COARSE);
|
||||
|
||||
/// Ждём пакета от клиента. При этом, каждые POLL_INTERVAL сек. проверяем, не требуется ли завершить работу.
|
||||
/// We are waiting for package from the client. Thus, every `POLL_INTERVAL` seconds check whether you do not need to complete the work.
|
||||
while (1)
|
||||
{
|
||||
if (static_cast<ReadBufferFromPocoSocket &>(*in).poll(global_settings.poll_interval * 1000000))
|
||||
break;
|
||||
|
||||
/// Если требуется завершить работу.
|
||||
/// If you need to shut down work.
|
||||
if (BaseDaemon::instance().isCancelled())
|
||||
return;
|
||||
|
||||
/** Если ждём данных уже слишком долго.
|
||||
* Если периодически poll-ить соединение, то receive_timeout у сокета сам по себе не срабатывает.
|
||||
* Поэтому, добавлена дополнительная проверка.
|
||||
/** If we wait for data for too long.
|
||||
* If we periodically poll, the receive_timeout of the socket itself does not work.
|
||||
* Therefore, an additional check is added.
|
||||
*/
|
||||
if (watch.elapsedSeconds() > global_settings.receive_timeout.totalSeconds())
|
||||
throw Exception("Timeout exceeded while receiving data from client", ErrorCodes::SOCKET_TIMEOUT);
|
||||
}
|
||||
|
||||
/// Если клиент отсоединился.
|
||||
/// If client disconnected.
|
||||
if (in->eof())
|
||||
return;
|
||||
|
||||
/// Принимаем и обрабатываем данные. А если они закончились, то выходим.
|
||||
/// We accept and process data. And if they are over, then we leave.
|
||||
if (!receivePacket())
|
||||
break;
|
||||
}
|
||||
@ -279,12 +279,12 @@ void TCPHandler::readData(const Settings & global_settings)
|
||||
|
||||
void TCPHandler::processInsertQuery(const Settings & global_settings)
|
||||
{
|
||||
/** Сделано выше остальных строк, чтобы в случае, когда функция writePrefix кидает эксепшен,
|
||||
* клиент получил эксепшен до того, как начнёт отправлять данные.
|
||||
/** Made above the rest of the lines, so that in case of `writePrefix` function throws an exception,
|
||||
* client receive exception before sending data.
|
||||
*/
|
||||
state.io.out->writePrefix();
|
||||
|
||||
/// Отправляем клиенту блок - структура таблицы.
|
||||
/// Send block to the client - table structure.
|
||||
Block block = state.io.out_sample;
|
||||
sendData(block);
|
||||
|
||||
@ -314,7 +314,7 @@ void TCPHandler::processOrdinaryQuery()
|
||||
{
|
||||
if (isQueryCancelled())
|
||||
{
|
||||
/// Получен пакет с просьбой прекратить выполнение запроса.
|
||||
/// A package was received requesting to stop execution of the request.
|
||||
async_in.cancel();
|
||||
break;
|
||||
}
|
||||
@ -322,26 +322,26 @@ void TCPHandler::processOrdinaryQuery()
|
||||
{
|
||||
if (state.progress.rows && after_send_progress.elapsed() / 1000 >= query_context.getSettingsRef().interactive_delay)
|
||||
{
|
||||
/// Прошло некоторое время и есть прогресс.
|
||||
/// Some time passed and there is a progress.
|
||||
after_send_progress.restart();
|
||||
sendProgress();
|
||||
}
|
||||
|
||||
if (async_in.poll(query_context.getSettingsRef().interactive_delay / 1000))
|
||||
{
|
||||
/// Есть следующий блок результата.
|
||||
/// There is the following result block.
|
||||
block = async_in.read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Если закончились данные, то отправим данные профайлинга и тотальные значения до
|
||||
* последнего нулевого блока, чтобы иметь возможность использовать
|
||||
* эту информацию в выводе суффикса output stream'а.
|
||||
* Если запрос был прерван, то вызывать методы sendTotals и другие нельзя,
|
||||
* потому что мы прочитали ещё не все данные, и в это время могут производиться какие-то
|
||||
* вычисления в других потоках.
|
||||
/** If data has run out, we will send the profiling data and total values to
|
||||
* the last zero block to be able to use
|
||||
* this information in the suffix output of stream.
|
||||
* If the request was interrupted, then `sendTotals` and other methods could not be called,
|
||||
* because we have not read all the data yet,
|
||||
* and there could be ongoing calculations in other threads at the same time.
|
||||
*/
|
||||
if (!block && !isQueryCancelled())
|
||||
{
|
||||
@ -420,7 +420,7 @@ void TCPHandler::sendExtremes()
|
||||
|
||||
void TCPHandler::receiveHello()
|
||||
{
|
||||
/// Получить hello пакет.
|
||||
/// Receive `hello` packet.
|
||||
UInt64 packet_type = 0;
|
||||
String user = "default";
|
||||
String password;
|
||||
@ -428,8 +428,8 @@ void TCPHandler::receiveHello()
|
||||
readVarUInt(packet_type, *in);
|
||||
if (packet_type != Protocol::Client::Hello)
|
||||
{
|
||||
/** Если случайно обратились по протоколу HTTP на порт, предназначенный для внутреннего TCP-протокола,
|
||||
* то вместо номера пакета будет G (GET) или P (POST), в большинстве случаев.
|
||||
/** If you accidentally accessed the HTTP protocol for a port destined for an internal TCP protocol,
|
||||
* Then instead of the package number, there will be G (GET) or P (POST), in most cases.
|
||||
*/
|
||||
if (packet_type == 'G' || packet_type == 'P')
|
||||
{
|
||||
@ -572,29 +572,29 @@ bool TCPHandler::receiveData()
|
||||
{
|
||||
initBlockInput();
|
||||
|
||||
/// Имя временной таблицы для записи данных, по умолчанию пустая строка
|
||||
/// The name of the temporary table for writing data, default to empty string
|
||||
String external_table_name;
|
||||
if (client_revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES)
|
||||
readStringBinary(external_table_name, *in);
|
||||
|
||||
/// Прочитать из сети один блок и записать его
|
||||
/// Read one block from the network and write it down
|
||||
Block block = state.block_in->read();
|
||||
|
||||
if (block)
|
||||
{
|
||||
/// Если запрос на вставку, то данные нужно писать напрямую в state.io.out.
|
||||
/// Иначе пишем блоки во временную таблицу external_table_name.
|
||||
/// If there is an insert request, then the data should be written directly to `state.io.out`.
|
||||
/// Otherwise, we write the blocks in the temporary `external_table_name` table.
|
||||
if (!state.need_receive_data_for_insert)
|
||||
{
|
||||
StoragePtr storage;
|
||||
/// Если такой таблицы не существовало, создаем ее.
|
||||
/// If such a table does not exist, create it.
|
||||
if (!(storage = query_context.tryGetExternalTable(external_table_name)))
|
||||
{
|
||||
NamesAndTypesListPtr columns = std::make_shared<NamesAndTypesList>(block.getColumnsList());
|
||||
storage = StorageMemory::create(external_table_name, columns);
|
||||
query_context.addExternalTable(external_table_name, storage);
|
||||
}
|
||||
/// Данные будем писать напрямую в таблицу.
|
||||
/// The data will be written directly to the table.
|
||||
state.io.out = storage->write(ASTPtr(), query_context.getSettingsRef());
|
||||
}
|
||||
if (block)
|
||||
@ -649,7 +649,7 @@ bool TCPHandler::isQueryCancelled()
|
||||
|
||||
after_check_cancelled.restart();
|
||||
|
||||
/// Во время выполнения запроса, единственный пакет, который может прийти от клиента - это остановка выполнения запроса.
|
||||
/// During request execution the only packet that can come from the client is stopping the query.
|
||||
if (static_cast<ReadBufferFromPocoSocket &>(*in).poll(0))
|
||||
{
|
||||
UInt64 packet_type = 0;
|
||||
@ -728,7 +728,7 @@ void TCPHandler::run()
|
||||
}
|
||||
catch (Poco::Exception & e)
|
||||
{
|
||||
/// Таймаут - не ошибка.
|
||||
/// Timeout - not an error.
|
||||
if (!strcmp(e.what(), "Timeout"))
|
||||
{
|
||||
LOG_DEBUG(log, "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
|
||||
|
@ -43,16 +43,16 @@ struct QueryState
|
||||
/// Streams of blocks, that are processing the query.
|
||||
BlockIO io;
|
||||
|
||||
/// Отменен ли запрос
|
||||
/// Is request cancelled
|
||||
bool is_cancelled = false;
|
||||
/// Пустой или нет
|
||||
/// empty or not
|
||||
bool is_empty = true;
|
||||
/// Данные были отправлены.
|
||||
/// Data was sent.
|
||||
bool sent_all_data = false;
|
||||
/// Запрос требует приёма данных от клиента (INSERT, но не INSERT SELECT).
|
||||
/// Request requires data from the client (INSERT, but not INSERT SELECT).
|
||||
bool need_receive_data_for_insert = false;
|
||||
|
||||
/// Для вывода прогресса - разница после предыдущей отправки прогресса.
|
||||
/// To output progress, the difference after the previous sending of progress.
|
||||
Progress progress;
|
||||
|
||||
|
||||
@ -92,18 +92,18 @@ private:
|
||||
Context connection_context;
|
||||
Context query_context;
|
||||
|
||||
/// Потоки для чтения/записи из/в сокет соединения с клиентом.
|
||||
std::shared_ptr<ReadBuffer> in;
|
||||
/// Streams for reading/writing from/to client connection socket.
|
||||
std::shared_ptr<ReadBuffer> in;
|
||||
std::shared_ptr<WriteBuffer> out;
|
||||
|
||||
/// Время после последней проверки остановки запроса и отправки прогресса.
|
||||
Stopwatch after_check_cancelled;
|
||||
/// Time after the last check to stop the request and send the progress.
|
||||
Stopwatch after_check_cancelled;
|
||||
Stopwatch after_send_progress;
|
||||
|
||||
String default_database;
|
||||
|
||||
/// На данный момент, поддерживается одновременное выполнение только одного запроса в соединении.
|
||||
QueryState state;
|
||||
/// At the moment, only one ongoing query in the connection is supported at a time.
|
||||
QueryState state;
|
||||
|
||||
CurrentMetrics::Increment metric_increment{CurrentMetrics::TCPConnection};
|
||||
|
||||
@ -116,14 +116,14 @@ private:
|
||||
bool receiveData();
|
||||
void readData(const Settings & global_settings);
|
||||
|
||||
/// Обработать запрос INSERT
|
||||
/// Process INSERT query
|
||||
void processInsertQuery(const Settings & global_settings);
|
||||
|
||||
/// Обработать запрос, который не требует приёма блоков данных от клиента
|
||||
/// Process a request that does not require the receiving of data blocks from the client
|
||||
void processOrdinaryQuery();
|
||||
|
||||
void sendHello();
|
||||
void sendData(Block & block); /// Записать в сеть блок.
|
||||
void sendData(Block & block); /// Write a block to the network.
|
||||
void sendException(const Exception & e);
|
||||
void sendProgress();
|
||||
void sendEndOfStream();
|
||||
@ -131,13 +131,13 @@ private:
|
||||
void sendTotals();
|
||||
void sendExtremes();
|
||||
|
||||
/// Создаёт state.block_in/block_out для чтения/записи блоков, в зависимости от того, включено ли сжатие.
|
||||
/// Creates state.block_in/block_out for blocks read/write, depending on whether compression is enabled.
|
||||
void initBlockInput();
|
||||
void initBlockOutput();
|
||||
|
||||
bool isQueryCancelled();
|
||||
|
||||
/// Эта функция вызывается из разных потоков.
|
||||
/// This function is called from different threads.
|
||||
void updateProgress(const Progress & value);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user