ClickHouse/dbms/include/DB/Storages/StorageMergeTree.h

184 lines
7.2 KiB
C
Raw Normal View History

2012-07-16 20:25:19 +00:00
#pragma once
2012-07-17 20:04:39 +00:00
#include <statdaemons/Increment.h>
2012-07-19 20:32:10 +00:00
#include <Yandex/MultiVersion.h>
2012-07-17 20:04:39 +00:00
#include <DB/Core/SortDescription.h>
2012-07-16 20:25:19 +00:00
#include <DB/Interpreters/Context.h>
2012-07-17 20:04:39 +00:00
#include <DB/Interpreters/Expression.h>
2012-07-16 20:25:19 +00:00
#include <DB/Storages/IStorage.h>
namespace DB
{
/** Движок, использующий merge tree для инкрементальной сортировки данных.
* Таблица представлена набором сортированных кусков.
* При вставке, данные сортируются по указанному выражению (первичному ключу) и пишутся в новый кусок.
* Куски объединяются в фоне, согласно некоторой эвристике.
* Для каждого куска, создаётся индексный файл, содержащий значение первичного ключа для каждой n-ой строки.
* Таким образом, реализуется эффективная выборка по диапазону первичного ключа.
*
* Дополнительно:
*
* Указывается столбец, содержащий дату.
* Для каждого куска пишется минимальная и максимальная дата.
* (по сути - ещё один индекс)
*
* Данные разделяются по разным месяцам (пишутся в разные куски для разных месяцев).
* Куски для разных месяцев не объединяются - для простоты эксплуатации.
* (дают локальность обновлений, что удобно для синхронизации и бэкапа)
*
* Структура файлов:
* / increment.txt - файл, содержащий одно число, увеличивающееся на 1 - для генерации идентификаторов кусков.
* / min-date _ max-date _ min-id _ max-id _ level / - директория с куском.
2012-07-18 19:16:16 +00:00
* / min-date _ max-date _ min-id _ max-id _ level / primary.idx - индексный файл.
2012-07-16 20:25:19 +00:00
* Внутри директории с куском:
* Column.bin - данные столбца
* Column.mrk - засечки, указывающие, откуда начинать чтение, чтобы пропустить n * k строк.
2012-07-19 20:32:10 +00:00
*
2012-07-21 03:45:48 +00:00
* NOTE: Может быть, все .mrk писать в один файл, так как их мало.
2012-07-19 20:32:10 +00:00
* А если надо, можно и все .bin писать в один файл
* (но, наверное, это усложнит добавление новых столбцов).
2012-07-16 20:25:19 +00:00
*/
class StorageMergeTree : public IStorage
{
2012-07-17 20:04:39 +00:00
friend class MergeTreeBlockOutputStream;
2012-07-16 20:25:19 +00:00
public:
/** Подцепить таблицу с соответствующим именем, по соответствующему пути (с / на конце),
* (корректность имён и путей не проверяется)
* состоящую из указанных столбцов.
*
* primary_expr - выражение для сортировки;
* date_column_name - имя столбца с датой;
* index_granularity - на сколько строчек пишется одно значение индекса.
*/
StorageMergeTree(const String & path_, const String & name_, NamesAndTypesListPtr columns_,
2012-07-17 20:04:39 +00:00
Context & context_,
ASTPtr & primary_expr_ast_, const String & date_column_name_,
size_t index_granularity_);
2012-07-16 20:25:19 +00:00
std::string getName() const { return "MergeTree"; }
std::string getTableName() const { return name; }
const NamesAndTypesList & getColumnsList() const { return *columns; }
/** При чтении, выбирается набор кусков, покрывающий нужный диапазон индекса.
*/
2012-07-21 03:45:48 +00:00
BlockInputStreams read(
2012-07-16 20:25:19 +00:00
const Names & column_names,
ASTPtr query,
QueryProcessingStage::Enum & processed_stage,
size_t max_block_size = DEFAULT_BLOCK_SIZE,
2012-07-21 03:45:48 +00:00
unsigned threads = 1);
2012-07-16 20:25:19 +00:00
/** При записи, данные сортируются и пишутся в новые куски.
*/
BlockOutputStreamPtr write(
ASTPtr query);
/** Выполнить очередной шаг объединения кусков.
* Для нормальной работы, этот метод требуется вызывать постоянно.
* (С некоторой задержкой, если возвращено has_more_work = false.)
*/
2012-07-18 19:40:22 +00:00
// void optimize(bool & done_something, bool & has_more_work);
2012-07-16 20:25:19 +00:00
2012-07-18 19:40:22 +00:00
// void drop();
2012-07-16 20:25:19 +00:00
2012-07-18 19:40:22 +00:00
// void rename(const String & new_path_to_db, const String & new_name);
2012-07-16 20:25:19 +00:00
private:
String path;
String name;
2012-07-17 20:04:39 +00:00
String full_path;
2012-07-16 20:25:19 +00:00
NamesAndTypesListPtr columns;
2012-07-17 20:04:39 +00:00
Context context;
ASTPtr primary_expr_ast;
2012-07-16 20:25:19 +00:00
String date_column_name;
size_t index_granularity;
2012-07-17 20:04:39 +00:00
2012-07-18 20:14:41 +00:00
SharedPtr<Expression> primary_expr;
2012-07-17 20:04:39 +00:00
SortDescription sort_descr;
Increment increment;
2012-07-19 20:32:10 +00:00
Logger * log;
/// Описание куска с данными.
struct DataPart
{
Yandex::DayNum_t left_date;
Yandex::DayNum_t right_date;
UInt64 left;
UInt64 right;
UInt32 level;
std::string name;
size_t size; /// в количестве засечек.
time_t modification_time;
Yandex::DayNum_t left_month;
Yandex::DayNum_t right_month;
/// TODO рефкаунт для того, чтобы можно было определить, когда можно удалить кусок.
void remove() const
{
/// TODO
}
bool operator< (const DataPart & rhs) const
{
if (left_month < rhs.left_month)
return true;
if (left_month > rhs.left_month)
return false;
if (right_month < rhs.right_month)
return true;
if (right_month > rhs.right_month)
return false;
if (left < rhs.left)
return true;
if (left > rhs.left)
return false;
if (right < rhs.right)
return true;
if (right > rhs.right)
return false;
if (level < rhs.level)
return true;
return false;
}
/// Содержит другой кусок (получен после объединения другого куска с каким-то ещё)
bool contains(const DataPart & rhs) const
{
return left_month == rhs.left_month /// Куски за разные месяцы не объединяются
&& right_month == rhs.right_month
&& level > rhs.level
&& left_date <= rhs.left_date
&& right_date >= rhs.right_date
&& left <= rhs.left
&& right >= rhs.right
&& (left == rhs.left /// У кусков общее начало или конец.
|| right == rhs.right); /// (только такие образуются после объединения)
}
};
/// Множество кусков с данными. Оно обычно небольшое (десятки элементов).
typedef std::set<DataPart> DataParts;
Yandex::MultiVersion<DataParts> data_parts;
static String getPartName(Yandex::DayNum_t left_date, Yandex::DayNum_t right_date, UInt64 left_id, UInt64 right_id, UInt64 level);
/// Загрузить множество кусков с данными с диска.
void loadDataParts();
2012-07-16 20:25:19 +00:00
};
}