[Clickhouse研究]: Clickhouse的同步锁

Clickhouse的存储锁

源码解析

代码主要在IStorage之中

1
2
3
4
5
6
7
8
class IStorage 
{
TableLockHolder lockForShare;
TableLockHolder lockForAlter;
TableExclusiveLockHolder lockExclusively;
mutable RWLock alter_lock;
mutable RWLock drop_lock;
}

从代码的定义上来, 只有drop和alter相关的才会加锁

排它锁lockExclusively的锁同时锁住alter_lockdrop_lock, 锁类型为写锁

1
2
3
4
5
6
7
8
9
10
11
12
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);

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;
}

排它锁只有很少的地方用到
image-20220228152910967

  1. 在renameTable时候用到
  2. 在DropTable的时候用到
  3. 在restartReplica时候用到

修改锁lockForAlter只锁了alter, 锁类型为写锁

1
2
3
4
5
6
7
8
9
TableLockHolder IStorage::lockForAlter(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
{
TableLockHolder result = tryLockTimed(alter_lock, RWLockImpl::Write, query_id, acquire_timeout);

if (is_dropped)
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);

return result;
}

都只在修改DDL时候用到: DDL语句执行和复制表的同步DDL时
image-20220228152931062

共享锁lockForShare的锁加入在drop_lock之中, 锁类型为读锁

1
2
3
4
5
6
7
8
9
TableLockHolder IStorage::lockForShare(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
{
TableLockHolder result = tryLockTimed(drop_lock, RWLockImpl::Read, query_id, acquire_timeout);

if (is_dropped)
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);

return result;
}

共享锁调用的地方非常多, 常见的Insert语句也是排它锁.

根据代码推论:

  1. 插入过程之中删除插入表, 删除动作会等待插入完成再执行
  2. 插入过程之中修改插入表, 表结构能够修改成功
  3. Insert语句锁住整个query执行时间

测试验证

建表语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CREATE TABLE `lineorder_local`
(
LO_ORDERKEY UInt32,
LO_LINENUMBER UInt8,
LO_CUSTKEY UInt32,
LO_PARTKEY UInt32,
LO_SUPPKEY UInt32,
LO_ORDERDATE Date,
LO_ORDERPRIORITY LowCardinality(String),
LO_SHIPPRIORITY UInt8,
LO_QUANTITY UInt8,
LO_EXTENDEDPRICE UInt32,
LO_ORDTOTALPRICE UInt32,
LO_DISCOUNT UInt8,
LO_REVENUE UInt32,
LO_SUPPLYCOST UInt32,
LO_TAX UInt8,
LO_COMMITDATE Date,
LO_SHIPMODE LowCardinality(String)
)
ENGINE = MergeTree
PARTITION BY toYear(LO_ORDERDATE)
ORDER BY (LO_ORDERDATE, LO_ORDERKEY);

插入语句

1
./clickhouse-client  --query "INSERT INTO hzw.lineorder_local FORMAT CSV" < lineorder.tbl

插入过程之中删除插入表

删除表语句

1
drop table lineorder_local;

image-20220228152954941

出现无法获取锁的问题

插入过程之中修改插入表

修改表语句

1
alter table lineorder_local drop column LO_QUANTITY;

执行后, 会立马成功
image-20220228153018786

由于乱序执行, 测试一个更加夸张的例子

1
alter table lineorder_local delete where 1=1;

image-20220228153033588
这里alter立马会成功, 数据会删除, 但是insert还在继续.