2020-04-05 12:18:51 +00:00
|
|
|
#include <iomanip>
|
|
|
|
|
|
|
|
#include <Core/Settings.h>
|
|
|
|
#include <Databases/DatabaseOnDisk.h>
|
2020-05-05 14:16:59 +00:00
|
|
|
#include <Databases/DatabaseOrdinary.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
#include <Databases/DatabaseReplicated.h>
|
|
|
|
#include <Databases/DatabasesCommon.h>
|
|
|
|
#include <IO/ReadBufferFromFile.h>
|
2020-05-11 12:55:17 +00:00
|
|
|
#include <IO/ReadBufferFromString.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
#include <IO/ReadHelpers.h>
|
|
|
|
#include <IO/WriteBufferFromFile.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Interpreters/InterpreterCreateQuery.h>
|
2020-05-11 12:55:17 +00:00
|
|
|
#include <Interpreters/executeQuery.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
#include <Parsers/ASTCreateQuery.h>
|
|
|
|
#include <Parsers/ASTSetQuery.h>
|
|
|
|
#include <Parsers/ParserCreateQuery.h>
|
|
|
|
#include <Parsers/formatAST.h>
|
|
|
|
#include <Parsers/parseQuery.h>
|
|
|
|
#include <Storages/StorageFactory.h>
|
|
|
|
#include <TableFunctions/TableFunctionFactory.h>
|
|
|
|
|
|
|
|
#include <Parsers/queryToString.h>
|
|
|
|
|
|
|
|
#include <Poco/DirectoryIterator.h>
|
|
|
|
#include <Poco/Event.h>
|
|
|
|
#include <Common/Stopwatch.h>
|
2020-05-11 12:55:17 +00:00
|
|
|
#include <Common/setThreadName.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
#include <Common/ThreadPool.h>
|
|
|
|
#include <Common/escapeForFileName.h>
|
|
|
|
#include <Common/quoteString.h>
|
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
#include <common/logger_useful.h>
|
2020-05-12 13:35:05 +00:00
|
|
|
#include <Common/Exception.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
|
|
|
|
#include <Common/ZooKeeper/KeeperException.h>
|
|
|
|
#include <Common/ZooKeeper/Types.h>
|
|
|
|
#include <Common/ZooKeeper/ZooKeeper.h>
|
2020-05-11 12:55:17 +00:00
|
|
|
#include <Common/ZooKeeper/Lock.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
|
|
|
|
#include <ext/scope_guard.h>
|
2020-05-11 12:55:17 +00:00
|
|
|
#include <common/sleep.h>
|
2020-04-05 12:18:51 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int NO_ZOOKEEPER;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DatabaseReplicated::setZooKeeper(zkutil::ZooKeeperPtr zookeeper)
|
|
|
|
{
|
|
|
|
std::lock_guard lock(current_zookeeper_mutex);
|
|
|
|
current_zookeeper = zookeeper;
|
|
|
|
}
|
|
|
|
|
|
|
|
zkutil::ZooKeeperPtr DatabaseReplicated::tryGetZooKeeper() const
|
|
|
|
{
|
|
|
|
std::lock_guard lock(current_zookeeper_mutex);
|
|
|
|
return current_zookeeper;
|
|
|
|
}
|
|
|
|
|
|
|
|
zkutil::ZooKeeperPtr DatabaseReplicated::getZooKeeper() const
|
|
|
|
{
|
|
|
|
auto res = tryGetZooKeeper();
|
|
|
|
if (!res)
|
|
|
|
throw Exception("Cannot get ZooKeeper", ErrorCodes::NO_ZOOKEEPER);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DatabaseReplicated::DatabaseReplicated(
|
|
|
|
const String & name_,
|
|
|
|
const String & metadata_path_,
|
|
|
|
const String & zookeeper_path_,
|
|
|
|
const String & replica_name_,
|
2020-05-05 14:16:59 +00:00
|
|
|
Context & context_)
|
|
|
|
// : DatabaseOrdinary(name_, metadata_path_, "data/" + escapeForFileName(name_) + "/", "DatabaseReplicated (" + name_ + ")", context_)
|
|
|
|
// TODO add constructor to Atomic and call it here with path and logger name specification
|
2020-05-13 14:44:01 +00:00
|
|
|
: DatabaseAtomic(name_, metadata_path_, context_)
|
2020-04-05 12:18:51 +00:00
|
|
|
, zookeeper_path(zookeeper_path_)
|
|
|
|
, replica_name(replica_name_)
|
|
|
|
{
|
|
|
|
if (!zookeeper_path.empty() && zookeeper_path.back() == '/')
|
|
|
|
zookeeper_path.resize(zookeeper_path.size() - 1);
|
2020-05-01 13:16:02 +00:00
|
|
|
// If zookeeper chroot prefix is used, path should start with '/', because chroot concatenates without it.
|
2020-04-05 12:18:51 +00:00
|
|
|
if (!zookeeper_path.empty() && zookeeper_path.front() != '/')
|
|
|
|
zookeeper_path = "/" + zookeeper_path;
|
2020-05-01 13:16:02 +00:00
|
|
|
|
2020-04-05 12:18:51 +00:00
|
|
|
replica_path = zookeeper_path + "/replicas/" + replica_name;
|
|
|
|
|
|
|
|
if (context_.hasZooKeeper()) {
|
|
|
|
current_zookeeper = context_.getZooKeeper();
|
|
|
|
}
|
|
|
|
if (!current_zookeeper)
|
|
|
|
{
|
2020-04-30 16:15:27 +00:00
|
|
|
throw Exception("Can't create replicated database without ZooKeeper", ErrorCodes::NO_ZOOKEEPER);
|
|
|
|
}
|
2020-04-05 12:18:51 +00:00
|
|
|
|
2020-05-13 17:00:47 +00:00
|
|
|
if (!current_zookeeper->exists(zookeeper_path, {}, NULL)) {
|
2020-05-24 17:13:53 +00:00
|
|
|
createDatabaseZKNodes();
|
|
|
|
}
|
|
|
|
|
|
|
|
// replica
|
|
|
|
if (!current_zookeeper->exists(replica_path, {}, NULL)) {
|
2020-05-13 17:00:47 +00:00
|
|
|
current_zookeeper->createAncestors(replica_path);
|
2020-05-24 17:13:53 +00:00
|
|
|
current_zookeeper->createOrUpdate(replica_path, String(), zkutil::CreateMode::Persistent);
|
2020-05-13 17:00:47 +00:00
|
|
|
}
|
2020-05-11 12:55:17 +00:00
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
//loadMetadataFromSnapshot();
|
|
|
|
|
|
|
|
background_log_executor = global_context.getReplicatedSchedulePool().createTask(database_name + "(DatabaseReplicated::the_threeeed)", [this]{ runBackgroundLogExecutor();} );
|
|
|
|
background_log_executor->schedule();
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
void DatabaseReplicated::createDatabaseZKNodes() {
|
|
|
|
current_zookeeper = getZooKeeper();
|
|
|
|
|
|
|
|
if (current_zookeeper->exists(zookeeper_path))
|
|
|
|
return;
|
|
|
|
|
|
|
|
current_zookeeper->createAncestors(zookeeper_path);
|
|
|
|
|
|
|
|
current_zookeeper->createIfNotExists(zookeeper_path, String());
|
|
|
|
current_zookeeper->createIfNotExists(zookeeper_path + "/last_entry", "0");
|
|
|
|
current_zookeeper->createIfNotExists(zookeeper_path + "/log", String());
|
|
|
|
current_zookeeper->createIfNotExists(zookeeper_path + "/snapshot", String());
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
void DatabaseReplicated::runBackgroundLogExecutor() {
|
|
|
|
current_zookeeper = getZooKeeper();
|
|
|
|
String last_n = current_zookeeper->get(zookeeper_path + "/last_entry", {}, NULL);
|
|
|
|
size_t last_n_parsed = parse<size_t>(last_n);
|
|
|
|
|
|
|
|
bool newEntries = current_log_entry_n < last_n_parsed;
|
|
|
|
while (current_log_entry_n < last_n_parsed) {
|
|
|
|
current_log_entry_n++;
|
|
|
|
String log_path = zookeeper_path + "/log/log." + std::to_string(current_log_entry_n);
|
|
|
|
executeFromZK(log_path);
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
2020-05-24 17:13:53 +00:00
|
|
|
if (newEntries) {
|
|
|
|
saveState();
|
|
|
|
}
|
|
|
|
background_log_executor->scheduleAfter(500);
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 17:00:47 +00:00
|
|
|
void DatabaseReplicated::saveState() {
|
|
|
|
current_zookeeper->createOrUpdate(replica_path + "/last_entry", std::to_string(current_log_entry_n), zkutil::CreateMode::Persistent);
|
|
|
|
// TODO rename vars
|
|
|
|
String statement = std::to_string(current_log_entry_n);
|
|
|
|
String metadatafile = getMetadataPath() + ".last_entry";
|
|
|
|
WriteBufferFromFile out(metadatafile, statement.size(), O_WRONLY | O_CREAT);
|
|
|
|
writeString(statement, out);
|
|
|
|
out.next();
|
|
|
|
if (global_context.getSettingsRef().fsync_metadata)
|
|
|
|
out.sync();
|
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
void DatabaseReplicated::executeFromZK(String & path) {
|
2020-05-11 12:55:17 +00:00
|
|
|
current_zookeeper = getZooKeeper();
|
2020-05-24 17:13:53 +00:00
|
|
|
String query_to_execute = current_zookeeper->get(path, {}, NULL);
|
2020-05-11 12:55:17 +00:00
|
|
|
ReadBufferFromString istr(query_to_execute);
|
|
|
|
String dummy_string;
|
|
|
|
WriteBufferFromString ostr(dummy_string);
|
2020-05-12 13:35:05 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
current_context = std::make_unique<Context>(global_context);
|
2020-05-26 15:08:09 +00:00
|
|
|
current_context->getClientInfo().query_kind = ClientInfo::QueryKind::REPLICATED_LOG_QUERY;
|
2020-05-12 14:25:36 +00:00
|
|
|
current_context->setCurrentDatabase(database_name);
|
2020-05-12 13:35:05 +00:00
|
|
|
current_context->setCurrentQueryId(""); // generate random query_id
|
|
|
|
executeQuery(istr, ostr, false, *current_context, {});
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2020-05-24 17:13:53 +00:00
|
|
|
tryLogCurrentException(log, "Query from zookeeper " + query_to_execute + " wasn't finished successfully");
|
2020-05-12 13:35:05 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Executed query: " << query_to_execute);
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 17:00:47 +00:00
|
|
|
// TODO Move to ZooKeeper/Lock and remove it from here and ddlworker
|
2020-05-11 12:55:17 +00:00
|
|
|
static std::unique_ptr<zkutil::Lock> createSimpleZooKeeperLock(
|
|
|
|
const std::shared_ptr<zkutil::ZooKeeper> & zookeeper, const String & lock_prefix, const String & lock_name, const String & lock_message)
|
|
|
|
{
|
|
|
|
auto zookeeper_holder = std::make_shared<zkutil::ZooKeeperHolder>();
|
|
|
|
zookeeper_holder->initFromInstance(zookeeper);
|
|
|
|
return std::make_unique<zkutil::Lock>(std::move(zookeeper_holder), lock_prefix, lock_name, lock_message);
|
2020-04-05 12:18:51 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 16:15:27 +00:00
|
|
|
|
2020-05-05 14:16:59 +00:00
|
|
|
void DatabaseReplicated::propose(const ASTPtr & query) {
|
2020-05-11 12:55:17 +00:00
|
|
|
// TODO remove that log message i think
|
2020-05-05 14:16:59 +00:00
|
|
|
LOG_DEBUG(log, "PROPOSING\n" << queryToString(query));
|
2020-04-05 12:18:51 +00:00
|
|
|
|
2020-05-11 12:55:17 +00:00
|
|
|
current_zookeeper = getZooKeeper();
|
2020-05-13 17:00:47 +00:00
|
|
|
auto lock = createSimpleZooKeeperLock(current_zookeeper, zookeeper_path, "propose_lock", replica_name);
|
|
|
|
|
|
|
|
// schedule and deactive combo
|
|
|
|
// ensures that replica is up to date
|
|
|
|
// and since propose lock is acquired,
|
|
|
|
// no other propose can happen from
|
|
|
|
// different replicas during this call
|
2020-05-24 17:13:53 +00:00
|
|
|
background_log_executor->schedule();
|
|
|
|
background_log_executor->deactivate();
|
2020-05-13 17:00:47 +00:00
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
// if (current_log_entry_n > 5) { // make a settings variable
|
|
|
|
// // TODO check that all the replicas are up to date!
|
|
|
|
// updateSnapshot();
|
|
|
|
// current_log_entry_n = 0;
|
|
|
|
// current_zookeeper->removeChildren(zookeeper_path + "/log");
|
|
|
|
// }
|
2020-05-11 12:55:17 +00:00
|
|
|
|
|
|
|
current_log_entry_n++; // starting from 1
|
2020-05-24 17:13:53 +00:00
|
|
|
String log_entry = zookeeper_path + "/log/log." + std::to_string(current_log_entry_n);
|
2020-05-11 12:55:17 +00:00
|
|
|
current_zookeeper->createOrUpdate(log_entry, queryToString(query), zkutil::CreateMode::Persistent);
|
|
|
|
|
|
|
|
current_zookeeper->createOrUpdate(zookeeper_path + "/last_entry", std::to_string(current_log_entry_n), zkutil::CreateMode::Persistent);
|
|
|
|
|
|
|
|
lock->unlock();
|
2020-05-13 17:00:47 +00:00
|
|
|
saveState();
|
|
|
|
}
|
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
void DatabaseReplicated::updateSnapshot() {
|
|
|
|
current_zookeeper = getZooKeeper();
|
|
|
|
current_zookeeper->tryRemoveChildren(zookeeper_path + "/snapshot");
|
2020-05-13 17:00:47 +00:00
|
|
|
for (auto iterator = getTablesIterator({}); iterator->isValid(); iterator->next()) {
|
|
|
|
String table_name = iterator->name();
|
|
|
|
auto query = getCreateQueryFromMetadata(getObjectMetadataPath(table_name), true);
|
|
|
|
String statement = queryToString(query);
|
|
|
|
current_zookeeper->createOrUpdate(zookeeper_path + "/snapshot/" + table_name, statement, zkutil::CreateMode::Persistent);
|
|
|
|
}
|
2020-05-11 12:55:17 +00:00
|
|
|
}
|
2020-04-05 12:18:51 +00:00
|
|
|
|
2020-05-24 17:13:53 +00:00
|
|
|
void DatabaseReplicated::loadMetadataFromSnapshot() {
|
|
|
|
current_zookeeper = getZooKeeper();
|
|
|
|
|
|
|
|
Strings metadatas;
|
|
|
|
if (current_zookeeper->tryGetChildren(zookeeper_path + "/snapshot", metadatas) != Coordination::ZOK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (auto t = metadatas.begin(); t != metadatas.end(); ++t) {
|
|
|
|
String path = zookeeper_path + "/snapshot/" + *t;
|
|
|
|
executeFromZK(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-05 12:18:51 +00:00
|
|
|
}
|