Merge pull request #570 from f1yegor/translate/comments

translate comments
This commit is contained in:
alexey-milovidov 2017-03-09 05:56:10 +04:00 committed by GitHub
commit e5c45ebff8
57 changed files with 722 additions and 729 deletions

View File

@ -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
{

View File

@ -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> >
{

View File

@ -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>
{

View File

@ -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>>

View File

@ -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
{

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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)
{

View File

@ -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> >

View File

@ -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

View File

@ -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> >
{

View File

@ -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>

View File

@ -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

View File

@ -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>>
{

View File

@ -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>

View File

@ -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
{

View File

@ -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)

View File

@ -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);

View File

@ -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(); }

View File

@ -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

View File

@ -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>>;

View File

@ -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();
};

View File

@ -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>

View File

@ -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)));

View File

@ -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();

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;

View File

@ -21,17 +21,17 @@ namespace ErrorCodes
extern const int BAD_ARGUMENTS;
}
/** олб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;

View File

@ -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));

View File

@ -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
{

View File

@ -22,8 +22,8 @@ namespace ErrorCodes
extern const int PARAMETER_OUT_OF_BOUND;
}
/** олб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);
}

View File

@ -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"; }

View File

@ -25,7 +25,7 @@ namespace ErrorCodes
}
/** олб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

View File

@ -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)
{

View File

@ -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,

View File

@ -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
{

View File

@ -259,7 +259,7 @@ private:
{
time_t current_time = time(0);
/// Плохо быть навязчивым.
/// It's bad to be intrusive.
if (current_time % 3 != 0)
return false;

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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: \

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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

View File

@ -8,7 +8,7 @@ namespace DB
{
/** Обеспечивает, что с одной директорией с данными может одновременно работать не более одного сервера.
/** Provides that no more than one server works with one data directory.
*/
class StatusFile : private boost::noncopyable
{

View File

@ -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()

View File

@ -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);
};