Initializing the Lock Table
Relevant source files
The following files were used as context for generating this wiki page:
- src/main/java/liquibase/ext/clickhouse/sqlgenerator/InitializeDatabaseChangeLogLockClickHouse.java
- src/main/java/liquibase/ext/clickhouse/sqlgenerator/CreateDatabaseChangeLogLockTableClickHouse.java
- src/main/java/liquibase/ext/clickhouse/lockservice/ClickHouseLockService.java
- src/main/java/liquibase/ext/clickhouse/sqlgenerator/SqlGeneratorUtil.java
- src/main/java/liquibase/ext/clickhouse/database/ClickHouseDatabase.java
- src/main/java/liquibase/ext/clickhouse/params/ParamsLoader.java
The initialization of the Database Change Log Lock table in the Liquibase ClickHouse extension ensures that the synchronization mechanism is properly set up before any schema migrations occur. This process involves creating the lock table structure, verifying its state, and inserting the initial seed record required for Liquibase's locking logic.
In ClickHouse, this initialization is specialized to handle specific engine requirements (such as MergeTree or ReplicatedMergeTree) and cluster-wide execution using the ON CLUSTER clause when configured. This ensures that the lock state is consistent across a distributed ClickHouse environment.
Architecture and Workflow
The lock initialization process is managed through a combination of a specialized LockService and specific SqlGenerator implementations. The ClickHouseLockService determines if initialization is necessary by checking for the existence of the table and the presence of the control row.
Initialization Flow
The following diagram illustrates the logical flow from checking the table status to executing the initialization SQL:
The ClickHouseLockService uses a standard query to check the row count in the lock table to determine if it has been initialized. If nbRows > 0, the table is considered initialized.
Sources: ClickHouseLockService.java:51-61, InitializeDatabaseChangeLogLockClickHouse.java:54-68
Lock Table Schema
The lock table is created with specific data types compatible with ClickHouse. The schema includes fields to track the lock status, the timestamp of the lock, and the identity of the process holding the lock.
| Column | ClickHouse Type | Description |
|---|---|---|
ID | Int64 | Primary identifier for the lock record (usually 1). |
LOCKED | UInt8 | Boolean flag (0 or 1) indicating if a lock is active. |
LOCKGRANTED | Nullable(DateTime64) | The timestamp when the lock was acquired. |
LOCKEDBY | Nullable(String) | Information about the host/process holding the lock. |
Sources: CreateDatabaseChangeLogLockTableClickHouse.java:56-61
Implementation Details
Table Creation Logic
The CreateDatabaseChangeLogLockTableClickHouse class generates the CREATE TABLE IF NOT EXISTS statement. It dynamically determines the table engine based on whether a cluster configuration is present via ParamsLoader.
- Single Instance: Uses
ENGINE MergeTree() ORDER BY ID. - Cluster Mode: Uses
ENGINE ReplicatedMergeTree(...) ORDER BY IDand appends theON CLUSTERclause.
Sources: CreateDatabaseChangeLogLockTableClickHouse.java:50-65, SqlGeneratorUtil.java:46-56
Seed Data Insertion
The InitializeDatabaseChangeLogLockClickHouse generator performs a two-step process to ensure a clean state:
- Cleanup: It issues an
ALTER TABLE ... DELETE WHERE 1withmutations_sync = 1to clear any stale records. - Insertion: It inserts the base record:
INSERT INTO ... (ID, LOCKED) VALUES (1, 0).
String clearDatabaseQuery =
String.format(
"ALTER TABLE `%s`.%s "
+ SqlGeneratorUtil.generateSqlOnClusterClause(properties)
+ "DELETE WHERE 1 SETTINGS mutations_sync = 1",
database.getDefaultSchemaName(),
database.getDatabaseChangeLogLockTableName());
String initLockQuery =
String.format(
"INSERT INTO `%s`.%s (ID, LOCKED) VALUES (1, 0)",
database.getDefaultSchemaName(), database.getDatabaseChangeLogLockTableName());
Sources: InitializeDatabaseChangeLogLockClickHouse.java:54-68
Cluster Configuration
When operating in a cluster, the extension retrieves parameters from liquibaseClickhouse.conf. These parameters influence how the lock table is initialized across the nodes.
| Parameter | Source | Usage in Lock Table |
|---|---|---|
clusterName | ClusterConfig | Used in ON CLUSTER '{clusterName}' clause. |
tableZooKeeperPathPrefix | ClusterConfig | Used for ReplicatedMergeTree ZK path. |
tableReplicaName | ClusterConfig | Used for ReplicatedMergeTree replica identification. |
Sources: ParamsLoader.java:83-100, ClusterConfig.java:23-28, SqlGeneratorUtil.java:41-44
Conclusion
Initializing the lock table in Liquibase ClickHouse is a critical prerequisite for safe database migrations. By leveraging specialized SQL generators, the extension ensures that the DATABASECHANGELOGLOCK table is created with the appropriate ClickHouse engine and seeded with a default unlocked record, supporting both standalone and clustered ClickHouse deployments.