2011-09-19 01:42:16 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
2015-01-08 18:52:48 +00:00
|
|
|
|
#include <mutex>
|
2015-01-11 02:00:26 +00:00
|
|
|
|
#include <memory>
|
2015-04-16 14:27:56 +00:00
|
|
|
|
#include <functional>
|
2012-03-05 07:58:34 +00:00
|
|
|
|
|
2015-11-30 19:57:46 +00:00
|
|
|
|
#include <Poco/TemporaryFile.h>
|
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/logger_useful.h>
|
2012-09-05 19:51:09 +00:00
|
|
|
|
|
2012-05-31 05:41:56 +00:00
|
|
|
|
#include <DB/Core/StringRef.h>
|
2013-02-08 19:34:44 +00:00
|
|
|
|
#include <DB/Common/Arena.h>
|
2014-12-30 18:04:53 +00:00
|
|
|
|
#include <DB/Common/HashTable/HashMap.h>
|
|
|
|
|
#include <DB/Common/HashTable/TwoLevelHashMap.h>
|
2016-08-02 01:46:05 +00:00
|
|
|
|
#include <DB/Common/ThreadPool.h>
|
2012-05-31 05:41:56 +00:00
|
|
|
|
|
2011-09-19 01:42:16 +00:00
|
|
|
|
#include <DB/DataStreams/IBlockInputStream.h>
|
2012-05-31 05:41:56 +00:00
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
#include <DB/Interpreters/AggregateDescription.h>
|
2012-08-23 23:49:28 +00:00
|
|
|
|
#include <DB/Interpreters/AggregationCommon.h>
|
2012-12-25 19:28:59 +00:00
|
|
|
|
#include <DB/Interpreters/Limits.h>
|
2015-01-10 02:30:03 +00:00
|
|
|
|
#include <DB/Interpreters/Compiler.h>
|
2011-09-19 01:42:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
#include <DB/Columns/ColumnString.h>
|
|
|
|
|
#include <DB/Columns/ColumnFixedString.h>
|
|
|
|
|
#include <DB/Columns/ColumnAggregateFunction.h>
|
2014-10-29 01:18:50 +00:00
|
|
|
|
#include <DB/Columns/ColumnVector.h>
|
2016-10-18 10:09:48 +00:00
|
|
|
|
#include <DB/Columns/ColumnNullable.h>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
|
2011-09-19 01:42:16 +00:00
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int UNKNOWN_AGGREGATED_DATA_VARIANT;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-21 04:24:28 +00:00
|
|
|
|
class IBlockOutputStream;
|
|
|
|
|
|
2011-09-19 01:42:16 +00:00
|
|
|
|
|
2011-12-19 08:06:31 +00:00
|
|
|
|
/** Разные структуры данных, которые могут использоваться для агрегации
|
2015-01-02 00:35:33 +00:00
|
|
|
|
* Для эффективности, сами данные для агрегации кладутся в пул.
|
2013-02-08 19:34:44 +00:00
|
|
|
|
* Владение данными (состояний агрегатных функций) и пулом
|
2015-01-02 03:16:28 +00:00
|
|
|
|
* захватывается позднее - в функции convertToBlocks, объектом ColumnAggregateFunction.
|
2015-01-02 00:35:33 +00:00
|
|
|
|
*
|
|
|
|
|
* Большинство структур данных существует в двух вариантах: обычном и двухуровневом (TwoLevel).
|
|
|
|
|
* Двухуровневая хэш-таблица работает чуть медленнее при маленьком количестве различных ключей,
|
|
|
|
|
* но при большом количестве различных ключей лучше масштабируется, так как позволяет
|
|
|
|
|
* распараллелить некоторые операции (слияние, пост-обработку) естественным образом.
|
|
|
|
|
*
|
|
|
|
|
* Чтобы обеспечить эффективную работу в большом диапазоне условий,
|
|
|
|
|
* сначала используются одноуровневые хэш-таблицы,
|
|
|
|
|
* а при достижении количеством различных ключей достаточно большого размера,
|
|
|
|
|
* они конвертируются в двухуровневые.
|
|
|
|
|
*
|
|
|
|
|
* PS. Существует много различных подходов к эффективной реализации параллельной и распределённой агрегации,
|
|
|
|
|
* лучшим образом подходящих для разных случаев, и этот подход - всего лишь один из них, выбранный по совокупности причин.
|
2011-12-19 08:06:31 +00:00
|
|
|
|
*/
|
2016-09-23 05:49:55 +00:00
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using AggregatedDataWithoutKey = AggregateDataPtr;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
2016-09-23 05:49:55 +00:00
|
|
|
|
using AggregatedDataWithUInt8Key = HashMap<UInt64, AggregateDataPtr, TrivialHash, HashTableFixedGrower<8>>;
|
|
|
|
|
using AggregatedDataWithUInt16Key = HashMap<UInt64, AggregateDataPtr, TrivialHash, HashTableFixedGrower<16>>;
|
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using AggregatedDataWithUInt64Key = HashMap<UInt64, AggregateDataPtr, HashCRC32<UInt64>>;
|
|
|
|
|
using AggregatedDataWithStringKey = HashMapWithSavedHash<StringRef, AggregateDataPtr>;
|
|
|
|
|
using AggregatedDataWithKeys128 = HashMap<UInt128, AggregateDataPtr, UInt128HashCRC32>;
|
|
|
|
|
using AggregatedDataWithKeys256 = HashMap<UInt256, AggregateDataPtr, UInt256HashCRC32>;
|
|
|
|
|
using AggregatedDataHashed = HashMap<UInt128, std::pair<StringRef*, AggregateDataPtr>, UInt128TrivialHash>;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using AggregatedDataWithUInt64KeyTwoLevel = TwoLevelHashMap<UInt64, AggregateDataPtr, HashCRC32<UInt64>>;
|
|
|
|
|
using AggregatedDataWithStringKeyTwoLevel = TwoLevelHashMapWithSavedHash<StringRef, AggregateDataPtr>;
|
|
|
|
|
using AggregatedDataWithKeys128TwoLevel = TwoLevelHashMap<UInt128, AggregateDataPtr, UInt128HashCRC32>;
|
|
|
|
|
using AggregatedDataWithKeys256TwoLevel = TwoLevelHashMap<UInt256, AggregateDataPtr, UInt256HashCRC32>;
|
|
|
|
|
using AggregatedDataHashedTwoLevel = TwoLevelHashMap<UInt128, std::pair<StringRef*, AggregateDataPtr>, UInt128TrivialHash>;
|
2011-09-26 07:25:22 +00:00
|
|
|
|
|
2016-09-23 05:49:55 +00:00
|
|
|
|
/** Variants with better hash function, using more than 32 bits for hash.
|
|
|
|
|
* Using for merging phase of external aggregation, where number of keys may be far greater than 4 billion,
|
|
|
|
|
* but we keep in memory and merge only sub-partition of them simultaneously.
|
|
|
|
|
* TODO We need to switch for better hash function not only for external aggregation,
|
|
|
|
|
* but also for huge aggregation results on machines with terabytes of RAM.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using AggregatedDataWithUInt64KeyHash64 = HashMap<UInt64, AggregateDataPtr, DefaultHash<UInt64>>;
|
|
|
|
|
using AggregatedDataWithStringKeyHash64 = HashMapWithSavedHash<StringRef, AggregateDataPtr, StringRefHash64>;
|
|
|
|
|
using AggregatedDataWithKeys128Hash64 = HashMap<UInt128, AggregateDataPtr, UInt128Hash>;
|
|
|
|
|
using AggregatedDataWithKeys256Hash64 = HashMap<UInt256, AggregateDataPtr, UInt256Hash>;
|
2014-10-29 01:18:50 +00:00
|
|
|
|
|
2014-10-29 02:35:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
/// Для случая, когда есть один числовой ключ.
|
2014-12-30 10:16:23 +00:00
|
|
|
|
template <typename FieldType, typename TData> /// UInt8/16/32/64 для любых типов соответствующей битности.
|
2014-10-29 01:18:50 +00:00
|
|
|
|
struct AggregationMethodOneNumber
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
Data data;
|
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
AggregationMethodOneNumber() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodOneNumber(const Other & other) : data(other.data) {}
|
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
/// Для использования одного Method в разных потоках, используйте разные State.
|
|
|
|
|
struct State
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 06:49:32 +00:00
|
|
|
|
const FieldType * vec;
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
/** Вызывается в начале обработки каждого блока.
|
|
|
|
|
* Устанавливает переменные, необходимые для остальных методов, вызываемых во внутренних циклах.
|
|
|
|
|
*/
|
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
vec = &static_cast<const ColumnVector<FieldType> *>(key_columns[0])->getData()[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Достать из ключевых столбцов ключ для вставки в хэш-таблицу.
|
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns, /// Ключевые столбцы.
|
|
|
|
|
size_t keys_size, /// Количество ключевых столбцов.
|
|
|
|
|
size_t i, /// Из какой строки блока достать ключ.
|
|
|
|
|
const Sizes & key_sizes, /// Если ключи фиксированной длины - их длины. Не используется в методах агрегации по ключам переменной длины.
|
2015-02-22 16:09:16 +00:00
|
|
|
|
StringRefs & keys, /// Сюда могут быть записаны ссылки на данные ключей в столбцах. Они могут быть использованы в дальнейшем.
|
|
|
|
|
Arena & pool) const
|
2015-01-03 06:49:32 +00:00
|
|
|
|
{
|
|
|
|
|
return unionCastToUInt64(vec[i]);
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
/// Из значения в хэш-таблице получить AggregateDataPtr.
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
/** Разместить дополнительные данные, если это необходимо, в случае, когда в хэш-таблицу был вставлен новый ключ.
|
|
|
|
|
*/
|
2015-01-03 05:39:21 +00:00
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
/** Действие, которое нужно сделать, если ключ не новый. Например, откатить выделение памяти в пуле.
|
|
|
|
|
*/
|
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool) {}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
/** Не использовать оптимизацию для идущих подряд ключей.
|
|
|
|
|
*/
|
|
|
|
|
static const bool no_consecutive_keys_optimization = false;
|
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
/** Вставить ключ из хэш-таблицы в столбцы.
|
|
|
|
|
*/
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static_cast<ColumnVector<FieldType> *>(key_columns[0])->insertData(reinterpret_cast<const char *>(&value.first), sizeof(value.first));
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Для случая, когда есть один строковый ключ.
|
2014-12-30 10:16:23 +00:00
|
|
|
|
template <typename TData>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
struct AggregationMethodString
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2014-10-29 02:35:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
Data data;
|
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
AggregationMethodString() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodString(const Other & other) : data(other.data) {}
|
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
struct State
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 06:49:32 +00:00
|
|
|
|
const ColumnString::Offsets_t * offsets;
|
|
|
|
|
const ColumnString::Chars_t * chars;
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
const IColumn & column = *key_columns[0];
|
|
|
|
|
const ColumnString & column_string = static_cast<const ColumnString &>(column);
|
|
|
|
|
offsets = &column_string.getOffsets();
|
|
|
|
|
chars = &column_string.getChars();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
2015-02-22 16:09:16 +00:00
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
2015-01-03 06:49:32 +00:00
|
|
|
|
{
|
|
|
|
|
return StringRef(
|
|
|
|
|
&(*chars)[i == 0 ? 0 : (*offsets)[i - 1]],
|
|
|
|
|
(i == 0 ? (*offsets)[i] : ((*offsets)[i] - (*offsets)[i - 1])) - 1);
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 05:39:21 +00:00
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 05:39:21 +00:00
|
|
|
|
value.first.data = pool.insert(value.first.data, value.first.size);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool) {}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
static const bool no_consecutive_keys_optimization = false;
|
|
|
|
|
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-02 00:35:33 +00:00
|
|
|
|
key_columns[0]->insertData(value.first.data, value.first.size);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Для случая, когда есть один строковый ключ фиксированной длины.
|
2014-12-30 10:16:23 +00:00
|
|
|
|
template <typename TData>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
struct AggregationMethodFixedString
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2014-10-29 02:35:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
Data data;
|
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
AggregationMethodFixedString() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodFixedString(const Other & other) : data(other.data) {}
|
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
struct State
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 06:49:32 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
const ColumnFixedString::Chars_t * chars;
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
const IColumn & column = *key_columns[0];
|
|
|
|
|
const ColumnFixedString & column_string = static_cast<const ColumnFixedString &>(column);
|
|
|
|
|
n = column_string.getN();
|
|
|
|
|
chars = &column_string.getChars();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
2015-02-22 16:09:16 +00:00
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
2015-01-03 06:49:32 +00:00
|
|
|
|
{
|
|
|
|
|
return StringRef(&(*chars)[i * n], n);
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 05:39:21 +00:00
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 05:39:21 +00:00
|
|
|
|
value.first.data = pool.insert(value.first.data, value.first.size);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool) {}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
static const bool no_consecutive_keys_optimization = false;
|
|
|
|
|
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-02 00:35:33 +00:00
|
|
|
|
key_columns[0]->insertData(value.first.data, value.first.size);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-10-21 16:50:41 +00:00
|
|
|
|
namespace aggregator_impl
|
|
|
|
|
{
|
|
|
|
|
|
2016-10-18 10:09:48 +00:00
|
|
|
|
/// This class is designed to provide the functionality that is required for
|
|
|
|
|
/// supporting nullable keys in AggregationMethodKeysFixed. If there are
|
|
|
|
|
/// no nullable keys, this class is merely implemented as an empty shell.
|
|
|
|
|
template <typename Key, bool has_nullable_keys>
|
|
|
|
|
class BaseStateKeysFixed;
|
|
|
|
|
|
|
|
|
|
/// Case where nullable keys are supported.
|
|
|
|
|
template <typename Key>
|
|
|
|
|
class BaseStateKeysFixed<Key, true>
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
void init(const ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
null_maps.reserve(key_columns.size());
|
|
|
|
|
actual_columns.reserve(key_columns.size());
|
|
|
|
|
|
|
|
|
|
for (const auto & col : key_columns)
|
|
|
|
|
{
|
|
|
|
|
if (col->isNullable())
|
|
|
|
|
{
|
|
|
|
|
const auto & nullable_col = static_cast<const ColumnNullable &>(*col);
|
|
|
|
|
actual_columns.push_back(nullable_col.getNestedColumn().get());
|
2016-12-30 05:13:14 +00:00
|
|
|
|
null_maps.push_back(nullable_col.getNullMapColumn().get());
|
2016-10-18 10:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
actual_columns.push_back(col);
|
|
|
|
|
null_maps.push_back(nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return the columns which actually contain the values of the keys.
|
|
|
|
|
/// For a given key column, if it is nullable, we return its nested
|
|
|
|
|
/// column. Otherwise we return the key column itself.
|
|
|
|
|
inline const ConstColumnPlainPtrs & getActualColumns() const
|
|
|
|
|
{
|
|
|
|
|
return actual_columns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create a bitmap that indicates whether, for a particular row,
|
|
|
|
|
/// a key column bears a null value or not.
|
|
|
|
|
KeysNullMap<Key> createBitmap(size_t row) const
|
|
|
|
|
{
|
|
|
|
|
KeysNullMap<Key> bitmap{};
|
|
|
|
|
|
|
|
|
|
for (size_t k = 0; k < null_maps.size(); ++k)
|
|
|
|
|
{
|
|
|
|
|
if (null_maps[k] != nullptr)
|
|
|
|
|
{
|
|
|
|
|
const auto & null_map = static_cast<const ColumnUInt8 &>(*null_maps[k]).getData();
|
|
|
|
|
if (null_map[row] == 1)
|
|
|
|
|
{
|
|
|
|
|
size_t bucket = k / 8;
|
|
|
|
|
size_t offset = k % 8;
|
|
|
|
|
bitmap[bucket] |= UInt8(1) << offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ConstColumnPlainPtrs actual_columns;
|
|
|
|
|
ConstColumnPlainPtrs null_maps;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Case where nullable keys are not supported.
|
|
|
|
|
template <typename Key>
|
|
|
|
|
class BaseStateKeysFixed<Key, false>
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
void init(const ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
throw Exception{"Internal error: calling init() for non-nullable"
|
|
|
|
|
" keys is forbidden", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ConstColumnPlainPtrs & getActualColumns() const
|
|
|
|
|
{
|
|
|
|
|
throw Exception{"Internal error: calling getActualColumns() for non-nullable"
|
|
|
|
|
" keys is forbidden", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KeysNullMap<Key> createBitmap(size_t row) const
|
|
|
|
|
{
|
|
|
|
|
throw Exception{"Internal error: calling createBitmap() for non-nullable keys"
|
|
|
|
|
" is forbidden", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2016-10-21 16:50:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 05:53:16 +00:00
|
|
|
|
/// Для случая, когда все ключи фиксированной длины, и они помещаются в N (например, 128) бит.
|
2016-10-18 10:09:48 +00:00
|
|
|
|
template <typename TData, bool has_nullable_keys_ = false>
|
2015-02-22 05:53:16 +00:00
|
|
|
|
struct AggregationMethodKeysFixed
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2016-10-18 10:09:48 +00:00
|
|
|
|
static constexpr bool has_nullable_keys = has_nullable_keys_;
|
2014-10-29 02:35:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
Data data;
|
|
|
|
|
|
2015-02-22 05:53:16 +00:00
|
|
|
|
AggregationMethodKeysFixed() {}
|
2014-12-30 12:58:02 +00:00
|
|
|
|
|
|
|
|
|
template <typename Other>
|
2015-02-22 05:53:16 +00:00
|
|
|
|
AggregationMethodKeysFixed(const Other & other) : data(other.data) {}
|
2014-12-30 12:58:02 +00:00
|
|
|
|
|
2016-10-21 16:50:41 +00:00
|
|
|
|
class State final : private aggregator_impl::BaseStateKeysFixed<Key, has_nullable_keys>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
public:
|
2016-10-21 16:50:41 +00:00
|
|
|
|
using Base = aggregator_impl::BaseStateKeysFixed<Key, has_nullable_keys>;
|
2016-10-18 10:09:48 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
if (has_nullable_keys)
|
|
|
|
|
Base::init(key_columns);
|
2015-01-03 06:49:32 +00:00
|
|
|
|
}
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
2015-02-22 16:09:16 +00:00
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
2015-01-03 06:49:32 +00:00
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
if (has_nullable_keys)
|
|
|
|
|
{
|
|
|
|
|
auto bitmap = Base::createBitmap(i);
|
|
|
|
|
return packFixed<Key>(i, keys_size, Base::getActualColumns(), key_sizes, bitmap);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return packFixed<Key>(i, keys_size, key_columns, key_sizes);
|
2015-01-03 06:49:32 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 05:39:21 +00:00
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool) {}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
static const bool no_consecutive_keys_optimization = false;
|
|
|
|
|
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
static constexpr auto bitmap_size = has_nullable_keys ? std::tuple_size<KeysNullMap<Key>>::value : 0;
|
|
|
|
|
/// In any hash key value, column values to be read start just after the bitmap, if it exists.
|
2016-10-18 12:36:36 +00:00
|
|
|
|
size_t pos = bitmap_size;
|
2016-10-18 10:09:48 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
IColumn * observed_column;
|
|
|
|
|
ColumnUInt8 * null_map;
|
|
|
|
|
|
|
|
|
|
/// If we have a nullable column, get its nested column and its null map.
|
|
|
|
|
if (has_nullable_keys && key_columns[i]->isNullable())
|
|
|
|
|
{
|
|
|
|
|
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*key_columns[i]);
|
|
|
|
|
observed_column = nullable_col.getNestedColumn().get();
|
2016-12-30 05:13:14 +00:00
|
|
|
|
null_map = static_cast<ColumnUInt8 *>(nullable_col.getNullMapColumn().get());
|
2016-10-18 10:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
observed_column = key_columns[i];
|
|
|
|
|
null_map = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_null;
|
|
|
|
|
if (has_nullable_keys && key_columns[i]->isNullable())
|
|
|
|
|
{
|
|
|
|
|
/// The current column is nullable. Check if the value of the
|
|
|
|
|
/// corresponding key is nullable. Update the null map accordingly.
|
|
|
|
|
size_t bucket = i / 8;
|
|
|
|
|
size_t offset = i % 8;
|
2016-10-18 12:36:36 +00:00
|
|
|
|
UInt8 val = (reinterpret_cast<const UInt8 *>(&value.first)[bucket] >> offset) & 1;
|
2016-10-18 10:09:48 +00:00
|
|
|
|
null_map->insert(val);
|
|
|
|
|
is_null = val == 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
is_null = false;
|
|
|
|
|
|
|
|
|
|
if (has_nullable_keys && is_null)
|
|
|
|
|
observed_column->insertDefault();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t size = key_sizes[i];
|
2016-10-18 12:36:36 +00:00
|
|
|
|
observed_column->insertData(reinterpret_cast<const char *>(&value.first) + pos, size);
|
|
|
|
|
pos += size;
|
2016-10-18 10:09:48 +00:00
|
|
|
|
}
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-10-04 06:10:48 +00:00
|
|
|
|
/// Агрегирует по конкатенации ключей. (При этом, строки, содержащие нули посередине, могут склеиться.)
|
2016-10-18 10:09:48 +00:00
|
|
|
|
template <typename TData, bool has_nullable_keys_ = false>
|
2015-02-22 16:09:16 +00:00
|
|
|
|
struct AggregationMethodConcat
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2015-02-22 16:09:16 +00:00
|
|
|
|
|
2016-10-18 10:09:48 +00:00
|
|
|
|
static constexpr bool has_nullable_keys = has_nullable_keys_;
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
Data data;
|
|
|
|
|
|
|
|
|
|
AggregationMethodConcat() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodConcat(const Other & other) : data(other.data) {}
|
|
|
|
|
|
|
|
|
|
struct State
|
|
|
|
|
{
|
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
|
|
|
|
{
|
2016-10-18 10:09:48 +00:00
|
|
|
|
return extractKeysAndPlaceInPoolContiguous<has_nullable_keys>(i, keys_size, key_columns, keys, pool);
|
2015-02-22 16:09:16 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2015-02-22 16:09:16 +00:00
|
|
|
|
|
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool)
|
|
|
|
|
{
|
|
|
|
|
pool.rollback(key.size + keys.size() * sizeof(keys[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
/// Если ключ уже был, то он удаляется из пула (затирается), и сравнить с ним следующий ключ уже нельзя.
|
|
|
|
|
static const bool no_consecutive_keys_optimization = true;
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2016-10-18 10:09:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (has_nullable_keys)
|
|
|
|
|
insertKeyIntoNullableColumnsImpl(value, key_columns, keys_size, key_sizes);
|
|
|
|
|
else
|
|
|
|
|
insertKeyIntoColumnsImpl(value, key_columns, keys_size, key_sizes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/// Insert the values of the specified keys into the corresponding columns.
|
|
|
|
|
/// Implementation for the case where there are no nullable keys.
|
|
|
|
|
static void insertKeyIntoColumnsImpl(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2015-02-22 16:09:16 +00:00
|
|
|
|
{
|
|
|
|
|
/// См. функцию extractKeysAndPlaceInPoolContiguous.
|
|
|
|
|
const StringRef * key_refs = reinterpret_cast<const StringRef *>(value.first.data + value.first.size);
|
|
|
|
|
|
2015-07-18 04:18:14 +00:00
|
|
|
|
if (unlikely(0 == value.first.size))
|
|
|
|
|
{
|
|
|
|
|
/** Исправление, если все ключи - пустые массивы. Для них в хэш-таблицу записывается StringRef нулевой длины, но с ненулевым указателем.
|
2016-10-18 10:09:48 +00:00
|
|
|
|
* Но при вставке в хэш-таблицу, такой StringRef оказывается равен другому ключу нулевой длины,
|
|
|
|
|
* у которого указатель на данные может быть любым мусором и использовать его нельзя.
|
|
|
|
|
*/
|
2015-07-18 04:18:14 +00:00
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
key_columns[i]->insertDefault();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
key_columns[i]->insertDataWithTerminatingZero(key_refs[i].data, key_refs[i].size);
|
|
|
|
|
}
|
2015-02-22 16:09:16 +00:00
|
|
|
|
}
|
2016-10-18 10:09:48 +00:00
|
|
|
|
|
|
|
|
|
/// Insert the value of the specified keys into the corresponding columns.
|
|
|
|
|
/// Implementation for the case where there is at least one nullable key.
|
|
|
|
|
static void insertKeyIntoNullableColumnsImpl(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
|
|
|
|
{
|
|
|
|
|
size_t compact_bitmap_size = keys_size / 8;
|
|
|
|
|
if ((keys_size % 8) != 0) { ++compact_bitmap_size; }
|
|
|
|
|
|
|
|
|
|
if (unlikely(value.first.size < compact_bitmap_size))
|
|
|
|
|
{
|
|
|
|
|
/// This code path is logically impossible.
|
|
|
|
|
/// Only a bug in the code base can trigger it.
|
|
|
|
|
throw Exception{"Aggregator: corrupted hash table key", ErrorCodes::LOGICAL_ERROR};
|
|
|
|
|
}
|
|
|
|
|
else if (unlikely(value.first.size == compact_bitmap_size))
|
|
|
|
|
{
|
|
|
|
|
/// This case occurs when each of the keys falls into either of the following two
|
|
|
|
|
/// categories: (i) it has a null value; (ii) it represents an empty array.
|
|
|
|
|
/// The remarks are the same as for the implementation of the non-nullable case above.
|
|
|
|
|
const UInt8 * compact_bitmap = reinterpret_cast<const UInt8 *>(value.first.data);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
{
|
|
|
|
|
IColumn * observed_column;
|
|
|
|
|
|
|
|
|
|
if (key_columns[i]->isNullable())
|
|
|
|
|
{
|
|
|
|
|
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*key_columns[i]);
|
|
|
|
|
observed_column = nullable_col.getNestedColumn().get();
|
2017-01-02 23:08:09 +00:00
|
|
|
|
ColumnUInt8 & null_map = nullable_col.getNullMapConcreteColumn();
|
2016-10-18 10:09:48 +00:00
|
|
|
|
|
|
|
|
|
size_t bucket = i / 8;
|
|
|
|
|
size_t offset = i % 8;
|
|
|
|
|
UInt8 is_null = (compact_bitmap[bucket] >> offset) & 1;
|
|
|
|
|
null_map.insert(is_null);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
observed_column = key_columns[i];
|
|
|
|
|
|
|
|
|
|
observed_column->insertDefault();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const UInt8 * compact_bitmap = reinterpret_cast<const UInt8 *>(value.first.data);
|
|
|
|
|
const StringRef * key_refs = reinterpret_cast<const StringRef *>(value.first.data + value.first.size);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
{
|
|
|
|
|
IColumn * observed_column;
|
|
|
|
|
ColumnUInt8 * null_map;
|
|
|
|
|
|
|
|
|
|
/// If we have a nullable column, get its nested column and its null map.
|
|
|
|
|
if (key_columns[i]->isNullable())
|
|
|
|
|
{
|
|
|
|
|
ColumnNullable & nullable_col = static_cast<ColumnNullable &>(*key_columns[i]);
|
|
|
|
|
observed_column = nullable_col.getNestedColumn().get();
|
2017-01-02 23:08:09 +00:00
|
|
|
|
null_map = &nullable_col.getNullMapConcreteColumn();
|
2016-10-18 10:09:48 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
observed_column = key_columns[i];
|
|
|
|
|
null_map = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_null;
|
|
|
|
|
if (key_columns[i]->isNullable())
|
|
|
|
|
{
|
|
|
|
|
/// The current column is nullable. Check if the value of the
|
|
|
|
|
/// corresponding key is nullable. Update the null map accordingly.
|
|
|
|
|
size_t bucket = i / 8;
|
|
|
|
|
size_t offset = i % 8;
|
|
|
|
|
UInt8 val = (compact_bitmap[bucket] >> offset) & 1;
|
|
|
|
|
null_map->insert(val);
|
|
|
|
|
is_null = val == 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
is_null = false;
|
|
|
|
|
|
|
|
|
|
if (is_null)
|
|
|
|
|
observed_column->insertDefault();
|
|
|
|
|
else
|
|
|
|
|
observed_column->insertDataWithTerminatingZero(key_refs[i].data, key_refs[i].size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-22 16:09:16 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-10-04 06:10:48 +00:00
|
|
|
|
/** Агрегирует по конкатенации сериализованных значений ключей.
|
|
|
|
|
* Похож на AggregationMethodConcat, но подходит, например, для массивов строк или нескольких массивов.
|
|
|
|
|
* Сериализованное значение отличается тем, что позволяет однозначно его десериализовать, имея только позицию, с которой оно начинается.
|
|
|
|
|
* То есть, например, для строк, оно содержит сначала сериализованную длину строки, а потом байты.
|
|
|
|
|
* Поэтому, при агрегации по нескольким строкам, неоднозначностей не возникает.
|
|
|
|
|
*/
|
|
|
|
|
template <typename TData>
|
|
|
|
|
struct AggregationMethodSerialized
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2015-10-04 06:10:48 +00:00
|
|
|
|
|
|
|
|
|
Data data;
|
|
|
|
|
|
|
|
|
|
AggregationMethodSerialized() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodSerialized(const Other & other) : data(other.data) {}
|
|
|
|
|
|
|
|
|
|
struct State
|
|
|
|
|
{
|
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
|
|
|
|
{
|
|
|
|
|
return serializeKeysToPoolContiguous(i, keys_size, key_columns, keys, pool);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value; }
|
2015-10-04 06:10:48 +00:00
|
|
|
|
|
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool)
|
|
|
|
|
{
|
|
|
|
|
pool.rollback(key.size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Если ключ уже был, то он удаляется из пула (затирается), и сравнить с ним следующий ключ уже нельзя.
|
|
|
|
|
static const bool no_consecutive_keys_optimization = true;
|
|
|
|
|
|
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
|
|
|
|
{
|
|
|
|
|
auto pos = value.first.data;
|
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
|
|
|
|
pos = key_columns[i]->deserializeAndInsertFromArena(pos);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
/// Для остальных случаев. Агрегирует по 128 битному хэшу от ключа. (При этом, строки, содержащие нули посередине, могут склеиться.)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
template <typename TData>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
struct AggregationMethodHashed
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using Data = TData;
|
|
|
|
|
using Key = typename Data::key_type;
|
|
|
|
|
using Mapped = typename Data::mapped_type;
|
|
|
|
|
using iterator = typename Data::iterator;
|
|
|
|
|
using const_iterator = typename Data::const_iterator;
|
2014-10-29 02:35:16 +00:00
|
|
|
|
|
2014-05-10 00:31:22 +00:00
|
|
|
|
Data data;
|
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
AggregationMethodHashed() {}
|
|
|
|
|
|
|
|
|
|
template <typename Other>
|
|
|
|
|
AggregationMethodHashed(const Other & other) : data(other.data) {}
|
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
struct State
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 06:49:32 +00:00
|
|
|
|
void init(ConstColumnPlainPtrs & key_columns)
|
|
|
|
|
{
|
|
|
|
|
}
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 06:49:32 +00:00
|
|
|
|
Key getKey(
|
|
|
|
|
const ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
size_t keys_size,
|
|
|
|
|
size_t i,
|
|
|
|
|
const Sizes & key_sizes,
|
2015-02-22 16:09:16 +00:00
|
|
|
|
StringRefs & keys,
|
|
|
|
|
Arena & pool) const
|
2015-01-03 06:49:32 +00:00
|
|
|
|
{
|
|
|
|
|
return hash128(i, keys_size, key_columns, keys);
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2016-09-19 13:31:42 +00:00
|
|
|
|
static AggregateDataPtr & getAggregateData(Mapped & value) { return value.second; }
|
|
|
|
|
static const AggregateDataPtr & getAggregateData(const Mapped & value) { return value.second; }
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
2015-01-03 05:39:21 +00:00
|
|
|
|
static void onNewKey(typename Data::value_type & value, size_t keys_size, size_t i, StringRefs & keys, Arena & pool)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
2015-01-03 05:39:21 +00:00
|
|
|
|
value.second.first = placeKeysInPool(i, keys_size, keys, pool);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 16:09:16 +00:00
|
|
|
|
static void onExistingKey(const Key & key, StringRefs & keys, Arena & pool) {}
|
|
|
|
|
|
2015-02-22 18:02:54 +00:00
|
|
|
|
static const bool no_consecutive_keys_optimization = false;
|
|
|
|
|
|
2015-01-02 00:35:33 +00:00
|
|
|
|
static void insertKeyIntoColumns(const typename Data::value_type & value, ColumnPlainPtrs & key_columns, size_t keys_size, const Sizes & key_sizes)
|
2014-05-10 00:31:22 +00:00
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < keys_size; ++i)
|
2015-01-02 00:35:33 +00:00
|
|
|
|
key_columns[i]->insertDataWithTerminatingZero(value.second.first[i].data, value.second.first[i].size);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Aggregator;
|
2011-09-26 07:25:22 +00:00
|
|
|
|
|
2013-12-16 02:32:00 +00:00
|
|
|
|
struct AggregatedDataVariants : private boost::noncopyable
|
2011-09-26 07:25:22 +00:00
|
|
|
|
{
|
2013-02-16 18:59:05 +00:00
|
|
|
|
/** Работа с состояниями агрегатных функций в пуле устроена следующим (неудобным) образом:
|
|
|
|
|
* - при агрегации, состояния создаются в пуле с помощью функции IAggregateFunction::create (внутри - placement new произвольной структуры);
|
|
|
|
|
* - они должны быть затем уничтожены с помощью IAggregateFunction::destroy (внутри - вызов деструктора произвольной структуры);
|
2015-01-02 03:16:28 +00:00
|
|
|
|
* - если агрегация завершена, то, в функции Aggregator::convertToBlocks, указатели на состояния агрегатных функций
|
2013-02-16 18:59:05 +00:00
|
|
|
|
* записываются в ColumnAggregateFunction; ColumnAggregateFunction "захватывает владение" ими, то есть - вызывает destroy в своём деструкторе.
|
2015-01-02 03:16:28 +00:00
|
|
|
|
* - если при агрегации, до вызова Aggregator::convertToBlocks вылетело исключение,
|
|
|
|
|
* то состояния агрегатных функций всё-равно должны быть уничтожены,
|
2013-02-16 18:59:05 +00:00
|
|
|
|
* иначе для сложных состояний (наприемер, AggregateFunctionUniq), будут утечки памяти;
|
|
|
|
|
* - чтобы, в этом случае, уничтожить состояния, в деструкторе вызывается метод Aggregator::destroyAggregateStates,
|
2014-04-08 07:58:53 +00:00
|
|
|
|
* но только если переменная aggregator (см. ниже) не nullptr;
|
2013-02-16 18:59:05 +00:00
|
|
|
|
* - то есть, пока вы не передали владение состояниями агрегатных функций в ColumnAggregateFunction, установите переменную aggregator,
|
|
|
|
|
* чтобы при возникновении исключения, состояния были корректно уничтожены.
|
|
|
|
|
*
|
|
|
|
|
* PS. Это можно исправить, сделав пул, который знает о том, какие состояния агрегатных функций и в каком порядке в него уложены, и умеет сам их уничтожать.
|
|
|
|
|
* Но это вряд ли можно просто сделать, так как в этот же пул планируется класть строки переменной длины.
|
|
|
|
|
* В этом случае, пул не сможет знать, по каким смещениям хранятся объекты.
|
|
|
|
|
*/
|
2014-04-08 07:31:51 +00:00
|
|
|
|
Aggregator * aggregator = nullptr;
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
size_t keys_size; /// Количество ключей NOTE нужно ли это поле?
|
|
|
|
|
Sizes key_sizes; /// Размеры ключей, если ключи фиксированной длины
|
2014-08-24 07:17:50 +00:00
|
|
|
|
|
2013-02-09 00:12:04 +00:00
|
|
|
|
/// Пулы для состояний агрегатных функций. Владение потом будет передано в ColumnAggregateFunction.
|
|
|
|
|
Arenas aggregates_pools;
|
2013-02-16 18:59:05 +00:00
|
|
|
|
Arena * aggregates_pool; /// Пул, который сейчас используется для аллокации.
|
2011-09-26 15:45:31 +00:00
|
|
|
|
|
2014-02-26 11:44:54 +00:00
|
|
|
|
/** Специализация для случая, когда ключи отсутствуют, и для ключей, не попавших в max_rows_to_group_by.
|
2013-05-04 15:46:50 +00:00
|
|
|
|
*/
|
2014-04-08 07:31:51 +00:00
|
|
|
|
AggregatedDataWithoutKey without_key = nullptr;
|
2011-09-26 15:45:31 +00:00
|
|
|
|
|
2014-12-30 10:16:23 +00:00
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt8, AggregatedDataWithUInt8Key>> key8;
|
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt16, AggregatedDataWithUInt16Key>> key16;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt32, AggregatedDataWithUInt64Key>> key32;
|
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt64, AggregatedDataWithUInt64Key>> key64;
|
2016-09-19 13:31:42 +00:00
|
|
|
|
std::unique_ptr<AggregationMethodString<AggregatedDataWithStringKey>> key_string;
|
|
|
|
|
std::unique_ptr<AggregationMethodFixedString<AggregatedDataWithStringKey>> key_fixed_string;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys128>> keys128;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys256>> keys256;
|
|
|
|
|
std::unique_ptr<AggregationMethodHashed<AggregatedDataHashed>> hashed;
|
|
|
|
|
std::unique_ptr<AggregationMethodConcat<AggregatedDataWithStringKey>> concat;
|
|
|
|
|
std::unique_ptr<AggregationMethodSerialized<AggregatedDataWithStringKey>> serialized;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt32, AggregatedDataWithUInt64KeyTwoLevel>> key32_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt64, AggregatedDataWithUInt64KeyTwoLevel>> key64_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodString<AggregatedDataWithStringKeyTwoLevel>> key_string_two_level;
|
2016-09-19 13:31:42 +00:00
|
|
|
|
std::unique_ptr<AggregationMethodFixedString<AggregatedDataWithStringKeyTwoLevel>> key_fixed_string_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys128TwoLevel>> keys128_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys256TwoLevel>> keys256_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodHashed<AggregatedDataHashedTwoLevel>> hashed_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodConcat<AggregatedDataWithStringKeyTwoLevel>> concat_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodSerialized<AggregatedDataWithStringKeyTwoLevel>> serialized_two_level;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
2016-09-23 05:49:55 +00:00
|
|
|
|
std::unique_ptr<AggregationMethodOneNumber<UInt64, AggregatedDataWithUInt64KeyHash64>> key64_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodString<AggregatedDataWithStringKeyHash64>> key_string_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodFixedString<AggregatedDataWithStringKeyHash64>> key_fixed_string_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys128Hash64>> keys128_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys256Hash64>> keys256_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodConcat<AggregatedDataWithStringKeyHash64>> concat_hash64;
|
|
|
|
|
std::unique_ptr<AggregationMethodSerialized<AggregatedDataWithStringKeyHash64>> serialized_hash64;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
2016-10-18 10:09:48 +00:00
|
|
|
|
/// Support for nullable keys.
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys128, true>> nullable_keys128;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys256, true>> nullable_keys256;
|
|
|
|
|
std::unique_ptr<AggregationMethodConcat<AggregatedDataWithStringKey, true>> nullable_concat;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys128TwoLevel, true>> nullable_keys128_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodKeysFixed<AggregatedDataWithKeys256TwoLevel, true>> nullable_keys256_two_level;
|
|
|
|
|
std::unique_ptr<AggregationMethodConcat<AggregatedDataWithStringKeyTwoLevel, true>> nullable_concat_two_level;
|
|
|
|
|
|
2015-01-13 01:57:22 +00:00
|
|
|
|
/// В этом и подобных макросах, вариант without_key не учитывается.
|
2015-01-02 03:16:28 +00:00
|
|
|
|
#define APPLY_FOR_AGGREGATED_VARIANTS(M) \
|
2014-12-30 10:16:23 +00:00
|
|
|
|
M(key8, false) \
|
|
|
|
|
M(key16, false) \
|
|
|
|
|
M(key32, false) \
|
|
|
|
|
M(key64, false) \
|
|
|
|
|
M(key_string, false) \
|
|
|
|
|
M(key_fixed_string, false) \
|
|
|
|
|
M(keys128, false) \
|
2015-02-22 05:53:16 +00:00
|
|
|
|
M(keys256, false) \
|
2014-12-30 10:16:23 +00:00
|
|
|
|
M(hashed, false) \
|
2015-02-22 16:09:16 +00:00
|
|
|
|
M(concat, false) \
|
2015-10-04 06:10:48 +00:00
|
|
|
|
M(serialized, false) \
|
2014-12-30 10:16:23 +00:00
|
|
|
|
M(key32_two_level, true) \
|
|
|
|
|
M(key64_two_level, true) \
|
|
|
|
|
M(key_string_two_level, true) \
|
|
|
|
|
M(key_fixed_string_two_level, true) \
|
|
|
|
|
M(keys128_two_level, true) \
|
2015-02-22 05:53:16 +00:00
|
|
|
|
M(keys256_two_level, true) \
|
2015-02-22 16:09:16 +00:00
|
|
|
|
M(hashed_two_level, true) \
|
2015-10-04 06:10:48 +00:00
|
|
|
|
M(concat_two_level, true) \
|
|
|
|
|
M(serialized_two_level, true) \
|
2016-09-23 05:49:55 +00:00
|
|
|
|
M(key64_hash64, false) \
|
|
|
|
|
M(key_string_hash64, false) \
|
|
|
|
|
M(key_fixed_string_hash64, false) \
|
|
|
|
|
M(keys128_hash64, false) \
|
|
|
|
|
M(keys256_hash64, false) \
|
|
|
|
|
M(concat_hash64, false) \
|
|
|
|
|
M(serialized_hash64, false) \
|
2016-10-18 10:09:48 +00:00
|
|
|
|
M(nullable_keys128, false) \
|
|
|
|
|
M(nullable_keys256, false) \
|
|
|
|
|
M(nullable_concat, false) \
|
|
|
|
|
M(nullable_keys128_two_level, true) \
|
|
|
|
|
M(nullable_keys256_two_level, true) \
|
|
|
|
|
M(nullable_concat_two_level, true)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
|
|
|
|
enum class Type
|
2012-02-27 06:28:20 +00:00
|
|
|
|
{
|
2014-10-29 01:18:50 +00:00
|
|
|
|
EMPTY = 0,
|
2014-12-30 10:16:23 +00:00
|
|
|
|
without_key,
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) NAME,
|
2015-01-02 03:16:28 +00:00
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
#undef M
|
2012-02-27 06:28:20 +00:00
|
|
|
|
};
|
2014-12-30 10:16:23 +00:00
|
|
|
|
Type type = Type::EMPTY;
|
2012-05-10 07:47:13 +00:00
|
|
|
|
|
2016-05-28 10:15:36 +00:00
|
|
|
|
AggregatedDataVariants() : aggregates_pools(1, std::make_shared<Arena>()), aggregates_pool(aggregates_pools.back().get()) {}
|
2014-12-30 10:16:23 +00:00
|
|
|
|
bool empty() const { return type == Type::EMPTY; }
|
2015-04-16 14:27:56 +00:00
|
|
|
|
void invalidate() { type = Type::EMPTY; }
|
2012-12-25 19:28:59 +00:00
|
|
|
|
|
2013-02-16 18:59:05 +00:00
|
|
|
|
~AggregatedDataVariants();
|
2013-02-09 02:20:26 +00:00
|
|
|
|
|
2013-12-16 02:32:00 +00:00
|
|
|
|
void init(Type type_)
|
|
|
|
|
{
|
2015-03-15 11:30:26 +00:00
|
|
|
|
switch (type_)
|
2013-12-16 02:32:00 +00:00
|
|
|
|
{
|
2014-12-30 10:16:23 +00:00
|
|
|
|
case Type::EMPTY: break;
|
|
|
|
|
case Type::without_key: break;
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
2016-09-23 20:33:06 +00:00
|
|
|
|
case Type::NAME: NAME = std::make_unique<decltype(NAME)::element_type>(); break;
|
2015-01-02 03:16:28 +00:00
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
#undef M
|
2013-12-16 02:32:00 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown aggregated data variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
|
|
|
|
}
|
2015-03-15 11:30:26 +00:00
|
|
|
|
|
|
|
|
|
type = type_;
|
2013-12-16 02:32:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-30 19:57:46 +00:00
|
|
|
|
/// Количество строк (разных ключей).
|
2012-12-25 19:28:59 +00:00
|
|
|
|
size_t size() const
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2014-12-30 10:16:23 +00:00
|
|
|
|
case Type::EMPTY: return 0;
|
|
|
|
|
case Type::without_key: return 1;
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
|
|
|
|
case Type::NAME: return NAME->data.size() + (without_key != nullptr);
|
2015-01-02 03:16:28 +00:00
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
#undef M
|
2012-12-25 19:28:59 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown aggregated data variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-09 01:02:52 +00:00
|
|
|
|
|
2015-01-15 19:29:37 +00:00
|
|
|
|
/// Размер без учёта строчки, в которую записываются данные для расчёта TOTALS.
|
|
|
|
|
size_t sizeWithoutOverflowRow() const
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case Type::EMPTY: return 0;
|
|
|
|
|
case Type::without_key: return 1;
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
|
|
|
|
case Type::NAME: return NAME->data.size();
|
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
|
|
|
|
#undef M
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown aggregated data variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-09 01:02:52 +00:00
|
|
|
|
const char * getMethodName() const
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2014-12-30 10:16:23 +00:00
|
|
|
|
case Type::EMPTY: return "EMPTY";
|
2014-12-30 11:27:58 +00:00
|
|
|
|
case Type::without_key: return "without_key";
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
|
|
|
|
case Type::NAME: return #NAME;
|
2015-01-02 03:16:28 +00:00
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
#undef M
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown aggregated data variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isTwoLevel() const
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case Type::EMPTY: return false;
|
|
|
|
|
case Type::without_key: return false;
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
|
|
|
|
case Type::NAME: return IS_TWO_LEVEL;
|
2015-01-02 03:16:28 +00:00
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
2014-12-30 10:16:23 +00:00
|
|
|
|
#undef M
|
2013-02-09 01:02:52 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Unknown aggregated data variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-30 12:58:02 +00:00
|
|
|
|
|
2015-01-13 01:57:22 +00:00
|
|
|
|
#define APPLY_FOR_VARIANTS_CONVERTIBLE_TO_TWO_LEVEL(M) \
|
|
|
|
|
M(key32) \
|
|
|
|
|
M(key64) \
|
|
|
|
|
M(key_string) \
|
|
|
|
|
M(key_fixed_string) \
|
|
|
|
|
M(keys128) \
|
2015-02-22 05:53:16 +00:00
|
|
|
|
M(keys256) \
|
2015-02-22 16:09:16 +00:00
|
|
|
|
M(hashed) \
|
2015-10-04 06:10:48 +00:00
|
|
|
|
M(concat) \
|
|
|
|
|
M(serialized) \
|
2016-10-18 10:09:48 +00:00
|
|
|
|
M(nullable_keys128) \
|
|
|
|
|
M(nullable_keys256) \
|
|
|
|
|
M(nullable_concat) \
|
2015-01-13 01:57:22 +00:00
|
|
|
|
|
|
|
|
|
#define APPLY_FOR_VARIANTS_NOT_CONVERTIBLE_TO_TWO_LEVEL(M) \
|
|
|
|
|
M(key8) \
|
|
|
|
|
M(key16) \
|
2016-09-23 05:49:55 +00:00
|
|
|
|
M(key64_hash64) \
|
|
|
|
|
M(key_string_hash64) \
|
|
|
|
|
M(key_fixed_string_hash64) \
|
|
|
|
|
M(keys128_hash64) \
|
|
|
|
|
M(keys256_hash64) \
|
|
|
|
|
M(concat_hash64) \
|
|
|
|
|
M(serialized_hash64) \
|
2015-01-13 01:57:22 +00:00
|
|
|
|
|
2015-12-06 07:32:47 +00:00
|
|
|
|
#define APPLY_FOR_VARIANTS_SINGLE_LEVEL(M) \
|
|
|
|
|
APPLY_FOR_VARIANTS_NOT_CONVERTIBLE_TO_TWO_LEVEL(M) \
|
|
|
|
|
APPLY_FOR_VARIANTS_CONVERTIBLE_TO_TWO_LEVEL(M) \
|
|
|
|
|
|
2014-12-30 12:58:02 +00:00
|
|
|
|
bool isConvertibleToTwoLevel() const
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
#define M(NAME) \
|
|
|
|
|
case Type::NAME: return true;
|
|
|
|
|
|
|
|
|
|
APPLY_FOR_VARIANTS_CONVERTIBLE_TO_TWO_LEVEL(M)
|
|
|
|
|
|
|
|
|
|
#undef M
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void convertToTwoLevel();
|
2015-01-02 03:16:28 +00:00
|
|
|
|
|
|
|
|
|
#define APPLY_FOR_VARIANTS_TWO_LEVEL(M) \
|
2016-09-23 05:49:55 +00:00
|
|
|
|
M(key32_two_level) \
|
|
|
|
|
M(key64_two_level) \
|
|
|
|
|
M(key_string_two_level) \
|
|
|
|
|
M(key_fixed_string_two_level) \
|
|
|
|
|
M(keys128_two_level) \
|
|
|
|
|
M(keys256_two_level) \
|
|
|
|
|
M(hashed_two_level) \
|
|
|
|
|
M(concat_two_level) \
|
2016-10-19 15:00:56 +00:00
|
|
|
|
M(serialized_two_level) \
|
|
|
|
|
M(nullable_keys128_two_level) \
|
|
|
|
|
M(nullable_keys256_two_level) \
|
|
|
|
|
M(nullable_concat_two_level)
|
2011-09-26 07:25:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-05-28 14:14:18 +00:00
|
|
|
|
using AggregatedDataVariantsPtr = std::shared_ptr<AggregatedDataVariants>;
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ManyAggregatedDataVariants = std::vector<AggregatedDataVariantsPtr>;
|
2012-02-27 06:28:20 +00:00
|
|
|
|
|
2015-11-09 18:45:55 +00:00
|
|
|
|
/** Как считаются "тотальные" значения при наличии WITH TOTALS?
|
|
|
|
|
* (Более подробно смотрите в TotalsHavingBlockInputStream.)
|
|
|
|
|
*
|
|
|
|
|
* В случае отсутствия group_by_overflow_mode = 'any', данные агрегируются как обычно, но состояния агрегатных функций не финализируются.
|
|
|
|
|
* Позже, состояния агрегатных функций для всех строк (прошедших через HAVING) мерджатся в одну - это и будет TOTALS.
|
|
|
|
|
*
|
|
|
|
|
* В случае наличия group_by_overflow_mode = 'any', данные агрегируются как обычно, кроме ключей, не поместившихся в max_rows_to_group_by.
|
|
|
|
|
* Для этих ключей, данные агрегируются в одну дополнительную строку - далее см. под названиями overflow_row, overflows...
|
|
|
|
|
* Позже, состояния агрегатных функций для всех строк (прошедших через HAVING) мерджатся в одну,
|
|
|
|
|
* а также к ним прибавляется или не прибавляется (в зависимости от настройки totals_mode) также overflow_row - это и будет TOTALS.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-09-19 01:42:16 +00:00
|
|
|
|
|
2012-03-05 07:58:34 +00:00
|
|
|
|
/** Агрегирует источник блоков.
|
2011-09-19 01:42:16 +00:00
|
|
|
|
*/
|
2011-09-19 03:34:23 +00:00
|
|
|
|
class Aggregator
|
2011-09-19 01:42:16 +00:00
|
|
|
|
{
|
|
|
|
|
public:
|
2015-11-30 16:57:05 +00:00
|
|
|
|
struct Params
|
|
|
|
|
{
|
|
|
|
|
/// Что считать.
|
|
|
|
|
Names key_names;
|
|
|
|
|
ColumnNumbers keys; /// Номера столбцов - вычисляются позже.
|
|
|
|
|
AggregateDescriptions aggregates;
|
|
|
|
|
size_t keys_size;
|
|
|
|
|
size_t aggregates_size;
|
|
|
|
|
|
|
|
|
|
/// Настройки приближённого вычисления GROUP BY.
|
2015-11-30 19:57:46 +00:00
|
|
|
|
const bool overflow_row; /// Нужно ли класть в AggregatedDataVariants::without_key агрегаты для ключей, не попавших в max_rows_to_group_by.
|
|
|
|
|
const size_t max_rows_to_group_by;
|
|
|
|
|
const OverflowMode group_by_overflow_mode;
|
2015-11-30 16:57:05 +00:00
|
|
|
|
|
|
|
|
|
/// Для динамической компиляции.
|
|
|
|
|
Compiler * compiler;
|
2015-11-30 19:57:46 +00:00
|
|
|
|
const UInt32 min_count_to_compile;
|
2015-11-30 16:57:05 +00:00
|
|
|
|
|
|
|
|
|
/// Настройки двухуровневой агрегации (используется для большого количества ключей).
|
2015-11-30 19:57:46 +00:00
|
|
|
|
/** При каком количестве ключей или размере состояния агрегации в байтах,
|
|
|
|
|
* начинает использоваться двухуровневая агрегация. Достаточно срабатывания хотя бы одного из порогов.
|
|
|
|
|
* 0 - соответствующий порог не задан.
|
2015-11-30 16:57:05 +00:00
|
|
|
|
*/
|
2015-11-30 19:57:46 +00:00
|
|
|
|
const size_t group_by_two_level_threshold;
|
|
|
|
|
const size_t group_by_two_level_threshold_bytes;
|
|
|
|
|
|
|
|
|
|
/// Настройки для сброса временных данных в файловую систему (внешняя агрегация).
|
|
|
|
|
const size_t max_bytes_before_external_group_by; /// 0 - не использовать внешнюю агрегацию.
|
|
|
|
|
const std::string tmp_path;
|
|
|
|
|
|
|
|
|
|
Params(
|
|
|
|
|
const Names & key_names_, const AggregateDescriptions & aggregates_,
|
|
|
|
|
bool overflow_row_, size_t max_rows_to_group_by_, OverflowMode group_by_overflow_mode_,
|
|
|
|
|
Compiler * compiler_, UInt32 min_count_to_compile_,
|
|
|
|
|
size_t group_by_two_level_threshold_, size_t group_by_two_level_threshold_bytes_,
|
|
|
|
|
size_t max_bytes_before_external_group_by_, const std::string & tmp_path_)
|
2015-11-30 16:57:05 +00:00
|
|
|
|
: key_names(key_names_), aggregates(aggregates_), aggregates_size(aggregates.size()),
|
2015-11-30 19:57:46 +00:00
|
|
|
|
overflow_row(overflow_row_), max_rows_to_group_by(max_rows_to_group_by_), group_by_overflow_mode(group_by_overflow_mode_),
|
|
|
|
|
compiler(compiler_), min_count_to_compile(min_count_to_compile_),
|
|
|
|
|
group_by_two_level_threshold(group_by_two_level_threshold_), group_by_two_level_threshold_bytes(group_by_two_level_threshold_bytes_),
|
|
|
|
|
max_bytes_before_external_group_by(max_bytes_before_external_group_by_), tmp_path(tmp_path_)
|
2015-11-30 16:57:05 +00:00
|
|
|
|
{
|
|
|
|
|
std::sort(key_names.begin(), key_names.end());
|
|
|
|
|
key_names.erase(std::unique(key_names.begin(), key_names.end()), key_names.end());
|
|
|
|
|
keys_size = key_names.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Только параметры, имеющие значение при мердже.
|
|
|
|
|
Params(const Names & key_names_, const AggregateDescriptions & aggregates_, bool overflow_row_)
|
2015-11-30 19:57:46 +00:00
|
|
|
|
: Params(key_names_, aggregates_, overflow_row_, 0, OverflowMode::THROW, nullptr, 0, 0, 0, 0, "") {}
|
2015-11-30 16:57:05 +00:00
|
|
|
|
|
|
|
|
|
/// Вычислить номера столбцов в keys и aggregates.
|
|
|
|
|
void calculateColumnNumbers(const Block & block);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Aggregator(const Params & params_)
|
|
|
|
|
: params(params_),
|
2015-04-16 14:27:56 +00:00
|
|
|
|
isCancelled([]() { return false; })
|
2012-09-12 18:49:21 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
2011-09-19 01:42:16 +00:00
|
|
|
|
|
2012-03-05 07:58:34 +00:00
|
|
|
|
/// Агрегировать источник. Получить результат в виде одной из структур данных.
|
2011-09-26 07:25:22 +00:00
|
|
|
|
void execute(BlockInputStreamPtr stream, AggregatedDataVariants & result);
|
2011-09-19 01:42:16 +00:00
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
using AggregateColumns = std::vector<ConstColumnPlainPtrs>;
|
|
|
|
|
using AggregateColumnsData = std::vector<ColumnAggregateFunction::Container_t *>;
|
|
|
|
|
using AggregateFunctionsPlainPtrs = std::vector<IAggregateFunction *>;
|
2014-05-10 05:16:23 +00:00
|
|
|
|
|
|
|
|
|
/// Обработать один блок. Вернуть false, если обработку следует прервать (при group_by_overflow_mode = 'break').
|
|
|
|
|
bool executeOnBlock(Block & block, AggregatedDataVariants & result,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns, AggregateColumns & aggregate_columns, /// Передаются, чтобы не создавать их заново на каждый блок
|
|
|
|
|
Sizes & key_sizes, StringRefs & keys, /// - передайте соответствующие объекты, которые изначально пустые.
|
|
|
|
|
bool & no_more_keys);
|
|
|
|
|
|
2013-09-01 04:55:41 +00:00
|
|
|
|
/** Преобразовать структуру данных агрегации в блок.
|
2015-01-02 03:50:14 +00:00
|
|
|
|
* Если overflow_row = true, то агрегаты для строк, не попавших в max_rows_to_group_by, кладутся в первый блок.
|
2013-11-03 23:35:18 +00:00
|
|
|
|
*
|
|
|
|
|
* Если final = false, то в качестве столбцов-агрегатов создаются ColumnAggregateFunction с состоянием вычислений,
|
|
|
|
|
* которые могут быть затем объединены с другими состояниями (для распределённой обработки запроса).
|
|
|
|
|
* Если final = true, то в качестве столбцов-агрегатов создаются столбцы с готовыми значениями.
|
2013-09-01 04:55:41 +00:00
|
|
|
|
*/
|
2015-12-08 02:01:46 +00:00
|
|
|
|
BlocksList convertToBlocks(AggregatedDataVariants & data_variants, bool final, size_t max_threads) const;
|
2012-02-27 06:28:20 +00:00
|
|
|
|
|
2015-12-06 16:22:01 +00:00
|
|
|
|
/** Объединить несколько структур данных агрегации и выдать результат в виде потока блоков.
|
|
|
|
|
*/
|
2015-12-08 02:01:46 +00:00
|
|
|
|
std::unique_ptr<IBlockInputStream> mergeAndConvertToBlocks(ManyAggregatedDataVariants & data_variants, bool final, size_t max_threads) const;
|
2015-12-06 16:22:01 +00:00
|
|
|
|
|
2015-07-30 23:41:02 +00:00
|
|
|
|
/** Объединить поток частично агрегированных блоков в одну структуру данных.
|
2013-09-01 04:55:41 +00:00
|
|
|
|
* (Доагрегировать несколько блоков, которые представляют собой результат независимых агрегаций с удалённых серверов.)
|
2012-05-30 01:38:02 +00:00
|
|
|
|
*/
|
2015-01-03 05:39:21 +00:00
|
|
|
|
void mergeStream(BlockInputStreamPtr stream, AggregatedDataVariants & result, size_t max_threads);
|
2012-05-30 01:38:02 +00:00
|
|
|
|
|
2015-07-30 23:41:02 +00:00
|
|
|
|
/** Объединить несколько частично агрегированных блоков в один.
|
|
|
|
|
*/
|
|
|
|
|
Block mergeBlocks(BlocksList & blocks, bool final);
|
|
|
|
|
|
2015-09-07 07:40:14 +00:00
|
|
|
|
/** Преобразовать (разрезать) блок частично-агрегированных данных на много блоков, как если бы использовался двухуровневый метод агрегации.
|
|
|
|
|
* Это нужно, чтобы потом было проще объединить результат с другими результатами, уже являющимися двухуровневыми.
|
|
|
|
|
*/
|
|
|
|
|
std::vector<Block> convertBlockToTwoLevel(const Block & block);
|
|
|
|
|
|
2015-04-16 14:27:56 +00:00
|
|
|
|
using CancellationHook = std::function<bool()>;
|
|
|
|
|
|
|
|
|
|
/** Установить функцию, которая проверяет, можно ли прервать текущую задачу.
|
|
|
|
|
*/
|
|
|
|
|
void setCancellationHook(const CancellationHook cancellation_hook);
|
|
|
|
|
|
2013-05-03 10:20:53 +00:00
|
|
|
|
/// Для IBlockInputStream.
|
|
|
|
|
String getID() const;
|
|
|
|
|
|
2015-12-01 16:58:15 +00:00
|
|
|
|
/// Для внешней агрегации.
|
2015-12-01 14:09:05 +00:00
|
|
|
|
void writeToTemporaryFile(AggregatedDataVariants & data_variants, size_t rows);
|
|
|
|
|
|
2015-12-01 21:20:14 +00:00
|
|
|
|
bool hasTemporaryFiles() const { return !temporary_files.empty(); }
|
2015-12-01 14:09:05 +00:00
|
|
|
|
|
2015-12-01 16:58:15 +00:00
|
|
|
|
struct TemporaryFiles
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::unique_ptr<Poco::TemporaryFile>> files;
|
|
|
|
|
size_t sum_size_uncompressed = 0;
|
|
|
|
|
size_t sum_size_compressed = 0;
|
2015-12-01 21:20:14 +00:00
|
|
|
|
mutable std::mutex mutex;
|
|
|
|
|
|
|
|
|
|
bool empty() const
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
|
return files.empty();
|
|
|
|
|
}
|
2015-12-01 16:58:15 +00:00
|
|
|
|
};
|
2015-12-01 14:09:05 +00:00
|
|
|
|
|
|
|
|
|
const TemporaryFiles & getTemporaryFiles() const { return temporary_files; }
|
|
|
|
|
|
2013-09-15 07:17:26 +00:00
|
|
|
|
protected:
|
2013-02-16 18:59:05 +00:00
|
|
|
|
friend struct AggregatedDataVariants;
|
2015-12-06 16:22:01 +00:00
|
|
|
|
friend class MergingAndConvertingBlockInputStream;
|
2014-08-24 07:17:50 +00:00
|
|
|
|
|
2015-11-30 16:57:05 +00:00
|
|
|
|
Params params;
|
|
|
|
|
|
2015-01-10 02:30:03 +00:00
|
|
|
|
AggregateFunctionsPlainPtrs aggregate_functions;
|
2015-11-21 19:46:27 +00:00
|
|
|
|
|
|
|
|
|
/** Данный массив служит для двух целей.
|
|
|
|
|
*
|
|
|
|
|
* 1. Аргументы функции собраны рядом, и их не нужно собирать из разных мест. Также массив сделан zero-terminated.
|
|
|
|
|
* Внутренний цикл (для случая without_key) получается почти в два раза компактнее; прирост производительности около 30%.
|
|
|
|
|
*
|
|
|
|
|
* 2. Вызов по указателю на функцию лучше, чем виртуальный вызов, потому что в случае виртуального вызова,
|
|
|
|
|
* GCC 5.1.2 генерирует код, который на каждой итерации цикла заново грузит из памяти в регистр адрес функции
|
|
|
|
|
* (значение по смещению в таблице виртуальных функций).
|
|
|
|
|
*/
|
|
|
|
|
struct AggregateFunctionInstruction
|
|
|
|
|
{
|
|
|
|
|
const IAggregateFunction * that;
|
|
|
|
|
IAggregateFunction::AddFunc func;
|
|
|
|
|
size_t state_offset;
|
|
|
|
|
const IColumn ** arguments;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using AggregateFunctionInstructions = std::vector<AggregateFunctionInstruction>;
|
|
|
|
|
|
2013-02-08 20:34:30 +00:00
|
|
|
|
Sizes offsets_of_aggregate_states; /// Смещение до n-ой агрегатной функции в строке из агрегатных функций.
|
2014-05-10 00:31:22 +00:00
|
|
|
|
size_t total_size_of_aggregate_states = 0; /// Суммарный размер строки из агрегатных функций.
|
|
|
|
|
bool all_aggregates_has_trivial_destructor = false;
|
2013-02-08 20:34:30 +00:00
|
|
|
|
|
2015-11-30 19:57:46 +00:00
|
|
|
|
/// Сколько было использовано оперативки для обработки запроса до начала обработки первого блока.
|
|
|
|
|
Int64 memory_usage_before_aggregation = 0;
|
|
|
|
|
|
2012-03-05 07:58:34 +00:00
|
|
|
|
/// Для инициализации от первого блока при конкуррентном использовании.
|
2014-05-10 00:31:22 +00:00
|
|
|
|
bool initialized = false;
|
2015-01-08 18:52:48 +00:00
|
|
|
|
std::mutex mutex;
|
2012-03-05 07:58:34 +00:00
|
|
|
|
|
2011-09-19 03:34:23 +00:00
|
|
|
|
Block sample;
|
2012-03-05 07:58:34 +00:00
|
|
|
|
|
2015-01-08 18:52:48 +00:00
|
|
|
|
Logger * log = &Logger::get("Aggregator");
|
2012-05-31 00:33:42 +00:00
|
|
|
|
|
2015-01-13 03:03:45 +00:00
|
|
|
|
/** Динамически скомпилированная библиотека для агрегации, если есть.
|
|
|
|
|
* Смысл динамической компиляции в том, чтобы специализировать код
|
|
|
|
|
* под конкретный список агрегатных функций.
|
|
|
|
|
* Это позволяет развернуть цикл по созданию и обновлению состояний агрегатных функций,
|
|
|
|
|
* а также использовать вместо виртуальных вызовов inline-код.
|
|
|
|
|
*/
|
2015-01-11 02:00:26 +00:00
|
|
|
|
struct CompiledData
|
|
|
|
|
{
|
|
|
|
|
SharedLibraryPtr compiled_aggregator;
|
|
|
|
|
|
|
|
|
|
/// Получены с помощью dlsym. Нужно ещё сделать reinterpret_cast в указатель на функцию.
|
2015-01-21 04:23:22 +00:00
|
|
|
|
void * compiled_method_ptr = nullptr;
|
|
|
|
|
void * compiled_two_level_method_ptr = nullptr;
|
2015-01-11 02:00:26 +00:00
|
|
|
|
};
|
|
|
|
|
/// shared_ptr - чтобы передавать в callback, который может пережить Aggregator.
|
|
|
|
|
std::shared_ptr<CompiledData> compiled_data { new CompiledData };
|
2015-01-10 02:30:03 +00:00
|
|
|
|
|
|
|
|
|
bool compiled_if_possible = false;
|
|
|
|
|
void compileIfPossible(AggregatedDataVariants::Type type);
|
|
|
|
|
|
2015-04-16 14:27:56 +00:00
|
|
|
|
/// Возвращает true, если можно прервать текущую задачу.
|
|
|
|
|
CancellationHook isCancelled;
|
|
|
|
|
|
2015-11-30 19:57:46 +00:00
|
|
|
|
/// Для внешней агрегации.
|
2015-12-01 14:09:05 +00:00
|
|
|
|
TemporaryFiles temporary_files;
|
2015-11-30 19:57:46 +00:00
|
|
|
|
|
2012-03-05 07:58:34 +00:00
|
|
|
|
/** Если заданы только имена столбцов (key_names, а также aggregates[i].column_name), то вычислить номера столбцов.
|
2015-12-09 02:56:18 +00:00
|
|
|
|
* Сформировать блок - пример результата. Он используется в методах convertToBlocks, mergeAndConvertToBlocks.
|
2012-03-05 07:58:34 +00:00
|
|
|
|
*/
|
2015-09-07 07:40:14 +00:00
|
|
|
|
void initialize(const Block & block);
|
2012-05-30 01:38:02 +00:00
|
|
|
|
|
2015-12-09 02:56:18 +00:00
|
|
|
|
/** Установить блок - пример результата,
|
|
|
|
|
* только если он ещё не был установлен.
|
|
|
|
|
*/
|
|
|
|
|
void setSampleBlock(const Block & block);
|
|
|
|
|
|
2012-05-30 01:38:02 +00:00
|
|
|
|
/** Выбрать способ агрегации на основе количества и типов ключей. */
|
2016-09-23 05:49:55 +00:00
|
|
|
|
AggregatedDataVariants::Type chooseAggregationMethod(const ConstColumnPlainPtrs & key_columns, Sizes & key_sizes) const;
|
2013-02-16 18:59:05 +00:00
|
|
|
|
|
2014-05-19 19:41:56 +00:00
|
|
|
|
/** Создать состояния агрегатных функций для одного ключа.
|
|
|
|
|
*/
|
|
|
|
|
void createAggregateStates(AggregateDataPtr & aggregate_data) const;
|
|
|
|
|
|
2013-02-16 18:59:05 +00:00
|
|
|
|
/** Вызвать методы destroy для состояний агрегатных функций.
|
|
|
|
|
* Используется в обработчике исключений при агрегации, так как RAII в данном случае не применим.
|
|
|
|
|
*/
|
2014-05-19 19:41:56 +00:00
|
|
|
|
void destroyAllAggregateStates(AggregatedDataVariants & result);
|
2014-05-10 00:31:22 +00:00
|
|
|
|
|
|
|
|
|
|
2014-12-30 10:16:23 +00:00
|
|
|
|
/// Обработать один блок данных, агрегировать данные в хэш-таблицу.
|
2014-05-10 00:31:22 +00:00
|
|
|
|
template <typename Method>
|
|
|
|
|
void executeImpl(
|
|
|
|
|
Method & method,
|
|
|
|
|
Arena * aggregates_pool,
|
|
|
|
|
size_t rows,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns,
|
2015-11-21 19:46:27 +00:00
|
|
|
|
AggregateFunctionInstruction * aggregate_instructions,
|
2014-05-10 00:31:22 +00:00
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
bool no_more_keys,
|
|
|
|
|
AggregateDataPtr overflow_row) const;
|
|
|
|
|
|
2015-01-13 01:57:22 +00:00
|
|
|
|
/// Специализация для конкретного значения no_more_keys.
|
2014-12-30 10:16:23 +00:00
|
|
|
|
template <bool no_more_keys, typename Method>
|
|
|
|
|
void executeImplCase(
|
|
|
|
|
Method & method,
|
2015-01-03 06:49:32 +00:00
|
|
|
|
typename Method::State & state,
|
2014-12-30 10:16:23 +00:00
|
|
|
|
Arena * aggregates_pool,
|
|
|
|
|
size_t rows,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns,
|
2015-11-21 19:46:27 +00:00
|
|
|
|
AggregateFunctionInstruction * aggregate_instructions,
|
2014-12-30 10:16:23 +00:00
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
AggregateDataPtr overflow_row) const;
|
|
|
|
|
|
2015-01-13 03:03:45 +00:00
|
|
|
|
/// Для случая, когда нет ключей (всё агрегировать в одну строку).
|
|
|
|
|
void executeWithoutKeyImpl(
|
|
|
|
|
AggregatedDataWithoutKey & res,
|
|
|
|
|
size_t rows,
|
2016-09-19 22:30:40 +00:00
|
|
|
|
AggregateFunctionInstruction * aggregate_instructions,
|
|
|
|
|
Arena * arena) const;
|
2015-01-13 03:03:45 +00:00
|
|
|
|
|
2015-11-30 19:57:46 +00:00
|
|
|
|
template <typename Method>
|
|
|
|
|
void writeToTemporaryFileImpl(
|
|
|
|
|
AggregatedDataVariants & data_variants,
|
|
|
|
|
Method & method,
|
|
|
|
|
IBlockOutputStream & out,
|
|
|
|
|
const String & path);
|
|
|
|
|
|
2015-01-11 00:57:21 +00:00
|
|
|
|
public:
|
|
|
|
|
/// Шаблоны, инстанцирующиеся путём динамической компиляции кода - см. SpecializedAggregator.h
|
|
|
|
|
|
|
|
|
|
template <typename Method, typename AggregateFunctionsList>
|
|
|
|
|
void executeSpecialized(
|
|
|
|
|
Method & method,
|
|
|
|
|
Arena * aggregates_pool,
|
|
|
|
|
size_t rows,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
AggregateColumns & aggregate_columns,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
bool no_more_keys,
|
|
|
|
|
AggregateDataPtr overflow_row) const;
|
2014-12-30 10:16:23 +00:00
|
|
|
|
|
2015-01-11 00:57:21 +00:00
|
|
|
|
template <bool no_more_keys, typename Method, typename AggregateFunctionsList>
|
|
|
|
|
void executeSpecializedCase(
|
|
|
|
|
Method & method,
|
|
|
|
|
typename Method::State & state,
|
|
|
|
|
Arena * aggregates_pool,
|
|
|
|
|
size_t rows,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
AggregateColumns & aggregate_columns,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
AggregateDataPtr overflow_row) const;
|
|
|
|
|
|
2015-01-13 03:03:45 +00:00
|
|
|
|
template <typename AggregateFunctionsList>
|
|
|
|
|
void executeSpecializedWithoutKey(
|
|
|
|
|
AggregatedDataWithoutKey & res,
|
|
|
|
|
size_t rows,
|
2016-09-21 16:39:44 +00:00
|
|
|
|
AggregateColumns & aggregate_columns,
|
|
|
|
|
Arena * arena) const;
|
2015-01-13 03:03:45 +00:00
|
|
|
|
|
2015-01-11 00:57:21 +00:00
|
|
|
|
protected:
|
2014-12-25 20:18:01 +00:00
|
|
|
|
/// Слить данные из хэш-таблицы src в dst.
|
|
|
|
|
template <typename Method, typename Table>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
void mergeDataImpl(
|
2014-12-25 20:18:01 +00:00
|
|
|
|
Table & table_dst,
|
2016-09-23 23:33:17 +00:00
|
|
|
|
Table & table_src,
|
|
|
|
|
Arena * arena) const;
|
2014-12-25 20:18:01 +00:00
|
|
|
|
|
2015-10-22 01:44:33 +00:00
|
|
|
|
/// Слить данные из хэш-таблицы src в dst, но только для ключей, которые уже есть в dst. В остальных случаях, слить данные в overflows.
|
|
|
|
|
template <typename Method, typename Table>
|
|
|
|
|
void mergeDataNoMoreKeysImpl(
|
|
|
|
|
Table & table_dst,
|
|
|
|
|
AggregatedDataWithoutKey & overflows,
|
2016-09-23 23:33:17 +00:00
|
|
|
|
Table & table_src,
|
|
|
|
|
Arena * arena) const;
|
2015-10-22 01:44:33 +00:00
|
|
|
|
|
|
|
|
|
/// То же самое, но игнорирует остальные ключи.
|
|
|
|
|
template <typename Method, typename Table>
|
|
|
|
|
void mergeDataOnlyExistingKeysImpl(
|
|
|
|
|
Table & table_dst,
|
2016-09-23 23:33:17 +00:00
|
|
|
|
Table & table_src,
|
|
|
|
|
Arena * arena) const;
|
2015-10-22 01:44:33 +00:00
|
|
|
|
|
2014-12-25 20:18:01 +00:00
|
|
|
|
void mergeWithoutKeyDataImpl(
|
|
|
|
|
ManyAggregatedDataVariants & non_empty_data) const;
|
|
|
|
|
|
|
|
|
|
template <typename Method>
|
|
|
|
|
void mergeSingleLevelDataImpl(
|
|
|
|
|
ManyAggregatedDataVariants & non_empty_data) const;
|
|
|
|
|
|
2015-01-02 03:16:28 +00:00
|
|
|
|
template <typename Method, typename Table>
|
2014-12-30 11:27:58 +00:00
|
|
|
|
void convertToBlockImpl(
|
|
|
|
|
Method & method,
|
2015-01-02 03:16:28 +00:00
|
|
|
|
Table & data,
|
2014-12-30 11:27:58 +00:00
|
|
|
|
ColumnPlainPtrs & key_columns,
|
|
|
|
|
AggregateColumnsData & aggregate_columns,
|
|
|
|
|
ColumnPlainPtrs & final_aggregate_columns,
|
|
|
|
|
const Sizes & key_sizes,
|
2015-01-02 03:16:28 +00:00
|
|
|
|
bool final) const;
|
2014-12-30 11:27:58 +00:00
|
|
|
|
|
2015-01-02 00:35:33 +00:00
|
|
|
|
template <typename Method, typename Table>
|
|
|
|
|
void convertToBlockImplFinal(
|
|
|
|
|
Method & method,
|
|
|
|
|
Table & data,
|
|
|
|
|
ColumnPlainPtrs & key_columns,
|
|
|
|
|
ColumnPlainPtrs & final_aggregate_columns,
|
2015-01-02 03:16:28 +00:00
|
|
|
|
const Sizes & key_sizes) const;
|
2015-01-02 00:35:33 +00:00
|
|
|
|
|
|
|
|
|
template <typename Method, typename Table>
|
|
|
|
|
void convertToBlockImplNotFinal(
|
|
|
|
|
Method & method,
|
|
|
|
|
Table & data,
|
|
|
|
|
ColumnPlainPtrs & key_columns,
|
|
|
|
|
AggregateColumnsData & aggregate_columns,
|
2015-01-02 03:16:28 +00:00
|
|
|
|
const Sizes & key_sizes) const;
|
|
|
|
|
|
|
|
|
|
template <typename Filler>
|
|
|
|
|
Block prepareBlockAndFill(
|
|
|
|
|
AggregatedDataVariants & data_variants,
|
|
|
|
|
bool final,
|
|
|
|
|
size_t rows,
|
|
|
|
|
Filler && filler) const;
|
|
|
|
|
|
2015-12-06 14:27:09 +00:00
|
|
|
|
template <typename Method>
|
|
|
|
|
Block convertOneBucketToBlock(
|
|
|
|
|
AggregatedDataVariants & data_variants,
|
|
|
|
|
Method & method,
|
|
|
|
|
bool final,
|
|
|
|
|
size_t bucket) const;
|
|
|
|
|
|
2015-11-09 18:45:55 +00:00
|
|
|
|
BlocksList prepareBlocksAndFillWithoutKey(AggregatedDataVariants & data_variants, bool final, bool is_overflows) const;
|
2015-01-02 03:16:28 +00:00
|
|
|
|
BlocksList prepareBlocksAndFillSingleLevel(AggregatedDataVariants & data_variants, bool final) const;
|
2016-08-02 01:46:05 +00:00
|
|
|
|
BlocksList prepareBlocksAndFillTwoLevel(AggregatedDataVariants & data_variants, bool final, ThreadPool * thread_pool) const;
|
2015-01-02 03:16:28 +00:00
|
|
|
|
|
|
|
|
|
template <typename Method>
|
|
|
|
|
BlocksList prepareBlocksAndFillTwoLevelImpl(
|
|
|
|
|
AggregatedDataVariants & data_variants,
|
|
|
|
|
Method & method,
|
|
|
|
|
bool final,
|
2016-08-02 01:46:05 +00:00
|
|
|
|
ThreadPool * thread_pool) const;
|
2015-01-02 00:35:33 +00:00
|
|
|
|
|
2015-10-23 01:43:42 +00:00
|
|
|
|
template <bool no_more_keys, typename Method, typename Table>
|
|
|
|
|
void mergeStreamsImplCase(
|
|
|
|
|
Block & block,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
Arena * aggregates_pool,
|
|
|
|
|
Method & method,
|
|
|
|
|
Table & data,
|
|
|
|
|
AggregateDataPtr overflow_row) const;
|
|
|
|
|
|
2015-01-03 05:39:21 +00:00
|
|
|
|
template <typename Method, typename Table>
|
|
|
|
|
void mergeStreamsImpl(
|
|
|
|
|
Block & block,
|
2015-03-23 01:10:06 +00:00
|
|
|
|
const Sizes & key_sizes,
|
2015-01-03 06:49:32 +00:00
|
|
|
|
Arena * aggregates_pool,
|
2015-01-03 05:39:21 +00:00
|
|
|
|
Method & method,
|
2015-10-23 01:43:42 +00:00
|
|
|
|
Table & data,
|
|
|
|
|
AggregateDataPtr overflow_row,
|
|
|
|
|
bool no_more_keys) const;
|
2015-01-03 05:39:21 +00:00
|
|
|
|
|
|
|
|
|
void mergeWithoutKeyStreamsImpl(
|
|
|
|
|
Block & block,
|
|
|
|
|
AggregatedDataVariants & result) const;
|
|
|
|
|
|
2015-12-06 16:22:01 +00:00
|
|
|
|
template <typename Method>
|
|
|
|
|
void mergeBucketImpl(
|
2016-09-26 16:50:13 +00:00
|
|
|
|
ManyAggregatedDataVariants & data, Int32 bucket, Arena * arena) const;
|
2015-12-06 16:22:01 +00:00
|
|
|
|
|
2015-09-07 07:40:14 +00:00
|
|
|
|
template <typename Method>
|
|
|
|
|
void convertBlockToTwoLevelImpl(
|
|
|
|
|
Method & method,
|
|
|
|
|
Arena * pool,
|
|
|
|
|
ConstColumnPlainPtrs & key_columns,
|
|
|
|
|
const Sizes & key_sizes,
|
|
|
|
|
StringRefs & keys,
|
|
|
|
|
const Block & source,
|
|
|
|
|
std::vector<Block> & destinations) const;
|
|
|
|
|
|
2015-12-06 19:42:28 +00:00
|
|
|
|
template <typename Method, typename Table>
|
2014-05-10 00:31:22 +00:00
|
|
|
|
void destroyImpl(
|
2015-12-06 19:42:28 +00:00
|
|
|
|
Method & method,
|
2015-12-23 07:03:50 +00:00
|
|
|
|
Table & table) const;
|
2015-12-06 19:42:28 +00:00
|
|
|
|
|
|
|
|
|
void destroyWithoutKey(
|
|
|
|
|
AggregatedDataVariants & result) const;
|
2015-10-22 01:44:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Проверяет ограничения на максимальное количество ключей для агрегации.
|
|
|
|
|
* Если оно превышено, то, в зависимости от group_by_overflow_mode, либо
|
|
|
|
|
* - кидает исключение;
|
|
|
|
|
* - возвращает false, что говорит о том, что выполнение нужно прервать;
|
|
|
|
|
* - выставляет переменную no_more_keys в true.
|
|
|
|
|
*/
|
|
|
|
|
bool checkLimits(size_t result_size, bool & no_more_keys) const;
|
2011-09-19 01:42:16 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-07-30 23:41:02 +00:00
|
|
|
|
/** Достать вариант агрегации по его типу. */
|
|
|
|
|
template <typename Method> Method & getDataVariant(AggregatedDataVariants & variants);
|
|
|
|
|
|
|
|
|
|
#define M(NAME, IS_TWO_LEVEL) \
|
|
|
|
|
template <> inline decltype(AggregatedDataVariants::NAME)::element_type & getDataVariant<decltype(AggregatedDataVariants::NAME)::element_type>(AggregatedDataVariants & variants) { return *variants.NAME; }
|
|
|
|
|
|
|
|
|
|
APPLY_FOR_AGGREGATED_VARIANTS(M)
|
|
|
|
|
|
|
|
|
|
#undef M
|
|
|
|
|
|
|
|
|
|
|
2011-09-19 01:42:16 +00:00
|
|
|
|
}
|