fix symlinks, add short syntax of attach database

This commit is contained in:
Alexander Tokmakov 2020-07-06 11:30:11 +03:00
parent 383c583bdd
commit d1be5ec641
13 changed files with 83 additions and 31 deletions

View File

@ -114,7 +114,7 @@ void ClusterCopierApp::mainImpl()
registerDisks(); registerDisks();
static const std::string default_database = "_local"; static const std::string default_database = "_local";
DatabaseCatalog::instance().attachDatabase(default_database, std::make_shared<DatabaseMemory>(default_database, *context)); DatabaseCatalog::instance().attachDatabase(default_database, UUIDHelpers::Nil, std::make_shared<DatabaseMemory>(default_database, *context));
context->setCurrentDatabase(default_database); context->setCurrentDatabase(default_database);
/// Initialize query scope just in case. /// Initialize query scope just in case.

View File

@ -164,7 +164,7 @@ static void attachSystemTables(const Context & context)
{ {
/// TODO: add attachTableDelayed into DatabaseMemory to speedup loading /// TODO: add attachTableDelayed into DatabaseMemory to speedup loading
system_database = std::make_shared<DatabaseMemory>(DatabaseCatalog::SYSTEM_DATABASE, context); system_database = std::make_shared<DatabaseMemory>(DatabaseCatalog::SYSTEM_DATABASE, context);
DatabaseCatalog::instance().attachDatabase(DatabaseCatalog::SYSTEM_DATABASE, system_database); DatabaseCatalog::instance().attachDatabase(DatabaseCatalog::SYSTEM_DATABASE, UUIDHelpers::Nil, system_database);
} }
attachSystemTablesLocal(*system_database); attachSystemTablesLocal(*system_database);
@ -241,7 +241,7 @@ try
* if such tables will not be dropped, clickhouse-server will not be able to load them due to security reasons. * if such tables will not be dropped, clickhouse-server will not be able to load them due to security reasons.
*/ */
std::string default_database = config().getString("default_database", "_local"); std::string default_database = config().getString("default_database", "_local");
DatabaseCatalog::instance().attachDatabase(default_database, std::make_shared<DatabaseMemory>(default_database, *context)); DatabaseCatalog::instance().attachDatabase(default_database, UUIDHelpers::Nil, std::make_shared<DatabaseMemory>(default_database, *context));
context->setCurrentDatabase(default_database); context->setCurrentDatabase(default_database);
applyCmdOptions(); applyCmdOptions();

View File

@ -102,7 +102,6 @@ void DatabaseAtomic::attachTable(const String & name, const StoragePtr & table,
assertDetachedTableNotInUse(table->getStorageID().uuid); assertDetachedTableNotInUse(table->getStorageID().uuid);
DatabaseWithDictionaries::attachTableUnlocked(name, table, lock); DatabaseWithDictionaries::attachTableUnlocked(name, table, lock);
table_name_to_path.emplace(std::make_pair(name, relative_table_path)); table_name_to_path.emplace(std::make_pair(name, relative_table_path));
//tryCreateSymlink(name, relative_table_path);
} }
StoragePtr DatabaseAtomic::detachTable(const String & name) StoragePtr DatabaseAtomic::detachTable(const String & name)
@ -113,7 +112,6 @@ StoragePtr DatabaseAtomic::detachTable(const String & name)
table_name_to_path.erase(name); table_name_to_path.erase(name);
detached_tables.emplace(table->getStorageID().uuid, table); detached_tables.emplace(table->getStorageID().uuid, table);
not_in_use = cleenupDetachedTables(); not_in_use = cleenupDetachedTables();
//tryRemoveSymlink(name);
return table; return table;
} }
@ -360,7 +358,7 @@ void DatabaseAtomic::tryCreateSymlink(const String & table_name, const String &
} }
catch (...) catch (...)
{ {
tryLogCurrentException(log); LOG_WARNING(log, getCurrentExceptionMessage(true));
} }
} }
@ -373,7 +371,7 @@ void DatabaseAtomic::tryRemoveSymlink(const String & table_name)
} }
catch (...) catch (...)
{ {
tryLogCurrentException(log); LOG_WARNING(log, getCurrentExceptionMessage(true));
} }
} }

View File

@ -52,6 +52,9 @@ public:
UUID tryGetTableUUID(const String & table_name) const override; UUID tryGetTableUUID(const String & table_name) const override;
void tryCreateSymlink(const String & table_name, const String & actual_data_path);
void tryRemoveSymlink(const String & table_name);
private: private:
void commitAlterTable(const StorageID & table_id, const String & table_metadata_tmp_path, const String & table_metadata_path) override; void commitAlterTable(const StorageID & table_id, const String & table_metadata_tmp_path, const String & table_metadata_path) override;
void commitCreateTable(const ASTCreateQuery & query, const StoragePtr & table, void commitCreateTable(const ASTCreateQuery & query, const StoragePtr & table,
@ -61,9 +64,6 @@ private:
typedef std::unordered_map<UUID, StoragePtr> DetachedTables; typedef std::unordered_map<UUID, StoragePtr> DetachedTables;
[[nodiscard]] DetachedTables cleenupDetachedTables(); [[nodiscard]] DetachedTables cleenupDetachedTables();
void tryCreateSymlink(const String & table_name, const String & actual_data_path);
void tryRemoveSymlink(const String & table_name);
//TODO store path in DatabaseWithOwnTables::tables //TODO store path in DatabaseWithOwnTables::tables
typedef std::unordered_map<String, String> NameToPathMap; typedef std::unordered_map<String, String> NameToPathMap;
NameToPathMap table_name_to_path; NameToPathMap table_name_to_path;

View File

@ -20,6 +20,7 @@
#include <Databases/DatabaseOrdinary.h> #include <Databases/DatabaseOrdinary.h>
#include <Databases/DatabaseAtomic.h> #include <Databases/DatabaseAtomic.h>
#include <Common/assert_cast.h>
namespace DB namespace DB
@ -305,6 +306,14 @@ void DatabaseOnDisk::renameTable(
to_database.createTable(context, to_table_name, table, attach_query); to_database.createTable(context, to_table_name, table, attach_query);
Poco::File(table_metadata_path).remove(); Poco::File(table_metadata_path).remove();
/// Special case: usually no actions with symlinks are required when detaching/attaching table,
/// but not when moving from Atomic database to Ordinary
if (from_atomic_to_ordinary)
{
auto & atomic_db = assert_cast<DatabaseAtomic &>(*this);
atomic_db.tryRemoveSymlink(table_name);
}
} }
ASTPtr DatabaseOnDisk::getCreateTableQueryImpl(const String & table_name, const Context &, bool throw_on_error) const ASTPtr DatabaseOnDisk::getCreateTableQueryImpl(const String & table_name, const Context &, bool throw_on_error) const
@ -444,7 +453,8 @@ ASTPtr DatabaseOnDisk::parseQueryFromMetadata(Poco::Logger * logger, const Conte
*/ */
if (remove_empty && query.empty()) if (remove_empty && query.empty())
{ {
LOG_ERROR(logger, "File {} is empty. Removing.", metadata_file_path); if (logger)
LOG_ERROR(logger, "File {} is empty. Removing.", metadata_file_path);
Poco::File(metadata_file_path).remove(); Poco::File(metadata_file_path).remove();
return nullptr; return nullptr;
} }
@ -467,7 +477,7 @@ ASTPtr DatabaseOnDisk::parseQueryFromMetadata(Poco::Logger * logger, const Conte
String table_name = Poco::Path(metadata_file_path).makeFile().getBaseName(); String table_name = Poco::Path(metadata_file_path).makeFile().getBaseName();
table_name = unescapeForFileName(table_name); table_name = unescapeForFileName(table_name);
if (create.table != TABLE_WITH_UUID_NAME_PLACEHOLDER) if (create.table != TABLE_WITH_UUID_NAME_PLACEHOLDER && logger)
LOG_WARNING(logger, "File {} contains both UUID and table name. Will use name `{}` instead of `{}`", metadata_file_path, table_name, create.table); LOG_WARNING(logger, "File {} contains both UUID and table name. Will use name `{}` instead of `{}`", metadata_file_path, table_name, create.table);
create.table = table_name; create.table = table_name;
} }

View File

@ -114,7 +114,7 @@ void DatabaseCatalog::loadDatabases()
drop_delay_sec = global_context->getConfigRef().getInt("database_atomic_delay_before_drop_table_sec", default_drop_delay_sec); drop_delay_sec = global_context->getConfigRef().getInt("database_atomic_delay_before_drop_table_sec", default_drop_delay_sec);
auto db_for_temporary_and_external_tables = std::make_shared<DatabaseMemory>(TEMPORARY_DATABASE, *global_context); auto db_for_temporary_and_external_tables = std::make_shared<DatabaseMemory>(TEMPORARY_DATABASE, *global_context);
attachDatabase(TEMPORARY_DATABASE, db_for_temporary_and_external_tables); attachDatabase(TEMPORARY_DATABASE, UUIDHelpers::Nil, db_for_temporary_and_external_tables);
loadMarkedAsDroppedTables(); loadMarkedAsDroppedTables();
auto task_holder = global_context->getSchedulePool().createTask("DatabaseCatalog", [this](){ this->dropTableDataTask(); }); auto task_holder = global_context->getSchedulePool().createTask("DatabaseCatalog", [this](){ this->dropTableDataTask(); });
@ -147,6 +147,7 @@ void DatabaseCatalog::shutdownImpl()
std::lock_guard lock(databases_mutex); std::lock_guard lock(databases_mutex);
assert(std::find_if_not(uuid_map.begin(), uuid_map.end(), [](const auto & elem) { return elem.map.empty(); }) == uuid_map.end()); assert(std::find_if_not(uuid_map.begin(), uuid_map.end(), [](const auto & elem) { return elem.map.empty(); }) == uuid_map.end());
databases.clear(); databases.clear();
db_uuid_map.clear();
view_dependencies.clear(); view_dependencies.clear();
} }
@ -246,11 +247,13 @@ void DatabaseCatalog::assertDatabaseDoesntExistUnlocked(const String & database_
throw Exception("Database " + backQuoteIfNeed(database_name) + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS); throw Exception("Database " + backQuoteIfNeed(database_name) + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS);
} }
void DatabaseCatalog::attachDatabase(const String & database_name, const DatabasePtr & database) void DatabaseCatalog::attachDatabase(const String & database_name, const UUID & uuid, const DatabasePtr & database)
{ {
std::lock_guard lock{databases_mutex}; std::lock_guard lock{databases_mutex};
assertDatabaseDoesntExistUnlocked(database_name); assertDatabaseDoesntExistUnlocked(database_name);
databases[database_name] = database; databases.emplace(database_name, database);
if (uuid != UUIDHelpers::Nil)
db_uuid_map.emplace(uuid, database);
} }
@ -275,6 +278,7 @@ DatabasePtr DatabaseCatalog::detachDatabase(const String & database_name, bool d
database_atomic->assertCanBeDetached(false); database_atomic->assertCanBeDetached(false);
} }
db_uuid_map.erase(db->getUUID());
databases.erase(database_name); databases.erase(database_name);
} }
@ -312,6 +316,25 @@ DatabasePtr DatabaseCatalog::tryGetDatabase(const String & database_name) const
return it->second; return it->second;
} }
DatabasePtr DatabaseCatalog::getDatabase(const UUID & uuid) const
{
std::lock_guard lock{databases_mutex};
auto it = db_uuid_map.find(uuid);
if (it == db_uuid_map.end())
throw Exception(ErrorCodes::UNKNOWN_DATABASE, "Database UUID {} does not exist", toString(uuid));
return it->second;
}
DatabasePtr DatabaseCatalog::tryGetDatabase(const UUID & uuid) const
{
assert(uuid != UUIDHelpers::Nil);
std::lock_guard lock{databases_mutex};
auto it = db_uuid_map.find(uuid);
if (it == db_uuid_map.end())
return {};
return it->second;
}
bool DatabaseCatalog::isDatabaseExist(const String & database_name) const bool DatabaseCatalog::isDatabaseExist(const String & database_name) const
{ {
assert(!database_name.empty()); assert(!database_name.empty());

View File

@ -121,12 +121,14 @@ public:
DatabasePtr getDatabaseForTemporaryTables() const; DatabasePtr getDatabaseForTemporaryTables() const;
DatabasePtr getSystemDatabase() const; DatabasePtr getSystemDatabase() const;
void attachDatabase(const String & database_name, const DatabasePtr & database); void attachDatabase(const String & database_name, const UUID & uuid, const DatabasePtr & database);
DatabasePtr detachDatabase(const String & database_name, bool drop = false, bool check_empty = true); DatabasePtr detachDatabase(const String & database_name, bool drop = false, bool check_empty = true);
/// database_name must be not empty /// database_name must be not empty
DatabasePtr getDatabase(const String & database_name) const; DatabasePtr getDatabase(const String & database_name) const;
DatabasePtr tryGetDatabase(const String & database_name) const; DatabasePtr tryGetDatabase(const String & database_name) const;
DatabasePtr getDatabase(const UUID & uuid) const;
DatabasePtr tryGetDatabase(const UUID & uuid) const;
bool isDatabaseExist(const String & database_name) const; bool isDatabaseExist(const String & database_name) const;
Databases getDatabases() const; Databases getDatabases() const;
@ -211,6 +213,8 @@ private:
static constexpr size_t reschedule_time_ms = 100; static constexpr size_t reschedule_time_ms = 100;
private: private:
using UUIDToDatabaseMap = std::unordered_map<UUID, DatabasePtr>;
/// For some reason Context is required to get Storage from Database object /// For some reason Context is required to get Storage from Database object
Context * global_context; Context * global_context;
mutable std::mutex databases_mutex; mutable std::mutex databases_mutex;
@ -218,6 +222,7 @@ private:
ViewDependencies view_dependencies; ViewDependencies view_dependencies;
Databases databases; Databases databases;
UUIDToDatabaseMap db_uuid_map;
UUIDToStorageMap uuid_map; UUIDToStorageMap uuid_map;
Poco::Logger * log; Poco::Logger * log;

View File

@ -47,6 +47,7 @@
#include <Databases/DatabaseFactory.h> #include <Databases/DatabaseFactory.h>
#include <Databases/IDatabase.h> #include <Databases/IDatabase.h>
#include <Databases/DatabaseOnDisk.h>
#include <Dictionaries/getDictionaryConfigurationFromAST.h> #include <Dictionaries/getDictionaryConfigurationFromAST.h>
@ -87,6 +88,7 @@ InterpreterCreateQuery::InterpreterCreateQuery(const ASTPtr & query_ptr_, Contex
BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create) BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
{ {
String database_name = create.database; String database_name = create.database;
assert(database_name != TABLE_WITH_UUID_NAME_PLACEHOLDER);
auto guard = DatabaseCatalog::instance().getDDLGuard(database_name, ""); auto guard = DatabaseCatalog::instance().getDDLGuard(database_name, "");
@ -99,7 +101,26 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
throw Exception("Database " + database_name + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS); throw Exception("Database " + database_name + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS);
} }
if (!create.storage)
/// Will write file with database metadata, if needed.
String database_name_escaped = escapeForFileName(database_name);
fs::path metadata_path = fs::canonical(context.getPath());
fs::path metadata_file_tmp_path = metadata_path / "metadata" / (database_name_escaped + ".sql.tmp");
fs::path metadata_file_path = metadata_path / "metadata" / (database_name_escaped + ".sql");
if (!create.storage && create.attach)
{
if (!fs::exists(metadata_file_path))
throw Exception("Database engine must be specified for ATTACH DATABASE query", ErrorCodes::UNKNOWN_DATABASE_ENGINE);
/// Short syntax: try read database definition from file
auto ast = DatabaseOnDisk::parseQueryFromMetadata(nullptr, context, metadata_file_path);
create = ast->as<ASTCreateQuery &>();
if (!create.table.empty() || !create.storage)
throw Exception(ErrorCodes::INCORRECT_QUERY, "Metadata file {} contains incorrect CREATE DATABASE query", metadata_file_path);
create.attach = true;
create.attach_short_syntax = true;
}
else if (!create.storage)
{ {
/// For new-style databases engine is explicitly specified in .sql /// For new-style databases engine is explicitly specified in .sql
/// When attaching old-style database during server startup, we must always use Ordinary engine /// When attaching old-style database during server startup, we must always use Ordinary engine
@ -120,12 +141,6 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
throw Exception("Unknown database engine: " + ostr.str(), ErrorCodes::UNKNOWN_DATABASE_ENGINE); throw Exception("Unknown database engine: " + ostr.str(), ErrorCodes::UNKNOWN_DATABASE_ENGINE);
} }
/// Will write file with database metadata, if needed.
String database_name_escaped = escapeForFileName(database_name);
fs::path metadata_path = fs::canonical(context.getPath());
fs::path metadata_file_tmp_path = metadata_path / "metadata" / (database_name_escaped + ".sql.tmp");
fs::path metadata_file_path = metadata_path / "metadata" / (database_name_escaped + ".sql");
if (create.storage->engine->name == "Atomic") if (create.storage->engine->name == "Atomic")
{ {
if (!context.getSettingsRef().allow_experimental_database_atomic && !internal) if (!context.getSettingsRef().allow_experimental_database_atomic && !internal)
@ -152,7 +167,8 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
metadata_path = metadata_path / "metadata" / database_name_escaped; metadata_path = metadata_path / "metadata" / database_name_escaped;
} }
DatabasePtr database = DatabaseFactory::get(database_name, metadata_path, create.storage, create.uuid, context); // FIXME
DatabasePtr database = DatabaseFactory::get(database_name, metadata_path / "", create.storage, create.uuid, context);
bool need_write_metadata = !create.attach || !fs::exists(metadata_file_path); bool need_write_metadata = !create.attach || !fs::exists(metadata_file_path);
@ -181,7 +197,7 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
try try
{ {
/// TODO Attach db only after it was loaded. Now it's not possible because of view dependencies /// TODO Attach db only after it was loaded. Now it's not possible because of view dependencies
DatabaseCatalog::instance().attachDatabase(database_name, database); DatabaseCatalog::instance().attachDatabase(database_name, create.uuid, database);
added = true; added = true;
if (need_write_metadata) if (need_write_metadata)

View File

@ -156,7 +156,7 @@ void loadMetadataSystem(Context & context)
Poco::File(global_path + "metadata/" SYSTEM_DATABASE).createDirectories(); Poco::File(global_path + "metadata/" SYSTEM_DATABASE).createDirectories();
auto system_database = std::make_shared<DatabaseOrdinary>(SYSTEM_DATABASE, global_path + "metadata/" SYSTEM_DATABASE "/", context); auto system_database = std::make_shared<DatabaseOrdinary>(SYSTEM_DATABASE, global_path + "metadata/" SYSTEM_DATABASE "/", context);
DatabaseCatalog::instance().attachDatabase(SYSTEM_DATABASE, system_database); DatabaseCatalog::instance().attachDatabase(SYSTEM_DATABASE, UUIDHelpers::Nil, system_database);
} }
} }

View File

@ -1167,7 +1167,7 @@ TestResult check(const TestEntry & entry)
auto storage_distributed_hits = StorageDistributedFake::create("distant_db", "distant_hits", entry.shard_count); auto storage_distributed_hits = StorageDistributedFake::create("distant_db", "distant_hits", entry.shard_count);
DB::DatabasePtr database = std::make_shared<DB::DatabaseOrdinary>("test", "./metadata/test/", context); DB::DatabasePtr database = std::make_shared<DB::DatabaseOrdinary>("test", "./metadata/test/", context);
DB::DatabaseCatalog::instance().attachDatabase("test", database); DB::DatabaseCatalog::instance().attachDatabase("test", UUIDHelpers::Nil, database);
database->attachTable("visits_all", storage_distributed_visits); database->attachTable("visits_all", storage_distributed_visits);
database->attachTable("hits_all", storage_distributed_hits); database->attachTable("hits_all", storage_distributed_hits);
context.setCurrentDatabase("test"); context.setCurrentDatabase("test");

View File

@ -42,7 +42,7 @@ private:
registerFunctions(); registerFunctions();
DatabasePtr database = std::make_shared<DatabaseMemory>("test", context); DatabasePtr database = std::make_shared<DatabaseMemory>("test", context);
database->attachTable("table", StorageMemory::create(StorageID("test", "table"), ColumnsDescription{columns}, ConstraintsDescription{})); database->attachTable("table", StorageMemory::create(StorageID("test", "table"), ColumnsDescription{columns}, ConstraintsDescription{}));
DatabaseCatalog::instance().attachDatabase("test", database); DatabaseCatalog::instance().attachDatabase("test", UUIDHelpers::Nil, database);
context.setCurrentDatabase("test"); context.setCurrentDatabase("test");
} }
}; };

View File

@ -18,7 +18,7 @@ wait
$CLICKHOUSE_CLIENT -q "ATTACH TABLE test_01107.mt" $CLICKHOUSE_CLIENT -q "ATTACH TABLE test_01107.mt"
$CLICKHOUSE_CLIENT -q "SELECT count(n), sum(n) FROM test_01107.mt" $CLICKHOUSE_CLIENT -q "SELECT count(n), sum(n) FROM test_01107.mt"
$CLICKHOUSE_CLIENT -q "DETACH DATABASE test_01107" $CLICKHOUSE_CLIENT -q "DETACH DATABASE test_01107"
$CLICKHOUSE_CLIENT --allow_experimental_database_atomic=1 -q "ATTACH DATABASE test_01107 ENGINE=Atomic" $CLICKHOUSE_CLIENT --allow_experimental_database_atomic=1 -q "ATTACH DATABASE test_01107"
$CLICKHOUSE_CLIENT -q "SELECT count(n), sum(n) FROM test_01107.mt" $CLICKHOUSE_CLIENT -q "SELECT count(n), sum(n) FROM test_01107.mt"
$CLICKHOUSE_CLIENT -q "INSERT INTO test_01107.mt SELECT number + sleepEachRow(1) FROM numbers(5)" && echo "end" & $CLICKHOUSE_CLIENT -q "INSERT INTO test_01107.mt SELECT number + sleepEachRow(1) FROM numbers(5)" && echo "end" &

View File

@ -12,8 +12,8 @@ $CLICKHOUSE_CLIENT --allow_experimental_database_atomic=1 -q "CREATE DATABASE te
$CLICKHOUSE_CLIENT --default_database_engine=Atomic --allow_experimental_database_atomic=1 -q "CREATE DATABASE test_01114_2" $CLICKHOUSE_CLIENT --default_database_engine=Atomic --allow_experimental_database_atomic=1 -q "CREATE DATABASE test_01114_2"
$CLICKHOUSE_CLIENT --default_database_engine=Ordinary -q "CREATE DATABASE test_01114_3" $CLICKHOUSE_CLIENT --default_database_engine=Ordinary -q "CREATE DATABASE test_01114_3"
$CLICKHOUSE_CLIENT -q "SHOW CREATE DATABASE test_01114_1" $CLICKHOUSE_CLIENT --show_table_uuid_in_table_create_query_if_not_nil=0 -q "SHOW CREATE DATABASE test_01114_1"
$CLICKHOUSE_CLIENT -q "SHOW CREATE DATABASE test_01114_2" $CLICKHOUSE_CLIENT --show_table_uuid_in_table_create_query_if_not_nil=0 -q "SHOW CREATE DATABASE test_01114_2"
$CLICKHOUSE_CLIENT -q "SHOW CREATE DATABASE test_01114_3" $CLICKHOUSE_CLIENT -q "SHOW CREATE DATABASE test_01114_3"
$CLICKHOUSE_CLIENT -q "SELECT name, engine, splitByChar('/', data_path)[-2], splitByChar('/', metadata_path)[-3], splitByChar('/', metadata_path)[-2] FROM system.databases WHERE name LIKE 'test_01114_%'" $CLICKHOUSE_CLIENT -q "SELECT name, engine, splitByChar('/', data_path)[-2], splitByChar('/', metadata_path)[-3], splitByChar('/', metadata_path)[-2] FROM system.databases WHERE name LIKE 'test_01114_%'"