ClickHouse/dbms/include/DB/Databases/DatabaseCloud.h

150 lines
8.1 KiB
C++
Raw Normal View History

#pragma once
#include <DB/Databases/IDatabase.h>
#include <DB/Common/UInt128.h>
#include <DB/Storages/IStorage.h>
namespace Poco { class Logger; }
namespace DB
{
/** Позволяет создавать "облачные таблицы".
* Список таких таблиц хранится в ZooKeeper.
* Все серверы, ссылающиеся на один путь в ZooKeeper, видят один и тот же список таблиц.
* CREATE, DROP, RENAME атомарны.
*
* Для БД задаётся уровень репликации N.
* При записи в "облачную" таблицу, некоторым образом выбирается N живых серверов в разных датацентрах,
* на каждом из них создаётся локальная таблица, и в них производится запись.
*
* Движок имеет параметры: Cloud(zookeeper_path, replication_factor, datacenter_name)
* Пример: Cloud('/clickhouse/clouds/production/', 3, 'FIN')
*
* Структура в ZooKeeper:
*
* cloud_path - путь к "облаку"; может существовать несколько разных независимых облаков
/table_definitions - множество уникальных определений таблиц, чтобы не писать их много раз для большого количества таблиц
/hash128 -> sql - отображение: хэш от определения таблицы (идентификатор) -> само определение таблицы в виде CREATE запроса
/tables - список таблиц
/database_name - имя базы данных
/name_hash_mod -> compressed_table_list
- список таблиц сделан двухуровневым, чтобы уменьшить количество узлов в ZooKeeper при наличии большого количества таблиц
- узлы создаются для каждого остатка от деления хэша от имени таблицы, например, на 4096
- и в каждом узле хранится список таблиц (имя таблицы, имя локальной таблицы, хэш от структуры, список хостов) в сжатом виде
/local_tables - список локальных таблиц, чтобы по имени локальной таблицы можно было определить её структуру
/database_name
/name_hash_mod -> compressed_table_list
- список пар (хэш от имени таблицы, хэш от структуры) в сжатом виде
/locality_keys - сериализованный список ключей локальности в порядке их появления
- ключ локальности - произвольная строка
- движок БД определяет серверы для расположения данных таким образом,
чтобы, при одинаковом множестве живых серверов,
одному ключу локальности соответствовала одна группа из N серверов для расположения данных.
/nodes - список серверов, на которых зарегистрированы облачные БД с таким путём в ZK
/hostname - имя хоста
TODO /alive - эфемерная нода для предварительной проверки живости
/datacenter - имя датацентра
TODO /disk_space
* К одному облаку может относиться несколько БД, названных по-разному. Например, БД hits и visits могут относиться к одному облаку.
*/
class DatabaseCloud : public IDatabase
{
private:
const String name;
const String data_path;
String zookeeper_path;
const size_t replication_factor;
const String hostname;
const String datacenter_name;
Logger * log;
Context & context;
/** Локальные таблицы - это таблицы, находящиеся непосредственно на локальном сервере.
* Они хранят данные облачных таблиц: облачная таблица представлена несколькими локальными таблицами на разных серверах.
* Эти таблицы не видны пользователю при перечислении таблиц, хотя доступны при обращении по имени.
* Имя локальных таблиц имеет специальную форму, например, начинаться на _local, чтобы они не путались с облачными таблицами.
* Локальные таблицы загружаются лениво, при первом обращении.
*/
Tables local_tables_cache;
mutable std::mutex local_tables_mutex;
friend class DatabaseCloudIterator;
public:
DatabaseCloud(
bool attach,
const String & name_,
const String & zookeeper_path_,
size_t replication_factor_,
const String & datacenter_name_,
Context & context_);
String getEngineName() const override { return "Cloud"; }
void loadTables(Context & context, ThreadPool * thread_pool, bool has_force_restore_data_flag) override;
bool isTableExist(const String & table_name) const override;
StoragePtr tryGetTable(const String & table_name) override;
DatabaseIteratorPtr getIterator() override;
bool empty() const override;
void createTable(
const String & table_name, const StoragePtr & table, const ASTPtr & query, const String & engine, const Settings & settings) override;
void removeTable(const String & table_name) override;
void attachTable(const String & table_name, const StoragePtr & table) override;
StoragePtr detachTable(const String & table_name) override;
void renameTable(
const Context & context, const String & table_name, IDatabase & to_database, const String & to_table_name, const Settings & settings) override;
time_t getTableMetadataModificationTime(const String & name) override;
ASTPtr getCreateQuery(const String & table_name) const override;
void shutdown() override;
void drop() override;
2016-05-13 21:08:19 +00:00
void alterTable(
const Context & context,
const String & name,
const NamesAndTypesList & columns,
const NamesAndTypesList & materialized_columns,
const NamesAndTypesList & alias_columns,
const ColumnDefaults & column_defaults,
const ASTModifier & engine_modifier) override
{
throw Exception("ALTER TABLE is not supported by database engine " + getEngineName(), ErrorCodes::NOT_IMPLEMENTED);
}
using Hash = UInt128;
private:
void createZookeeperNodes();
/// Получить имя узла, в котором будет храниться часть списка таблиц. (Список таблиц является двухуровневым.)
String getNameOfNodeWithTables(const String & table_name) const;
/// Хэшировать имя таблицы вместе с именем БД.
Hash getTableHash(const String & table_name) const;
/// Определения таблиц хранятся косвенным образом и адресуются своим хэшом. Вычислить хэш.
Hash getHashForTableDefinition(const String & definition) const;
/// Пойти в ZooKeeper и по хэшу получить определение таблицы.
String getTableDefinitionFromHash(Hash hash) const;
/// Определить серверы, на которых будут храниться данные таблицы.
std::vector<String> selectHostsForTable(const String & locality_key) const;
};
}