2021-08-18 22:19:14 +00:00
|
|
|
#include <Interpreters/InterpreterBackupQuery.h>
|
2022-04-25 14:33:25 +00:00
|
|
|
#include <Backups/BackupSettings.h>
|
|
|
|
#include <Backups/RestoreSettings.h>
|
2022-01-19 18:56:08 +00:00
|
|
|
#include <Backups/IBackup.h>
|
|
|
|
#include <Backups/IBackupEntry.h>
|
|
|
|
#include <Backups/IRestoreTask.h>
|
2021-08-18 22:19:14 +00:00
|
|
|
#include <Backups/BackupFactory.h>
|
|
|
|
#include <Backups/BackupUtils.h>
|
2022-04-20 07:38:12 +00:00
|
|
|
#include <Backups/BackupsWorker.h>
|
2022-01-19 18:56:08 +00:00
|
|
|
#include <Backups/RestoreUtils.h>
|
2021-08-18 22:19:14 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2022-04-19 18:15:27 +00:00
|
|
|
#include <Interpreters/executeDDLQueryOnCluster.h>
|
2022-04-20 07:38:12 +00:00
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
|
|
|
#include <DataTypes/DataTypeEnum.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
2022-04-19 18:15:27 +00:00
|
|
|
#include <Processors/Executors/PullingPipelineExecutor.h>
|
2022-04-20 07:38:12 +00:00
|
|
|
#include <Processors/Sources/SourceFromSingleChunk.h>
|
2022-04-19 18:15:27 +00:00
|
|
|
#include <base/logger_useful.h>
|
2021-08-18 22:19:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
{
|
2022-04-19 18:15:27 +00:00
|
|
|
BackupMutablePtr createBackup(const UUID & backup_uuid, const BackupInfo & backup_info, const BackupSettings & backup_settings, const ContextPtr & context)
|
2021-08-18 22:19:14 +00:00
|
|
|
{
|
2021-11-05 14:18:23 +00:00
|
|
|
BackupFactory::CreateParams params;
|
2022-01-28 17:33:35 +00:00
|
|
|
params.open_mode = IBackup::OpenMode::WRITE;
|
2021-11-05 14:18:23 +00:00
|
|
|
params.context = context;
|
2022-01-19 22:13:16 +00:00
|
|
|
params.backup_info = backup_info;
|
2022-01-31 06:35:07 +00:00
|
|
|
params.base_backup_info = backup_settings.base_backup_info;
|
2022-01-28 17:33:35 +00:00
|
|
|
params.compression_method = backup_settings.compression_method;
|
|
|
|
params.compression_level = backup_settings.compression_level;
|
|
|
|
params.password = backup_settings.password;
|
2022-04-19 18:15:27 +00:00
|
|
|
params.backup_uuid = backup_uuid;
|
|
|
|
params.is_internal_backup = backup_settings.internal;
|
|
|
|
params.coordination_zk_path = backup_settings.coordination_zk_path;
|
2022-01-28 17:33:35 +00:00
|
|
|
return BackupFactory::instance().createBackup(params);
|
|
|
|
}
|
|
|
|
|
|
|
|
BackupMutablePtr openBackup(const BackupInfo & backup_info, const RestoreSettings & restore_settings, const ContextPtr & context)
|
|
|
|
{
|
|
|
|
BackupFactory::CreateParams params;
|
|
|
|
params.open_mode = IBackup::OpenMode::READ;
|
|
|
|
params.context = context;
|
|
|
|
params.backup_info = backup_info;
|
2022-01-31 06:35:07 +00:00
|
|
|
params.base_backup_info = restore_settings.base_backup_info;
|
2022-01-28 17:33:35 +00:00
|
|
|
params.password = restore_settings.password;
|
2021-11-05 14:18:23 +00:00
|
|
|
return BackupFactory::instance().createBackup(params);
|
2021-08-18 22:19:14 +00:00
|
|
|
}
|
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
void executeBackupSync(const ASTBackupQuery & query, size_t task_id, const ContextPtr & context, const BackupInfo & backup_info, const BackupSettings & backup_settings, bool no_throw = false)
|
2021-08-18 22:19:14 +00:00
|
|
|
{
|
2022-04-20 07:38:12 +00:00
|
|
|
auto & worker = BackupsWorker::instance();
|
2022-04-19 18:15:27 +00:00
|
|
|
bool is_internal_backup = backup_settings.internal;
|
|
|
|
|
2022-04-20 07:38:12 +00:00
|
|
|
try
|
|
|
|
{
|
2022-04-19 18:15:27 +00:00
|
|
|
UUID backup_uuid = UUIDHelpers::generateV4();
|
|
|
|
|
|
|
|
auto new_backup_settings = backup_settings;
|
|
|
|
if (!query.cluster.empty() && backup_settings.coordination_zk_path.empty())
|
|
|
|
new_backup_settings.coordination_zk_path = query.cluster.empty() ? "" : ("/clickhouse/backups/backup-" + toString(backup_uuid));
|
|
|
|
std::shared_ptr<ASTBackupQuery> new_query = std::static_pointer_cast<ASTBackupQuery>(query.clone());
|
|
|
|
new_backup_settings.copySettingsToBackupQuery(*new_query);
|
|
|
|
|
|
|
|
BackupMutablePtr backup = createBackup(backup_uuid, backup_info, new_backup_settings, context);
|
|
|
|
|
|
|
|
if (!query.cluster.empty())
|
|
|
|
{
|
|
|
|
if (!is_internal_backup)
|
|
|
|
worker.update(task_id, BackupStatus::MAKING_BACKUP);
|
|
|
|
|
|
|
|
DDLQueryOnClusterParams params;
|
2022-04-25 10:54:13 +00:00
|
|
|
params.shard_index = new_backup_settings.shard_num;
|
|
|
|
params.replica_index = new_backup_settings.replica_num;
|
2022-04-19 18:15:27 +00:00
|
|
|
params.allow_multiple_replicas = new_backup_settings.allow_storing_multiple_replicas;
|
|
|
|
auto res = executeDDLQueryOnCluster(new_query, context, params);
|
|
|
|
|
|
|
|
PullingPipelineExecutor executor(res.pipeline);
|
|
|
|
Block block;
|
|
|
|
while (executor.pull(block));
|
|
|
|
|
|
|
|
backup->finalizeWriting();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto backup_entries = makeBackupEntries(context, new_query->elements, new_backup_settings);
|
|
|
|
|
|
|
|
if (!is_internal_backup)
|
|
|
|
worker.update(task_id, BackupStatus::MAKING_BACKUP);
|
|
|
|
|
|
|
|
writeBackupEntries(backup, std::move(backup_entries), context->getSettingsRef().max_backup_threads);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_internal_backup)
|
|
|
|
worker.update(task_id, BackupStatus::BACKUP_COMPLETE);
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2022-04-19 18:15:27 +00:00
|
|
|
if (!is_internal_backup)
|
|
|
|
worker.update(task_id, BackupStatus::FAILED_TO_BACKUP, getCurrentExceptionMessage(false));
|
2022-04-20 07:38:12 +00:00
|
|
|
if (!no_throw)
|
|
|
|
throw;
|
|
|
|
}
|
2021-08-18 22:19:14 +00:00
|
|
|
}
|
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
void executeRestoreSync(const ASTBackupQuery & query, size_t task_id, ContextMutablePtr context, const BackupInfo & backup_info, const RestoreSettings & restore_settings, bool no_throw = false)
|
2021-08-18 22:19:14 +00:00
|
|
|
{
|
2022-04-20 07:38:12 +00:00
|
|
|
auto & worker = BackupsWorker::instance();
|
2022-04-19 18:15:27 +00:00
|
|
|
bool is_internal_restore = restore_settings.internal;
|
|
|
|
|
2022-04-20 07:38:12 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
BackupPtr backup = openBackup(backup_info, restore_settings, context);
|
2022-04-19 18:15:27 +00:00
|
|
|
|
|
|
|
auto new_restore_settings = restore_settings;
|
|
|
|
if (!query.cluster.empty() && new_restore_settings.coordination_zk_path.empty())
|
|
|
|
{
|
|
|
|
UUID restore_uuid = UUIDHelpers::generateV4();
|
|
|
|
new_restore_settings.coordination_zk_path
|
|
|
|
= query.cluster.empty() ? "" : ("/clickhouse/backups/restore-" + toString(restore_uuid));
|
|
|
|
}
|
|
|
|
std::shared_ptr<ASTBackupQuery> new_query = std::static_pointer_cast<ASTBackupQuery>(query.clone());
|
|
|
|
new_restore_settings.copySettingsToRestoreQuery(*new_query);
|
|
|
|
|
|
|
|
if (!query.cluster.empty())
|
|
|
|
{
|
|
|
|
DDLQueryOnClusterParams params;
|
2022-04-25 10:54:13 +00:00
|
|
|
params.shard_index = new_restore_settings.shard_num;
|
|
|
|
params.replica_index = new_restore_settings.replica_num;
|
2022-04-19 18:15:27 +00:00
|
|
|
auto res = executeDDLQueryOnCluster(new_query, context, params);
|
|
|
|
|
|
|
|
PullingPipelineExecutor executor(res.pipeline);
|
|
|
|
Block block;
|
|
|
|
while (executor.pull(block));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto restore_tasks = makeRestoreTasks(context, backup, new_query->elements, new_restore_settings);
|
|
|
|
executeRestoreTasks(std::move(restore_tasks), context->getSettingsRef().max_backup_threads);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_internal_restore)
|
|
|
|
worker.update(task_id, BackupStatus::RESTORED);
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2022-04-19 18:15:27 +00:00
|
|
|
if (!is_internal_restore)
|
|
|
|
worker.update(task_id, BackupStatus::FAILED_TO_RESTORE, getCurrentExceptionMessage(false));
|
2022-04-20 07:38:12 +00:00
|
|
|
if (!no_throw)
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
size_t executeBackup(const ASTBackupQuery & query, const ContextPtr & context)
|
2022-04-20 07:38:12 +00:00
|
|
|
{
|
|
|
|
const auto backup_info = BackupInfo::fromAST(*query.backup_name);
|
|
|
|
const auto backup_settings = BackupSettings::fromBackupQuery(query);
|
|
|
|
|
2022-04-19 18:15:27 +00:00
|
|
|
size_t task_id = 0;
|
|
|
|
if (!backup_settings.internal)
|
|
|
|
task_id = BackupsWorker::instance().add(backup_info.toString(), BackupStatus::PREPARING);
|
|
|
|
|
2022-04-26 16:33:19 +00:00
|
|
|
if (backup_settings.async)
|
2022-04-20 07:38:12 +00:00
|
|
|
{
|
2022-04-26 16:33:19 +00:00
|
|
|
BackupsWorker::instance().run([query, task_id, context, backup_info, backup_settings]{ executeBackupSync(query, task_id, context, backup_info, backup_settings, /* no_throw = */ true); });
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-04-26 16:33:19 +00:00
|
|
|
executeBackupSync(query, task_id, context, backup_info, backup_settings, /* no_throw = */ false);
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
return task_id;
|
|
|
|
}
|
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
size_t executeRestore(const ASTBackupQuery & query, ContextMutablePtr context)
|
2022-04-20 07:38:12 +00:00
|
|
|
{
|
|
|
|
const auto backup_info = BackupInfo::fromAST(*query.backup_name);
|
|
|
|
const auto restore_settings = RestoreSettings::fromRestoreQuery(query);
|
2022-04-19 18:15:27 +00:00
|
|
|
|
|
|
|
size_t task_id = 0;
|
|
|
|
if (!restore_settings.internal)
|
|
|
|
task_id = BackupsWorker::instance().add(backup_info.toString(), BackupStatus::RESTORING);
|
2022-04-20 07:38:12 +00:00
|
|
|
|
2022-04-26 16:33:19 +00:00
|
|
|
if (restore_settings.async)
|
2022-04-20 07:38:12 +00:00
|
|
|
{
|
2022-04-26 16:33:19 +00:00
|
|
|
BackupsWorker::instance().run([query, task_id, context, backup_info, restore_settings]{ executeRestoreSync(query, task_id, context, backup_info, restore_settings, /* no_throw = */ true); });
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-04-26 16:33:19 +00:00
|
|
|
executeRestoreSync(query, task_id, context, backup_info, restore_settings, /* no_throw = */ false);
|
2022-04-20 07:38:12 +00:00
|
|
|
}
|
|
|
|
return task_id;
|
|
|
|
}
|
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
Block getResultRow(size_t task_id)
|
2022-04-20 07:38:12 +00:00
|
|
|
{
|
2022-04-19 18:15:27 +00:00
|
|
|
if (!task_id)
|
|
|
|
return {};
|
2022-04-20 07:38:12 +00:00
|
|
|
auto entry = BackupsWorker::instance().getEntry(task_id);
|
|
|
|
|
|
|
|
Block res_columns;
|
|
|
|
|
|
|
|
auto column_task_id = ColumnUInt64::create();
|
|
|
|
column_task_id->insert(task_id);
|
|
|
|
res_columns.insert(0, {std::move(column_task_id), std::make_shared<DataTypeUInt64>(), "task_id"});
|
|
|
|
|
|
|
|
auto column_backup_name = ColumnString::create();
|
|
|
|
column_backup_name->insert(entry.backup_name);
|
|
|
|
res_columns.insert(1, {std::move(column_backup_name), std::make_shared<DataTypeString>(), "backup_name"});
|
|
|
|
|
|
|
|
auto column_status = ColumnInt8::create();
|
|
|
|
column_status->insert(static_cast<Int8>(entry.status));
|
|
|
|
res_columns.insert(2, {std::move(column_status), std::make_shared<DataTypeEnum8>(getBackupStatusEnumValues()), "status"});
|
|
|
|
|
|
|
|
return res_columns;
|
2021-08-18 22:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BlockIO InterpreterBackupQuery::execute()
|
|
|
|
{
|
|
|
|
const auto & query = query_ptr->as<const ASTBackupQuery &>();
|
2022-04-19 18:15:27 +00:00
|
|
|
|
2022-04-25 14:33:25 +00:00
|
|
|
size_t task_id;
|
2021-08-18 22:19:14 +00:00
|
|
|
if (query.kind == ASTBackupQuery::BACKUP)
|
2022-04-19 18:15:27 +00:00
|
|
|
task_id = executeBackup(query, context);
|
2022-04-20 07:38:12 +00:00
|
|
|
else
|
2022-04-19 18:15:27 +00:00
|
|
|
task_id = executeRestore(query, context);
|
2022-04-20 07:38:12 +00:00
|
|
|
|
|
|
|
BlockIO res_io;
|
|
|
|
res_io.pipeline = QueryPipeline(std::make_shared<SourceFromSingleChunk>(getResultRow(task_id)));
|
|
|
|
return res_io;
|
2021-08-18 22:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|