Merge pull request #30658 from ClickHouse/std_mutex_alter_lock

Change `alter_lock` from `RWLock` to `std::timed_mutex`
This commit is contained in:
alesapin 2021-10-27 11:14:11 +03:00 committed by GitHub
commit 2af950d4d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 39 additions and 37 deletions

View File

@ -76,7 +76,8 @@ BlockIO InterpreterAlterQuery::executeToTable(const ASTAlterQuery & alter)
StoragePtr table = DatabaseCatalog::instance().getTable(table_id, getContext());
if (table->isStaticStorage())
throw Exception(ErrorCodes::TABLE_IS_READ_ONLY, "Table is read-only");
auto alter_lock = table->lockForAlter(getContext()->getCurrentQueryId(), getContext()->getSettingsRef().lock_acquire_timeout);
auto table_lock = table->lockForShare(getContext()->getCurrentQueryId(), getContext()->getSettingsRef().lock_acquire_timeout);
auto alter_lock = table->lockForAlter(getContext()->getSettingsRef().lock_acquire_timeout);
auto metadata_snapshot = table->getInMemoryMetadataPtr();
/// Add default database to table identifiers that we can encounter in e.g. default expressions, mutation expression, etc.

View File

@ -60,27 +60,31 @@ TableLockHolder IStorage::lockForShare(const String & query_id, const std::chron
return result;
}
TableLockHolder IStorage::lockForAlter(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
IStorage::AlterLockHolder IStorage::lockForAlter(const std::chrono::milliseconds & acquire_timeout)
{
TableLockHolder result = tryLockTimed(alter_lock, RWLockImpl::Write, query_id, acquire_timeout);
AlterLockHolder lock{alter_lock, std::defer_lock};
if (!lock.try_lock_for(acquire_timeout))
throw Exception(ErrorCodes::DEADLOCK_AVOIDED,
"Locking attempt for ALTER on \"{}\" has timed out! ({} ms) "
"Possible deadlock avoided. Client should retry.",
getStorageID().getFullTableName(), std::to_string(acquire_timeout.count()));
if (is_dropped)
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);
return result;
return lock;
}
TableExclusiveLockHolder IStorage::lockExclusively(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
{
TableExclusiveLockHolder result;
result.alter_lock = tryLockTimed(alter_lock, RWLockImpl::Write, query_id, acquire_timeout);
result.drop_lock = tryLockTimed(drop_lock, RWLockImpl::Write, query_id, acquire_timeout);
if (is_dropped)
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);
result.drop_lock = tryLockTimed(drop_lock, RWLockImpl::Write, query_id, acquire_timeout);
return result;
}
@ -126,7 +130,7 @@ Pipe IStorage::alterPartition(
throw Exception("Partition operations are not supported by storage " + getName(), ErrorCodes::NOT_IMPLEMENTED);
}
void IStorage::alter(const AlterCommands & params, ContextPtr context, TableLockHolder &)
void IStorage::alter(const AlterCommands & params, ContextPtr context, AlterLockHolder &)
{
auto table_id = getStorageID();
StorageInMemoryMetadata new_metadata = getInMemoryMetadata();

View File

@ -238,7 +238,8 @@ public:
/// Lock table for alter. This lock must be acuqired in ALTER queries to be
/// sure, that we execute only one simultaneous alter. Doesn't affect share lock.
TableLockHolder lockForAlter(const String & query_id, const std::chrono::milliseconds & acquire_timeout);
using AlterLockHolder = std::unique_lock<std::timed_mutex>;
AlterLockHolder lockForAlter(const std::chrono::milliseconds & acquire_timeout);
/// Lock table exclusively. This lock must be acquired if you want to be
/// sure, that no other thread (SELECT, merge, ALTER, etc.) doing something
@ -417,7 +418,7 @@ public:
/** ALTER tables in the form of column changes that do not affect the change
* to Storage or its parameters. Executes under alter lock (lockForAlter).
*/
virtual void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & alter_lock_holder);
virtual void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & alter_lock_holder);
/** Checks that alter commands can be applied to storage. For example, columns can be modified,
* or primary key can be changes, etc.
@ -596,12 +597,9 @@ public:
virtual bool dropTableImmediately() { return false; }
private:
/// Lock required for alter queries (lockForAlter). Always taken for write
/// (actually can be replaced with std::mutex, but for consistency we use
/// RWLock). Allows to execute only one simultaneous alter query. Also it
/// should be taken by DROP-like queries, to be sure, that all alters are
/// finished.
mutable RWLock alter_lock = RWLockImpl::create();
/// Lock required for alter queries (lockForAlter).
/// Allows to execute only one simultaneous alter query.
mutable std::timed_mutex alter_lock;
/// Lock required for drop queries. Every thread that want to ensure, that
/// table is not dropped have to table this lock for read (lockForShare).

View File

@ -2211,7 +2211,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeData::createPart(
void MergeTreeData::changeSettings(
const ASTPtr & new_settings,
TableLockHolder & /* table_lock_holder */)
AlterLockHolder & /* table_lock_holder */)
{
if (new_settings)
{

View File

@ -583,7 +583,7 @@ public:
/// Change MergeTreeSettings
void changeSettings(
const ASTPtr & new_settings,
TableLockHolder & table_lock_holder);
AlterLockHolder & table_lock_holder);
/// Should be called if part data is suspected to be corrupted.
void reportBrokenPart(const String & name) const

View File

@ -1066,7 +1066,7 @@ std::optional<UInt64> StorageBuffer::totalBytes(const Settings & /*settings*/) c
return total_writes.bytes;
}
void StorageBuffer::alter(const AlterCommands & params, ContextPtr local_context, TableLockHolder &)
void StorageBuffer::alter(const AlterCommands & params, ContextPtr local_context, AlterLockHolder &)
{
auto table_id = getStorageID();
checkAlterIsPossible(params, local_context);

View File

@ -107,7 +107,7 @@ public:
void checkAlterIsPossible(const AlterCommands & commands, ContextPtr context) const override;
/// The structure of the subordinate table is not checked and does not change.
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & table_lock_holder) override;
std::optional<UInt64> totalRows(const Settings & settings) const override;
std::optional<UInt64> totalBytes(const Settings & settings) const override;

View File

@ -785,7 +785,7 @@ void StorageDistributed::checkAlterIsPossible(const AlterCommands & commands, Co
}
}
void StorageDistributed::alter(const AlterCommands & params, ContextPtr local_context, TableLockHolder &)
void StorageDistributed::alter(const AlterCommands & params, ContextPtr local_context, AlterLockHolder &)
{
auto table_id = getStorageID();

View File

@ -94,7 +94,7 @@ public:
/// in the sub-tables, you need to manually add and delete columns
/// the structure of the sub-table is not checked
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & table_lock_holder) override;
void startup() override;
void shutdown() override;

View File

@ -274,7 +274,7 @@ bool StorageMaterializedView::optimize(
void StorageMaterializedView::alter(
const AlterCommands & params,
ContextPtr local_context,
TableLockHolder &)
AlterLockHolder &)
{
auto table_id = getStorageID();
StorageInMemoryMetadata new_metadata = getInMemoryMetadata();

View File

@ -50,7 +50,7 @@ public:
const Names & deduplicate_by_columns,
ContextPtr context) override;
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & table_lock_holder) override;
void checkMutationIsPossible(const MutationCommands & commands, const Settings & settings) const override;

View File

@ -651,7 +651,7 @@ void StorageMerge::checkAlterIsPossible(const AlterCommands & commands, ContextP
}
void StorageMerge::alter(
const AlterCommands & params, ContextPtr local_context, TableLockHolder &)
const AlterCommands & params, ContextPtr local_context, AlterLockHolder &)
{
auto table_id = getStorageID();

View File

@ -43,7 +43,7 @@ public:
/// you need to add and remove columns in the sub-tables manually
/// the structure of sub-tables is not checked
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & table_lock_holder) override;
bool mayBenefitFromIndexForIn(
const ASTPtr & left_in_operand, ContextPtr query_context, const StorageMetadataPtr & metadata_snapshot) const override;

View File

@ -271,7 +271,7 @@ void StorageMergeTree::truncate(const ASTPtr &, const StorageMetadataPtr &, Cont
void StorageMergeTree::alter(
const AlterCommands & commands,
ContextPtr local_context,
TableLockHolder & table_lock_holder)
AlterLockHolder & table_lock_holder)
{
auto table_id = getStorageID();
auto old_storage_settings = getSettings();

View File

@ -86,7 +86,7 @@ public:
void drop() override;
void truncate(const ASTPtr &, const StorageMetadataPtr &, ContextPtr, TableExclusiveLockHolder &) override;
void alter(const AlterCommands & commands, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & commands, ContextPtr context, AlterLockHolder & table_lock_holder) override;
void checkTableCanBeDropped() const override;

View File

@ -64,7 +64,7 @@ void StorageNull::checkAlterIsPossible(const AlterCommands & commands, ContextPt
}
void StorageNull::alter(const AlterCommands & params, ContextPtr context, TableLockHolder &)
void StorageNull::alter(const AlterCommands & params, ContextPtr context, AlterLockHolder &)
{
auto table_id = getStorageID();

View File

@ -43,7 +43,7 @@ public:
void checkAlterIsPossible(const AlterCommands & commands, ContextPtr context) const override;
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & table_lock_holder) override;
std::optional<UInt64> totalRows(const Settings &) const override
{

View File

@ -91,7 +91,7 @@ public:
IStorage::renameInMemory(new_table_id);
}
void alter(const AlterCommands & params, ContextPtr context, TableLockHolder & alter_lock_holder) override
void alter(const AlterCommands & params, ContextPtr context, AlterLockHolder & alter_lock_holder) override
{
getNested()->alter(params, context, alter_lock_holder);
IStorage::setInMemoryMetadata(getNested()->getInMemoryMetadata());

View File

@ -4355,7 +4355,8 @@ bool StorageReplicatedMergeTree::executeMetadataAlter(const StorageReplicatedMer
zookeeper->multi(requests);
{
auto lock = lockForAlter(RWLockImpl::NO_QUERY, getSettings()->lock_acquire_timeout_for_background_operations);
auto table_lock_holder = lockForShare(RWLockImpl::NO_QUERY, getSettings()->lock_acquire_timeout_for_background_operations);
auto alter_lock_holder = lockForAlter(getSettings()->lock_acquire_timeout_for_background_operations);
LOG_INFO(log, "Metadata changed in ZooKeeper. Applying changes locally.");
auto metadata_diff = ReplicatedMergeTreeTableMetadata(*this, getInMemoryMetadataPtr()).checkAndFindDiff(metadata_from_entry);
@ -4427,7 +4428,7 @@ PartitionBlockNumbersHolder StorageReplicatedMergeTree::allocateBlockNumbersInAf
void StorageReplicatedMergeTree::alter(
const AlterCommands & commands, ContextPtr query_context, TableLockHolder & table_lock_holder)
const AlterCommands & commands, ContextPtr query_context, AlterLockHolder & table_lock_holder)
{
assertNotReadonly();
@ -4632,7 +4633,7 @@ void StorageReplicatedMergeTree::alter(
}
}
table_lock_holder.reset();
table_lock_holder.unlock();
LOG_DEBUG(log, "Updated shared metadata nodes in ZooKeeper. Waiting for replicas to apply changes.");
waitForLogEntryToBeProcessedIfNecessary(*alter_entry, query_context, "Some replicas doesn't finish metadata alter: ");

View File

@ -129,7 +129,7 @@ public:
const Names & deduplicate_by_columns,
ContextPtr query_context) override;
void alter(const AlterCommands & commands, ContextPtr query_context, TableLockHolder & table_lock_holder) override;
void alter(const AlterCommands & commands, ContextPtr query_context, AlterLockHolder & table_lock_holder) override;
void mutate(const MutationCommands & commands, ContextPtr context) override;
void waitMutation(const String & znode_name, size_t mutations_sync) const;

View File

@ -16,8 +16,6 @@ struct TableExclusiveLockHolder
private:
friend class IStorage;
/// Order is important.
TableLockHolder alter_lock;
TableLockHolder drop_lock;
};